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




CommitLineData
f15b049d 1/* License information for this code is in license.txt */
2
09d0556c 3#include "grpapi.h"
4#include "../LoadStorm/storm.h"
5#include <malloc.h>
6
7#ifdef GRPAPI_STATIC
8#define DllMain GrpMain
9
10#include "grp_static.h"
11
12struct GRPLIBMODULE {
13 GRPLIBMODULE();
14 ~GRPLIBMODULE();
15} GrpLib;
16
17BOOL APIENTRY DllMain(HINSTANCE hInstDLL, DWORD ul_reason_for_call, LPVOID lpReserved);
18
19GRPLIBMODULE::GRPLIBMODULE()
20{
21 GrpMain(0,DLL_PROCESS_ATTACH,0);
22}
23
24GRPLIBMODULE::~GRPLIBMODULE()
25{
26 GrpMain(0,DLL_PROCESS_DETACH,0);
27}
28
29#endif
30
31typedef struct {
32 BYTE Left;
33 BYTE Top;
34 BYTE Width;
35 BYTE Height;
36 DWORD Offset;
37} FRAMEHEADER;
38
39typedef struct {
40 WORD *lpRowOffsets;
41 WORD *lpRowSizes;
42 LPBYTE *lpRowData;
43 DWORD Size;
44} FRAMEDATA;
45
46GETPIXELPROC MyGetPixel = GetPixel;
47SETPIXELPROC MySetPixel = (SETPIXELPROC)SetPixelV;
48
49void __inline SetPix(HDC hDC, int X, int Y, COLORREF clrColor, DWORD *dwPalette, DWORD dwFlags, DWORD dwAlpha);
50void EncodeFrameData(signed short *lpImageData, WORD nFrame, GRPHEADER *lpGrpHeader, FRAMEHEADER *lpFrameHeader, FRAMEDATA *lpFrameData, BOOL bNoCompress);
51BOOL VerifyRow(signed short *lpRawRow, int nWidth, LPBYTE lpEncRow, int nSize, BOOL bNoCompress);
52
53extern HINSTANCE hStorm;
54
55BOOL 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 }
71
72 return TRUE;
73}
74
75BOOL GRPAPI WINAPI LoadGrpApi()
76{
77 if (!hStorm) return FALSE;
78 else return TRUE;
79}
80
81void GRPAPI WINAPI FreeGrpApi()
82{
83}
84
85/*
86HANDLE hProcessHeap = NULL;
87
88void * SFAlloc(size_t nSize)
89{
90 if (!hProcessHeap) hProcessHeap = GetProcessHeap();
91 if (hProcessHeap) return HeapAlloc(hProcessHeap, 0, nSize);
92 else return NULL;
93}
94
95void SFFree(void *lpMem)
96{
97 if (!hProcessHeap) hProcessHeap = GetProcessHeap();
98 if (hProcessHeap) HeapFree(hProcessHeap, 0, lpMem);
99}
100*/
101
102BOOL GRPAPI WINAPI SetMpqDll(LPCSTR lpDllFileName)
103{
104 if (LoadStorm((char *)lpDllFileName)) return TRUE;
105 else return FALSE;
106}
107
108BOOL GRPAPI WINAPI LoadPalette(LPCSTR lpFileName, DWORD *dwPaletteBuffer)
109{
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;
162}
163
164HANDLE GRPAPI WINAPI LoadGrp(LPCSTR lpFileName)
165{
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;
203}
204
205BOOL GRPAPI WINAPI DestroyGrp(HANDLE hGrp)
206{
207 if (!hGrp || hGrp==INVALID_HANDLE_VALUE) return FALSE;
208 free(hGrp);
209 return TRUE;
210}
211
212BOOL GRPAPI WINAPI DrawGrp(HANDLE hGrp, HDC hdcDest, int nXDest, int nYDest, WORD nFrame, DWORD *dwPalette, DWORD dwFlags, DWORD dwAlpha)
213{
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;
249
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;
407}
408
409BOOL GRPAPI WINAPI GetGrpInfo(HANDLE hGrp, GRPHEADER *GrpInfo)
410{
411 if (!hGrp || hGrp==INVALID_HANDLE_VALUE || !GrpInfo) return FALSE;
412 memcpy(GrpInfo,hGrp,6);
413 return TRUE;
414}
415
416BOOL GRPAPI WINAPI GetGrpFrameInfo(HANDLE hGrp, WORD nFrame, DWORD *nLeft, DWORD *nTop, DWORD *nWidth, DWORD *nHeight)
417{
418 if (!hGrp || hGrp==INVALID_HANDLE_VALUE) return FALSE;
419 FRAMEHEADER *GrpFrame = &((FRAMEHEADER *)(((char *)hGrp)+6))[nFrame];
420
421 if (nLeft) *nLeft = GrpFrame->Left;
422 if (nTop) *nTop = GrpFrame->Top;
423 if (nWidth) *nWidth = GrpFrame->Width;
424 if (nHeight) *nHeight = GrpFrame->Height;
425
426 return TRUE;
427}
428
429void GRPAPI WINAPI SetFunctionGetPixel(GETPIXELPROC lpGetPixelProc)
430{
431 if (!lpGetPixelProc)
432 MyGetPixel = GetPixel;
433 else
434 MyGetPixel = lpGetPixelProc;
435}
436
437void GRPAPI WINAPI SetFunctionSetPixel(SETPIXELPROC lpSetPixelProc)
438{
439 if (!lpSetPixelProc)
440 MySetPixel = (SETPIXELPROC)SetPixelV;
441 else
442 MySetPixel = lpSetPixelProc;
443}
444
445void __inline SetPix(HDC hDC, int X, int Y, COLORREF clrColor, DWORD *dwPalette, DWORD dwFlags, DWORD dwAlpha)
446{
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);
456
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];*/
467
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);
483}
484
485HANDLE GRPAPI WINAPI CreateGrp(signed short *lpImageData, WORD nFrames, WORD wMaxWidth, WORD wMaxHeight, BOOL bNoCompress, DWORD *nGrpSize)
486{
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;
493
494 if (!lpImageData || !nGrpSize) return (HANDLE)-1;
495
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);
502
503 for (i = 0; i < nFrames; i++) {
504 lpFrameHeaders[i].Offset = nLastOffset;
505
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;
529
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;
535
536 for (y = 0; y < lpFrameHeaders[i].Height; y++) {
537 if (memcmp(&lpImageData[y1], &lpImageData[y2], lpFrameHeaders[i].Width * sizeof(short)) != 0)
538 break;
539
540 y1 += wMaxWidth;
541 y2 += wMaxWidth;
542 }
543
544 if (y == lpFrameHeaders[i].Height) {
545 break;
546 }
547 }
548 }
549
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 }
559
560 EncodeFrameData(lpImageData, i, &GrpHeader, &lpFrameHeaders[i], &lpFrameData[i], bNoCompress);
561 nLastOffset = lpFrameHeaders[i].Offset + lpFrameData[i].Size;
562 }
563
564 lpGrpData = (LPBYTE)malloc(nLastOffset);
565
566 // Write completed GRP to buffer
567 memcpy(lpGrpData, &GrpHeader, sizeof(GRPHEADER));
568 memcpy(lpGrpData + sizeof(GRPHEADER), lpFrameHeaders, nFrames * sizeof(FRAMEHEADER));
569
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));
574
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 }
581
582 free(lpFrameData[i].lpRowOffsets);
583 free(lpFrameData[i].lpRowSizes);
584 free(lpFrameData[i].lpRowData);
585 }
586 }
587
588 free(lpFrameHeaders);
589 free(lpFrameData);
590
591 *nGrpSize = nLastOffset;
592 return (HANDLE)lpGrpData;
593}
594
595void EncodeFrameData(signed short *lpImageData, WORD nFrame, GRPHEADER *lpGrpHeader, FRAMEHEADER *lpFrameHeader, FRAMEDATA *lpFrameData, BOOL bNoCompress)
596{
597 int x, y, i, j, nBufPos, nRepeat;
598 LPBYTE lpRowBuf;
599 WORD nLastOffset = 0;
600
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);
605
606 if (!bNoCompress)
607 nLastOffset = lpFrameHeader->Height * sizeof(WORD);
608
609 for (y = 0; y < lpFrameHeader->Height; y++) {
610 i = nFrame * lpGrpHeader->wMaxWidth * lpGrpHeader->wMaxHeight + (lpFrameHeader->Top + y) * lpGrpHeader->wMaxWidth;
611
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 }
621
622 if (x < y) {
623 lpFrameData->lpRowOffsets[y] = lpFrameData->lpRowOffsets[x];
624 lpFrameData->lpRowSizes[y] = 0;
625 lpFrameData->lpRowData[y] = 0;
626
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
632
633 continue;
634 }
635 }
636
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 }
652
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++) {}
655
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;
669
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 }
703
704#ifdef _DEBUG
705 if (!VerifyRow(&lpImageData[i+lpFrameHeader->Left], lpFrameHeader->Width, lpRowBuf, nBufPos, bNoCompress)) {
706 nBufPos = nBufPos;
707 }
708#endif
709
710 lpFrameData->lpRowOffsets[y] = nLastOffset;
711 nLastOffset = lpFrameData->lpRowOffsets[y] + nBufPos;
712
713 lpFrameData->lpRowSizes[y] = nBufPos;
714 lpFrameData->lpRowData[y] = (LPBYTE)malloc(nBufPos);
715 memcpy(lpFrameData->lpRowData[y], lpRowBuf, nBufPos);
716 }
717
718 lpFrameData->Size = nLastOffset;
719
720 free(lpRowBuf);
721}
722
723#ifdef _DEBUG
724BOOL VerifyRow(signed short *lpRawRow, int nWidth, LPBYTE lpEncRow, int nSize, BOOL bNoCompress)
725{
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 }
759
760 if (x != nWidth || ofs != nSize) return FALSE;
761
762 return TRUE;
763}
764#endif