#include "diablo.h" #include "../3rdParty/Storm/Source/storm.h" #ifdef USE_ASM #pragma warning(disable : 4731) // frame pointer register 'ebp' modified by inline assembly code #endif char gbPixelCol; // automap pixel color 8-bit (palette entry) BOOL gbRotateMap; // flip - if y < x int orgseed; int sgnWidth; int sglGameSeed; #ifdef __cplusplus static CCritSect sgMemCrit; #endif int SeedCount; BOOL gbNotInView; // valid - if x/y are in bounds const int RndInc = 1; const int RndMult = 0x015A4E35; __FINLINE BYTE *CelGetFrame(BYTE *pCelBuff, int nCel, int *nDataSize) { DWORD *pFrameTable; DWORD nCellStart; pFrameTable = (DWORD *)pCelBuff; nCellStart = SwapLE32(pFrameTable[nCel]); *nDataSize = SwapLE32(pFrameTable[nCel + 1]) - nCellStart; return pCelBuff + nCellStart; } __FINLINE int CelGetFrameSize(BYTE *pCelBuff, int nCel) { DWORD *pFrameTable; pFrameTable = (DWORD *)pCelBuff; return SwapLE32(pFrameTable[nCel + 1]) - SwapLE32(pFrameTable[nCel]); } void CelBlit(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth) { int w; /// ASSERT: assert(pDecodeTo != NULL); if (!pDecodeTo) return; /// ASSERT: assert(pRLEBytes != NULL); if (!pRLEBytes) return; #ifdef USE_ASM __asm { mov esi, pRLEBytes mov edi, pDecodeTo mov eax, BUFFER_WIDTH add eax, nWidth mov w, eax mov ebx, nDataSize add ebx, esi label1: mov edx, nWidth label2: xor eax, eax lodsb or al, al js label6 sub edx, eax mov ecx, eax shr ecx, 1 jnb label3 movsb jecxz label5 label3: shr ecx, 1 jnb label4 movsw jecxz label5 label4: rep movsd label5: or edx, edx jz label7 jmp label2 label6: neg al add edi, eax sub edx, eax jnz label2 label7: sub edi, w cmp ebx, esi jnz label1 } #else 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; } } } #endif } void CelDraw(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth) { int nDataSize; BYTE *pRLEBytes; /// ASSERT: assert(gpBuffer); if (!gpBuffer) return; /// ASSERT: assert(pCelBuff != NULL); if (!pCelBuff) return; pRLEBytes = CelGetFrame(pCelBuff, nCel, &nDataSize); CelBlit(&gpBuffer[sx + PitchTbl[sy]], pRLEBytes, nDataSize, nWidth); } void CelBlitFrame(BYTE *pBuff, BYTE *pCelBuff, int nCel, int nWidth) { int nDataSize; BYTE *pRLEBytes; /// ASSERT: assert(pCelBuff != NULL); if (!pCelBuff) return; /// ASSERT: assert(pBuff != NULL); if (!pBuff) return; pRLEBytes = CelGetFrame(pCelBuff, nCel, &nDataSize); CelBlit(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 CelClippedDraw(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { BYTE *pRLEBytes; DWORD *pFrameTable; int nDataStart, nDataSize, nDataCap; /// 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; CelBlit( &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 CelClippedBlit(BYTE *pBuff, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { BYTE *pRLEBytes; DWORD *pFrameTable; int nDataStart, nDataSize, nDataCap; /// 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; CelBlit(pBuff, pRLEBytes + nDataStart, nDataSize, nWidth); } void CelBlitLight(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; #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 label1: mov edx, nWidth label2: xor eax, eax lodsb or al, al js label3 push ebx mov ebx, tbl sub edx, eax mov ecx, eax push edx call CelBlitLightEntry pop edx pop ebx or edx, edx jnz label2 jmp label4 label3: neg al add edi, eax sub edx, eax jnz label2 label4: sub edi, w cmp ebx, esi jnz label1 jmp labexit } /* Assembly Macro */ // clang-format off __asm { CelBlitLightEntry: shr cl, 1 jnb label5 mov dl, [esi] mov dl, [ebx+edx] mov [edi], dl add esi, 1 add edi, 1 label5: shr cl, 1 jnb label6 mov dl, [esi] mov ch, [ebx+edx] mov [edi], ch mov dl, [esi+1] mov ch, [ebx+edx] mov [edi+1], ch add esi, 2 add edi, 2 label6: test cl, cl jz labret label7: mov eax, [esi] add esi, 4 mov dl, al mov ch, [ebx+edx] mov dl, ah ror eax, 10h mov [edi], ch mov ch, [ebx+edx] mov dl, al mov [edi+1], ch mov ch, [ebx+edx] mov dl, ah mov [edi+2], ch mov ch, [ebx+edx] mov [edi+3], ch add edi, 4 dec cl jnz label7 labret: retn } // clang-format on __asm { labexit: } #else 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; } } } #endif } void CelBlitLightTrans(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 CelDrawLight(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth) { int nDataSize; BYTE *pDecodeTo, *pRLEBytes; /// ASSERT: assert(gpBuffer); if (!gpBuffer) return; /// ASSERT: assert(pCelBuff != NULL); if (!pCelBuff) return; pRLEBytes = CelGetFrame(pCelBuff, nCel, &nDataSize); pDecodeTo = &gpBuffer[sx + PitchTbl[sy]]; if (light_table_index) CelBlitLight(pDecodeTo, pRLEBytes, nDataSize, nWidth); else CelBlit(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 CelClippedDrawLight(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) CelBlitLight(pDecodeTo, pRLEBytes, nDataSize, nWidth); else CelBlit(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 CelClippedBlitLightTrans(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) CelBlitLightTrans(pBuff, pRLEBytes, nDataSize, nWidth); else if (light_table_index) CelBlitLight(pBuff, pRLEBytes, nDataSize, nWidth); else CelBlit(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 CelDrawLightRed(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; #ifdef USE_ASM __asm { mov eax, pLightTbl add eax, idx mov tbl, eax mov esi, pRLEBytes mov edi, dst mov eax, BUFFER_WIDTH add eax, nWidth mov w, eax /* use C for w? w = BUFFER_WIDTH + nWidth */ mov ebx, nDataSize add ebx, esi label1: mov edx, nWidth label2: xor eax, eax mov al, [esi] inc esi test al, al js label4 push ebx mov ebx, tbl sub edx, eax mov ecx, eax label3: mov al, [esi] inc esi mov al, [ebx+eax] mov [edi], al dec ecx lea edi, [edi+1] jnz label3 pop ebx test edx, edx jz label5 jmp label2 label4: neg al add edi, eax sub edx, eax jnz label2 label5: sub edi, w cmp ebx, esi jnz label1 } #else 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; } } } #endif } /** * @brief Same as CelBlit but checks for drawing outside the buffer */ void CelBlitSafe(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; #ifdef USE_ASM __asm { mov esi, pRLEBytes mov edi, pDecodeTo mov eax, BUFFER_WIDTH add eax, nWidth mov w, eax mov ebx, nDataSize add ebx, esi label1: mov edx, nWidth label2: xor eax, eax lodsb or al, al js label7 sub edx, eax cmp edi, gpBufEnd jb label3 add esi, eax add edi, eax jmp label6 label3: mov ecx, eax shr ecx, 1 jnb label4 movsb jecxz label6 label4: shr ecx, 1 jnb label5 movsw jecxz label6 label5: rep movsd label6: or edx, edx jz label8 jmp label2 label7: neg al add edi, eax sub edx, eax jnz label2 label8: sub edi, w cmp ebx, esi jnz label1 } #else 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; } } } #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 CelClippedDrawSafe(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { BYTE *pRLEBytes; DWORD *pFrameTable; int nDataStart, nDataSize, nDataCap; /// 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; CelBlitSafe( &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 CelClippedBlitSafe(BYTE *pBuff, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { BYTE *pRLEBytes; DWORD *pFrameTable; int nDataStart, nDataSize, nDataCap; /// 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; CelBlitSafe(pBuff, pRLEBytes + nDataStart, nDataSize, nWidth); } /** * @brief Same as CelBlitLight but checks for drawing outside the buffer */ void CelBlitLightSafe(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; #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 label1: mov edx, nWidth label2: xor eax, eax lodsb or al, al js label5 push ebx mov ebx, tbl sub edx, eax cmp edi, gpBufEnd jb label3 add esi, eax add edi, eax jmp label4 label3: mov ecx, eax push edx call Cel2DecDatLightEntry pop edx label4: pop ebx or edx, edx jz label6 jmp label2 label5: neg al add edi, eax sub edx, eax jnz label2 label6: sub edi, w cmp ebx, esi jnz label1 jmp labexit } /* Assembly Macro */ // clang-format off __asm { Cel2DecDatLightEntry: shr cl, 1 jnb label7 mov dl, [esi] mov dl, [ebx+edx] mov [edi], dl add esi, 1 add edi, 1 label7: shr cl, 1 jnb label8 mov dl, [esi] mov ch, [ebx+edx] mov [edi], ch mov dl, [esi+1] mov ch, [ebx+edx] mov [edi+1], ch add esi, 2 add edi, 2 label8: test cl, cl jz labret label9: mov eax, [esi] add esi, 4 mov dl, al mov ch, [ebx+edx] mov dl, ah ror eax, 10h mov [edi], ch mov ch, [ebx+edx] mov dl, al mov [edi+1], ch mov ch, [ebx+edx] mov dl, ah mov [edi+2], ch mov ch, [ebx+edx] mov [edi+3], ch add edi, 4 dec cl jnz label9 labret: retn } // clang-format on __asm { labexit: } #else 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; } } } #endif } /** * @brief Same as CelBlitLightTrans but checks for drawing outside the buffer */ void CelBlitLightTransSafe(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 CelDrawLightSafe(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) CelBlitLightSafe(pDecodeTo, pRLEBytes, nDataSize, nWidth); else CelBlitSafe(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 CelClippedBlitLightTransSafe(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) CelBlitLightTransSafe(pBuff, pRLEBytes, nDataSize, nWidth); else if (light_table_index) CelBlitLightSafe(pBuff, pRLEBytes, nDataSize, nWidth); else CelBlitSafe(pBuff, pRLEBytes, nDataSize, nWidth); } /** * @brief Same as CelDrawLightRed but checks for drawing outside the buffer * @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 CelDrawLightRedSafe(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]; #ifdef USE_ASM w = BUFFER_WIDTH + nWidth; __asm { mov esi, pRLEBytes mov edi, dst mov ecx, nDataSize add ecx, esi label1: push ecx mov edx, nWidth xor ecx, ecx label2: xor eax, eax mov al, [esi] inc esi test al, al js label5 mov ebx, tbl sub edx, eax cmp edi, gpBufEnd jb label3 add esi, eax add edi, eax jmp label4 label3: mov cl, [esi] inc esi mov cl, [ebx+ecx] mov [edi], cl dec eax lea edi, [edi+1] jnz label3 label4: test edx, edx jz label6 jmp label2 label5: neg al add edi, eax sub edx, eax jnz label2 label6: pop ecx sub edi, w cmp ecx, esi jnz label1 } #else 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; } } } #endif } /** * @brief Blit to a buffer at given coordinates * @param pBuff Target buffer * @param x Cordinate in pBuff buffer * @param y Cordinate in pBuff buffer * @param wdt Width of pBuff * @param pCelBuff Cel data * @param nCel Frame of cel * @param nWidth Width of cel */ void CelBlitWidth(BYTE *pBuff, int x, int y, 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; #ifdef USE_ASM __asm { mov ebx, pCelBuff mov eax, nCel shl eax, 2 add ebx, eax mov eax, [ebx+4] sub eax, [ebx] mov end, eax mov eax, pCelBuff add eax, [ebx] mov pRLEBytes, eax } dst = &pBuff[y * wdt + x]; __asm { mov esi, pRLEBytes mov edi, dst mov eax, wdt add eax, nWidth mov wdt, eax mov ebx, end add ebx, esi label1: mov edx, nWidth label2: xor eax, eax lodsb or al, al js label6 sub edx, eax mov ecx, eax shr ecx, 1 jnb label3 movsb jecxz label5 label3: shr ecx, 1 jnb label4 movsw jecxz label5 label4: rep movsd label5: or edx, edx jz label7 jmp label2 label6: neg al add edi, eax sub edx, eax jnz label2 label7: sub edi, wdt cmp ebx, esi jnz label1 } #else int i, nDataSize; BYTE width; pRLEBytes = CelGetFrame(pCelBuff, nCel, &nDataSize); end = &pRLEBytes[nDataSize]; dst = &pBuff[y * wdt + x]; 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; } } } #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 CelBlitOutline(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; #ifdef USE_ASM __asm { mov ebx, pCelBuff mov eax, nCel shl eax, 2 add ebx, eax mov eax, [ebx+4] sub eax, [ebx] mov nDataSize, eax mov edx, pCelBuff add edx, [ebx] mov pRLEBytes, edx add edx, CelSkip xor eax, eax mov ax, [edx] mov nDataStart, eax mov edx, pRLEBytes add edx, CelCap mov ax, [edx] mov nDataCap, eax } if (!nDataStart) return; if (CelCap == 8) nDataCap = 0; if (nDataCap) nDataSize = nDataCap - nDataStart; else nDataSize -= nDataStart; pRLEBytes += nDataStart; dst = &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]]; __asm { mov esi, pRLEBytes mov edi, dst mov eax, BUFFER_WIDTH add eax, nWidth mov w, eax mov ebx, nDataSize add ebx, esi label1: mov edx, nWidth label2: xor eax, eax lodsb or al, al js label5 sub edx, eax mov ecx, eax mov ah, col label3: lodsb or al, al jz label4 mov [edi-BUFFER_WIDTH], ah mov [edi-1], ah mov [edi+1], ah mov [edi+BUFFER_WIDTH], ah label4: inc edi loop label3 or edx, edx jz label6 jmp label2 label5: neg al add edi, eax sub edx, eax jnz label2 label6: sub edi, w cmp ebx, esi jnz label1 } #else 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; } } } #endif } /** * @brief Same as CelBlitOutline but checks for drawing outside the buffer * @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 CelBlitOutlineSafe(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; #ifdef USE_ASM __asm { mov ebx, pCelBuff mov eax, nCel shl eax, 2 add ebx, eax mov eax, [ebx+4] sub eax, [ebx] mov nDataSize, eax mov edx, pCelBuff add edx, [ebx] mov pRLEBytes, edx add edx, CelSkip xor eax, eax mov ax, [edx] mov nDataStart, eax mov edx, pRLEBytes add edx, CelCap mov ax, [edx] mov nDataCap, eax } if (!nDataStart) return; if (CelCap == 8) nDataCap = 0; if (nDataCap) nDataSize = nDataCap - nDataStart; else nDataSize -= nDataStart; pRLEBytes += nDataStart; dst = &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]]; __asm { mov esi, pRLEBytes mov edi, dst mov eax, BUFFER_WIDTH add eax, nWidth mov w, eax mov ebx, nDataSize add ebx, esi label1: mov edx, nWidth label2: xor eax, eax lodsb or al, al js label10 sub edx, eax mov ecx, gpBufEnd cmp edi, ecx jb label3 add esi, eax add edi, eax jmp label9 label3: sub ecx, BUFFER_WIDTH cmp edi, ecx jnb label6 mov ecx, eax mov ah, col label4: lodsb or al, al jz label5 mov [edi-BUFFER_WIDTH], ah mov [edi-1], ah mov [edi+1], ah mov [edi+BUFFER_WIDTH], ah label5: inc edi loop label4 jmp label9 label6: mov ecx, eax mov ah, col label7: lodsb or al, al jz label8 mov [edi-BUFFER_WIDTH], ah mov [edi-1], ah mov [edi+1], ah label8: inc edi loop label7 label9: or edx, edx jz label11 jmp label2 label10: neg al add edi, eax sub edx, eax jnz label2 label11: sub edi, w cmp ebx, esi jnz label1 } #else 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; } } } #endif } 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]]; #ifdef USE_ASM __asm { mov edi, dst cmp edi, gpBufEnd jnb label1 mov al, col mov [edi], al label1: } #else if (dst < gpBufEnd) *dst = col; #endif } 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]]; } #ifdef USE_ASM __asm { mov edi, dst cmp edi, gpBufEnd jnb label1 mov al, gbPixelCol mov [edi], al label1: } #else if (dst < gpBufEnd) *dst = gbPixelCol; #endif } // 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 { if (my >= 0) { ny = -mx; md = DIR_W; if (2 * ny < my) md = DIR_SW; } else { ny = -mx; 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() >> 16) % v; return GetRndSeed() % v; } void engine_debug_trap(BOOL show_cursor) { /* TMemBlock *pCurr; sgMemCrit.Enter(); while(sgpMemBlock != NULL) { pCurr = sgpMemBlock->pNext; SMemFree(sgpMemBlock, "C:\\Diablo\\Direct\\ENGINE.CPP", 1970); sgpMemBlock = pCurr; } sgMemCrit.Leave(); */ } BYTE *DiabloAllocPtr(DWORD dwBytes) { BYTE *buf; #ifdef __cplusplus sgMemCrit.Enter(); #endif buf = (BYTE *)SMemAlloc(dwBytes, "C:\\Src\\Diablo\\Source\\ENGINE.CPP", 2236, 0); #ifdef __cplusplus sgMemCrit.Leave(); #endif if (buf == NULL) { ErrDlg(IDD_DIALOG2, GetLastError(), "C:\\Src\\Diablo\\Source\\ENGINE.CPP", 2269); } return buf; } void mem_free_dbg(void *p) { if (p) { #ifdef __cplusplus sgMemCrit.Enter(); #endif SMemFree(p, "C:\\Src\\Diablo\\Source\\ENGINE.CPP", 2317, 0); #ifdef __cplusplus sgMemCrit.Leave(); #endif } } 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; } /** * @brief Apply the color swaps to a CL2 sprite */ 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 = CelGetFrameSize(p, i) - 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 Cl2Draw(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { BYTE *pRLEBytes; DWORD *pFrameTable; int nDataStart, nDataSize; /// 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]; Cl2Blit( &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]], pRLEBytes + nDataStart, nDataSize - nDataStart, nWidth); } void Cl2Blit(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth) { #ifdef USE_ASM __asm { push ebx push esi push edi mov esi, edx /// UNSAFE: use 'mov esi, pRLEBytes' mov edi, ecx /// UNSAFE: use 'mov edi, pDecodeTo' xor eax, eax mov ebx, nWidth mov ecx, nDataSize label1: mov al, [esi] inc esi dec ecx test al, al jns label6 neg al cmp al, 41h jle label3 sub al, 41h dec ecx mov dl, [esi] inc esi sub ebx, eax label2: mov [edi], dl dec eax lea edi, [edi+1] jnz label2 jmp label5 label3: sub ecx, eax sub ebx, eax label4: mov dl, [esi] inc esi mov [edi], dl dec eax lea edi, [edi+1] jnz label4 label5: test ebx, ebx jnz label10 mov ebx, nWidth sub edi, BUFFER_WIDTH sub edi, ebx jmp label10 label6: cmp eax, ebx jle label7 mov edx, ebx add edi, ebx sub eax, ebx jmp label8 label7: mov edx, eax add edi, eax xor eax, eax label8: sub ebx, edx jnz label9 mov ebx, nWidth sub edi, BUFFER_WIDTH sub edi, ebx label9: test eax, eax jnz label6 label10: test ecx, ecx jnz label1 pop edi pop esi pop ebx } #else 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; } } } #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 Cl2DrawOutline(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]; Cl2BlitOutline( &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]], pRLEBytes + nDataStart, nDataSize - nDataStart, nWidth, col); } void Cl2BlitOutline(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth, char col) { #ifdef USE_ASM __asm { push ebx push esi push edi mov esi, edx /// UNSAFE: use 'mov esi, pRLEBytes' mov edi, ecx /// UNSAFE: use 'mov edi, pDecodeTo' xor eax, eax mov ebx, nWidth xor edx, edx mov ecx, nDataSize mov dl, col label1: mov al, [esi] inc esi dec ecx test al, al jns label7 neg al cmp al, 41h jle label3 sub al, 41h dec ecx mov dh, [esi] inc esi test dh, dh jz label7 mov [edi-1], dl sub ebx, eax mov [edi+eax], dl label2: mov [edi-BUFFER_WIDTH], dl mov [edi+BUFFER_WIDTH], dl dec eax lea edi, [edi+1] jnz label2 jmp label6 label3: sub ecx, eax sub ebx, eax label4: mov dh, [esi] inc esi test dh, dh jz label5 mov [edi-1], dl mov [edi+1], dl mov [edi-BUFFER_WIDTH], dl mov [edi+BUFFER_WIDTH], dl label5: dec eax lea edi, [edi+1] jnz label4 label6: test ebx, ebx jnz label11 mov ebx, nWidth sub edi, BUFFER_WIDTH sub edi, ebx jmp label11 label7: cmp eax, ebx jle label8 mov edx, ebx add edi, ebx sub eax, ebx jmp label9 label8: mov edx, eax add edi, eax xor eax, eax label9: sub ebx, edx jnz label10 mov ebx, nWidth sub edi, BUFFER_WIDTH sub edi, ebx label10: test eax, eax jnz label7 mov dl, col label11: test ecx, ecx jnz label1 pop edi pop esi pop ebx } #else 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; } } } #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 Cl2DrawLightTbl(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; Cl2BlitLight( pDecodeTo, pRLEBytes, nSize, nWidth, &pLightTbl[idx]); } void Cl2BlitLight(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth, BYTE *pTable) { #ifdef USE_ASM __asm { push ebx push esi push edi mov esi, edx /// UNSAFE: use 'mov esi, pRLEBytes' mov edi, ecx /// UNSAFE: use 'mov edi, pDecodeTo' mov ebx, nWidth mov ecx, nDataSize mov edx, pTable push ebp mov sgnWidth, ebx mov ebp, edx xor eax, eax xor edx, edx label1: mov al, [esi] inc esi dec ecx test al, al jns label6 neg al cmp al, 41h jle label3 sub al, 41h dec ecx sub ebx, eax mov dl, [esi] inc esi mov dl, [ebp+edx] label2: mov [edi], dl dec eax lea edi, [edi+1] jnz label2 jmp label5 label3: sub ecx, eax sub ebx, eax label4: mov dl, [esi] inc esi mov dl, [ebp+edx] mov [edi], dl dec eax lea edi, [edi+1] jnz label4 label5: test ebx, ebx jnz label10 mov ebx, sgnWidth sub edi, BUFFER_WIDTH sub edi, ebx jmp label10 label6: cmp eax, ebx jle label7 mov edx, ebx add edi, ebx sub eax, ebx jmp label8 label7: mov edx, eax add edi, eax xor eax, eax label8: sub ebx, edx jnz label9 mov ebx, sgnWidth sub edi, BUFFER_WIDTH sub edi, ebx label9: test eax, eax jnz label6 label10: test ecx, ecx jnz label1 pop ebp pop edi pop esi pop ebx } #else 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; } } } #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 Cl2DrawLight(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) Cl2BlitLight(pDecodeTo, pRLEBytes, nSize, nWidth, &pLightTbl[light_table_index * 256]); else Cl2Blit(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 Cl2DrawSafe(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap) { BYTE *pRLEBytes; DWORD *pFrameTable; int nDataStart, nDataSize; /// 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]; Cl2BlitSafe( &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]], pRLEBytes + nDataStart, nDataSize - nDataStart, nWidth); } void Cl2BlitSafe(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth) { #ifdef USE_ASM __asm { push ebx push esi push edi mov esi, edx /// UNSAFE: use 'mov esi, pRLEBytes' mov edi, ecx /// UNSAFE: use 'mov edi, pDecodeTo' xor eax, eax mov ebx, nWidth mov ecx, nDataSize label1: mov al, [esi] inc esi dec ecx test al, al jns label7 neg al cmp al, 41h jle label3 sub al, 41h dec ecx mov dl, [esi] inc esi cmp edi, gpBufEnd jge label7 sub ebx, eax label2: mov [edi], dl dec eax lea edi, [edi+1] jnz label2 jmp label6 label3: sub ecx, eax cmp edi, gpBufEnd jl label4 add esi, eax jmp label7 label4: sub ebx, eax label5: mov dl, [esi] inc esi mov [edi], dl dec eax lea edi, [edi+1] jnz label5 label6: test ebx, ebx jnz label11 mov ebx, nWidth sub edi, BUFFER_WIDTH sub edi, ebx jmp label11 label7: cmp eax, ebx jle label8 mov edx, ebx add edi, ebx sub eax, ebx jmp label9 label8: mov edx, eax add edi, eax xor eax, eax label9: sub ebx, edx jnz label10 mov ebx, nWidth sub edi, BUFFER_WIDTH sub edi, ebx label10: test eax, eax jnz label7 label11: test ecx, ecx jnz label1 pop edi pop esi pop ebx } #else 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; } } } #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 Cl2DrawOutlineSafe(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; Cl2BlitOutlineSafe( &gpBuffer[sx + PitchTbl[sy - 16 * CelSkip]], pRLEBytes + nDataStart, nDataSize - nDataStart, nWidth, col); gpBufEnd += BUFFER_WIDTH; } void Cl2BlitOutlineSafe(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth, char col) { #ifdef USE_ASM __asm { push ebx push esi push edi mov esi, edx /// UNSAFE: use 'mov esi, pRLEBytes' mov edi, ecx /// UNSAFE: use 'mov edi, pDecodeTo' xor eax, eax mov ebx, nWidth xor edx, edx mov ecx, nDataSize mov dl, col label1: mov al, [esi] inc esi dec ecx test al, al jns label9 neg al cmp al, 41h jle label3 sub al, 41h dec ecx mov dh, [esi] inc esi test dh, dh jz label9 cmp edi, gpBufEnd jge label9 mov [edi-1], dl sub ebx, eax mov [edi+eax], dl label2: mov [edi-BUFFER_WIDTH], dl mov [edi+BUFFER_WIDTH], dl dec eax lea edi, [edi+1] jnz label2 jmp label7 label3: sub ecx, eax cmp edi, gpBufEnd jl label4 add esi, eax jmp label9 label4: sub ebx, eax label5: mov dh, [esi] inc esi test dh, dh jz label6 mov [edi-1], dl mov [edi+1], dl mov [edi-BUFFER_WIDTH], dl mov [edi+BUFFER_WIDTH], dl label6: dec eax lea edi, [edi+1] jnz label5 label7: test ebx, ebx jnz label13 mov ebx, nWidth sub edi, BUFFER_WIDTH sub edi, ebx jmp label13 label9: cmp eax, ebx jle label10 mov edx, ebx add edi, ebx sub eax, ebx jmp label11 label10: mov edx, eax add edi, eax xor eax, eax label11: sub ebx, edx jnz label12 mov ebx, nWidth sub edi, BUFFER_WIDTH sub edi, ebx label12: test eax, eax jnz label9 mov dl, col label13: test ecx, ecx jnz label1 pop edi pop esi pop ebx } #else 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; } } } #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 Cl2DrawLightTblSafe(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; Cl2BlitLightSafe( pDecodeTo, pRLEBytes, nSize, nWidth, &pLightTbl[idx]); } void Cl2BlitLightSafe(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth, BYTE *pTable) { #ifdef USE_ASM __asm { push ebx push esi push edi mov esi, edx /// UNSAFE: use 'mov esi, pRLEBytes' mov edi, ecx /// UNSAFE: use 'mov edi, pDecodeTo' mov ebx, nWidth mov ecx, nDataSize mov edx, pTable push ebp mov sgnWidth, ebx mov ebp, edx xor eax, eax xor edx, edx label1: mov al, [esi] inc esi dec ecx test al, al jns label7 neg al cmp al, 41h jle label3 sub al, 41h dec ecx mov dl, [esi] inc esi mov dl, [ebp+edx] cmp edi, gpBufEnd jge label7 sub ebx, eax label2: mov [edi], dl dec eax lea edi, [edi+1] jnz label2 jmp label6 label3: sub ecx, eax cmp edi, gpBufEnd jl label4 add esi, eax jmp label7 label4: sub ebx, eax label5: mov dl, [esi] inc esi mov dl, [ebp+edx] mov [edi], dl dec eax lea edi, [edi+1] jnz label5 label6: test ebx, ebx jnz label11 mov ebx, sgnWidth sub edi, BUFFER_WIDTH sub edi, ebx jmp label11 label7: cmp eax, ebx jle label8 mov edx, ebx add edi, ebx sub eax, ebx jmp label9 label8: mov edx, eax add edi, eax xor eax, eax label9: sub ebx, edx jnz label10 mov ebx, sgnWidth sub edi, BUFFER_WIDTH sub edi, ebx label10: test eax, eax jnz label7 label11: test ecx, ecx jnz label1 pop ebp pop edi pop esi pop ebx } #else 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; } } } #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 Cl2DrawLightSafe(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) Cl2BlitLightSafe(pDecodeTo, pRLEBytes, nSize, nWidth, &pLightTbl[light_table_index * 256]); else Cl2BlitSafe(pDecodeTo, pRLEBytes, nSize, nWidth); } void PlayInGameMovie(char *pszMovie) { PaletteFadeOut(8); play_movie(pszMovie, FALSE); ClearScreenBuffer(); force_redraw = 255; scrollrt_draw_game_screen(1); PaletteFadeIn(8); force_redraw = 255; }