From 2ba8a7a2dde21d2d414d67881cb2200ab595d5b1 Mon Sep 17 00:00:00 2001 From: Justin Marshall Date: Sat, 20 Jun 2020 09:51:38 -0700 Subject: [PATCH] Tileset stamps are now loaded before the level is rendered. --- code/REDALERT/CDATA.CPP | 6 ++ code/REDALERT/CELL.CPP | 12 ++-- code/REDALERT/DISPLAY.CPP | 7 +++ code/REDALERT/DISPLAY.H | 4 ++ code/REDALERT/Image.h | 12 ++-- code/REDALERT/NEWBLIT.CPP | 4 +- code/REDALERT/NEWBLIT.H | 2 +- code/REDALERT/TDATA.CPP | 7 +++ code/REDALERT/TILESET.CPP | 93 ++++++++++++++++++------------- code/REDALERT/WIN32LIB/DRAWBUFF.H | 2 + code/REDALERT/WINSTUB.CPP | 74 ++++++++++++++++++++++++ 11 files changed, 168 insertions(+), 55 deletions(-) diff --git a/code/REDALERT/CDATA.CPP b/code/REDALERT/CDATA.CPP index 02e12b5..06cdfc4 100644 --- a/code/REDALERT/CDATA.CPP +++ b/code/REDALERT/CDATA.CPP @@ -3136,6 +3136,12 @@ void TemplateTypeClass::Init(TheaterType theater) ((unsigned char &)tplate.Width) = Get_IconSet_MapWidth(ptr); ((unsigned char &)tplate.Height) = Get_IconSet_MapHeight(ptr); + + { + char tmp[512]; + sprintf(tmp, "icon_%s", fullname); + ((void const*&)tplate.HDImageData) = Load_Stamp(fullname, tplate.ImageData); + } } } } diff --git a/code/REDALERT/CELL.CPP b/code/REDALERT/CELL.CPP index 6d776c7..c3be89a 100644 --- a/code/REDALERT/CELL.CPP +++ b/code/REDALERT/CELL.CPP @@ -1091,7 +1091,9 @@ void CellClass::Draw_It(int x, int y, bool objects) const ** This is the underlying terrain icon. */ if (ttype->Get_Image_Data()) { - LogicPage->Draw_Stamp(ttype, icon, x, y, NULL, WINDOW_TACTICAL); +// jmarshall - hd image should always be valid even if loading legacy assets + LogicPage->Draw_Stamp(ttype->Get_HDImage_Data(), icon, x, y, NULL, WINDOW_TACTICAL); +// jmarshall end if (remap) { LogicPage->Remap(x+Map.TacPixelX, y+Map.TacPixelY, ICON_PIXEL_W, ICON_PIXEL_H, remap); } @@ -1190,9 +1192,9 @@ void CellClass::Draw_It(int x, int y, bool objects) const ** Draw the hash-mark cursor: */ if (Map.ProximityCheck && Is_Clear_To_Build(loco)) { - LogicPage->Draw_Stamp(DisplayClass::TransIconset, 0, x, y, NULL, WINDOW_TACTICAL); + LogicPage->Draw_Stamp(DisplayClass::TransIconsetHD, 0, x, y, NULL, WINDOW_TACTICAL); } else { - LogicPage->Draw_Stamp(DisplayClass::TransIconset, 2, x, y, NULL, WINDOW_TACTICAL); + LogicPage->Draw_Stamp(DisplayClass::TransIconsetHD, 2, x, y, NULL, WINDOW_TACTICAL); } #ifdef SCENARIO_EDITOR @@ -1213,8 +1215,8 @@ void CellClass::Draw_It(int x, int y, bool objects) const icon = (Cell_X(cell) - Cell_X(Map.ZoneCell + Map.ZoneOffset)) + (Cell_Y(cell) - Cell_Y(Map.ZoneCell + Map.ZoneOffset)) * tptr->Width; -// jmarshall - pass in raw tptr - LogicPage->Draw_Stamp(tptr, icon, x, y, NULL, WINDOW_TACTICAL); +// jmarshall - hd image should always be valid even if loading legacy assets + LogicPage->Draw_Stamp(tptr->Get_HDImage_Data(), icon, x, y, NULL, WINDOW_TACTICAL); // jmarshall end } break; diff --git a/code/REDALERT/DISPLAY.CPP b/code/REDALERT/DISPLAY.CPP index 85c4438..c162eea 100644 --- a/code/REDALERT/DISPLAY.CPP +++ b/code/REDALERT/DISPLAY.CPP @@ -108,6 +108,9 @@ unsigned char DisplayClass::TranslucentTable[(MAGIC_COL_COUNT+1)*256]; unsigned char DisplayClass::WhiteTranslucentTable[(1+1)*256]; unsigned char DisplayClass::MouseTranslucentTable[(4+1)*256]; void const * DisplayClass::TransIconset; +// jmarshall +Image_t* DisplayClass::TransIconsetHD; +// jmarshall end unsigned char DisplayClass::UnitShadow[(USHADOW_COL_COUNT+1)*256]; unsigned char DisplayClass::UnitShadowAir[(USHADOW_COL_COUNT+1)*256]; unsigned char DisplayClass::SpecialGhost[2*256]; @@ -187,6 +190,7 @@ DisplayClass::DisplayClass(void) : { ShadowShapes = 0; TransIconset = 0; + TransIconsetHD = 0; Set_View_Dimensions(0, 8 * RESFACTOR, ScreenWidth, ScreenHeight); } @@ -228,6 +232,9 @@ void DisplayClass::One_Time(void) ** Load the generic transparent icon set. */ TransIconset = MFCD::Retrieve("TRANS.ICN"); +// jmarshall + TransIconsetHD = Load_Stamp("TRANS_ICON", TransIconset); +// jmarshall end #ifndef NDEBUG RawFileClass file("SHADOW.SHP"); diff --git a/code/REDALERT/DISPLAY.H b/code/REDALERT/DISPLAY.H index 73c37b0..f47315a 100644 --- a/code/REDALERT/DISPLAY.H +++ b/code/REDALERT/DISPLAY.H @@ -38,6 +38,7 @@ #include "map.h" #include "layer.h" +struct Image_t; #define ICON_PIXEL_W 24 #define ICON_PIXEL_H 24 @@ -114,6 +115,9 @@ class DisplayClass: public MapClass static unsigned char WhiteTranslucentTable[(1+1)*256]; static unsigned char MouseTranslucentTable[(4+1)*256]; static void const *TransIconset; +// jmarshall + static Image_t* TransIconsetHD; +// jmarshall end static unsigned char UnitShadow[(USHADOW_COL_COUNT+1)*256]; static unsigned char UnitShadowAir[(USHADOW_COL_COUNT+1)*256]; static unsigned char SpecialGhost[2*256]; diff --git a/code/REDALERT/Image.h b/code/REDALERT/Image.h index 51700f2..9c01ed8 100644 --- a/code/REDALERT/Image.h +++ b/code/REDALERT/Image.h @@ -15,20 +15,18 @@ struct Image_t { int height; int renderwidth; int renderheight; - //unsigned char* buffer[MAX_HOUSE_COLORS][MAX_IMAGE_FRAMES]; + void* IconMapPtr; }; __forceinline Image_t::Image_t() { -// buffer = NULL; + IconMapPtr = NULL; numAnimFrames = 0; } __forceinline Image_t::~Image_t() { - //if (buffer) { - // delete buffer; - // buffer = NULL; - //} } Image_t* Image_LoadImage(const char* name, bool loadAnims = false, bool loadHouseColor = false); -Image_t* Image_CreateImageFrom8Bit(const char* name, int Width, int Height, unsigned char* data, unsigned char *remap = NULL); \ No newline at end of file +Image_t* Image_CreateImageFrom8Bit(const char* name, int Width, int Height, unsigned char* data, unsigned char *remap = NULL); +Image_t* Find_Image(const char* name); +void Image_Add8BitImage(Image_t* image, int HouseId, int ShapeID, int Width, int Height, unsigned char* data, unsigned char* remap); \ No newline at end of file diff --git a/code/REDALERT/NEWBLIT.CPP b/code/REDALERT/NEWBLIT.CPP index 693953c..cccf6d0 100644 --- a/code/REDALERT/NEWBLIT.CPP +++ b/code/REDALERT/NEWBLIT.CPP @@ -18,10 +18,10 @@ void GL_ResetClipRect(void) { ImGui::GetForegroundDrawList()->PopClipRect(); } -void GL_RenderImage(Image_t* image, int x, int y, int width, int height, int colorRemap) { +void GL_RenderImage(Image_t* image, int x, int y, int width, int height, int colorRemap, int shapeId) { ImVec2 mi(x, y); ImVec2 ma(x + width, y + height); - ImGui::GetForegroundDrawList()->AddImage((ImTextureID)image->image[colorRemap][0], mi, ma); + ImGui::GetForegroundDrawList()->AddImage((ImTextureID)image->image[colorRemap][shapeId], mi, ma); } void GL_FillRect(int color, int x, int y, int width, int height) { diff --git a/code/REDALERT/NEWBLIT.H b/code/REDALERT/NEWBLIT.H index b3e9508..36cab3a 100644 --- a/code/REDALERT/NEWBLIT.H +++ b/code/REDALERT/NEWBLIT.H @@ -2,7 +2,7 @@ // struct Image_t; -void GL_RenderImage(Image_t* image, int x, int y, int width, int height, int colorRemap = 0); +void GL_RenderImage(Image_t* image, int x, int y, int width, int height, int colorRemap = 0, int shapeId = 0); void GL_DrawText(int color, int x, int y, char* text); void GL_FillRect(int color, int x, int y, int width, int height); void GL_DrawLine(int color, int x, int y, int dx, int dy); diff --git a/code/REDALERT/TDATA.CPP b/code/REDALERT/TDATA.CPP index cc463f2..3dadc71 100644 --- a/code/REDALERT/TDATA.CPP +++ b/code/REDALERT/TDATA.CPP @@ -49,6 +49,7 @@ #include "function.h" #include "terrain.h" #include "type.h" +#include "Image.h" static short const _List000011101000[] = {MAP_CELL_W, MAP_CELL_W+1, MAP_CELL_W+2, MAP_CELL_W*2, REFRESH_EOL}; @@ -689,6 +690,12 @@ void TerrainTypeClass::Init(TheaterType theater) _makepath(fullname, NULL, NULL, terrain.IniName, Theaters[theater].Suffix); ((void const *&)terrain.ImageData) = MFCD::Retrieve(fullname); + { + char tmp[512]; + sprintf(tmp, "icon_%s", fullname); + ((void const*&)terrain.HDImageData) = Load_Stamp(fullname, terrain.ImageData); + } + IsTheaterShape = true; //Let Build_Frame know that this is a theater specific shape if (terrain.RadarIcon != NULL) delete[] (char *)terrain.RadarIcon; ((void const *&)terrain.RadarIcon) = Get_Radar_Icon(terrain.Get_Image_Data(), 0, 1, 3); diff --git a/code/REDALERT/TILESET.CPP b/code/REDALERT/TILESET.CPP index 95f639e..a17da1d 100644 --- a/code/REDALERT/TILESET.CPP +++ b/code/REDALERT/TILESET.CPP @@ -32,8 +32,6 @@ class GraphicViewPortClass; #define TD_TILESET_CHECK 0x20 -Image_t* tileset_icon_cache[4096]; - /** * @brief union is to handle the parts of the header which vary between TD and RA format tiles. */ @@ -103,8 +101,7 @@ static int IconSize; static int IconCount; void __cdecl Init_Stamps(IconControlType* iconset) -{ - memset(&tileset_icon_cache, 0, sizeof(tileset_icon_cache)); +{ if (iconset && LastIconset != iconset) { IconCount = (iconset->count); IconWidth = (iconset->width); @@ -193,51 +190,67 @@ void __cdecl Buffer_Draw_Stamp2(GraphicViewPortClass& viewport, IconControlType* } } +struct Image_t *__cdecl Load_Stamp(const char *name, const void* icondata) +{ + IconControlType* tileset = (IconControlType*)icondata; + + if (!tileset) { + return NULL; + } + + if (LastIconset != tileset) { + Init_Stamps(tileset); + } + + + int icon_index = 0; + + if (icon_index >= IconCount) { + return NULL; + } + + uint8_t* src = &StampPtr[IconSize * icon_index]; + + // Check to see if the image is already loaded. + { + Image_t* image = Find_Image(name); + if (image) { + return image; + } + } + + Image_t *image = Image_CreateImageFrom8Bit(name, IconWidth, IconHeight, (unsigned char*)src); + image->IconMapPtr = MapPtr; + if (IconCount == 1) + return image; + + for (int i = 1; i < IconCount; i++) { + icon_index = i; + src = &StampPtr[IconSize * icon_index]; + Image_Add8BitImage(image, 0, i, IconWidth, IconHeight, src, NULL); + } + + return image; +} + void __cdecl Buffer_Draw_Stamp_Clip2(GraphicViewPortClass& viewport, const void *icondata, int icon, int x, int y, const void* remapper, int left, int top, int right, int bottom) { - const TemplateTypeClass* ttype = (TemplateTypeClass const*)icondata; - IconControlType* tileset = (IconControlType * )ttype->Get_Image_Data(); - - // This is a awful hack, but need type info to generate unique id's for tileset generation. - if (icondata == DisplayClass::TransIconset) { - tileset = (IconControlType*)DisplayClass::TransIconset; - ttype = NULL; - } - - if (!tileset) { - return; - } - - if (LastIconset != tileset) { - Init_Stamps(tileset); - } - - int icon_index = MapPtr != nullptr ? MapPtr[icon] : icon; - - if (icon_index < IconCount) { + Image_t* iconImage = (Image_t*)icondata; + uint8_t* MapPtr = (uint8_t * )iconImage->IconMapPtr; + int icon_index = MapPtr != nullptr ? MapPtr[icon] : icon; + { 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 (!tileset_icon_cache[icon_index]) { - char tmp[512]; - if (ttype != NULL) { - sprintf(tmp, "icon_%d_%d", ttype->Type, icon_index); - } - else { - sprintf(tmp, "icon_%d_%d", icondata, icon_index); - } - tileset_icon_cache[icon_index] = Image_CreateImageFrom8Bit(tmp, IconWidth, IconHeight, (unsigned char *)src); - } - + if (xstart < width && ystart < height && IconHeight + ystart > top && IconWidth + xstart > left) { if (xstart < left) { - src += left - xstart; +// src += left - xstart; blit_width -= left - xstart; xstart = left; } @@ -251,7 +264,7 @@ void __cdecl Buffer_Draw_Stamp_Clip2(GraphicViewPortClass& viewport, const void if (top > ystart) { blit_height = IconHeight - (top - ystart); - src += IconWidth * (top - ystart); + // src += IconWidth * (top - ystart); ystart = top; } @@ -308,7 +321,7 @@ void __cdecl Buffer_Draw_Stamp_Clip2(GraphicViewPortClass& viewport, const void //} GL_SetClipRect(xstart, ystart, blit_width, blit_height); - GL_RenderImage(tileset_icon_cache[icon_index], xstart, ystart, blit_width, blit_height); + GL_RenderImage(iconImage, xstart, ystart, blit_width, blit_height, 0, icon_index); GL_ResetClipRect(); } } diff --git a/code/REDALERT/WIN32LIB/DRAWBUFF.H b/code/REDALERT/WIN32LIB/DRAWBUFF.H index 38b46d4..72ace4c 100644 --- a/code/REDALERT/WIN32LIB/DRAWBUFF.H +++ b/code/REDALERT/WIN32LIB/DRAWBUFF.H @@ -61,6 +61,8 @@ extern "C" { void * __cdecl Get_Font_Palette_Ptr ( void ); } +struct Image_t* __cdecl Load_Stamp(const char* name, const void* icondata); + extern GraphicViewPortClass *LogicPage; extern BOOL AllowHardwareBlitFills; #endif diff --git a/code/REDALERT/WINSTUB.CPP b/code/REDALERT/WINSTUB.CPP index 0b988dd..7a9f856 100644 --- a/code/REDALERT/WINSTUB.CPP +++ b/code/REDALERT/WINSTUB.CPP @@ -290,6 +290,25 @@ Image_t* Image_LoadImage(const char* name, bool loadAnims, bool loadHouseColor) return image; } +Image_t *Find_Image(const char* name) { + int64_t hash = generateHashValue(name, strlen(name)); + + int image_table_size = loaded_images.size(); + if (image_table_size > 0) + { + Image_t** image_table = &loaded_images[0]; + + // Check to see if the image is already loaded. + for (int i = 0; i < image_table_size; i++) { + if (image_table[i]->namehash == hash) { + return image_table[i]; + } + } + } + + return NULL; +} + Image_t* Image_CreateImageFrom8Bit(const char* name, int Width, int Height, unsigned char *data, unsigned char* remap) { int64_t hash = generateHashValue(name, strlen(name)); @@ -360,6 +379,61 @@ Image_t* Image_CreateImageFrom8Bit(const char* name, int Width, int Height, unsi return image; } +void Image_Add8BitImage(Image_t *image, int HouseId, int ShapeID, int Width, int Height, unsigned char* data, unsigned char* remap) { + unsigned char* buffer = new unsigned char[Width * Height * 4]; + unsigned char* ccpalete = (unsigned char*)CCPalette.Get_Data(); + + if (image->width != Width || image->height != Height) { + assert(!"Image_Add8BitImage: Invalid new dimensions!"); + } + + for (int i = 0; i < Width * Height; i++) { + unsigned char c = data[i]; + if (remap) { + c = remap[c]; + } + + unsigned char r = ccpalete[(c * 3) + 0] << 2; + unsigned char g = ccpalete[(c * 3) + 1] << 2; + unsigned char b = ccpalete[(c * 3) + 2] << 2; + unsigned char a = 0; + + if ((r == 84 && g == 252 && b == 84) || (r == 0 && g == 168 && b == 0)) { + r = 0; + g = 0; + b = 0; + a = 128; + } + else if (c != 0) { + a = 255; + } + + + buffer[(i * 4) + 0] = r; + buffer[(i * 4) + 1] = g; + buffer[(i * 4) + 2] = b; + buffer[(i * 4) + 3] = a; + } + + + GLuint texture; + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + + image->image[HouseId][ShapeID] = texture; + image->numAnimFrames = -1; + image->renderwidth = image->width = Width; + image->renderheight = image->height = Height; + + delete buffer; +} + + BOOL Set_Video_Mode(HWND hwnd, int w, int h, int bits_per_pixel) { // Todo implement resoluton scaling.