#include "diablo.h" #include "../3rdParty/Storm/Source/storm.h" DEVILUTION_BEGIN_NAMESPACE char gbPixelCol; // automap pixel color 8-bit (palette entry) BOOL gbRotateMap; // flip - if y < x int orgseed; int sgnWidth; int sglGameSeed; static CCritSect sgMemCrit; int SeedCount; BOOL gbNotInView; // valid - if x/y are in bounds const int RndInc = 1; const int RndMult = 0x015A4E35; void CelDrawDatOnly(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth) { int w; /// ASSERT: assert(pDecodeTo != NULL); if (!pDecodeTo) return; /// ASSERT: assert(pRLEBytes != NULL); if (!pRLEBytes) return; int i; BYTE width; BYTE *src, *dst; src = pRLEBytes; dst = pDecodeTo; w = nWidth; for (; src != &pRLEBytes[nDataSize]; dst -= BUFFER_WIDTH + w) { for (i = w; i;) { width = *src++; if (!(width & 0x80)) { i -= width; if (width & 1) { dst[0] = src[0]; src++; dst++; } width >>= 1; if (width & 1) { dst[0] = src[0]; dst[1] = src[1]; src += 2; dst += 2; } width >>= 1; for (; width; width--) { dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; src += 4; dst += 4; } } else { width = -(char)width; dst += width; i -= width; } } } } void CelDecodeOnly(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth) { DWORD *pFrameTable; /// ASSERT: assert(gpBuffer); if (!gpBuffer) return; /// ASSERT: assert(pCelBuff != NULL); if (!pCelBuff) return; pFrameTable = (DWORD *)pCelBuff; CelDrawDatOnly( &gpBuffer[sx + PitchTbl[sy]], &pCelBuff[pFrameTable[nCel]], pFrameTable[nCel + 1] - pFrameTable[nCel], nWidth); } void CelDecDatOnly(BYTE *pBuff, BYTE *pCelBuff, int nCel, int nWidth) { DWORD *pFrameTable; /// ASSERT: assert(pCelBuff != NULL); if (!pCelBuff) return; /// ASSERT: assert(pBuff != NULL); if (!pBuff) return; pFrameTable = (DWORD *)pCelBuff; CelDrawDatOnly( pBuff, &pCelBuff[pFrameTable[nCel]], pFrameTable[nCel + 1] - pFrameTable[nCel], nWidth); } /** * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void CelDrawHdrOnly(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { int nDataStart, nDataSize, nDataCap; BYTE *pRLEBytes; DWORD *pFrameTable; /// ASSERT: assert(gpBuffer); if (!gpBuffer) return; /// ASSERT: assert(pCelBuff != NULL); if (!pCelBuff) return; pFrameTable = (DWORD *)pCelBuff; pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; if (CelCap == 8) nDataCap = 0; else nDataCap = *(WORD *)&pRLEBytes[CelCap]; if (nDataCap) nDataSize = nDataCap - nDataStart; else nDataSize -= nDataStart; CelDrawDatOnly( &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]], pRLEBytes + nDataStart, nDataSize, nWidth); } /** * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void CelDecodeHdrOnly(BYTE *pBuff, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { int nDataStart, nDataSize, nDataCap; BYTE *pRLEBytes; DWORD *pFrameTable; /// ASSERT: assert(pCelBuff != NULL); if (!pCelBuff) return; /// ASSERT: assert(pBuff != NULL); if (!pBuff) return; pFrameTable = (DWORD *)pCelBuff; pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; if (CelCap == 8) nDataCap = 0; else nDataCap = *(WORD *)&pRLEBytes[CelCap]; if (nDataCap) nDataSize = nDataCap - nDataStart; else nDataSize -= nDataStart; CelDrawDatOnly(pBuff, pRLEBytes + nDataStart, nDataSize, nWidth); } void CelDecDatLightOnly(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth) { int w; BYTE *tbl; /// ASSERT: assert(pDecodeTo != NULL); if (!pDecodeTo) return; /// ASSERT: assert(pRLEBytes != NULL); if (!pRLEBytes) return; int i; BYTE width; BYTE *src, *dst; src = pRLEBytes; dst = pDecodeTo; tbl = &pLightTbl[light_table_index * 256]; w = nWidth; for (; src != &pRLEBytes[nDataSize]; dst -= BUFFER_WIDTH + w) { for (i = w; i;) { width = *src++; if (!(width & 0x80)) { i -= width; if (width & 1) { dst[0] = tbl[src[0]]; src++; dst++; } width >>= 1; if (width & 1) { dst[0] = tbl[src[0]]; dst[1] = tbl[src[1]]; src += 2; dst += 2; } width >>= 1; for (; width; width--) { dst[0] = tbl[src[0]]; dst[1] = tbl[src[1]]; dst[2] = tbl[src[2]]; dst[3] = tbl[src[3]]; src += 4; dst += 4; } } else { width = -(char)width; dst += width; i -= width; } } } } void CelDecDatLightTrans(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth) { int w; BOOL shift; BYTE *tbl; /// ASSERT: assert(pDecodeTo != NULL); if (!pDecodeTo) return; /// ASSERT: assert(pRLEBytes != NULL); if (!pRLEBytes) return; #ifdef USE_ASM __asm { mov eax, light_table_index shl eax, 8 add eax, pLightTbl mov tbl, eax mov esi, pRLEBytes mov edi, pDecodeTo mov eax, BUFFER_WIDTH add eax, nWidth mov w, eax mov ebx, nDataSize add ebx, esi mov eax, edi and eax, 1 mov shift, eax label1: mov edx, nWidth label2: xor eax, eax lodsb or al, al js label9 push ebx mov ebx, tbl sub edx, eax mov ecx, eax mov eax, edi and eax, 1 cmp eax, shift jnz label5 shr ecx, 1 jnb label3 inc esi inc edi jecxz label8 jmp label6 label3: shr ecx, 1 jnb label4 inc esi inc edi lodsb xlat stosb jecxz label8 label4: lodsd inc edi ror eax, 8 xlat stosb ror eax, 10h inc edi xlat stosb loop label4 jmp label8 label5: shr ecx, 1 jnb label6 lodsb xlat stosb jecxz label8 jmp label3 label6: shr ecx, 1 jnb label7 lodsb xlat stosb inc esi inc edi jecxz label8 label7: lodsd xlat stosb inc edi ror eax, 10h xlat stosb inc edi loop label7 label8: pop ebx or edx, edx jz label10 jmp label2 label9: neg al add edi, eax sub edx, eax jnz label2 label10: sub edi, w mov eax, shift inc eax and eax, 1 mov shift, eax cmp ebx, esi jnz label1 } #else int i; BYTE width; BYTE *src, *dst; src = pRLEBytes; dst = pDecodeTo; tbl = &pLightTbl[light_table_index * 256]; w = nWidth; shift = (BYTE)dst & 1; for (; src != &pRLEBytes[nDataSize]; dst -= BUFFER_WIDTH + w, shift = (shift + 1) & 1) { for (i = w; i;) { width = *src++; if (!(width & 0x80)) { i -= width; if (((BYTE)dst & 1) == shift) { if (!(width & 1)) { goto L_ODD; } else { src++; dst++; L_EVEN: width >>= 1; if (width & 1) { dst[0] = tbl[src[0]]; src += 2; dst += 2; } width >>= 1; for (; width; width--) { dst[0] = tbl[src[0]]; dst[2] = tbl[src[2]]; src += 4; dst += 4; } } } else { if (!(width & 1)) { goto L_EVEN; } else { dst[0] = tbl[src[0]]; src++; dst++; L_ODD: width >>= 1; if (width & 1) { dst[1] = tbl[src[1]]; src += 2; dst += 2; } width >>= 1; for (; width; width--) { dst[1] = tbl[src[1]]; dst[3] = tbl[src[3]]; src += 4; dst += 4; } } } } else { width = -(char)width; dst += width; i -= width; } } } #endif } void CelDecodeLightOnly(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth) { int nDataSize; BYTE *pDecodeTo, *pRLEBytes; DWORD *pFrameTable; /// ASSERT: assert(gpBuffer); if (!gpBuffer) return; /// ASSERT: assert(pCelBuff != NULL); if (!pCelBuff) return; pFrameTable = (DWORD *)pCelBuff; nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; pRLEBytes = &pCelBuff[pFrameTable[nCel]]; pDecodeTo = &gpBuffer[sx + PitchTbl[sy]]; if (light_table_index) CelDecDatLightOnly(pDecodeTo, pRLEBytes, nDataSize, nWidth); else CelDrawDatOnly(pDecodeTo, pRLEBytes, nDataSize, nWidth); } /** * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void CelDecodeHdrLightOnly(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { int nDataStart, nDataSize, nDataCap; BYTE *pRLEBytes, *pDecodeTo; DWORD *pFrameTable; /// ASSERT: assert(gpBuffer); if (!gpBuffer) return; /// ASSERT: assert(pCelBuff != NULL); if (!pCelBuff) return; pFrameTable = (DWORD *)pCelBuff; pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; if (CelCap == 8) nDataCap = 0; else nDataCap = *(WORD *)&pRLEBytes[CelCap]; if (nDataCap) nDataSize = nDataCap - nDataStart; else nDataSize -= nDataStart; pRLEBytes += nDataStart; pDecodeTo = &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]]; if (light_table_index) CelDecDatLightOnly(pDecodeTo, pRLEBytes, nDataSize, nWidth); else CelDrawDatOnly(pDecodeTo, pRLEBytes, nDataSize, nWidth); } /** * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void CelDecodeHdrLightTrans(BYTE *pBuff, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { int nDataStart, nDataSize, nDataCap; BYTE *pRLEBytes; DWORD *pFrameTable; /// ASSERT: assert(pCelBuff != NULL); if (!pCelBuff) return; /// ASSERT: assert(pBuff != NULL); if (!pBuff) return; pFrameTable = (DWORD *)pCelBuff; pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; if (CelCap == 8) nDataCap = 0; else nDataCap = *(WORD *)&pRLEBytes[CelCap]; if (nDataCap) nDataSize = nDataCap - nDataStart; else nDataSize -= nDataStart; pRLEBytes += nDataStart; if (cel_transparency_active) CelDecDatLightTrans(pBuff, pRLEBytes, nDataSize, nWidth); else if (light_table_index) CelDecDatLightOnly(pBuff, pRLEBytes, nDataSize, nWidth); else CelDrawDatOnly(pBuff, pRLEBytes, nDataSize, nWidth); } /** * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void CelDrawHdrLightRed(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap, char light) { int nDataStart, nDataSize, nDataCap, w, idx; BYTE *pRLEBytes, *dst, *tbl; DWORD *pFrameTable; /// ASSERT: assert(gpBuffer); if (!gpBuffer) return; /// ASSERT: assert(pCelBuff != NULL); if (!pCelBuff) return; pFrameTable = (DWORD *)pCelBuff; pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; if (CelCap == 8) nDataCap = 0; else nDataCap = *(WORD *)&pRLEBytes[CelCap]; if (nDataCap) nDataSize = nDataCap - nDataStart; else nDataSize -= nDataStart; pRLEBytes += nDataStart; dst = &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]]; idx = light4flag ? 1024 : 4096; if (light == 2) idx += 256; if (light >= 4) idx += (light - 1) << 8; BYTE width; BYTE *end; tbl = &pLightTbl[idx]; end = &pRLEBytes[nDataSize]; for (; pRLEBytes != end; dst -= BUFFER_WIDTH + nWidth) { for (w = nWidth; w;) { width = *pRLEBytes++; if (!(width & 0x80)) { w -= width; while (width) { *dst = tbl[*pRLEBytes]; pRLEBytes++; dst++; width--; } } else { width = -(char)width; dst += width; w -= width; } } } } void Cel2DecDatOnly(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth) { int w; /// ASSERT: assert(pDecodeTo != NULL); if (!pDecodeTo) return; /// ASSERT: assert(pRLEBytes != NULL); if (!pRLEBytes) return; /// ASSERT: assert(gpBuffer); if (!gpBuffer) return; int i; BYTE width; BYTE *src, *dst; src = pRLEBytes; dst = pDecodeTo; w = nWidth; for (; src != &pRLEBytes[nDataSize]; dst -= BUFFER_WIDTH + w) { for (i = w; i;) { width = *src++; if (!(width & 0x80)) { i -= width; if (dst < gpBufEnd) { if (width & 1) { dst[0] = src[0]; src++; dst++; } width >>= 1; if (width & 1) { dst[0] = src[0]; dst[1] = src[1]; src += 2; dst += 2; } width >>= 1; for (; width; width--) { dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; src += 4; dst += 4; } } else { src += width; dst += width; } } else { width = -(char)width; dst += width; i -= width; } } } } /** * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void Cel2DrawHdrOnly(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { int nDataStart, nDataSize, nDataCap; BYTE *pRLEBytes; DWORD *pFrameTable; /// ASSERT: assert(gpBuffer); if (!gpBuffer) return; /// ASSERT: assert(pCelBuff != NULL); if (!pCelBuff) return; pFrameTable = (DWORD *)pCelBuff; pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; if (CelCap == 8) nDataCap = 0; else nDataCap = *(WORD *)&pRLEBytes[CelCap]; if (nDataCap) nDataSize = nDataCap - nDataStart; else nDataSize -= nDataStart; Cel2DecDatOnly( &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]], pRLEBytes + nDataStart, nDataSize, nWidth); } /** * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void Cel2DecodeHdrOnly(BYTE *pBuff, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { int nDataStart, nDataSize, nDataCap; BYTE *pRLEBytes; DWORD *pFrameTable; /// ASSERT: assert(pCelBuff != NULL); if (!pCelBuff) return; /// ASSERT: assert(pBuff != NULL); if (!pBuff) return; pFrameTable = (DWORD *)pCelBuff; pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; nDataCap = *(WORD *)&pRLEBytes[CelCap]; if (CelCap == 8) nDataCap = 0; if (nDataCap) nDataSize = nDataCap - nDataStart; else nDataSize -= nDataStart; Cel2DecDatOnly(pBuff, pRLEBytes + nDataStart, nDataSize, nWidth); } void Cel2DecDatLightOnly(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth) { int w; BYTE *tbl; /// ASSERT: assert(pDecodeTo != NULL); if (!pDecodeTo) return; /// ASSERT: assert(pRLEBytes != NULL); if (!pRLEBytes) return; /// ASSERT: assert(gpBuffer); if (!gpBuffer) return; int i; BYTE width; BYTE *src, *dst; src = pRLEBytes; dst = pDecodeTo; tbl = &pLightTbl[light_table_index * 256]; w = nWidth; for (; src != &pRLEBytes[nDataSize]; dst -= BUFFER_WIDTH + w) { for (i = w; i;) { width = *src++; if (!(width & 0x80)) { i -= width; if (dst < gpBufEnd) { if (width & 1) { dst[0] = tbl[src[0]]; src++; dst++; } width >>= 1; if (width & 1) { dst[0] = tbl[src[0]]; dst[1] = tbl[src[1]]; src += 2; dst += 2; } width >>= 1; for (; width; width--) { dst[0] = tbl[src[0]]; dst[1] = tbl[src[1]]; dst[2] = tbl[src[2]]; dst[3] = tbl[src[3]]; src += 4; dst += 4; } } else { src += width; dst += width; } } else { width = -(char)width; dst += width; i -= width; } } } } void Cel2DecDatLightTrans(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth) { int w; BOOL shift; BYTE *tbl; /// ASSERT: assert(pDecodeTo != NULL); if (!pDecodeTo) return; /// ASSERT: assert(pRLEBytes != NULL); if (!pRLEBytes) return; /// ASSERT: assert(gpBuffer); if (!gpBuffer) return; #ifdef USE_ASM __asm { mov eax, light_table_index shl eax, 8 add eax, pLightTbl mov tbl, eax mov esi, pRLEBytes mov edi, pDecodeTo mov eax, BUFFER_WIDTH add eax, nWidth mov w, eax mov ebx, nDataSize add ebx, esi mov eax, edi and eax, 1 mov shift, eax label1: mov edx, nWidth label2: xor eax, eax lodsb or al, al js label10 push ebx mov ebx, tbl sub edx, eax cmp edi, gpBufEnd jb label3 add esi, eax add edi, eax jmp label9 label3: mov ecx, eax mov eax, edi and eax, 1 cmp eax, shift jnz label6 shr ecx, 1 jnb label4 inc esi inc edi jecxz label9 jmp label7 label4: shr ecx, 1 jnb label5 inc esi inc edi lodsb xlat stosb jecxz label9 label5: lodsd inc edi ror eax, 8 xlat stosb ror eax, 10h inc edi xlat stosb loop label5 jmp label9 label6: shr ecx, 1 jnb label7 lodsb xlat stosb jecxz label9 jmp label4 label7: shr ecx, 1 jnb label8 lodsb xlat stosb inc esi inc edi jecxz label9 label8: lodsd xlat stosb inc edi ror eax, 10h xlat stosb inc edi loop label8 label9: pop ebx or edx, edx jz label11 jmp label2 label10: neg al add edi, eax sub edx, eax jnz label2 label11: sub edi, w mov eax, shift inc eax and eax, 1 mov shift, eax cmp ebx, esi jnz label1 } #else int i; BYTE width; BYTE *src, *dst; src = pRLEBytes; dst = pDecodeTo; tbl = &pLightTbl[light_table_index * 256]; w = nWidth; shift = (BYTE)dst & 1; for (; src != &pRLEBytes[nDataSize]; dst -= BUFFER_WIDTH + w, shift = (shift + 1) & 1) { for (i = w; i;) { width = *src++; if (!(width & 0x80)) { i -= width; if (dst < gpBufEnd) { if (((BYTE)dst & 1) == shift) { if (!(width & 1)) { goto L_ODD; } else { src++; dst++; L_EVEN: width >>= 1; if (width & 1) { dst[0] = tbl[src[0]]; src += 2; dst += 2; } width >>= 1; for (; width; width--) { dst[0] = tbl[src[0]]; dst[2] = tbl[src[2]]; src += 4; dst += 4; } } } else { if (!(width & 1)) { goto L_EVEN; } else { dst[0] = tbl[src[0]]; src++; dst++; L_ODD: width >>= 1; if (width & 1) { dst[1] = tbl[src[1]]; src += 2; dst += 2; } width >>= 1; for (; width; width--) { dst[1] = tbl[src[1]]; dst[3] = tbl[src[3]]; src += 4; dst += 4; } } } } else { src += width; dst += width; } } else { width = -(char)width; dst += width; i -= width; } } } #endif } /** * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void Cel2DecodeHdrLight(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { int nDataStart, nDataSize, nDataCap; BYTE *pRLEBytes, *pDecodeTo; DWORD *pFrameTable; /// ASSERT: assert(gpBuffer); if (!gpBuffer) return; /// ASSERT: assert(pCelBuff != NULL); if (!pCelBuff) return; pFrameTable = (DWORD *)pCelBuff; pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; nDataCap = *(WORD *)&pRLEBytes[CelCap]; if (CelCap == 8) nDataCap = 0; if (nDataCap) nDataSize = nDataCap - nDataStart; else nDataSize -= nDataStart; pRLEBytes += nDataStart; pDecodeTo = &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]]; if (light_table_index) Cel2DecDatLightOnly(pDecodeTo, pRLEBytes, nDataSize, nWidth); else Cel2DecDatOnly(pDecodeTo, pRLEBytes, nDataSize, nWidth); } /** * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void Cel2DecodeLightTrans(BYTE *pBuff, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { int nDataStart, nDataSize, nDataCap; BYTE *pRLEBytes; DWORD *pFrameTable; /// ASSERT: assert(pCelBuff != NULL); if (!pCelBuff) return; pFrameTable = (DWORD *)pCelBuff; pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; nDataCap = *(WORD *)&pRLEBytes[CelCap]; if (CelCap == 8) nDataCap = 0; if (nDataCap) nDataSize = nDataCap - nDataStart; else nDataSize -= nDataStart; pRLEBytes += nDataStart; if (cel_transparency_active) Cel2DecDatLightTrans(pBuff, pRLEBytes, nDataSize, nWidth); else if (light_table_index) Cel2DecDatLightOnly(pBuff, pRLEBytes, nDataSize, nWidth); else Cel2DecDatOnly(pBuff, pRLEBytes, nDataSize, nWidth); } /** * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void Cel2DrawHdrLightRed(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap, char light) { int nDataStart, nDataSize, nDataCap, w, idx; BYTE *pRLEBytes, *dst, *tbl; DWORD *pFrameTable; /// ASSERT: assert(gpBuffer); if (!gpBuffer) return; /// ASSERT: assert(pCelBuff != NULL); if (!pCelBuff) return; pFrameTable = (DWORD *)pCelBuff; pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; if (CelCap == 8) nDataCap = 0; else nDataCap = *(WORD *)&pRLEBytes[CelCap]; if (nDataCap) nDataSize = nDataCap - nDataStart; else nDataSize -= nDataStart; pRLEBytes += nDataStart; dst = &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]]; idx = light4flag ? 1024 : 4096; if (light == 2) idx += 256; if (light >= 4) idx += (light - 1) << 8; tbl = &pLightTbl[idx]; BYTE width; BYTE *end; end = &pRLEBytes[nDataSize]; for (; pRLEBytes != end; dst -= BUFFER_WIDTH + nWidth) { for (w = nWidth; w;) { width = *pRLEBytes++; if (!(width & 0x80)) { w -= width; if (dst < gpBufEnd) { while (width) { *dst = tbl[*pRLEBytes]; pRLEBytes++; dst++; width--; } } else { pRLEBytes += width; dst += width; } } else { width = -(char)width; dst += width; w -= width; } } } } void CelDecodeRect(BYTE *pBuff, int CelSkip, int hgt, int wdt, BYTE *pCelBuff, int nCel, int nWidth) { BYTE *pRLEBytes, *dst, *end; /// ASSERT: assert(pCelBuff != NULL); if (!pCelBuff) return; /// ASSERT: assert(pBuff != NULL); if (!pBuff) return; int i; BYTE width; DWORD *pFrameTable; pFrameTable = (DWORD *)&pCelBuff[4 * nCel]; pRLEBytes = &pCelBuff[pFrameTable[0]]; end = &pRLEBytes[pFrameTable[1] - pFrameTable[0]]; dst = &pBuff[hgt * wdt + CelSkip]; for (; pRLEBytes != end; dst -= wdt + nWidth) { for (i = nWidth; i;) { width = *pRLEBytes++; if (!(width & 0x80)) { i -= width; if (width & 1) { dst[0] = pRLEBytes[0]; pRLEBytes++; dst++; } width >>= 1; if (width & 1) { dst[0] = pRLEBytes[0]; dst[1] = pRLEBytes[1]; pRLEBytes += 2; dst += 2; } width >>= 1; while (width) { dst[0] = pRLEBytes[0]; dst[1] = pRLEBytes[1]; dst[2] = pRLEBytes[2]; dst[3] = pRLEBytes[3]; pRLEBytes += 4; dst += 4; width--; } } else { width = -(char)width; dst += width; i -= width; } } } } /** * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void CelDecodeClr(char col, int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { int nDataStart, nDataSize, nDataCap, w; BYTE *pRLEBytes, *dst; /// ASSERT: assert(pCelBuff != NULL); if (!pCelBuff) return; /// ASSERT: assert(gpBuffer); if (!gpBuffer) return; BYTE width; BYTE *end, *src; DWORD *pFrameTable; pFrameTable = (DWORD *)&pCelBuff[4 * nCel]; pRLEBytes = &pCelBuff[pFrameTable[0]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; nDataCap = *(WORD *)&pRLEBytes[CelCap]; if (CelCap == 8) nDataCap = 0; if (nDataCap) nDataSize = nDataCap - nDataStart; else nDataSize = pFrameTable[1] - pFrameTable[0] - nDataStart; src = pRLEBytes + nDataStart; end = &src[nDataSize]; dst = &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]]; for (; src != end; dst -= BUFFER_WIDTH + nWidth) { for (w = nWidth; w;) { width = *src++; if (!(width & 0x80)) { w -= width; while (width) { if (*src++) { dst[-BUFFER_WIDTH] = col; dst[-1] = col; dst[1] = col; dst[BUFFER_WIDTH] = col; } dst++; width--; } } else { width = -(char)width; dst += width; w -= width; } } } } /** * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void CelDrawHdrClrHL(char col, int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { int nDataStart, nDataSize, nDataCap, w; BYTE *pRLEBytes, *dst; /// ASSERT: assert(pCelBuff != NULL); if (!pCelBuff) return; /// ASSERT: assert(gpBuffer); if (!gpBuffer) return; BYTE width; BYTE *end, *src; DWORD *pFrameTable; pFrameTable = (DWORD *)&pCelBuff[4 * nCel]; pRLEBytes = &pCelBuff[pFrameTable[0]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; nDataCap = *(WORD *)&pRLEBytes[CelCap]; if (CelCap == 8) nDataCap = 0; if (nDataCap) nDataSize = nDataCap - nDataStart; else nDataSize = pFrameTable[1] - pFrameTable[0] - nDataStart; src = pRLEBytes + nDataStart; end = &src[nDataSize]; dst = &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]]; for (; src != end; dst -= BUFFER_WIDTH + nWidth) { for (w = nWidth; w;) { width = *src++; if (!(width & 0x80)) { w -= width; if (dst < gpBufEnd) { if (dst >= gpBufEnd - BUFFER_WIDTH) { while (width) { if (*src++) { dst[-BUFFER_WIDTH] = col; dst[-1] = col; dst[1] = col; } dst++; width--; } } else { while (width) { if (*src++) { dst[-BUFFER_WIDTH] = col; dst[-1] = col; dst[1] = col; dst[BUFFER_WIDTH] = col; } dst++; width--; } } } else { src += width; dst += width; } } else { width = -(char)width; dst += width; w -= width; } } } } void ENG_set_pixel(int sx, int sy, BYTE col) { BYTE *dst; /// ASSERT: assert(gpBuffer); if (sy < 0 || sy >= SCREEN_HEIGHT + SCREEN_Y || sx < SCREEN_X || sx >= SCREEN_WIDTH + SCREEN_X) return; dst = &gpBuffer[sx + PitchTbl[sy]]; if (dst < gpBufEnd) *dst = col; } void engine_draw_pixel(int sx, int sy) { BYTE *dst; /// ASSERT: assert(gpBuffer); if (gbRotateMap) { if (gbNotInView && (sx < 0 || sx >= SCREEN_HEIGHT + SCREEN_Y || sy < SCREEN_X || sy >= SCREEN_WIDTH + SCREEN_X)) return; dst = &gpBuffer[sy + PitchTbl[sx]]; } else { if (gbNotInView && (sy < 0 || sy >= SCREEN_HEIGHT + SCREEN_Y || sx < SCREEN_X || sx >= SCREEN_WIDTH + SCREEN_X)) return; dst = &gpBuffer[sx + PitchTbl[sy]]; } if (dst < gpBufEnd) *dst = gbPixelCol; } // Exact copy from https://github.com/erich666/GraphicsGems/blob/dad26f941e12c8bf1f96ea21c1c04cd2206ae7c9/gems/DoubleLine.c // Except: // * not in view checks // * global variable instead of reverse flag // * condition for pixels_left < 0 removed /* Symmetric Double Step Line Algorithm by Brian Wyvill from "Graphics Gems", Academic Press, 1990 */ #define GG_SWAP(A, B) \ { \ (A) ^= (B); \ (B) ^= (A); \ (A) ^= (B); \ } #define GG_ABSOLUTE(I, J, K) (((I) - (J)) * ((K) = (((I) - (J)) < 0 ? -1 : 1))) void DrawLine(int x0, int y0, int x1, int y1, BYTE col) { int dx, dy, incr1, incr2, D, x, y, xend, c, pixels_left; int sign_x, sign_y, step, i; int x1_, y1_; gbPixelCol = col; gbNotInView = FALSE; if (x0 < 0 + SCREEN_X || x0 >= SCREEN_WIDTH + SCREEN_X) { gbNotInView = TRUE; } if (x1 < 0 + SCREEN_X || x1 >= SCREEN_WIDTH + SCREEN_X) { gbNotInView = TRUE; } if (y0 < 0 + SCREEN_Y || y0 >= PANEL_Y) { gbNotInView = TRUE; } if (y1 < 0 + SCREEN_Y || y1 >= PANEL_Y) { gbNotInView = TRUE; } dx = GG_ABSOLUTE(x1, x0, sign_x); dy = GG_ABSOLUTE(y1, y0, sign_y); /* decide increment sign by the slope sign */ if (sign_x == sign_y) step = 1; else step = -1; if (dy > dx) { /* chooses axis of greatest movement (make * dx) */ GG_SWAP(x0, y0); GG_SWAP(x1, y1); GG_SWAP(dx, dy); gbRotateMap = TRUE; } else gbRotateMap = FALSE; /* note error check for dx==0 should be included here */ if (x0 > x1) { /* start from the smaller coordinate */ x = x1; y = y1; x1_ = x0; y1_ = y0; } else { x = x0; y = y0; x1_ = x1; y1_ = y1; } /* Note dx=n implies 0 - n or (dx+1) pixels to be set */ /* Go round loop dx/4 times then plot last 0,1,2 or 3 pixels */ /* In fact (dx-1)/4 as 2 pixels are already plotted */ xend = (dx - 1) / 4; pixels_left = (dx - 1) % 4; /* number of pixels left over at the end */ engine_draw_pixel(x, y); engine_draw_pixel(x1_, y1_); /* plot first two points */ incr2 = 4 * dy - 2 * dx; if (incr2 < 0) { /* slope less than 1/2 */ c = 2 * dy; incr1 = 2 * c; D = incr1 - dx; for (i = 0; i < xend; i++) { /* plotting loop */ ++x; --x1_; if (D < 0) { /* pattern 1 forwards */ engine_draw_pixel(x, y); engine_draw_pixel(++x, y); /* pattern 1 backwards */ engine_draw_pixel(x1_, y1_); engine_draw_pixel(--x1_, y1_); D += incr1; } else { if (D < c) { /* pattern 2 forwards */ engine_draw_pixel(x, y); engine_draw_pixel(++x, y += step); /* pattern 2 backwards */ engine_draw_pixel(x1_, y1_); engine_draw_pixel(--x1_, y1_ -= step); } else { /* pattern 3 forwards */ engine_draw_pixel(x, y += step); engine_draw_pixel(++x, y); /* pattern 3 backwards */ engine_draw_pixel(x1_, y1_ -= step); engine_draw_pixel(--x1_, y1_); } D += incr2; } } /* end for */ /* plot last pattern */ if (pixels_left) { if (D < 0) { engine_draw_pixel(++x, y); /* pattern 1 */ if (pixels_left > 1) engine_draw_pixel(++x, y); if (pixels_left > 2) engine_draw_pixel(--x1_, y1_); } else { if (D < c) { engine_draw_pixel(++x, y); /* pattern 2 */ if (pixels_left > 1) engine_draw_pixel(++x, y += step); if (pixels_left > 2) engine_draw_pixel(--x1_, y1_); } else { /* pattern 3 */ engine_draw_pixel(++x, y += step); if (pixels_left > 1) engine_draw_pixel(++x, y); if (pixels_left > 2) engine_draw_pixel(--x1_, y1_ -= step); } } } /* end if pixels_left */ } /* end slope < 1/2 */ else { /* slope greater than 1/2 */ c = 2 * (dy - dx); incr1 = 2 * c; D = incr1 + dx; for (i = 0; i < xend; i++) { ++x; --x1_; if (D > 0) { /* pattern 4 forwards */ engine_draw_pixel(x, y += step); engine_draw_pixel(++x, y += step); /* pattern 4 backwards */ engine_draw_pixel(x1_, y1_ -= step); engine_draw_pixel(--x1_, y1_ -= step); D += incr1; } else { if (D < c) { /* pattern 2 forwards */ engine_draw_pixel(x, y); engine_draw_pixel(++x, y += step); /* pattern 2 backwards */ engine_draw_pixel(x1_, y1_); engine_draw_pixel(--x1_, y1_ -= step); } else { /* pattern 3 forwards */ engine_draw_pixel(x, y += step); engine_draw_pixel(++x, y); /* pattern 3 backwards */ engine_draw_pixel(x1_, y1_ -= step); engine_draw_pixel(--x1_, y1_); } D += incr2; } } /* end for */ /* plot last pattern */ if (pixels_left) { if (D > 0) { engine_draw_pixel(++x, y += step); /* pattern 4 */ if (pixels_left > 1) engine_draw_pixel(++x, y += step); if (pixels_left > 2) engine_draw_pixel(--x1_, y1_ -= step); } else { if (D < c) { engine_draw_pixel(++x, y); /* pattern 2 */ if (pixels_left > 1) engine_draw_pixel(++x, y += step); if (pixels_left > 2) engine_draw_pixel(--x1_, y1_); } else { /* pattern 3 */ engine_draw_pixel(++x, y += step); if (pixels_left > 1) engine_draw_pixel(++x, y); if (pixels_left > 2) { if (D > c) /* step 3 */ engine_draw_pixel(--x1_, y1_ -= step); else /* step 2 */ engine_draw_pixel(--x1_, y1_); } } } } } } int GetDirection(int x1, int y1, int x2, int y2) { int mx, my; int md, ny; mx = x2 - x1; my = y2 - y1; if (mx >= 0) { if (my >= 0) { md = DIR_S; if (2 * mx < my) md = DIR_SW; } else { my = -my; md = DIR_E; if (2 * mx < my) md = DIR_NE; } if (2 * my < mx) return DIR_SE; } else { ny = -mx; if (my >= 0) { md = DIR_W; if (2 * ny < my) md = DIR_SW; } else { my = -my; md = DIR_N; if (2 * ny < my) md = DIR_NE; } if (2 * my < ny) return DIR_NW; } return md; } void SetRndSeed(int s) { SeedCount = 0; sglGameSeed = s; orgseed = s; } int GetRndSeed() { SeedCount++; sglGameSeed = RndMult * sglGameSeed + RndInc; return abs(sglGameSeed); } int random(BYTE idx, int v) { if (v <= 0) return 0; if (v >= 0xFFFF) return GetRndSeed() % v; return (GetRndSeed() >> 16) % v; } void engine_debug_trap(BOOL show_cursor) { /* TMemBlock *pCurr; sgMemCrit.Enter(); while(sgpMemBlock != NULL) { pCurr = sgpMemBlock->pNext; SMemFree(sgpMemBlock, __FILE__, __LINE__); sgpMemBlock = pCurr; } sgMemCrit.Leave(); */ } BYTE *DiabloAllocPtr(DWORD dwBytes) { BYTE *buf; sgMemCrit.Enter(); buf = (BYTE *)SMemAlloc(dwBytes, __FILE__, __LINE__, 0); sgMemCrit.Leave(); if (buf == NULL) { ERR_DLG(IDD_DIALOG2, GetLastError()); } return buf; } void mem_free_dbg(void *p) { if (p) { sgMemCrit.Enter(); SMemFree(p, __FILE__, __LINE__, 0); sgMemCrit.Leave(); } } BYTE *LoadFileInMem(char *pszName, DWORD *pdwFileLen) { HANDLE file; BYTE *buf; int fileLen; WOpenFile(pszName, &file, FALSE); fileLen = WGetFileSize(file, NULL); if (pdwFileLen) *pdwFileLen = fileLen; if (!fileLen) app_fatal("Zero length SFILE:\n%s", pszName); buf = (BYTE *)DiabloAllocPtr(fileLen); WReadFile(file, buf, fileLen); WCloseFile(file); return buf; } DWORD LoadFileWithMem(const char *pszName, void *p) { DWORD dwFileLen; HANDLE hsFile; /// ASSERT: assert(pszName); if (p == NULL) { app_fatal("LoadFileWithMem(NULL):\n%s", pszName); } WOpenFile(pszName, &hsFile, FALSE); dwFileLen = WGetFileSize(hsFile, NULL); if (dwFileLen == 0) { app_fatal("Zero length SFILE:\n%s", pszName); } WReadFile(hsFile, p, dwFileLen); WCloseFile(hsFile); return dwFileLen; } void Cl2ApplyTrans(BYTE *p, BYTE *ttbl, int nCel) { int i, nDataSize; char width; BYTE *dst; DWORD *pFrameTable; /// ASSERT: assert(p != NULL); /// ASSERT: assert(ttbl != NULL); for (i = 1; i <= nCel; i++) { pFrameTable = (DWORD *)&p[4 * i]; dst = &p[pFrameTable[0] + 10]; nDataSize = pFrameTable[1] - pFrameTable[0] - 10; while (nDataSize) { width = *dst++; nDataSize--; /// ASSERT: assert(nDataSize >= 0); if (width < 0) { width = -width; if (width > 65) { nDataSize--; /// ASSERT: assert(nDataSize >= 0); *dst = ttbl[*dst]; dst++; } else { nDataSize -= width; /// ASSERT: assert(nDataSize >= 0); while (width) { *dst = ttbl[*dst]; dst++; width--; } } } } } } /** * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void Cl2DecodeFrm1(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { int nDataStart, nDataSize; BYTE *pRLEBytes; DWORD *pFrameTable; /// ASSERT: assert(gpBuffer != NULL); if (!gpBuffer) return; /// ASSERT: assert(pCelBuff != NULL); if (!pCelBuff) return; /// ASSERT: assert(nCel > 0); if (nCel <= 0) return; pFrameTable = (DWORD *)pCelBuff; /// ASSERT: assert(nCel <= (int) pFrameTable[0]); pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; if (CelCap == 8) nDataSize = 0; else nDataSize = *(WORD *)&pRLEBytes[CelCap]; if (!nDataSize) nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; Cl2DecDatFrm1( &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]], pRLEBytes + nDataStart, nDataSize - nDataStart, nWidth); } void Cl2DecDatFrm1(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth) { int w; char width; BYTE fill; BYTE *src, *dst; src = pRLEBytes; dst = pDecodeTo; w = nWidth; while (nDataSize) { width = *src++; nDataSize--; if (width < 0) { width = -width; if (width > 65) { width -= 65; nDataSize--; fill = *src++; w -= width; while (width) { *dst = fill; dst++; width--; } if (!w) { w = nWidth; dst -= BUFFER_WIDTH + w; } continue; } else { nDataSize -= width; w -= width; while (width) { *dst = *src; src++; dst++; width--; } if (!w) { w = nWidth; dst -= BUFFER_WIDTH + w; } continue; } } while (width) { if (width > w) { dst += w; width -= w; w = 0; } else { dst += width; w -= width; width = 0; } if (!w) { w = nWidth; dst -= BUFFER_WIDTH + w; } } } } /** * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void Cl2DecodeFrm2(char col, int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { int nDataStart, nDataSize; BYTE *pRLEBytes; DWORD *pFrameTable; /// ASSERT: assert(gpBuffer != NULL); if (!gpBuffer) return; /// ASSERT: assert(pCelBuff != NULL); if (!pCelBuff) return; /// ASSERT: assert(nCel > 0); if (nCel <= 0) return; pFrameTable = (DWORD *)pCelBuff; /// ASSERT: assert(nCel <= (int) pFrameTable[0]); pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; if (CelCap == 8) nDataSize = 0; else nDataSize = *(WORD *)&pRLEBytes[CelCap]; if (!nDataSize) nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; Cl2DecDatFrm2( &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]], pRLEBytes + nDataStart, nDataSize - nDataStart, nWidth, col); } void Cl2DecDatFrm2(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth, char col) { int w; char width; BYTE *src, *dst; src = pRLEBytes; dst = pDecodeTo; w = nWidth; while (nDataSize) { width = *src++; nDataSize--; if (width < 0) { width = -width; if (width > 65) { width -= 65; nDataSize--; if (*src++) { w -= width; dst[-1] = col; dst[width] = col; while (width) { dst[-BUFFER_WIDTH] = col; dst[BUFFER_WIDTH] = col; dst++; width--; } if (!w) { w = nWidth; dst -= BUFFER_WIDTH + w; } continue; } } else { nDataSize -= width; w -= width; while (width) { if (*src++) { dst[-1] = col; dst[1] = col; dst[-BUFFER_WIDTH] = col; dst[BUFFER_WIDTH] = col; } dst++; width--; } if (!w) { w = nWidth; dst -= BUFFER_WIDTH + w; } continue; } } while (width) { if (width > w) { dst += w; width -= w; w = 0; } else { dst += width; w -= width; width = 0; } if (!w) { w = nWidth; dst -= BUFFER_WIDTH + w; } } } } /** * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void Cl2DecodeFrm3(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap, char light) { int nDataStart, nDataSize, idx, nSize; BYTE *pRLEBytes, *pDecodeTo; DWORD *pFrameTable; /// ASSERT: assert(gpBuffer != NULL); if (!gpBuffer) return; /// ASSERT: assert(pCelBuff != NULL); if (!pCelBuff) return; /// ASSERT: assert(nCel > 0); if (nCel <= 0) return; pFrameTable = (DWORD *)pCelBuff; /// ASSERT: assert(nCel <= (int) pFrameTable[0]); pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; if (CelCap == 8) nDataSize = 0; else nDataSize = *(WORD *)&pRLEBytes[CelCap]; if (!nDataSize) nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; nSize = nDataSize - nDataStart; pRLEBytes += nDataStart; pDecodeTo = &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]]; idx = light4flag ? 1024 : 4096; if (light == 2) idx += 256; if (light >= 4) idx += (light - 1) << 8; Cl2DecDatLightTbl1( pDecodeTo, pRLEBytes, nSize, nWidth, &pLightTbl[idx]); } void Cl2DecDatLightTbl1(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth, BYTE *pTable) { int w; char width; BYTE fill; BYTE *src, *dst; src = pRLEBytes; dst = pDecodeTo; w = nWidth; sgnWidth = nWidth; while (nDataSize) { width = *src++; nDataSize--; if (width < 0) { width = -width; if (width > 65) { width -= 65; nDataSize--; fill = pTable[*src++]; w -= width; while (width) { *dst = fill; dst++; width--; } if (!w) { w = sgnWidth; dst -= BUFFER_WIDTH + w; } continue; } else { nDataSize -= width; w -= width; while (width) { *dst = pTable[*src]; src++; dst++; width--; } if (!w) { w = sgnWidth; dst -= BUFFER_WIDTH + w; } continue; } } while (width) { if (width > w) { dst += w; width -= w; w = 0; } else { dst += width; w -= width; width = 0; } if (!w) { w = sgnWidth; dst -= BUFFER_WIDTH + w; } } } } /** * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void Cl2DecodeLightTbl(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { int nDataStart, nDataSize, nSize; BYTE *pRLEBytes, *pDecodeTo; DWORD *pFrameTable; /// ASSERT: assert(gpBuffer != NULL); if (!gpBuffer) return; /// ASSERT: assert(pCelBuff != NULL); if (!pCelBuff) return; /// ASSERT: assert(nCel > 0); if (nCel <= 0) return; pFrameTable = (DWORD *)pCelBuff; /// ASSERT: assert(nCel <= (int) pFrameTable[0]); pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; if (CelCap == 8) nDataSize = 0; else nDataSize = *(WORD *)&pRLEBytes[CelCap]; if (!nDataSize) nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; nSize = nDataSize - nDataStart; pRLEBytes += nDataStart; pDecodeTo = &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]]; if (light_table_index) Cl2DecDatLightTbl1(pDecodeTo, pRLEBytes, nSize, nWidth, &pLightTbl[light_table_index * 256]); else Cl2DecDatFrm1(pDecodeTo, pRLEBytes, nSize, nWidth); } /** * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void Cl2DecodeFrm4(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { int nDataStart, nDataSize; BYTE *pRLEBytes; DWORD *pFrameTable; /// ASSERT: assert(gpBuffer != NULL); if (!gpBuffer) return; /// ASSERT: assert(pCelBuff != NULL); if (!pCelBuff) return; /// ASSERT: assert(nCel > 0); if (nCel <= 0) return; pFrameTable = (DWORD *)pCelBuff; /// ASSERT: assert(nCel <= (int) pFrameTable[0]); pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; if (CelCap == 8) nDataSize = 0; else nDataSize = *(WORD *)&pRLEBytes[CelCap]; if (!nDataSize) nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; Cl2DecDatFrm4( &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]], pRLEBytes + nDataStart, nDataSize - nDataStart, nWidth); } void Cl2DecDatFrm4(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth) { int w; char width; BYTE fill; BYTE *src, *dst; src = pRLEBytes; dst = pDecodeTo; w = nWidth; while (nDataSize) { width = *src++; nDataSize--; if (width < 0) { width = -width; if (width > 65) { width -= 65; nDataSize--; fill = *src++; if (dst < gpBufEnd) { w -= width; while (width) { *dst = fill; dst++; width--; } if (!w) { w = nWidth; dst -= BUFFER_WIDTH + w; } continue; } } else { nDataSize -= width; if (dst < gpBufEnd) { w -= width; while (width) { *dst = *src; src++; dst++; width--; } if (!w) { w = nWidth; dst -= BUFFER_WIDTH + w; } continue; } else { src += width; } } } while (width) { if (width > w) { dst += w; width -= w; w = 0; } else { dst += width; w -= width; width = 0; } if (!w) { w = nWidth; dst -= BUFFER_WIDTH + w; } } } } /** * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void Cl2DecodeClrHL(char col, int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { int nDataStart, nDataSize; BYTE *pRLEBytes; DWORD *pFrameTable; /// ASSERT: assert(gpBuffer != NULL); if (!gpBuffer) return; /// ASSERT: assert(pCelBuff != NULL); if (!pCelBuff) return; /// ASSERT: assert(nCel > 0); if (nCel <= 0) return; pFrameTable = (DWORD *)pCelBuff; /// ASSERT: assert(nCel <= (int) pFrameTable[0]); pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; if (CelCap == 8) nDataSize = 0; else nDataSize = *(WORD *)&pRLEBytes[CelCap]; if (!nDataSize) nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; gpBufEnd -= BUFFER_WIDTH; Cl2DecDatClrHL( &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]], pRLEBytes + nDataStart, nDataSize - nDataStart, nWidth, col); gpBufEnd += BUFFER_WIDTH; } void Cl2DecDatClrHL(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth, char col) { int w; char width; BYTE *src, *dst; src = pRLEBytes; dst = pDecodeTo; w = nWidth; while (nDataSize) { width = *src++; nDataSize--; if (width < 0) { width = -width; if (width > 65) { width -= 65; nDataSize--; if (*src++ && dst < gpBufEnd) { w -= width; dst[-1] = col; dst[width] = col; while (width) { dst[-BUFFER_WIDTH] = col; dst[BUFFER_WIDTH] = col; dst++; width--; } if (!w) { w = nWidth; dst -= BUFFER_WIDTH + w; } continue; } } else { nDataSize -= width; if (dst < gpBufEnd) { w -= width; while (width) { if (*src++) { dst[-1] = col; dst[1] = col; dst[-BUFFER_WIDTH] = col; dst[BUFFER_WIDTH] = col; } dst++; width--; } if (!w) { w = nWidth; dst -= BUFFER_WIDTH + w; } continue; } else { src += width; } } } while (width) { if (width > w) { dst += w; width -= w; w = 0; } else { dst += width; w -= width; width = 0; } if (!w) { w = nWidth; dst -= BUFFER_WIDTH + w; } } } } /** * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void Cl2DecodeFrm5(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap, char light) { int nDataStart, nDataSize, idx, nSize; BYTE *pRLEBytes, *pDecodeTo; DWORD *pFrameTable; /// ASSERT: assert(gpBuffer != NULL); if (!gpBuffer) return; /// ASSERT: assert(pCelBuff != NULL); if (!pCelBuff) return; /// ASSERT: assert(nCel > 0); if (nCel <= 0) return; pFrameTable = (DWORD *)pCelBuff; /// ASSERT: assert(nCel <= (int) pFrameTable[0]); pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; if (CelCap == 8) nDataSize = 0; else nDataSize = *(WORD *)&pRLEBytes[CelCap]; if (!nDataSize) nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; nSize = nDataSize - nDataStart; pRLEBytes += nDataStart; pDecodeTo = &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]]; idx = light4flag ? 1024 : 4096; if (light == 2) idx += 256; if (light >= 4) idx += (light - 1) << 8; Cl2DecDatLightTbl2( pDecodeTo, pRLEBytes, nSize, nWidth, &pLightTbl[idx]); } void Cl2DecDatLightTbl2(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth, BYTE *pTable) { int w; char width; BYTE fill; BYTE *src, *dst; src = pRLEBytes; dst = pDecodeTo; w = nWidth; sgnWidth = nWidth; while (nDataSize) { width = *src++; nDataSize--; if (width < 0) { width = -width; if (width > 65) { width -= 65; nDataSize--; fill = pTable[*src++]; if (dst < gpBufEnd) { w -= width; while (width) { *dst = fill; dst++; width--; } if (!w) { w = sgnWidth; dst -= BUFFER_WIDTH + w; } continue; } } else { nDataSize -= width; if (dst < gpBufEnd) { w -= width; while (width) { *dst = pTable[*src]; src++; dst++; width--; } if (!w) { w = sgnWidth; dst -= BUFFER_WIDTH + w; } continue; } else { src += width; } } } while (width) { if (width > w) { dst += w; width -= w; w = 0; } else { dst += width; w -= width; width = 0; } if (!w) { w = sgnWidth; dst -= BUFFER_WIDTH + w; } } } } /** * @param CelSkip Skip lower parts of sprite, must be multiple of 2, max 8 * @param CelCap Amount of sprite to render from lower to upper, must be multiple of 2, max 8 */ void Cl2DecodeFrm6(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { int nDataStart, nDataSize, nSize; BYTE *pRLEBytes, *pDecodeTo; DWORD *pFrameTable; /// ASSERT: assert(gpBuffer != NULL); if (!gpBuffer) return; /// ASSERT: assert(pCelBuff != NULL); if (!pCelBuff) return; /// ASSERT: assert(nCel > 0); if (nCel <= 0) return; pFrameTable = (DWORD *)pCelBuff; /// ASSERT: assert(nCel <= (int) pFrameTable[0]); pRLEBytes = &pCelBuff[pFrameTable[nCel]]; nDataStart = *(WORD *)&pRLEBytes[CelSkip]; if (!nDataStart) return; if (CelCap == 8) nDataSize = 0; else nDataSize = *(WORD *)&pRLEBytes[CelCap]; if (!nDataSize) nDataSize = pFrameTable[nCel + 1] - pFrameTable[nCel]; nSize = nDataSize - nDataStart; pRLEBytes += nDataStart; pDecodeTo = &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]]; if (light_table_index) Cl2DecDatLightTbl2(pDecodeTo, pRLEBytes, nSize, nWidth, &pLightTbl[light_table_index * 256]); else Cl2DecDatFrm4(pDecodeTo, pRLEBytes, nSize, nWidth); } void PlayInGameMovie(char *pszMovie) { PaletteFadeOut(8); play_movie(pszMovie, 0); ClearScreenBuffer(); drawpanflag = 255; scrollrt_draw_game_screen(1); PaletteFadeIn(8); drawpanflag = 255; } DEVILUTION_END_NAMESPACE