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




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