Commit | Line | Data |
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 | |
12 | struct GRPLIBMODULE { |
13 | GRPLIBMODULE(); |
14 | ~GRPLIBMODULE(); |
15 | } GrpLib; |
16 | |
17 | BOOL APIENTRY DllMain(HINSTANCE hInstDLL, DWORD ul_reason_for_call, LPVOID lpReserved); |
18 | |
19 | GRPLIBMODULE::GRPLIBMODULE() |
20 | { |
21 | GrpMain(0,DLL_PROCESS_ATTACH,0); |
22 | } |
23 | |
24 | GRPLIBMODULE::~GRPLIBMODULE() |
25 | { |
26 | GrpMain(0,DLL_PROCESS_DETACH,0); |
27 | } |
28 | |
29 | #endif |
30 | |
31 | typedef struct { |
32 | BYTE Left; |
33 | BYTE Top; |
34 | BYTE Width; |
35 | BYTE Height; |
36 | DWORD Offset; |
37 | } FRAMEHEADER; |
38 | |
39 | typedef struct { |
40 | WORD *lpRowOffsets; |
41 | WORD *lpRowSizes; |
42 | LPBYTE *lpRowData; |
43 | DWORD Size; |
44 | } FRAMEDATA; |
45 | |
46 | GETPIXELPROC MyGetPixel = GetPixel; |
47 | SETPIXELPROC MySetPixel = (SETPIXELPROC)SetPixelV; |
48 | |
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); |
52 | |
53 | extern HINSTANCE hStorm; |
54 | |
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 | } |
71 | |
72 | return TRUE; |
73 | } |
74 | |
75 | BOOL GRPAPI WINAPI LoadGrpApi() |
76 | { |
77 | if (!hStorm) return FALSE; |
78 | else return TRUE; |
79 | } |
80 | |
81 | void GRPAPI WINAPI FreeGrpApi() |
82 | { |
83 | } |
84 | |
85 | /* |
86 | HANDLE hProcessHeap = NULL; |
87 | |
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 | } |
94 | |
95 | void SFFree(void *lpMem) |
96 | { |
97 | if (!hProcessHeap) hProcessHeap = GetProcessHeap(); |
98 | if (hProcessHeap) HeapFree(hProcessHeap, 0, lpMem); |
99 | } |
100 | */ |
101 | |
102 | BOOL GRPAPI WINAPI SetMpqDll(LPCSTR lpDllFileName) |
103 | { |
104 | if (LoadStorm((char *)lpDllFileName)) return TRUE; |
105 | else return FALSE; |
106 | } |
107 | |
108 | BOOL 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 | |
164 | HANDLE 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 | |
205 | BOOL GRPAPI WINAPI DestroyGrp(HANDLE hGrp) |
206 | { |
207 | if (!hGrp || hGrp==INVALID_HANDLE_VALUE) return FALSE; |
208 | free(hGrp); |
209 | return TRUE; |
210 | } |
211 | |
212 | BOOL 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 | |
409 | BOOL 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 | |
416 | BOOL 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 | |
429 | void GRPAPI WINAPI SetFunctionGetPixel(GETPIXELPROC lpGetPixelProc) |
430 | { |
431 | if (!lpGetPixelProc) |
432 | MyGetPixel = GetPixel; |
433 | else |
434 | MyGetPixel = lpGetPixelProc; |
435 | } |
436 | |
437 | void GRPAPI WINAPI SetFunctionSetPixel(SETPIXELPROC lpSetPixelProc) |
438 | { |
439 | if (!lpSetPixelProc) |
440 | MySetPixel = (SETPIXELPROC)SetPixelV; |
441 | else |
442 | MySetPixel = lpSetPixelProc; |
443 | } |
444 | |
445 | void __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 | |
485 | HANDLE 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 | |
595 | void 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 |
724 | BOOL 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 |