Used additional Chronoshift code to remove legacy assembly for stamp/icon rendering.

This commit is contained in:
Justin Marshall
2020-06-15 11:47:17 -07:00
parent 6bc8e75194
commit 92cc33e4aa
3 changed files with 289 additions and 517 deletions
+1
View File
@@ -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
+288
View File
@@ -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 <cstring>
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<uint8_t*>(this) + td.icons;
}
else {
return reinterpret_cast<uint8_t*>(this) + ra.icons;
}
}
uint8_t* Get_Icon_Map()
{
if (td.icons == TD_TILESET_CHECK) {
return reinterpret_cast<uint8_t*>(this) + td.map;
}
else {
return reinterpret_cast<uint8_t*>(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<uint8_t*>(iconset) + (iconset->td.map);
StampPtr = reinterpret_cast<uint8_t*>(iconset) + (iconset->td.icons);
TransFlagPtr = reinterpret_cast<uint8_t*>(iconset) + (iconset->td.trans_flag);
}
else {
MapPtr = reinterpret_cast<uint8_t*>(iconset) + (iconset->ra.map);
StampPtr = reinterpret_cast<uint8_t*>(iconset) + (iconset->ra.icons);
TransFlagPtr = reinterpret_cast<uint8_t*>(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<const uint8_t*>(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<const uint8_t*>(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<IconControlType*>(temp)->td.icons) == TD_TILESET_CHECK) {
return static_cast<uint8_t*>(temp) + (static_cast<IconControlType*>(temp)->td.icons);
}
else {
return static_cast<uint8_t*>(temp) + (static_cast<IconControlType*>(temp)->ra.icons);
}
}
return nullptr;
}
-517
View File
@@ -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);