From 92cc33e4aa8db58b7709a531775f457e40ebc668 Mon Sep 17 00:00:00 2001 From: Justin Marshall Date: Mon, 15 Jun 2020 11:47:17 -0700 Subject: [PATCH] Used additional Chronoshift code to remove legacy assembly for stamp/icon rendering. --- code/CMakeLists.txt | 1 + code/REDALERT/TILESET.CPP | 288 ++++++++++++++++ code/REDALERT/WIN32LIB/DrawMisc.cpp | 517 ---------------------------- 3 files changed, 289 insertions(+), 517 deletions(-) create mode 100644 code/REDALERT/TILESET.CPP diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 2b594ea..a8fa477 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -547,6 +547,7 @@ set(src_redalert ./RedAlert/TEXTBTN.H ./RedAlert/THEME.CPP ./RedAlert/THEME.H + ./RedAlert/TILESET.CPP ./RedAlert/TOGGLE.CPP ./RedAlert/TOGGLE.H ./RedAlert/TOOLTIP.CPP diff --git a/code/REDALERT/TILESET.CPP b/code/REDALERT/TILESET.CPP new file mode 100644 index 0000000..8d2fdff --- /dev/null +++ b/code/REDALERT/TILESET.CPP @@ -0,0 +1,288 @@ +/** + * @file + * + * @author CCHyper + * @author OmniBlade + * + * @brief Low level functions for loading and rendering C&C terrain tilesets. + * + * @copyright Chronoshift is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 2 of the License, or (at your option) any later version. + * A full copy of the GNU General Public License can be found in + * LICENSE + */ +#include "FUNCTION.H" +#include "gbuffer.h" +#include + +using std::memcpy; + +class GraphicViewPortClass; + +#define TD_TILESET_CHECK 0x20 + +/** +* @brief union is to handle the parts of the header which vary between TD and RA format tiles. +*/ +struct IconControlType +{ + uint8_t* Get_Icon_Data() + { + if (td.icons == TD_TILESET_CHECK) { + return reinterpret_cast(this) + td.icons; + } + else { + return reinterpret_cast(this) + ra.icons; + } + } + + uint8_t* Get_Icon_Map() + { + if (td.icons == TD_TILESET_CHECK) { + return reinterpret_cast(this) + td.map; + } + else { + return reinterpret_cast(this) + ra.map; + } + } + + int16_t width; // always 24 (ICON_WIDTH) + int16_t height; // always 24 (ICON_HEIGHT) + int16_t count; // count of cells in set, not same as images + int16_t allocated; // is treated like a bool, always 0 in the file? + + union + { + struct + { + int32_t size; // filesize + int32_t icons; // always 0x00000020 + int32_t palettes; // seems to always be 0x00000000 + int32_t remaps; // unknown, bitfield? + int32_t trans_flag; // array of images length, unknown + int32_t map; // image index for each cell + } td; + + struct + { + int16_t map_width; // tile width in cells + int16_t map_height; // tile height in cells + int32_t size; // filesize + int32_t icons; // always 0x00000028 + int32_t palettes; // seems to always be 0x00000000 + int32_t remaps; // unknown, bitfield? + int32_t trans_flag; // array of images length, unknown + int32_t color_map; // terrain type index, ra only + int32_t map; // image index for each cell + } ra; + }; +}; + +static int IconEntry; +static void* IconData; +static IconControlType* LastIconset; +static uint8_t* StampPtr; +static uint8_t* TransFlagPtr; +static uint8_t* MapPtr; +static int IconWidth; +static int IconHeight; +static int IconSize; +static int IconCount; + +void __cdecl Init_Stamps(IconControlType* iconset) +{ + if (iconset && LastIconset != iconset) { + IconCount = (iconset->count); + IconWidth = (iconset->width); + IconHeight = (iconset->height); + LastIconset = iconset; + IconSize = IconWidth * IconHeight; + + // TD and RA tileset headers are slightly different, so check a constant that only exists in one type. + if ((iconset->td.icons) == TD_TILESET_CHECK) { + MapPtr = reinterpret_cast(iconset) + (iconset->td.map); + StampPtr = reinterpret_cast(iconset) + (iconset->td.icons); + TransFlagPtr = reinterpret_cast(iconset) + (iconset->td.trans_flag); + } + else { + MapPtr = reinterpret_cast(iconset) + (iconset->ra.map); + StampPtr = reinterpret_cast(iconset) + (iconset->ra.icons); + TransFlagPtr = reinterpret_cast(iconset) + (iconset->ra.trans_flag); + } + } +} + +void __cdecl Buffer_Draw_Stamp2(GraphicViewPortClass& viewport, IconControlType* tileset, int icon, int x, int y, const void* remapper) +{ + if (!tileset) { + return; + } + + if (LastIconset != tileset) { + Init_Stamps(tileset); + } + + int32_t icon_index = MapPtr != nullptr ? MapPtr[icon] : icon; + + if (icon_index < IconCount) { + + int32_t fullpitch = viewport.Get_Full_Pitch(); //(viewport.Get_Pitch() + viewport.Get_XAdd() + viewport.Get_Width()); + uint8_t* dst = x + y * fullpitch + (uint8_t*)(viewport.Get_Offset()); + int32_t blitpitch = fullpitch - IconWidth; + uint8_t* src = &StampPtr[IconSize * icon_index]; + + if (remapper) { + const uint8_t* remap = static_cast(remapper); + for (int i = 0; i < IconHeight; ++i) { + for (int j = 0; j < IconWidth; ++j) { + uint8_t cur_byte = remap[*src++]; + + if (cur_byte) { + *dst = cur_byte; + } + + ++dst; + } + + dst += blitpitch; + } + + } + else if (TransFlagPtr[icon_index]) { + for (int i = 0; i < IconHeight; ++i) { + for (int j = 0; j < IconWidth; ++j) { + uint8_t cur_byte = *src++; + + if (cur_byte) { + *dst = cur_byte; + } + + ++dst; + } + + dst += blitpitch; + } + } + else { + for (int32_t i = 0; i < IconHeight; ++i) { + memcpy(dst, src, IconWidth); + dst += fullpitch; + src += IconWidth; + } + } + } +} + +void __cdecl Buffer_Draw_Stamp_Clip2(GraphicViewPortClass& viewport, IconControlType* tileset, int icon, int x, int y, const void* remapper, int left, int top, int right, int bottom) +{ + if (!tileset) { + return; + } + + if (LastIconset != tileset) { + Init_Stamps(tileset); + } + + int icon_index = MapPtr != nullptr ? MapPtr[icon] : icon; + + if (icon_index < IconCount) { + int blit_height = IconHeight; + int blit_width = IconWidth; + uint8_t* src = &StampPtr[IconSize * icon_index]; + int width = left + right; + int xstart = left + x; + int height = top + bottom; + int ystart = top + y; + + if (xstart < width && ystart < height && IconHeight + ystart > top && IconWidth + xstart > left) { + if (xstart < left) { + src += left - xstart; + blit_width -= left - xstart; + xstart = left; + } + + int src_pitch = IconWidth - blit_width; + + if (blit_width + xstart > width) { + src_pitch += blit_width - (width - xstart); + blit_width = width - xstart; + } + + if (top > ystart) { + blit_height = IconHeight - (top - ystart); + src += IconWidth * (top - ystart); + ystart = top; + } + + if (blit_height + ystart > height) { + blit_height = height - ystart; + } + + int full_pitch = viewport.Get_Full_Pitch(); //(viewport.Get_Pitch() + viewport.Get_XAdd() + viewport.Get_Width()); + uint8_t* dst = xstart + ystart * full_pitch + (uint8_t*)(viewport.Get_Offset()); + int dst_pitch = full_pitch - blit_width; + + if (remapper) { + const uint8_t* remap = static_cast(remapper); + for (int i = 0; i < blit_height; ++i) { + for (int j = 0; j < blit_width; ++j) { + uint8_t cur_byte = remap[*src++]; + if (cur_byte) { + *dst = cur_byte; + } + + ++dst; + } + dst += dst_pitch; + } + + } + else if (TransFlagPtr[icon_index]) { + for (int i = 0; i < blit_height; ++i) { + for (int j = 0; j < blit_width; ++j) { + uint8_t cur_byte = *src++; + if (cur_byte) { + *dst = cur_byte; + } + + ++dst; + } + src += src_pitch; + dst += dst_pitch; + } + + } + else { + for (int i = 0; i < blit_height; ++i) { + memcpy(dst, src, blit_width); + dst += full_pitch; + src += IconWidth; + } + } + } + } +} + +extern "C" void __cdecl Buffer_Draw_Stamp_Clip(void const* this_object, void const* icondata, int icon, int x_pixel, int y_pixel, void const* remap, int min_x, int min_y, int max_x, int max_y) { + Buffer_Draw_Stamp_Clip2(*((GraphicViewPortClass*)this_object), (IconControlType*)icondata, icon, x_pixel, y_pixel, remap, min_x, min_y, max_x, max_y); +} + +extern "C" void __cdecl Buffer_Draw_Stamp(void const* thisptr, void const* icondata, int icon, int x_pixel, int y_pixel, void const* remap) { + Buffer_Draw_Stamp2(*((GraphicViewPortClass*)thisptr), (IconControlType*)icondata, icon, x_pixel, y_pixel, remap); +} + +uint8_t* Get_Icon_Set_Map(void* temp) +{ + if (temp != nullptr) { + if ((static_cast(temp)->td.icons) == TD_TILESET_CHECK) { + return static_cast(temp) + (static_cast(temp)->td.icons); + } + else { + return static_cast(temp) + (static_cast(temp)->ra.icons); + } + } + + return nullptr; +} diff --git a/code/REDALERT/WIN32LIB/DrawMisc.cpp b/code/REDALERT/WIN32LIB/DrawMisc.cpp index 24e970a..49f00bd 100644 --- a/code/REDALERT/WIN32LIB/DrawMisc.cpp +++ b/code/REDALERT/WIN32LIB/DrawMisc.cpp @@ -1689,523 +1689,6 @@ fini: } -/* -;*********************************************************** - -;*********************************************************** -; DRAW_STAMP -; -; VOID cdecl Buffer_Draw_Stamp(VOID *icondata, WORD icon, WORD x_pixel, WORD y_pixel, VOID *remap); -; -; This routine renders the icon at the given coordinate. -; -; The remap table is a 256 byte simple pixel translation table to use when -; drawing the icon. Transparency check is performed AFTER the remap so it is possible to -; remap valid colors to be invisible (for special effect reasons). -; This routine is fastest when no remap table is passed in. -;* -*/ - -void __cdecl Buffer_Draw_Stamp(void const *this_object, void const *icondata, int icon, int x_pixel, int y_pixel, void const *remap) -{ - unsigned int modulo = 0; - unsigned int iwidth = 0; - unsigned char doremap = 0; - - -/* - PROC Buffer_Draw_Stamp C near - - ARG this_object:DWORD ; this is a member function - ARG icondata:DWORD ; Pointer to icondata. - ARG icon:DWORD ; Icon number to draw. - ARG x_pixel:DWORD ; X coordinate of icon. - ARG y_pixel:DWORD ; Y coordinate of icon. - ARG remap:DWORD ; Remap table. - - LOCAL modulo:DWORD ; Modulo to get to next row. - LOCAL iwidth:DWORD ; Icon width (here for speedy access). - LOCAL doremap:BYTE ; Should remapping occur? -*/ - - __asm { - - pushad - cmp [icondata],0 - je proc_out - - ; Initialize the stamp data if necessary. - mov eax,[icondata] - cmp [LastIconset],eax - je short noreset - push eax - call Init_Stamps - pop eax // Clean up stack. ST - 12/20/2018 10:42AM -noreset: - - ; Determine if the icon number requested is actually in the set. - ; Perform the logical icon to actual icon number remap if necessary. - mov ebx,[icon] - cmp [MapPtr],0 - je short notmap - mov edi,[MapPtr] - mov bl,[edi+ebx] -notmap: - cmp ebx,[IconCount] - jae proc_out - mov [icon],ebx ; Updated icon number. - - ; If the remap table pointer passed in is NULL, then flag this condition - ; so that the faster (non-remapping) icon draw loop will be used. - cmp [remap],0 - setne [doremap] - - ; Get pointer to position to render icon. EDI = ptr to destination page. - mov ebx,[this_object] - mov edi,[ebx]GraphicViewPortClass.Offset - mov eax,[ebx]GraphicViewPortClass.Width - add eax,[ebx]GraphicViewPortClass.XAdd - add eax,[ebx]GraphicViewPortClass.Pitch - push eax ; save viewport full width for lower - mul [y_pixel] - add edi,eax - add edi,[x_pixel] - - ; Determine row modulo for advancing to next line. - pop eax ; retrieve viewport width - sub eax,[IconWidth] - mov [modulo],eax - - ; Setup some working variables. - mov ecx,[IconHeight] ; Row counter. - mov eax,[IconWidth] - mov [iwidth],eax ; Stack copy of byte width for easy BP access. - - ; Fetch pointer to start of icon's data. ESI = ptr to icon data. - mov eax,[icon] - mul [IconSize] - mov esi,[StampPtr] - add esi,eax - - ; Determine whether simple icon draw is sufficient or whether the - ; extra remapping icon draw is needed. - cmp [BYTE PTR doremap],0 - je short istranscheck - - ;************************************************************ - ; Complex icon draw -- extended remap. - ; EBX = Palette pointer (ready for XLAT instruction). - ; EDI = Pointer to icon destination in page. - ; ESI = Pointer to icon data. - ; ECX = Number of pixel rows. - ;;; mov edx,[remap] - mov ebx,[remap] - xor eax,eax -xrowloop: - push ecx - mov ecx,[iwidth] - -xcolumnloop: - lodsb - ;;; mov ebx,edx - ;;; add ebx,eax - ;;; mov al,[ebx] ; New real color to draw. - xlatb - or al,al - jz short xskip1 ; Transparency skip check. - mov [edi],al -xskip1: - inc edi - loop xcolumnloop - - pop ecx - add edi,[modulo] - loop xrowloop - jmp short proc_out - - - ;************************************************************ - ; Check to see if transparent or generic draw is necessary. -istranscheck: - mov ebx,[IsTrans] - add ebx,[icon] - cmp [BYTE PTR ebx],0 - jne short rowloop - - ;************************************************************ - ; Fast non-transparent icon draw routine. - ; ES:DI = Pointer to icon destination in page. - ; DS:SI = Pointer to icon data. - ; CX = Number of pixel rows. - mov ebx,ecx - shr ebx,2 - mov edx,[modulo] - mov eax,[iwidth] - shr eax,2 -loop1: - mov ecx,eax - rep movsd - add edi,edx - - mov ecx,eax - rep movsd - add edi,edx - - mov ecx,eax - rep movsd - add edi,edx - - mov ecx,eax - rep movsd - add edi,edx - - dec ebx - jnz loop1 - jmp short proc_out - - ;************************************************************ - ; Transparent icon draw routine -- no extended remap. - ; ES:DI = Pointer to icon destination in page. - ; DS:SI = Pointer to icon data. - ; CX = Number of pixel rows. -rowloop: - push ecx - mov ecx,[iwidth] - -columnloop: - lodsb - or al,al - jz short skip1 ; Transparency check. - mov [edi],al -skip1: - inc edi - loop columnloop - - pop ecx - add edi,[modulo] - loop rowloop - - ; Cleanup and exit icon drawing routine. -proc_out: - popad - //ret - } -} - - - - -/* -;*********************************************************** -; DRAW_STAMP_CLIP -; -; VOID cdecl MCGA_Draw_Stamp_Clip(VOID *icondata, WORD icon, WORD x_pixel, WORD y_pixel, VOID *remap, LONG min_x, LONG min_y, LONG max_x, LONG max_y); -; -; This routine renders the icon at the given coordinate. -; -; The remap table is a 256 byte simple pixel translation table to use when -; drawing the icon. Transparency check is performed AFTER the remap so it is possible to -; remap valid colors to be invisible (for special effect reasons). -; This routine is fastest when no remap table is passed in. -;* -*/ -void __cdecl Buffer_Draw_Stamp_Clip(void const *this_object, void const *icondata, int icon, int x_pixel, int y_pixel, void const *remap, int min_x, int min_y, int max_x, int max_y) -{ - unsigned int modulo = 0; - unsigned int iwidth = 0; - unsigned int skip = 0; - unsigned char doremap = 0; - - -/* - ARG this_object:DWORD ; this is a member function - ARG icondata:DWORD ; Pointer to icondata. - ARG icon:DWORD ; Icon number to draw. - ARG x_pixel:DWORD ; X coordinate of icon. - ARG y_pixel:DWORD ; Y coordinate of icon. - ARG remap:DWORD ; Remap table. - ARG min_x:DWORD ; Clipping rectangle boundary - ARG min_y:DWORD ; Clipping rectangle boundary - ARG max_x:DWORD ; Clipping rectangle boundary - ARG max_y:DWORD ; Clipping rectangle boundary - - LOCAL modulo:DWORD ; Modulo to get to next row. - LOCAL iwidth:DWORD ; Icon width (here for speedy access). - LOCAL skip:DWORD ; amount to skip per row of icon data - LOCAL doremap:BYTE ; Should remapping occur? -*/ - __asm { - pushad - cmp [icondata],0 - je proc_out - - ; Initialize the stamp data if necessary. - mov eax,[icondata] - cmp [LastIconset],eax - je short noreset2 - push eax - call Init_Stamps - pop eax // Clean up stack. ST - 12/20/2018 10:42AM -noreset2: - - ; Determine if the icon number requested is actually in the set. - ; Perform the logical icon to actual icon number remap if necessary. - mov ebx,[icon] - cmp [MapPtr],0 - je short notmap2 - mov edi,[MapPtr] - mov bl,[edi+ebx] -notmap2: - cmp ebx,[IconCount] - jae proc_out - mov [icon],ebx ; Updated icon number. - - ; Setup some working variables. - mov ecx,[IconHeight] ; Row counter. - mov eax,[IconWidth] - mov [iwidth],eax ; Stack copy of byte width for easy BP access. - - ; Fetch pointer to start of icon's data. ESI = ptr to icon data. - mov eax,[icon] - mul [IconSize] - mov esi,[StampPtr] - add esi,eax - - ; Update the clipping window coordinates to be valid maxes instead of width & height - ; , and change the coordinates to be window-relative - mov ebx,[min_x] - add [max_x],ebx - add [x_pixel],ebx ; make it window-relative - mov ebx,[min_y] - add [max_y],ebx - add [y_pixel],ebx ; make it window-relative - - ; See if the icon is within the clipping window - ; First, verify that the icon position is less than the maximums - mov ebx,[x_pixel] - cmp ebx,[max_x] - jge proc_out - mov ebx,[y_pixel] - cmp ebx,[max_y] - jge proc_out - ; Now verify that the icon position is >= the minimums - add ebx,[IconHeight] - cmp ebx,[min_y] - jle proc_out - mov ebx,[x_pixel] - add ebx,[IconWidth] - cmp ebx,[min_x] - jle proc_out - - ; Now, clip the x, y, width, and height variables to be within the - ; clipping rectangle - mov ebx,[x_pixel] - cmp ebx,[min_x] - jge nominxclip - ; x < minx, so must clip - mov ebx,[min_x] - sub ebx,[x_pixel] - add esi,ebx ; source ptr += (minx - x) - sub [iwidth],ebx ; icon width -= (minx - x) - mov ebx,[min_x] - mov [x_pixel],ebx - -nominxclip: - mov eax,[IconWidth] - sub eax,[iwidth] - mov [skip],eax - - ; Check for x+width > max_x - mov eax,[x_pixel] - add eax,[iwidth] - cmp eax,[max_x] - jle nomaxxclip - ; x+width is greater than max_x, so must clip width down - mov eax,[iwidth] ; eax = old width - mov ebx,[max_x] - sub ebx,[x_pixel] - mov [iwidth],ebx ; iwidth = max_x - xpixel - sub eax,ebx - add [skip],eax ; skip += (old width - iwidth) -nomaxxclip: - ; check if y < miny - mov eax,[min_y] - cmp eax,[y_pixel] ; if(miny <= y_pixel), no clip needed - jle nominyclip - sub eax,[y_pixel] - sub ecx,eax ; height -= (miny - y) - mul [IconWidth] - add esi,eax ; icon source ptr += (width * (miny - y)) - mov eax,[min_y] - mov [y_pixel],eax ; y = miny -nominyclip: - ; check if (y+height) > max y - mov eax,[y_pixel] - add eax,ecx - cmp eax,[max_y] ; if (y + height <= max_y), no clip needed - jle nomaxyclip - mov ecx,[max_y] ; height = max_y - y_pixel - sub ecx,[y_pixel] -nomaxyclip: - - ; If the remap table pointer passed in is NULL, then flag this condition - ; so that the faster (non-remapping) icon draw loop will be used. - cmp [remap],0 - setne [doremap] - - ; Get pointer to position to render icon. EDI = ptr to destination page. - mov ebx,[this_object] - mov edi,[ebx]GraphicViewPortClass.Offset - mov eax,[ebx]GraphicViewPortClass.Width - add eax,[ebx]GraphicViewPortClass.XAdd - add eax,[ebx]GraphicViewPortClass.Pitch - push eax ; save viewport full width for lower - mul [y_pixel] - add edi,eax - add edi,[x_pixel] - - ; Determine row modulo for advancing to next line. - pop eax ; retrieve viewport width - sub eax,[iwidth] - mov [modulo],eax - - ; Determine whether simple icon draw is sufficient or whether the - ; extra remapping icon draw is needed. - cmp [BYTE PTR doremap],0 - je short istranscheck2 - - ;************************************************************ - ; Complex icon draw -- extended remap. - ; EBX = Palette pointer (ready for XLAT instruction). - ; EDI = Pointer to icon destination in page. - ; ESI = Pointer to icon data. - ; ECX = Number of pixel rows. - mov ebx,[remap] - xor eax,eax -xrowloopc: - push ecx - mov ecx,[iwidth] - -xcolumnloopc: - lodsb - xlatb - or al,al - jz short xskip1c ; Transparency skip check. - mov [edi],al -xskip1c: - inc edi - loop xcolumnloopc - - pop ecx - add edi,[modulo] - add esi,[skip] - loop xrowloopc - jmp short proc_out - - - ;************************************************************ - ; Check to see if transparent or generic draw is necessary. -istranscheck2: - mov ebx,[IsTrans] - add ebx,[icon] - cmp [BYTE PTR ebx],0 - jne short rowloopc - - ;************************************************************ - ; Fast non-transparent icon draw routine. - ; ES:DI = Pointer to icon destination in page. - ; DS:SI = Pointer to icon data. - ; CX = Number of pixel rows. - mov ebx,ecx - mov edx,[modulo] - mov eax,[iwidth] - - ; - ; Optimise copy by dword aligning the destination - ; -loop1c: - push eax - //rept 3 // No rept in inline asm. ST - 12/20/2018 10:43AM - test edi,3 - jz aligned - movsb - dec eax - jz finishedit - - test edi,3 - jz aligned - movsb - dec eax - jz finishedit - - test edi,3 - jz aligned - movsb - dec eax - jz finishedit - - //endm -aligned: - mov ecx,eax - shr ecx,2 - rep movsd - mov ecx,eax - and ecx,3 - rep movsb - -finishedit: - add edi,edx - add esi,[skip] - pop eax - - dec ebx - jnz loop1c - jmp short proc_out - - ;************************************************************ - ; Transparent icon draw routine -- no extended remap. - ; ES:DI = Pointer to icon destination in page. - ; DS:SI = Pointer to icon data. - ; CX = Number of pixel rows. -rowloopc: - push ecx - mov ecx,[iwidth] - -columnloopc: - lodsb - or al,al - jz short skip1c ; Transparency check. - mov [edi],al -skip1c: - inc edi - loop columnloopc - - pop ecx - add edi,[modulo] - add esi,[skip] - loop rowloopc - - ; Cleanup and exit icon drawing routine. -proc_out: - popad - //ret - } -} - - - - - - - - - - - - - - - VOID __cdecl Buffer_Draw_Line(void *thisptr, int sx, int sy, int dx, int dy, unsigned char color); VOID __cdecl Buffer_Fill_Rect(void *thisptr, int sx, int sy, int dx, int dy, unsigned char color); VOID __cdecl Buffer_Remap(void * thisptr, int sx, int sy, int width, int height, void *remap);