X-Git-Url: https://sfsrealm.hopto.org/projects/gitweb.cgi?a=blobdiff_plain;f=grpapi%2Fgrpapi.cpp;h=b002e12c0764cee168c178c7eaf5cb0f020bbf2b;hb=72c72f15ec4375bf64517c7526fce3510b6729c8;hp=3de6be8cb7d619c1d9df30ebb712dca7c9480076;hpb=c483a082ba5c516a59a3ae91e3efee095f0f59a3;p=grpapi.git diff --git a/grpapi/grpapi.cpp b/grpapi/grpapi.cpp index 3de6be8..b002e12 100644 --- a/grpapi/grpapi.cpp +++ b/grpapi/grpapi.cpp @@ -38,13 +38,15 @@ typedef struct { WORD *lpRowOffsets; WORD *lpRowSizes; LPBYTE *lpRowData; + DWORD Size; } FRAMEDATA; GETPIXELPROC MyGetPixel = GetPixel; SETPIXELPROC MySetPixel = (SETPIXELPROC)SetPixelV; void __inline SetPix(HDC hDC, int X, int Y, COLORREF clrColor, DWORD *dwPalette, DWORD dwFlags, DWORD dwAlpha); -void EncodeFrameData(signed short *lpImageData, WORD nFrame, GRPHEADER *lpGrpHeader, FRAMEHEADER *lpFrameHeader, FRAMEDATA *lpFrameData); +void EncodeFrameData(signed short *lpImageData, WORD nFrame, GRPHEADER *lpGrpHeader, FRAMEHEADER *lpFrameHeader, FRAMEDATA *lpFrameData, BOOL bNoCompress); +BOOL VerifyRow(signed short *lpRawRow, int nWidth, LPBYTE lpEncRow, int nSize, BOOL bNoCompress); extern HINSTANCE hStorm; @@ -78,6 +80,23 @@ void GRPAPI WINAPI FreeGrpApi() { } +/* +HANDLE hProcessHeap = NULL; + +void * SFAlloc(size_t nSize) +{ + if (!hProcessHeap) hProcessHeap = GetProcessHeap(); + if (hProcessHeap) return HeapAlloc(hProcessHeap, 0, nSize); + else return NULL; +} + +void SFFree(void *lpMem) +{ + if (!hProcessHeap) hProcessHeap = GetProcessHeap(); + if (hProcessHeap) HeapFree(hProcessHeap, 0, lpMem); +} +*/ + BOOL GRPAPI WINAPI SetMpqDll(LPCSTR lpDllFileName) { if (LoadStorm((char *)lpDllFileName)) return TRUE; @@ -205,23 +224,33 @@ BOOL GRPAPI WINAPI DrawGrp(HANDLE hGrp, HDC hdcDest, int nXDest, int nYDest, WOR BYTE *GrpRaw = (BYTE *)GrpOffsets; BYTE *RowData; WORD x,ofs; - DWORD y; + DWORD y, nMaxOffset = 0; WORD i; - int j; - if (nFrame + 1 < GrpFile->nFrames) { - for (i = 0; i + 1 < GrpFile->nFrames; i++) { - j = GrpFrames[i].Offset - GrpFrame->Offset; - if (j > 0 && j < FrameSize) - FrameSize = j; - } + int j, nFirstNonBlankFrame = 0; + for (i = 0; i < GrpFile->nFrames; i++) { + j = GrpFrames[i].Offset - GrpFrame->Offset; + if (j > 0 && j < FrameSize) + FrameSize = j; + if (GrpFrames[i].Offset > nMaxOffset) + nMaxOffset = GrpFrames[i].Offset; } - if (FrameSize == 0xFFFFFF) { - for (i = 0; i + 1 < GrpFile->nFrames; i++) { - j = GrpFrames[i].Offset - GrpFrames[0].Offset; + if (FrameSize == 0xFFFFFF || FrameSize == GrpFrame->Width * GrpFrame->Height) { + FrameSize = 0xFFFFFF; + for (i = 0; i < GrpFile->nFrames; i++) { + if (GrpFrames[i].Width != 0 && GrpFrames[i].Height != 0 && GrpFrames[i].Offset != GrpFrame->Offset && GrpFrames[i].Offset != nMaxOffset) { + nFirstNonBlankFrame = i; + break; + } + } + if (i == GrpFile->nFrames) + nFirstNonBlankFrame = nFrame; + + for (i = 0; i < GrpFile->nFrames; i++) { + j = GrpFrames[i].Offset - GrpFrames[nFirstNonBlankFrame].Offset; if (j > 0 && j < FrameSize) FrameSize = j; } - if (FrameSize == GrpFrames[0].Width * GrpFrames[0].Height) + if (FrameSize == GrpFrames[nFirstNonBlankFrame].Width * GrpFrames[nFirstNonBlankFrame].Height) FrameSize = GrpFrame->Width * GrpFrame->Height; } if (!(dwFlags&HORIZONTAL_FLIP) && !(dwFlags&VERTICAL_FLIP)) { @@ -382,6 +411,19 @@ BOOL GRPAPI WINAPI GetGrpInfo(HANDLE hGrp, GRPHEADER *GrpInfo) return TRUE; } +BOOL GRPAPI WINAPI GetGrpFrameInfo(HANDLE hGrp, WORD nFrame, DWORD *nLeft, DWORD *nTop, DWORD *nWidth, DWORD *nHeight) +{ + if (!hGrp || hGrp==INVALID_HANDLE_VALUE) return FALSE; + FRAMEHEADER *GrpFrame = &((FRAMEHEADER *)(((char *)hGrp)+6))[nFrame]; + + if (nLeft) *nLeft = GrpFrame->Left; + if (nTop) *nTop = GrpFrame->Top; + if (nWidth) *nWidth = GrpFrame->Width; + if (nHeight) *nHeight = GrpFrame->Height; + + return TRUE; +} + void GRPAPI WINAPI SetFunctionGetPixel(GETPIXELPROC lpGetPixelProc) { if (!lpGetPixelProc) @@ -438,37 +480,26 @@ void __inline SetPix(HDC hDC, int X, int Y, COLORREF clrColor, DWORD *dwPalette, MySetPixel(hDC,X,Y,clrColor); } -HANDLE GRPAPI WINAPI CreateGrp(signed short *lpImageData, WORD nFrames, WORD wMaxWidth, WORD wMaxHeight, DWORD *nGrpSize) +HANDLE GRPAPI WINAPI CreateGrp(signed short *lpImageData, WORD nFrames, WORD wMaxWidth, WORD wMaxHeight, BOOL bNoCompress, DWORD *nGrpSize) { GRPHEADER GrpHeader; FRAMEHEADER *lpFrameHeaders; FRAMEDATA *lpFrameData; LPBYTE lpGrpData; - int i, x, y, x1, x2, y1, y2; + int i, j, x, y, x1, x2, y1, y2; + DWORD nLastOffset; if (!lpImageData || !nGrpSize) return (HANDLE)-1; GrpHeader.nFrames = nFrames; GrpHeader.wMaxWidth = wMaxWidth; GrpHeader.wMaxHeight = wMaxHeight; - lpFrameHeaders = (FRAMEHEADER *)malloc((nFrames + 1) * sizeof(FRAMEHEADER)); + lpFrameHeaders = (FRAMEHEADER *)malloc(nFrames * sizeof(FRAMEHEADER)); lpFrameData = (FRAMEDATA *)malloc(nFrames * sizeof(FRAMEDATA)); + nLastOffset = sizeof(GRPHEADER) + nFrames * sizeof(FRAMEHEADER); - for (i = 0; i <= nFrames; i++) { - if (i == 0) { - lpFrameHeaders[i].Offset = sizeof(GRPHEADER) + nFrames * sizeof(FRAMEHEADER); - } - else { - y = lpFrameHeaders[i-1].Height; - if (y > 0) { - y--; - lpFrameHeaders[i].Offset = lpFrameHeaders[i-1].Offset + lpFrameData[i-1].lpRowOffsets[y] + lpFrameData[i-1].lpRowSizes[y]; - } - else { - lpFrameHeaders[i].Offset = lpFrameHeaders[i-1].Offset; - } - } - if (i == nFrames) continue; + for (i = 0; i < nFrames; i++) { + lpFrameHeaders[i].Offset = nLastOffset; // Scan frame to find dimensions of used part x1 = y1 = 0x10000; @@ -483,107 +514,249 @@ HANDLE GRPAPI WINAPI CreateGrp(signed short *lpImageData, WORD nFrames, WORD wMa } } } + x2 = x2 - x1 + 1; + y2 = y2 - y1 + 1; + if ((WORD)x1 > 255) x1 = 255; + if ((WORD)y1 > 255) y1 = 255; + if ((WORD)x2 > 255) x2 = 255; + if ((WORD)y2 > 255) y2 = 255; lpFrameHeaders[i].Left = x1; lpFrameHeaders[i].Top = y1; - lpFrameHeaders[i].Width = x2 - x1 + 1; - lpFrameHeaders[i].Height = y2 - y1 + 1; + lpFrameHeaders[i].Width = x2; + lpFrameHeaders[i].Height = y2; + + // Search for duplicate frames + for (j = 0; j < i; j++) { + if (lpFrameData[j].lpRowOffsets && lpFrameHeaders[i].Width == lpFrameHeaders[j].Width && lpFrameHeaders[i].Height == lpFrameHeaders[j].Height) { + y1 = i * wMaxWidth * wMaxHeight + lpFrameHeaders[i].Top * wMaxWidth + lpFrameHeaders[i].Left; + y2 = j * wMaxWidth * wMaxHeight + lpFrameHeaders[j].Top * wMaxWidth + lpFrameHeaders[j].Left; + + for (y = 0; y < lpFrameHeaders[i].Height; y++) { + if (memcmp(&lpImageData[y1], &lpImageData[y2], lpFrameHeaders[i].Width * sizeof(short)) != 0) + break; + + y1 += wMaxWidth; + y2 += wMaxWidth; + } + + if (y == lpFrameHeaders[i].Height) { + break; + } + } + } + + if (j < i) { + // Duplicate frame found, set offset and flag as duplicate + lpFrameHeaders[i].Offset = lpFrameHeaders[j].Offset; + lpFrameData[i].lpRowOffsets = 0; + lpFrameData[i].lpRowSizes = 0; + lpFrameData[i].lpRowData = 0; + lpFrameData[i].Size = 0; + continue; + } - EncodeFrameData(lpImageData, i, &GrpHeader, &lpFrameHeaders[i], &lpFrameData[i]); + EncodeFrameData(lpImageData, i, &GrpHeader, &lpFrameHeaders[i], &lpFrameData[i], bNoCompress); + nLastOffset = lpFrameHeaders[i].Offset + lpFrameData[i].Size; } - lpGrpData = (LPBYTE)malloc(lpFrameHeaders[nFrames].Offset); + lpGrpData = (LPBYTE)malloc(nLastOffset); // Write completed GRP to buffer memcpy(lpGrpData, &GrpHeader, sizeof(GRPHEADER)); memcpy(lpGrpData + sizeof(GRPHEADER), lpFrameHeaders, nFrames * sizeof(FRAMEHEADER)); for (i = 0; i < nFrames; i++) { - memcpy(lpGrpData + lpFrameHeaders[i].Offset, lpFrameData[i].lpRowOffsets, lpFrameHeaders[i].Height * sizeof(WORD)); + if (lpFrameData[i].lpRowOffsets) { + if (!bNoCompress) + memcpy(lpGrpData + lpFrameHeaders[i].Offset, lpFrameData[i].lpRowOffsets, lpFrameHeaders[i].Height * sizeof(WORD)); + + for (y = 0; y < lpFrameHeaders[i].Height; y++) { + if (lpFrameData[i].lpRowData[y]) { + memcpy(lpGrpData + lpFrameHeaders[i].Offset + lpFrameData[i].lpRowOffsets[y], lpFrameData[i].lpRowData[y], lpFrameData[i].lpRowSizes[y]); + free(lpFrameData[i].lpRowData[y]); + } + } - for (y = 0; y < lpFrameHeaders[i].Height; y++) { - memcpy(lpGrpData + lpFrameHeaders[i].Offset + lpFrameData[i].lpRowOffsets[y], lpFrameData[i].lpRowData[y], lpFrameData[i].lpRowSizes[y]); - free(lpFrameData[i].lpRowData[y]); + free(lpFrameData[i].lpRowOffsets); + free(lpFrameData[i].lpRowSizes); + free(lpFrameData[i].lpRowData); } - - free(lpFrameData[i].lpRowOffsets); - free(lpFrameData[i].lpRowSizes); - free(lpFrameData[i].lpRowData); } - *nGrpSize = lpFrameHeaders[nFrames].Offset; free(lpFrameHeaders); free(lpFrameData); + *nGrpSize = nLastOffset; return (HANDLE)lpGrpData; } -void EncodeFrameData(signed short *lpImageData, WORD nFrame, GRPHEADER *lpGrpHeader, FRAMEHEADER *lpFrameHeader, FRAMEDATA *lpFrameData) +void EncodeFrameData(signed short *lpImageData, WORD nFrame, GRPHEADER *lpGrpHeader, FRAMEHEADER *lpFrameHeader, FRAMEDATA *lpFrameData, BOOL bNoCompress) { - int x, y, i, nBufPos; + int x, y, i, j, nBufPos, nRepeat; LPBYTE lpRowBuf; + WORD nLastOffset = 0; lpFrameData->lpRowOffsets = (WORD *)malloc(lpFrameHeader->Height * sizeof(WORD)); lpFrameData->lpRowSizes = (WORD *)malloc(lpFrameHeader->Height * sizeof(WORD)); lpFrameData->lpRowData = (LPBYTE *)malloc(lpFrameHeader->Height * sizeof(LPBYTE)); lpRowBuf = (LPBYTE)malloc(lpFrameHeader->Width * 2); + if (!bNoCompress) + nLastOffset = lpFrameHeader->Height * sizeof(WORD); + for (y = 0; y < lpFrameHeader->Height; y++) { i = nFrame * lpGrpHeader->wMaxWidth * lpGrpHeader->wMaxHeight + (lpFrameHeader->Top + y) * lpGrpHeader->wMaxWidth; + + if (!bNoCompress) { + // Search for duplicate rows + for (x = 0; x < y; x++) { + j = nFrame * lpGrpHeader->wMaxWidth * lpGrpHeader->wMaxHeight + (lpFrameHeader->Top + x) * lpGrpHeader->wMaxWidth; + if (memcmp(&lpImageData[i+lpFrameHeader->Left], + &lpImageData[j+lpFrameHeader->Left], + lpGrpHeader->wMaxWidth * sizeof(short)) == 0) + break; + } + + if (x < y) { + lpFrameData->lpRowOffsets[y] = lpFrameData->lpRowOffsets[x]; + lpFrameData->lpRowSizes[y] = 0; + lpFrameData->lpRowData[y] = 0; + +#ifdef _DEBUG + if (!VerifyRow(&lpImageData[i+lpFrameHeader->Left], lpFrameHeader->Width, lpFrameData->lpRowData[x], lpFrameData->lpRowSizes[x], bNoCompress)) { + nBufPos = nBufPos; + } +#endif + + continue; + } + } + nBufPos = 0; - if (lpFrameHeader->Width > 1) { - for (x = lpFrameHeader->Left; x < lpFrameHeader->Left + lpFrameHeader->Width - 1; x++) { - if (lpImageData[i+x] < 0) { - lpRowBuf[nBufPos] = 0x80; - for (; lpImageData[i+x] < 0 && x < lpFrameHeader->Left + lpFrameHeader->Width; x++) { - lpRowBuf[nBufPos]++; + if (lpFrameHeader->Width > 0) { + for (x = lpFrameHeader->Left; x < lpFrameHeader->Left + lpFrameHeader->Width; x++) { + if (!bNoCompress) { + if (x < lpFrameHeader->Left + lpFrameHeader->Width - 1) { + if (lpImageData[i+x] < 0) { + lpRowBuf[nBufPos] = 0x80; + for (; lpImageData[i+x] < 0 && x < lpFrameHeader->Left + lpFrameHeader->Width && lpRowBuf[nBufPos] < 0xFF; x++) { + lpRowBuf[nBufPos]++; + } + x--; + if (nLastOffset + nBufPos + 1 <= 0xFFFF) + nBufPos++; + continue; + } + + // Count repeating pixels, nRepeat = number of pixels - 1, ignore if there are less than 4 duplicates + for (nRepeat = 0; lpImageData[i+x+nRepeat] == lpImageData[i+x+nRepeat+1] && x+nRepeat < lpFrameHeader->Left + lpFrameHeader->Width - 1 && nRepeat < 0x3E; nRepeat++) {} + + if (nRepeat > 2) { + lpRowBuf[nBufPos] = 0x41 + nRepeat; + lpRowBuf[nBufPos+1] = (BYTE)(lpImageData[i+x]); + x += nRepeat; + if (nLastOffset + nBufPos + 2 <= 0xFFFF) + nBufPos += 2; + } + else { + lpRowBuf[nBufPos] = 0; + for (; lpImageData[i+x] >= 0 && x < lpFrameHeader->Left + lpFrameHeader->Width && lpRowBuf[nBufPos] < 0x3F; x++) { + // Count repeating pixels, ignore if there are less than 4 duplicates + for (nRepeat = 0; lpImageData[i+x+nRepeat] == lpImageData[i+x+nRepeat+1] && x+nRepeat < lpFrameHeader->Left + lpFrameHeader->Width - 1 && nRepeat < 3; nRepeat++) {} + if (nRepeat > 2) break; + + lpRowBuf[nBufPos]++; + lpRowBuf[nBufPos+lpRowBuf[nBufPos]] = (BYTE)(lpImageData[i+x]); + } + if (lpImageData[i+x] >= 0 && x == lpFrameHeader->Left + lpFrameHeader->Width - 1 && lpRowBuf[nBufPos] < 0x3F) { + lpRowBuf[nBufPos]++; + lpRowBuf[nBufPos+lpRowBuf[nBufPos]] = (BYTE)(lpImageData[i+x]); + } + x--; + if (nLastOffset + nBufPos + 1 + lpRowBuf[nBufPos] <= 0xFFFF) + nBufPos += 1 + lpRowBuf[nBufPos]; + } } - x--; - nBufPos++; - } - else if (lpImageData[i+x] == lpImageData[i+x+1]) { - lpRowBuf[nBufPos] = 0x41; - lpRowBuf[nBufPos+1] = (BYTE)lpImageData[i+x]; - for (; lpImageData[i+x] == lpImageData[i+x+1] && x < lpFrameHeader->Left + lpFrameHeader->Width - 1; x++) { - lpRowBuf[nBufPos]++; + else { + if (lpImageData[i+x] < 0) { + lpRowBuf[nBufPos] = 0x81; + if (nLastOffset + nBufPos + 1 <= 0xFFFF) + nBufPos++; + } + else { + lpRowBuf[nBufPos] = 1; + lpRowBuf[nBufPos+1] = (BYTE)(lpImageData[i+x]); + if (nLastOffset + nBufPos + 2 <= 0xFFFF) + nBufPos += 2; + } } - nBufPos += 2; } else { - lpRowBuf[nBufPos] = 1; - lpRowBuf[nBufPos+1] = (BYTE)lpImageData[i+x]; - x++; - for (; lpImageData[i+x] != lpImageData[i+x+1] && x < lpFrameHeader->Left + lpFrameHeader->Width - 1; x++) { - lpRowBuf[nBufPos]++; - lpRowBuf[nBufPos+lpRowBuf[nBufPos]] = (BYTE)lpImageData[i+x]; - } - x--; - nBufPos += 1 + lpRowBuf[nBufPos]; + lpRowBuf[nBufPos] = (BYTE)(lpImageData[i+x]); + if (nLastOffset + nBufPos + 1 <= 0xFFFF) + nBufPos++; } } } - else if (lpFrameHeader->Width == 1){ - if (lpImageData[i] < 0) { - lpRowBuf[nBufPos] = 0x81; - nBufPos++; - } - else { - lpRowBuf[nBufPos] = 1; - lpRowBuf[nBufPos+1] = (BYTE)lpImageData[i+1]; - nBufPos += 2; - } - } - if (y == 0) { - lpFrameData->lpRowOffsets[y] = lpFrameHeader->Height * sizeof(WORD); - } - else { - lpFrameData->lpRowOffsets[y] = lpFrameData->lpRowOffsets[y-1] + lpFrameData->lpRowSizes[y-1]; +#ifdef _DEBUG + if (!VerifyRow(&lpImageData[i+lpFrameHeader->Left], lpFrameHeader->Width, lpRowBuf, nBufPos, bNoCompress)) { + nBufPos = nBufPos; } +#endif + + lpFrameData->lpRowOffsets[y] = nLastOffset; + nLastOffset = lpFrameData->lpRowOffsets[y] + nBufPos; lpFrameData->lpRowSizes[y] = nBufPos; lpFrameData->lpRowData[y] = (LPBYTE)malloc(nBufPos); memcpy(lpFrameData->lpRowData[y], lpRowBuf, nBufPos); } + lpFrameData->Size = nLastOffset; + free(lpRowBuf); } + +#ifdef _DEBUG +BOOL VerifyRow(signed short *lpRawRow, int nWidth, LPBYTE lpEncRow, int nSize, BOOL bNoCompress) +{ + int i,x=0,ofs=0; + while (x < nWidth && ofs < nSize) { + if (!bNoCompress) { + if (!(lpEncRow[ofs] & 0x80)) { + if (!(lpEncRow[ofs] & 0x40)) { + for (i=1;i<=lpEncRow[ofs] && x= 0) return FALSE; + } + x+=lpEncRow[ofs]-128; + ofs++; + } + } + else { + if (lpEncRow[ofs] != (BYTE)lpRawRow[x]) return FALSE; + x++; + ofs++; + } + } + + if (x != nWidth || ofs != nSize) return FALSE; + + return TRUE; +} +#endif