Current News
Archived News
Search News
Discussion Forum


Old Forum
Install Programs More Downloads...
Troubleshooting
Source Code
Format Specs.
Misc. Information
Non-SF Stuff
Links




ad088c319e89fece14c816c56aeabfb77b8755ed
1 #include "grpapi.h"
2 #include "../LoadStorm/storm.h"
3 #include <malloc.h>
5 #ifdef GRPAPI_STATIC
6 #define DllMain GrpMain
8 #include "grp_static.h"
10 struct GRPLIBMODULE {
11         GRPLIBMODULE();
12         ~GRPLIBMODULE();
13 } GrpLib;
15 BOOL APIENTRY DllMain(HINSTANCE hInstDLL, DWORD  ul_reason_for_call, LPVOID lpReserved);
17 GRPLIBMODULE::GRPLIBMODULE()
18 {
19         GrpMain(0,DLL_PROCESS_ATTACH,0);
20 }
22 GRPLIBMODULE::~GRPLIBMODULE()
23 {
24         GrpMain(0,DLL_PROCESS_DETACH,0);
25 }
27 #endif
29 typedef struct {
30         BYTE Left;
31         BYTE Top;
32         BYTE Width;
33         BYTE Height;
34         DWORD Offset;
35 } FRAMEHEADER;
37 typedef struct {
38         WORD *lpRowOffsets;
39         WORD *lpRowSizes;
40         LPBYTE *lpRowData;
41         DWORD Size;
42 } FRAMEDATA;
44 GETPIXELPROC MyGetPixel = GetPixel;
45 SETPIXELPROC MySetPixel = (SETPIXELPROC)SetPixelV;
47 void __inline SetPix(HDC hDC, int X, int Y, COLORREF clrColor, DWORD *dwPalette, DWORD dwFlags, DWORD dwAlpha);
48 void EncodeFrameData(signed short *lpImageData, WORD nFrame, GRPHEADER *lpGrpHeader, FRAMEHEADER *lpFrameHeader, FRAMEDATA *lpFrameData, BOOL bNoCompress);
49 BOOL VerifyRow(signed short *lpRawRow, int nWidth, LPBYTE lpEncRow, int nSize, BOOL bNoCompress);
51 extern HINSTANCE hStorm;
53 BOOL APIENTRY DllMain( HINSTANCE hInstDLL, 
54                        DWORD  ul_reason_for_call, 
55                        LPVOID lpReserved
56                                          )
57 {
58     switch (ul_reason_for_call)
59         {
60                 case DLL_PROCESS_ATTACH:
61                         break;
62                 case DLL_THREAD_ATTACH:
63                         break;
64                 case DLL_THREAD_DETACH:
65                         break;
66                 case DLL_PROCESS_DETACH:
67                         break;
68     }
70     return TRUE;
71 }
73 BOOL GRPAPI WINAPI LoadGrpApi()
74 {
75         if (!hStorm) return FALSE;
76         else return TRUE;
77 }
79 void GRPAPI WINAPI FreeGrpApi()
80 {
81 }
83 /*
84 HANDLE hProcessHeap = NULL;
86 void * SFAlloc(size_t nSize)
87 {
88         if (!hProcessHeap) hProcessHeap = GetProcessHeap();
89         if (hProcessHeap) return HeapAlloc(hProcessHeap, 0, nSize);
90         else return NULL;
91 }
93 void SFFree(void *lpMem)
94 {
95         if (!hProcessHeap) hProcessHeap = GetProcessHeap();
96         if (hProcessHeap) HeapFree(hProcessHeap, 0, lpMem);
97 }
98 */
100 BOOL GRPAPI WINAPI SetMpqDll(LPCSTR lpDllFileName)
102         if (LoadStorm((char *)lpDllFileName)) return TRUE;
103         else return FALSE;
106 BOOL GRPAPI WINAPI LoadPalette(LPCSTR lpFileName, DWORD *dwPaletteBuffer)
108         if (!lpFileName || !dwPaletteBuffer) return FALSE;
109         HANDLE hFile;
110         if (SFileOpenFileEx && SFileGetFileSize
111          && SFileSetFilePointer && SFileReadFile
112          && SFileCloseFile) {
113                 if (!SFileOpenFileEx(0,lpFileName,1,&hFile)) return FALSE;
114                 DWORD fsz = SFileGetFileSize(hFile,0);
115                 SFileSetFilePointer(hFile,0,0,FILE_BEGIN);
116                 if (fsz>=1024) {
117                         memset(dwPaletteBuffer,0,1024);
118                         SFileReadFile(hFile,dwPaletteBuffer,1024,0,0);
119                 }
120                 else if (fsz==768) {
121                         char *buffer = (char *)_alloca(768);
122                         memset(buffer,0,768);
123                         SFileReadFile(hFile,buffer,768,0,0);
124                         for (DWORD i=0;i<256;i++) {
125                                 memcpy(&dwPaletteBuffer[i],buffer+i*3,3);
126                                 *(((char *)&dwPaletteBuffer[i])+3) = 0;
127                         }
128                 }
129                 else {
130                         memset(dwPaletteBuffer,0,1024);
131                         SFileReadFile(hFile,dwPaletteBuffer,fsz,0,0);
132                 }
133                 SFileCloseFile(hFile);
134         }
135         else {
136                 hFile = CreateFile(lpFileName,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
137                 if (hFile==INVALID_HANDLE_VALUE) return FALSE;
138                 DWORD fsz = GetFileSize(hFile,0),tsz;
139                 SetFilePointer(hFile,0,0,FILE_BEGIN);
140                 if (fsz>=1024) {
141                         memset(dwPaletteBuffer,0,1024);
142                         ReadFile(hFile,dwPaletteBuffer,1024,&tsz,0);
143                 }
144                 else if (fsz==768) {
145                         char *buffer = (char *)_alloca(768);
146                         memset(buffer,0,768);
147                         ReadFile(hFile,buffer,768,&tsz,0);
148                         for (DWORD i=0;i<256;i++) {
149                                 memcpy(&dwPaletteBuffer[i],buffer+i*3,3);
150                                 *(((char *)&dwPaletteBuffer[i])+3) = 0;
151                         }
152                 }
153                 else {
154                         memset(dwPaletteBuffer,0,1024);
155                         ReadFile(hFile,dwPaletteBuffer,fsz,&tsz,0);
156                 }
157                 CloseHandle(hFile);
158         }
159         return TRUE;
162 HANDLE GRPAPI WINAPI LoadGrp(LPCSTR lpFileName)
164         if (!lpFileName) return (HANDLE)-1;
165         HANDLE hFile;
166         char *GrpFile;
167         if (SFileOpenFileEx && SFileGetFileSize
168          && SFileSetFilePointer && SFileReadFile
169          && SFileCloseFile) {
170                 if (!SFileOpenFileEx(0,lpFileName,1,&hFile)) return (HANDLE)-1;
171                 DWORD fsz = SFileGetFileSize(hFile,0);
172                 if (fsz<6) {
173                         SFileCloseFile(hFile);
174                         return (HANDLE)-1;
175                 }
176                 GrpFile = (char *)malloc(fsz);
177                 if (GrpFile) {
178                         SFileSetFilePointer(hFile,0,0,FILE_BEGIN);
179                         SFileReadFile(hFile,GrpFile,fsz,0,0);
180                 }
181                 else GrpFile=(char *)-1;
182                 SFileCloseFile(hFile);
183         }
184         else {
185                 hFile = CreateFile(lpFileName,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
186                 if (hFile==INVALID_HANDLE_VALUE) return (HANDLE)-1;
187                 DWORD fsz = GetFileSize(hFile,0),tsz;
188                 if (fsz<6) {
189                         CloseHandle(hFile);
190                         return (HANDLE)-1;
191                 }
192                 GrpFile = (char *)malloc(fsz);
193                 if (GrpFile) {
194                         SetFilePointer(hFile,0,0,FILE_BEGIN);
195                         ReadFile(hFile,GrpFile,fsz,&tsz,0);
196                 }
197                 else GrpFile=(char *)-1;
198                 CloseHandle(hFile);
199         }
200         return (HANDLE)GrpFile;
203 BOOL GRPAPI WINAPI DestroyGrp(HANDLE hGrp)
205         if (!hGrp || hGrp==INVALID_HANDLE_VALUE) return FALSE;
206         free(hGrp);
207         return TRUE;
210 BOOL GRPAPI WINAPI DrawGrp(HANDLE hGrp, HDC hdcDest, int nXDest, int nYDest, WORD nFrame, DWORD *dwPalette, DWORD dwFlags, DWORD dwAlpha)
212         if (!hGrp || hGrp==INVALID_HANDLE_VALUE || hdcDest==0 || (!dwPalette && !(dwFlags&USE_INDEX))) return FALSE;
213         GRPHEADER *GrpFile = (GRPHEADER *)hGrp;
214         nFrame %= GrpFile->nFrames;
215         FRAMEHEADER *GrpFrame = &((FRAMEHEADER *)(((char *)GrpFile)+6))[nFrame];
216         FRAMEHEADER *GrpFrames = &((FRAMEHEADER *)(((char *)GrpFile)+6))[0];
217         int FrameSize = 0xFFFFFF;
218         DWORD Right,Bottom;
219         if (dwFlags&HORIZONTAL_FLIP) Right = nXDest+GrpFile->wMaxWidth-1-GrpFrame->Left;
220         if (dwFlags&VERTICAL_FLIP) Bottom = nYDest+GrpFile->wMaxHeight-1-GrpFrame->Top;
221         nXDest += GrpFrame->Left;
222         nYDest += GrpFrame->Top;
223         WORD *GrpOffsets = ((WORD *)(((char *)GrpFile)+GrpFrame->Offset));
224         BYTE *GrpRaw = (BYTE *)GrpOffsets;
225         BYTE *RowData;
226         WORD x,ofs;
227         DWORD y, nMaxOffset = 0;
228         WORD i;
229         int j, nFirstNonBlankFrame = 0;
230         for (i = 0; i < GrpFile->nFrames; i++) {
231                 j = GrpFrames[i].Offset - GrpFrame->Offset;
232                 if (j > 0 && j < FrameSize)
233                         FrameSize = j;
234                 if (GrpFrames[i].Offset > nMaxOffset)
235                         nMaxOffset = GrpFrames[i].Offset;
236         }
237         if (FrameSize == 0xFFFFFF || FrameSize == GrpFrame->Width * GrpFrame->Height) {
238                 FrameSize = 0xFFFFFF;
239                 for (i = 0; i < GrpFile->nFrames; i++) {
240                         if (GrpFrames[i].Width != 0 && GrpFrames[i].Height != 0 && GrpFrames[i].Offset != GrpFrame->Offset && GrpFrames[i].Offset != nMaxOffset) {
241                                 nFirstNonBlankFrame = i;
242                                 break;
243                         }
244                 }
245                 if (i == GrpFile->nFrames)
246                         nFirstNonBlankFrame = nFrame;
248                 for (i = 0; i < GrpFile->nFrames; i++) {
249                         j = GrpFrames[i].Offset - GrpFrames[nFirstNonBlankFrame].Offset;
250                         if (j > 0 && j < FrameSize)
251                                 FrameSize = j;
252                 }
253                 if (FrameSize == GrpFrames[nFirstNonBlankFrame].Width * GrpFrames[nFirstNonBlankFrame].Height)
254                         FrameSize = GrpFrame->Width * GrpFrame->Height;
255         }
256         if (!(dwFlags&HORIZONTAL_FLIP) && !(dwFlags&VERTICAL_FLIP)) {
257                 if (FrameSize != GrpFrame->Width * GrpFrame->Height) {
258                         for (y=0;y<GrpFrame->Height;y++) {
259                                 RowData = ((BYTE *)(((char *)GrpOffsets)+GrpOffsets[y]));
260                                 x=0; ofs=0;
261                                 while (x<GrpFrame->Width) {
262                                         if (!(RowData[ofs] & 0x80)) {
263                                                 if (!(RowData[ofs] & 0x40)) {
264                                                         for (i=1;i<=RowData[ofs] && x<GrpFrame->Width;i++) {
265                                                                 SetPix(hdcDest,nXDest+x,nYDest+y,RowData[ofs+i],dwPalette,dwFlags,dwAlpha);
266                                                                 x++;
267                                                         }
268                                                         ofs+=RowData[ofs]+1;
269                                                 }
270                                                 else {
271                                                         for (i=0;i<RowData[ofs]-64 && x<GrpFrame->Width;i++) {
272                                                                 SetPix(hdcDest,nXDest+x,nYDest+y,RowData[ofs+1],dwPalette,dwFlags,dwAlpha);
273                                                                 x++;
274                                                         }
275                                                         ofs+=2;
276                                                 }
277                                         }
278                                         else {
279                                                 x+=RowData[ofs]-128;
280                                                 ofs++;
281                                         }
282                                 }
283                         }
284                 }
285                 else {
286                         for (y=0;y<GrpFrame->Height;y++) {
287                                 for (x=0;x<GrpFrame->Width;x++) {
288                                         SetPix(hdcDest,nXDest+x,nYDest+y,GrpRaw[y * GrpFrame->Width + x],dwPalette,dwFlags,dwAlpha);
289                                 }
290                         }
291                 }
292         }
293         else if (dwFlags&HORIZONTAL_FLIP && !(dwFlags&VERTICAL_FLIP)) {
294                 if (FrameSize != GrpFrame->Width * GrpFrame->Height) {
295                         for (y=0;y<GrpFrame->Height;y++) {
296                                 RowData = ((BYTE *)(((char *)GrpOffsets)+GrpOffsets[y]));
297                                 x=0; ofs=0;
298                                 while (x<GrpFrame->Width) {
299                                         if (!(RowData[ofs] & 0x80)) {
300                                                 if (!(RowData[ofs] & 0x40)) {
301                                                         for (i=1;i<=RowData[ofs] && x<GrpFrame->Width;i++) {
302                                                                 SetPix(hdcDest,Right-x,nYDest+y,RowData[ofs+i],dwPalette,dwFlags,dwAlpha);
303                                                                 x++;
304                                                         }
305                                                         ofs+=RowData[ofs]+1;
306                                                 }
307                                                 else {
308                                                         for (i=0;i<RowData[ofs]-64 && x<GrpFrame->Width;i++) {
309                                                                 SetPix(hdcDest,Right-x,nYDest+y,RowData[ofs+1],dwPalette,dwFlags,dwAlpha);
310                                                                 x++;
311                                                         }
312                                                         ofs+=2;
313                                                 }
314                                         }
315                                         else {
316                                                 x+=RowData[ofs]-128;
317                                                 ofs++;
318                                         }
319                                 }
320                         }
321                 }
322                 else {
323                         for (y=0;y<GrpFrame->Height;y++) {
324                                 for (x=0;x<GrpFrame->Width;x++) {
325                                         SetPix(hdcDest,Right-x,nYDest+y,GrpRaw[y * GrpFrame->Width + x],dwPalette,dwFlags,dwAlpha);
326                                 }
327                         }
328                 }
329         }
330         else if (!(dwFlags&HORIZONTAL_FLIP) && dwFlags&VERTICAL_FLIP) {
331                 if (FrameSize != GrpFrame->Width * GrpFrame->Height) {
332                         for (y=0;y<GrpFrame->Height;y++) {
333                                 RowData = ((BYTE *)(((char *)GrpOffsets)+GrpOffsets[y]));
334                                 x=0; ofs=0;
335                                 while (x<GrpFrame->Width) {
336                                         if (!(RowData[ofs] & 0x80)) {
337                                                 if (!(RowData[ofs] & 0x40)) {
338                                                         for (i=1;i<=RowData[ofs] && x<GrpFrame->Width;i++) {
339                                                                 SetPix(hdcDest,nXDest+x,Bottom-y,RowData[ofs+i],dwPalette,dwFlags,dwAlpha);
340                                                                 x++;
341                                                         }
342                                                         ofs+=RowData[ofs]+1;
343                                                 }
344                                                 else {
345                                                         for (i=0;i<RowData[ofs]-64 && x<GrpFrame->Width;i++) {
346                                                                 SetPix(hdcDest,nXDest+x,Bottom-y,RowData[ofs+1],dwPalette,dwFlags,dwAlpha);
347                                                                 x++;
348                                                         }
349                                                         ofs+=2;
350                                                 }
351                                         }
352                                         else {
353                                                 x+=RowData[ofs]-128;
354                                                 ofs++;
355                                         }
356                                 }
357                         }
358                 }
359                 else {
360                         for (y=0;y<GrpFrame->Height;y++) {
361                                 for (x=0;x<GrpFrame->Width;x++) {
362                                         SetPix(hdcDest,nXDest+x,Bottom-y,GrpRaw[y * GrpFrame->Width + x],dwPalette,dwFlags,dwAlpha);
363                                 }
364                         }
365                 }
366         }
367         else {
368                 if (FrameSize != GrpFrame->Width * GrpFrame->Height) {
369                         for (y=0;y<GrpFrame->Height;y++) {
370                                 RowData = ((BYTE *)(((char *)GrpOffsets)+GrpOffsets[y]));
371                                 x=0; ofs=0;
372                                 while (x<GrpFrame->Width) {
373                                         if (!(RowData[ofs] & 0x80)) {
374                                                 if (!(RowData[ofs] & 0x40)) {
375                                                         for (i=1;i<=RowData[ofs] && x<GrpFrame->Width;i++) {
376                                                                 SetPix(hdcDest,Right-x,Bottom-y,RowData[ofs+i],dwPalette,dwFlags,dwAlpha);
377                                                                 x++;
378                                                         }
379                                                         ofs+=RowData[ofs]+1;
380                                                 }
381                                                 else {
382                                                         for (i=0;i<RowData[ofs]-64 && x<GrpFrame->Width;i++) {
383                                                                 SetPix(hdcDest,Right-x,Bottom-y,RowData[ofs+1],dwPalette,dwFlags,dwAlpha);
384                                                                 x++;
385                                                         }
386                                                         ofs+=2;
387                                                 }
388                                         }
389                                         else {
390                                                 x+=RowData[ofs]-128;
391                                                 ofs++;
392                                         }
393                                 }
394                         }
395                 }
396                 else {
397                         for (y=0;y<GrpFrame->Height;y++) {
398                                 for (x=0;x<GrpFrame->Width;x++) {
399                                         SetPix(hdcDest,Right-x,Bottom-y,GrpRaw[y * GrpFrame->Width + x],dwPalette,dwFlags,dwAlpha);
400                                 }
401                         }
402                 }
403         }
404         return TRUE;
407 BOOL GRPAPI WINAPI GetGrpInfo(HANDLE hGrp, GRPHEADER *GrpInfo)
409         if (!hGrp || hGrp==INVALID_HANDLE_VALUE || !GrpInfo) return FALSE;
410         memcpy(GrpInfo,hGrp,6);
411         return TRUE;
414 BOOL GRPAPI WINAPI GetGrpFrameInfo(HANDLE hGrp, WORD nFrame, DWORD *nLeft, DWORD *nTop, DWORD *nWidth, DWORD *nHeight)
416         if (!hGrp || hGrp==INVALID_HANDLE_VALUE) return FALSE;
417         FRAMEHEADER *GrpFrame = &((FRAMEHEADER *)(((char *)hGrp)+6))[nFrame];
419         if (nLeft) *nLeft = GrpFrame->Left;
420         if (nTop) *nTop = GrpFrame->Top;
421         if (nWidth) *nWidth = GrpFrame->Width;
422         if (nHeight) *nHeight = GrpFrame->Height;
424         return TRUE;
427 void GRPAPI WINAPI SetFunctionGetPixel(GETPIXELPROC lpGetPixelProc)
429         if (!lpGetPixelProc)
430                 MyGetPixel = GetPixel;
431         else
432                 MyGetPixel = lpGetPixelProc;
435 void GRPAPI WINAPI SetFunctionSetPixel(SETPIXELPROC lpSetPixelProc)
437         if (!lpSetPixelProc)
438                 MySetPixel = (SETPIXELPROC)SetPixelV;
439         else
440                 MySetPixel = lpSetPixelProc;
443 void __inline SetPix(HDC hDC, int X, int Y, COLORREF clrColor, DWORD *dwPalette, DWORD dwFlags, DWORD dwAlpha)
445         if (!(dwFlags&USE_INDEX)) {
446                 if (dwFlags&SHADOW_COLOR) {
447                         clrColor = (dwFlags >> 8) & 0x00FFFFFF;
448                 }
449                 else {
450                         clrColor = dwPalette[clrColor];
451                 }
452                 if (dwFlags&ALPHA_BLEND) {
453                         DWORD dwColor = MyGetPixel(hDC,X,Y);
455                         // Old alpha
456                         /*((BYTE *)&dwColor)[0]*=1-((float)((BYTE *)&dwAlpha)[0]/256);
457                         ((BYTE *)&dwColor)[1]*=1-((float)((BYTE *)&dwAlpha)[1]/256);
458                         ((BYTE *)&dwColor)[2]*=1-((float)((BYTE *)&dwAlpha)[2]/256);
459                         ((BYTE *)&clrColor)[0]*=(float)((BYTE *)&dwAlpha)[0]/256;
460                         ((BYTE *)&clrColor)[1]*=(float)((BYTE *)&dwAlpha)[1]/256;
461                         ((BYTE *)&clrColor)[2]*=(float)((BYTE *)&dwAlpha)[2]/256;
462                         ((BYTE *)&clrColor)[0]+=((BYTE *)&dwColor)[0];
463                         ((BYTE *)&clrColor)[1]+=((BYTE *)&dwColor)[1];
464                         ((BYTE *)&clrColor)[2]+=((BYTE *)&dwColor)[2];*/
466                         /* blendedcolor =
467                                  ( ( forecolor * ( 1 - alpha ) ) >> 8 )
468                            + ( ( backcolor * ( 256 - alpha ) ) >> 8 ) */
469                         ((BYTE *)&clrColor)[0] =
470                                 ( ( ((BYTE *)&clrColor)[0] * ( ((BYTE *)&dwAlpha)[0] + 1 ) ) >> 8 )
471                                 + ( ( ((BYTE *)&dwColor)[0] * ( 256 - ((BYTE *)&dwAlpha)[0] ) ) >> 8 );
472                         ((BYTE *)&clrColor)[1] =
473                                 ( ( ((BYTE *)&clrColor)[1] * ( ((BYTE *)&dwAlpha)[1] + 1 ) ) >> 8 )
474                                 + ( ( ((BYTE *)&dwColor)[1] * ( 256 - ((BYTE *)&dwAlpha)[1] ) ) >> 8 );
475                         ((BYTE *)&clrColor)[2] =
476                                 ( ( ((BYTE *)&clrColor)[2] * ( ((BYTE *)&dwAlpha)[2] + 1 ) ) >> 8 )
477                                 + ( ( ((BYTE *)&dwColor)[2] * ( 256 - ((BYTE *)&dwAlpha)[2] ) ) >> 8 );
478                 }
479         }
480         MySetPixel(hDC,X,Y,clrColor);
483 HANDLE GRPAPI WINAPI CreateGrp(signed short *lpImageData, WORD nFrames, WORD wMaxWidth, WORD wMaxHeight, BOOL bNoCompress, DWORD *nGrpSize)
485         GRPHEADER GrpHeader;
486         FRAMEHEADER *lpFrameHeaders;
487         FRAMEDATA *lpFrameData;
488         LPBYTE lpGrpData;
489         int i, j, x, y, x1, x2, y1, y2;
490         DWORD nLastOffset;
492         if (!lpImageData || !nGrpSize) return (HANDLE)-1;
494         GrpHeader.nFrames = nFrames;
495         GrpHeader.wMaxWidth = wMaxWidth;
496         GrpHeader.wMaxHeight = wMaxHeight;
497         lpFrameHeaders = (FRAMEHEADER *)malloc(nFrames * sizeof(FRAMEHEADER));
498         lpFrameData = (FRAMEDATA *)malloc(nFrames * sizeof(FRAMEDATA));
499         nLastOffset = sizeof(GRPHEADER) + nFrames * sizeof(FRAMEHEADER);
501         for (i = 0; i < nFrames; i++) {
502                 lpFrameHeaders[i].Offset = nLastOffset;
504                 // Scan frame to find dimensions of used part
505                 x1 = y1 = 0x10000;
506                 x2 = y2 = -1;
507                 for (y = 0; y < wMaxHeight; y++) {
508                         for (x = 0; x < wMaxWidth; x++) {
509                                 if (lpImageData[i * wMaxWidth * wMaxHeight + y * wMaxWidth + x] >= 0) {
510                                         if (x < x1) x1 = x;
511                                         if (x > x2) x2 = x;
512                                         if (y < y1) y1 = y;
513                                         if (y > y2) y2 = y;
514                                 }
515                         }
516                 }
517                 x2 = x2 - x1 + 1;
518                 y2 = y2 - y1 + 1;
519                 if ((WORD)x1 > 255) x1 = 255;
520                 if ((WORD)y1 > 255) y1 = 255;
521                 if ((WORD)x2 > 255) x2 = 255;
522                 if ((WORD)y2 > 255) y2 = 255;
523                 lpFrameHeaders[i].Left = x1;
524                 lpFrameHeaders[i].Top = y1;
525                 lpFrameHeaders[i].Width = x2;
526                 lpFrameHeaders[i].Height = y2;
528                 // Search for duplicate frames
529                 for (j = 0; j < i; j++) {
530                         if (lpFrameData[j].lpRowOffsets && lpFrameHeaders[i].Width == lpFrameHeaders[j].Width && lpFrameHeaders[i].Height == lpFrameHeaders[j].Height) {
531                                 y1 = i * wMaxWidth * wMaxHeight + lpFrameHeaders[i].Top * wMaxWidth + lpFrameHeaders[i].Left;
532                                 y2 = j * wMaxWidth * wMaxHeight + lpFrameHeaders[j].Top * wMaxWidth + lpFrameHeaders[j].Left;
534                                 for (y = 0; y < lpFrameHeaders[i].Height; y++) {
535                                         if (memcmp(&lpImageData[y1], &lpImageData[y2], lpFrameHeaders[i].Width * sizeof(short)) != 0)
536                                                 break;
538                                         y1 += wMaxWidth;
539                                         y2 += wMaxWidth;
540                                 }
542                                 if (y == lpFrameHeaders[i].Height) {
543                                         break;
544                                 }
545                         }
546                 }
548                 if (j < i) {
549                         // Duplicate frame found, set offset and flag as duplicate
550                         lpFrameHeaders[i].Offset = lpFrameHeaders[j].Offset;
551                         lpFrameData[i].lpRowOffsets = 0;
552                         lpFrameData[i].lpRowSizes = 0;
553                         lpFrameData[i].lpRowData = 0;
554                         lpFrameData[i].Size = 0;
555                         continue;
556                 }
558                 EncodeFrameData(lpImageData, i, &GrpHeader, &lpFrameHeaders[i], &lpFrameData[i], bNoCompress);
559                 nLastOffset = lpFrameHeaders[i].Offset + lpFrameData[i].Size;
560         }
562         lpGrpData = (LPBYTE)malloc(nLastOffset);
564         // Write completed GRP to buffer
565         memcpy(lpGrpData, &GrpHeader, sizeof(GRPHEADER));
566         memcpy(lpGrpData + sizeof(GRPHEADER), lpFrameHeaders, nFrames * sizeof(FRAMEHEADER));
568         for (i = 0; i < nFrames; i++) {
569                 if (lpFrameData[i].lpRowOffsets) {
570                         if (!bNoCompress)
571                                 memcpy(lpGrpData + lpFrameHeaders[i].Offset, lpFrameData[i].lpRowOffsets, lpFrameHeaders[i].Height * sizeof(WORD));
573                         for (y = 0; y < lpFrameHeaders[i].Height; y++) {
574                                 if (lpFrameData[i].lpRowData[y]) {
575                                         memcpy(lpGrpData + lpFrameHeaders[i].Offset + lpFrameData[i].lpRowOffsets[y], lpFrameData[i].lpRowData[y], lpFrameData[i].lpRowSizes[y]);
576                                         free(lpFrameData[i].lpRowData[y]);
577                                 }
578                         }
580                         free(lpFrameData[i].lpRowOffsets);
581                         free(lpFrameData[i].lpRowSizes);
582                         free(lpFrameData[i].lpRowData);
583                 }
584         }
586         free(lpFrameHeaders);
587         free(lpFrameData);
589         *nGrpSize = nLastOffset;
590         return (HANDLE)lpGrpData;
593 void EncodeFrameData(signed short *lpImageData, WORD nFrame, GRPHEADER *lpGrpHeader, FRAMEHEADER *lpFrameHeader, FRAMEDATA *lpFrameData, BOOL bNoCompress)
595         int x, y, i, j, nBufPos, nRepeat;
596         LPBYTE lpRowBuf;
597         WORD nLastOffset = 0;
599         lpFrameData->lpRowOffsets = (WORD *)malloc(lpFrameHeader->Height * sizeof(WORD));
600         lpFrameData->lpRowSizes = (WORD *)malloc(lpFrameHeader->Height * sizeof(WORD));
601         lpFrameData->lpRowData = (LPBYTE *)malloc(lpFrameHeader->Height * sizeof(LPBYTE));
602         lpRowBuf = (LPBYTE)malloc(lpFrameHeader->Width * 2);
604         if (!bNoCompress)
605                 nLastOffset = lpFrameHeader->Height * sizeof(WORD);
607         for (y = 0; y < lpFrameHeader->Height; y++) {
608                 i = nFrame * lpGrpHeader->wMaxWidth * lpGrpHeader->wMaxHeight + (lpFrameHeader->Top + y) * lpGrpHeader->wMaxWidth;
610                 if (!bNoCompress) {
611                         // Search for duplicate rows
612                         for (x = 0; x < y; x++) {
613                                 j = nFrame * lpGrpHeader->wMaxWidth * lpGrpHeader->wMaxHeight + (lpFrameHeader->Top + x) * lpGrpHeader->wMaxWidth;
614                                 if (memcmp(&lpImageData[i+lpFrameHeader->Left],
615                                                    &lpImageData[j+lpFrameHeader->Left],
616                                                    lpGrpHeader->wMaxWidth * sizeof(short)) == 0)
617                                         break;
618                         }
620                         if (x < y) {
621                                 lpFrameData->lpRowOffsets[y] = lpFrameData->lpRowOffsets[x];
622                                 lpFrameData->lpRowSizes[y] = 0;
623                                 lpFrameData->lpRowData[y] = 0;
625 #ifdef _DEBUG
626                                 if (!VerifyRow(&lpImageData[i+lpFrameHeader->Left], lpFrameHeader->Width, lpFrameData->lpRowData[x], lpFrameData->lpRowSizes[x], bNoCompress)) {
627                                         nBufPos = nBufPos;
628                                 }
629 #endif
631                                 continue;
632                         }
633                 }
635                 nBufPos = 0;
636                 if (lpFrameHeader->Width > 0) {
637                         for (x = lpFrameHeader->Left; x < lpFrameHeader->Left + lpFrameHeader->Width; x++) {
638                                 if (!bNoCompress) {
639                                         if (x < lpFrameHeader->Left + lpFrameHeader->Width - 1) {
640                                                 if (lpImageData[i+x] < 0) {
641                                                         lpRowBuf[nBufPos] = 0x80;
642                                                         for (; lpImageData[i+x] < 0 && x < lpFrameHeader->Left + lpFrameHeader->Width && lpRowBuf[nBufPos] < 0xFF; x++) {
643                                                                 lpRowBuf[nBufPos]++;
644                                                         }
645                                                         x--;
646                                                         if (nLastOffset + nBufPos + 1 <= 0xFFFF)
647                                                                 nBufPos++;
648                                                         continue;
649                                                 }
651                                                 // Count repeating pixels, nRepeat = number of pixels - 1, ignore if there are less than 4 duplicates
652                                                 for (nRepeat = 0; lpImageData[i+x+nRepeat] == lpImageData[i+x+nRepeat+1] && x+nRepeat < lpFrameHeader->Left + lpFrameHeader->Width - 1 && nRepeat < 0x3E; nRepeat++) {}
654                                                 if (nRepeat > 2) {
655                                                         lpRowBuf[nBufPos] = 0x41 + nRepeat;
656                                                         lpRowBuf[nBufPos+1] = (BYTE)(lpImageData[i+x]);
657                                                         x += nRepeat;
658                                                         if (nLastOffset + nBufPos + 2 <= 0xFFFF)
659                                                                 nBufPos += 2;
660                                                 }
661                                                 else {
662                                                         lpRowBuf[nBufPos] = 0;
663                                                         for (; lpImageData[i+x] >= 0 && x < lpFrameHeader->Left + lpFrameHeader->Width && lpRowBuf[nBufPos] < 0x3F; x++) {
664                                                                 // Count repeating pixels, ignore if there are less than 4 duplicates
665                                                                 for (nRepeat = 0; lpImageData[i+x+nRepeat] == lpImageData[i+x+nRepeat+1] && x+nRepeat < lpFrameHeader->Left + lpFrameHeader->Width - 1 && nRepeat < 3; nRepeat++) {}
666                                                                 if (nRepeat > 2) break;
668                                                                 lpRowBuf[nBufPos]++;
669                                                                 lpRowBuf[nBufPos+lpRowBuf[nBufPos]] = (BYTE)(lpImageData[i+x]);
670                                                         }
671                                                         if (lpImageData[i+x] >= 0 && x == lpFrameHeader->Left + lpFrameHeader->Width - 1 && lpRowBuf[nBufPos] < 0x3F) {
672                                                                 lpRowBuf[nBufPos]++;
673                                                                 lpRowBuf[nBufPos+lpRowBuf[nBufPos]] = (BYTE)(lpImageData[i+x]);
674                                                         }
675                                                         x--;
676                                                         if (nLastOffset + nBufPos + 1 + lpRowBuf[nBufPos] <= 0xFFFF)
677                                                                 nBufPos += 1 + lpRowBuf[nBufPos];
678                                                 }
679                                         }
680                                         else {
681                                                 if (lpImageData[i+x] < 0) {
682                                                         lpRowBuf[nBufPos] = 0x81;
683                                                         if (nLastOffset + nBufPos + 1 <= 0xFFFF)
684                                                                 nBufPos++;
685                                                 }
686                                                 else {
687                                                         lpRowBuf[nBufPos] = 1;
688                                                         lpRowBuf[nBufPos+1] = (BYTE)(lpImageData[i+x]);
689                                                         if (nLastOffset + nBufPos + 2 <= 0xFFFF)
690                                                                 nBufPos += 2;
691                                                 }
692                                         }
693                                 }
694                                 else {
695                                         lpRowBuf[nBufPos] = (BYTE)(lpImageData[i+x]);
696                                         if (nLastOffset + nBufPos + 1 <= 0xFFFF)
697                                                 nBufPos++;
698                                 }
699                         }
700                 }
702 #ifdef _DEBUG
703                 if (!VerifyRow(&lpImageData[i+lpFrameHeader->Left], lpFrameHeader->Width, lpRowBuf, nBufPos, bNoCompress)) {
704                         nBufPos = nBufPos;
705                 }
706 #endif
708                 lpFrameData->lpRowOffsets[y] = nLastOffset;
709                 nLastOffset = lpFrameData->lpRowOffsets[y] + nBufPos;
711                 lpFrameData->lpRowSizes[y] = nBufPos;
712                 lpFrameData->lpRowData[y] = (LPBYTE)malloc(nBufPos);
713                 memcpy(lpFrameData->lpRowData[y], lpRowBuf, nBufPos);
714         }
716         lpFrameData->Size = nLastOffset;
718         free(lpRowBuf);
721 #ifdef _DEBUG
722 BOOL VerifyRow(signed short *lpRawRow, int nWidth, LPBYTE lpEncRow, int nSize, BOOL bNoCompress)
724         int i,x=0,ofs=0;
725         while (x < nWidth && ofs < nSize) {
726                 if (!bNoCompress) {
727                         if (!(lpEncRow[ofs] & 0x80)) {
728                                 if (!(lpEncRow[ofs] & 0x40)) {
729                                         for (i=1;i<=lpEncRow[ofs] && x<nWidth;i++) {
730                                                 if (lpEncRow[ofs+i] != (BYTE)lpRawRow[x]) return FALSE;
731                                                 x++;
732                                         }
733                                         ofs+=lpEncRow[ofs]+1;
734                                 }
735                                 else {
736                                         for (i=0;i<lpEncRow[ofs]-64 && x<nWidth;i++) {
737                                                 if (lpEncRow[ofs+1] != (BYTE)lpRawRow[x]) return FALSE;
738                                                 x++;
739                                         }
740                                         ofs+=2;
741                                 }
742                         }
743                         else {
744                                 for (i=0;i<lpEncRow[ofs]-128 && x<nWidth;i++) {
745                                         if (lpRawRow[x] >= 0) return FALSE;
746                                 }
747                                 x+=lpEncRow[ofs]-128;
748                                 ofs++;
749                         }
750                 }
751                 else {
752                         if (lpEncRow[ofs] != (BYTE)lpRawRow[x]) return FALSE;
753                         x++;
754                         ofs++;
755                 }
756         }
758         if (x != nWidth || ofs != nSize) return FALSE;
760         return TRUE;
762 #endif