From 95e0bbb3aaf5d169860557adb29108cfc8a6539e Mon Sep 17 00:00:00 2001 From: Justin Marshall Date: Sun, 21 Jun 2020 14:56:25 -0700 Subject: [PATCH] Added remaster units support, Image_t now supports multiple image resolutions per shape. --- code/CMakeLists.txt | 1 + code/REDALERT/BDATA.CPP | 23 +++---- code/REDALERT/CONQUER.CPP | 4 +- code/REDALERT/CONSOLE.CPP | 6 +- code/REDALERT/FUNCTION.H | 3 + code/REDALERT/Image.h | 6 +- code/REDALERT/STARTUP.CPP | 1 + code/REDALERT/TILESET.CPP | 18 +++--- code/REDALERT/UDATA.CPP | 44 +++++++++++++- code/REDALERT/UNIT.CPP | 37 ++++++++++-- code/REDALERT/UNITXML.CPP | 99 +++++++++++++++++++++++++++++++ code/REDALERT/WIN32LIB/DRAWBUFF.H | 2 +- code/REDALERT/WINSTUB.CPP | 15 +++-- code/TIBERIANDAWN/UDATA.CPP | 2 +- 14 files changed, 223 insertions(+), 38 deletions(-) create mode 100644 code/REDALERT/UNITXML.CPP diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index b7c0663..ee219fd 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -427,6 +427,7 @@ set(src_redalert ./RedAlert/OPTIONS.H ./RedAlert/OVERLAY.CPP ./RedAlert/OVERLAY.H + ./RedAlert/UNITXML.CPP ./RedAlert/PACKET.CPP ./RedAlert/PACKET.H ./RedAlert/PALETTEC.CPP diff --git a/code/REDALERT/BDATA.CPP b/code/REDALERT/BDATA.CPP index 7a4df0c..0c21468 100644 --- a/code/REDALERT/BDATA.CPP +++ b/code/REDALERT/BDATA.CPP @@ -3173,15 +3173,18 @@ void BuildingTypeClass::One_Time(void) } image->numFrames = numBuildingAnims; ((void const*&)building.HDImageData) = image; - } - if (building.ImageData != NULL && building.HDImageData != NULL) { - int width = Get_Build_Frame_Width(building.ImageData); - int height = Get_Build_Frame_Height(building.ImageData); + if (building.ImageData != NULL && building.HDImageData != NULL) { + int width = Get_Build_Frame_Width(building.ImageData); + int height = Get_Build_Frame_Height(building.ImageData); - building.HDImageData->renderwidth = width; - building.HDImageData->renderheight = height; - } + for (int d = 0; d < shapeId; d++) + { + building.HDImageData->renderwidth[d] = width; + building.HDImageData->renderheight[d] = height; + } + } + } } } @@ -3261,7 +3264,7 @@ void BuildingTypeClass::Display(int x, int y, WindowNumberType window, HousesTyp //CC_Draw_Shape((Image_t *)Get_HDImage_Data(), 0, x, y, window, SHAPE_CENTER | SHAPE_WIN_REL, NULL, NULL, DIR_N); x += WindowList[window][WINDOWX]; y += WindowList[window][WINDOWY]; - GL_RenderImage(hdimage, x, y, hdimage->renderwidth, hdimage->renderheight); + GL_RenderImage(hdimage, x, y, hdimage->renderwidth[0], hdimage->renderheight[0]); } else { void const* ptr = Get_Cameo_Data(); @@ -3458,8 +3461,8 @@ void BuildingTypeClass::Init(TheaterType theater) int width = Get_Build_Frame_Width(classptr->ImageData); int height = Get_Build_Frame_Height(classptr->ImageData); - classptr->HDImageData->renderwidth = width; - classptr->HDImageData->renderheight = height; + classptr->HDImageData->renderwidth[0] = width; + classptr->HDImageData->renderheight[0] = height; } } // jmarshall end diff --git a/code/REDALERT/CONQUER.CPP b/code/REDALERT/CONQUER.CPP index 7d2ca71..d2ca0b7 100644 --- a/code/REDALERT/CONQUER.CPP +++ b/code/REDALERT/CONQUER.CPP @@ -3499,8 +3499,8 @@ void CC_Draw_Shape(Image_t* image, int shapenum, int x, int y, WindowNumberType if (image != NULL && shapenum != -1) { - int width = image->renderwidth; - int height = image->renderheight; + int width = image->renderwidth[shapenum]; + int height = image->renderheight[shapenum]; #ifdef NEVER /* diff --git a/code/REDALERT/CONSOLE.CPP b/code/REDALERT/CONSOLE.CPP index 6d96959..a246994 100644 --- a/code/REDALERT/CONSOLE.CPP +++ b/code/REDALERT/CONSOLE.CPP @@ -229,11 +229,11 @@ void Console_Printf(const char* fmt, ...) { vsprintf(msg, fmt, argptr); va_end(argptr); - int len = strlen(msg); - strcpy(&console_text[console_text_len], msg); + //int len = strlen(msg); + //strcpy(&console_text[console_text_len], msg); OutputDebugStringA(msg); - console_text_len += len; + //console_text_len += len; } /* diff --git a/code/REDALERT/FUNCTION.H b/code/REDALERT/FUNCTION.H index 394f889..ce28b7c 100644 --- a/code/REDALERT/FUNCTION.H +++ b/code/REDALERT/FUNCTION.H @@ -1181,11 +1181,14 @@ __forceinline void COM_SetExtension(char* path, int maxSize, const char* extensi void Tileset_LoadRules(void); void Buildings_LoadRules(void); +void Units_LoadRules(void); const char* Tileset_FindHDTexture(int theaterType, const char* shapeFileName, int shapeNum, int frameNum); int Tileset_GetNumFramesForTile(int theaterType, const char* shapeFileName, int shapeNum); int Buildings_GetNumFramesForTile(const char* shapeFileName, int shapeNum); const char* Buildings_FindHDTexture(const char* shapeFileName, int shapeNum, int frameNum); +int Units_GetNumFramesForTile(const char* shapeFileName, int shapeNum); +const char* Units_FindHDTexture(const char* shapeFileName, int shapeNum, int frameNum); extern bool g_inMainMenu; extern KeyNumType g_globalKeyNumType; diff --git a/code/REDALERT/Image.h b/code/REDALERT/Image.h index ff224fa..d12f2d8 100644 --- a/code/REDALERT/Image.h +++ b/code/REDALERT/Image.h @@ -19,8 +19,9 @@ struct Image_t { unsigned int numAnimFrames; int width; int height; - int renderwidth; - int renderheight; + int renderwidth[MAX_IMAGE_SHAPES]; + int renderheight[MAX_IMAGE_SHAPES]; + bool perFrameRenderDimen; int numFrames; void* IconMapPtr; }; @@ -28,6 +29,7 @@ struct Image_t { __forceinline Image_t::Image_t() { IconMapPtr = NULL; numAnimFrames = 0; + perFrameRenderDimen = false; memset(HouseImages, 0, sizeof(HouseImages)); } diff --git a/code/REDALERT/STARTUP.CPP b/code/REDALERT/STARTUP.CPP index 5f98dd5..921d451 100644 --- a/code/REDALERT/STARTUP.CPP +++ b/code/REDALERT/STARTUP.CPP @@ -390,6 +390,7 @@ int PASCAL WinMain ( HINSTANCE instance , HINSTANCE , char * command_line , int // Load all of the XML files. Tileset_LoadRules(); Buildings_LoadRules(); + Units_LoadRules(); if (Parse_Command_Line(argc, argv)) { diff --git a/code/REDALERT/TILESET.CPP b/code/REDALERT/TILESET.CPP index b4498dd..0929f67 100644 --- a/code/REDALERT/TILESET.CPP +++ b/code/REDALERT/TILESET.CPP @@ -248,12 +248,14 @@ Image_t* Load_StampHD(int theater, const char* iconName, const void* icondata) { return image; } -void Get_Stamp_Size(const void* icondata, int& width, int& height) { +void Get_Stamp_Size(const void* icondata, int* width, int* height) { IconControlType* tileset = (IconControlType*)icondata; if (!tileset) { - width = -1; - height = -1; + for (int i = 0; i < MAX_IMAGE_SHAPES; i++) { + *width = -1; + *height = -1; + } return; } @@ -261,8 +263,10 @@ void Get_Stamp_Size(const void* icondata, int& width, int& height) { Init_Stamps(tileset); } - width = IconWidth; - height = IconHeight; + for (int i = 0; i < MAX_IMAGE_SHAPES; i++) { + width[i] = IconWidth; + height[i] = IconHeight; + } } Image_t * Load_Stamp(const char *name, const void* icondata) @@ -314,8 +318,8 @@ void __cdecl Buffer_Draw_Stamp_Clip2(GraphicViewPortClass& viewport, const void uint8_t* MapPtr = (uint8_t * )iconImage->IconMapPtr; int icon_index = MapPtr != nullptr ? MapPtr[icon] : icon; { - int blit_height = iconImage->renderheight; - int blit_width = iconImage->renderwidth; + int blit_height = iconImage->renderheight[0]; + int blit_width = iconImage->renderwidth[0]; int width = left + right; int xstart = left + x; diff --git a/code/REDALERT/UDATA.CPP b/code/REDALERT/UDATA.CPP index 22774b3..7ff9096 100644 --- a/code/REDALERT/UDATA.CPP +++ b/code/REDALERT/UDATA.CPP @@ -48,6 +48,7 @@ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "function.h" +#include "image.h" /* ** This is the list of animation stages to use when the harvester @@ -1113,10 +1114,51 @@ void UnitTypeClass::One_Time(void) ((void const *&)uclass.ImageData) = ptr; if (ptr != NULL) { - largest = max(largest, (int)Get_Build_Frame_Width(ptr)); largest = max(largest, (int)Get_Build_Frame_Height(ptr)); } + { + const char* imageFileName = Units_FindHDTexture(fullname, 0, 0); + + if (imageFileName) { + Image_t* image = Image_LoadImage(imageFileName, true, true); + int numUnitsAnims = Units_GetNumFramesForTile(fullname, 0); + int shapeId = 1; + + // Load the old school animation pipeline. + { + while (true) { + imageFileName = Units_FindHDTexture(fullname, shapeId, 0); + if (imageFileName == NULL) + break; + + for (int d = 0; d < MAX_MPLAYER_COLORS; d++) { + Image_Add32BitImage(imageFileName, image, d, shapeId, 0); + } + shapeId++; + } + } + + for (int d = 0; d < shapeId; d++) { + image->renderwidth[d] = image->renderwidth[d] / 5; + image->renderheight[d] = image->renderheight[d] / 5; + } + + if (numUnitsAnims > 0) + { + for (int i = 1; i < numUnitsAnims; i++) { + imageFileName = Units_FindHDTexture(fullname, 0, i); + for (int d = 0; d < MAX_MPLAYER_COLORS; d++) { + Image_Add32BitImage(imageFileName, image, d, 0, i); + } + } + } + + image->numFrames = numUnitsAnims; + ((void const*&)uclass.HDImageData) = image; + } + } + ((int &)uclass.MaxSize) = max(largest, 8); } diff --git a/code/REDALERT/UNIT.CPP b/code/REDALERT/UNIT.CPP index 8b63fef..1d0e4e3 100644 --- a/code/REDALERT/UNIT.CPP +++ b/code/REDALERT/UNIT.CPP @@ -2051,11 +2051,13 @@ void UnitClass::Draw_It(int x, int y, WindowNumberType window) const int tfacing = Dir_To_32(SecondaryFacing); DirType rotation = DIR_N; int scale = 0x0100; + Image_t* hdShapeFile; /* ** Verify the legality of the unit class. */ shapefile = Get_Image_Data(); + hdShapeFile = Get_HDImage_Data(); if (shapefile == NULL) return; /* @@ -2076,7 +2078,12 @@ void UnitClass::Draw_It(int x, int y, WindowNumberType window) const /* ** Actually perform the draw. Overlay an optional shimmer effect as necessary. */ - Techno_Draw_Object(shapefile, shapenum, x, y, window, rotation, scale); + if (hdShapeFile) { + Techno_Draw_Object_HD(hdShapeFile, shapenum, x, y, window, rotation, scale); + } + else { + Techno_Draw_Object(shapefile, shapenum, x, y, window, rotation, scale); + } /* ** If there is a rotating radar dish, draw it now. @@ -2086,7 +2093,12 @@ void UnitClass::Draw_It(int x, int y, WindowNumberType window) const int x2 = x, y2 = y; shapenum = 32 + (Frame & 7); Class->Turret_Adjust(PrimaryFacing, x2, y2); - Techno_Draw_Object(shapefile, shapenum, x2, y2, window); + if (hdShapeFile) { + Techno_Draw_Object_HD(hdShapeFile, shapenum, x, y, window); + } + else { + Techno_Draw_Object(shapefile, shapenum, x2, y2, window); + } } else { //#ifdef FIXIT_PHASETRANSPORT // checked - ajw 9/28/98 // if (*this == UNIT_PHASE) { @@ -2099,9 +2111,19 @@ void UnitClass::Draw_It(int x, int y, WindowNumberType window) const //#endif #ifdef FIXIT_CSII // checked - ajw 9/28/98 if (*this == UNIT_TESLATANK) { - Techno_Draw_Object(shapefile, shapenum, x, y, window); + if (hdShapeFile) { + Techno_Draw_Object_HD(hdShapeFile, shapenum, x, y, window); + } + else { + Techno_Draw_Object(shapefile, shapenum, x, y, window); + } } else { - Techno_Draw_Object(shapefile, shapenum, x, y-5, window); + if (hdShapeFile) { + Techno_Draw_Object_HD(hdShapeFile, shapenum, x, y - 5, window); + } + else { + Techno_Draw_Object(shapefile, shapenum, x, y - 5, window); + } } #else Techno_Draw_Object(shapefile, shapenum, x, y-5, window); @@ -2139,7 +2161,12 @@ void UnitClass::Draw_It(int x, int y, WindowNumberType window) const /* ** Actually perform the draw. Overlay an optional shimmer effect as necessary. */ - Techno_Draw_Object(shapefile, shapenum, xx, yy, window); + if (hdShapeFile) { + Techno_Draw_Object_HD(hdShapeFile, shapenum, xx, yy - 4, window); // jmarshall - 4 pixel offset for turrets feels wrong, but visually looks alright. + } + else { + Techno_Draw_Object(shapefile, shapenum, xx, yy, window); + } } } diff --git a/code/REDALERT/UNITXML.CPP b/code/REDALERT/UNITXML.CPP new file mode 100644 index 0000000..56dfeb4 --- /dev/null +++ b/code/REDALERT/UNITXML.CPP @@ -0,0 +1,99 @@ +// UNITXML.CPP +// + + +#include "FUNCTION.H" +#include "tinyxml2.h" + +#include +#include + +int64_t generateHashValue(const char* fname, const int size); + +struct UnitsTileRule_t { + std::string name; + int64_t hash; + int shape; + std::vector frames; +}; + +struct UnitsXMLInfo_t { + std::vector tiles; +}; + +UnitsXMLInfo_t unitsXmlRules; + +const char* Units_FindHDTexture(const char* shapeFileName, int shapeNum, int frameNum) { + char tmpFileName[2048]; + strcpy(tmpFileName, shapeFileName); + COM_SetExtension(tmpFileName, strlen(tmpFileName), ""); + int64_t hash = generateHashValue(tmpFileName, strlen(tmpFileName)); + for (int i = 0; i < unitsXmlRules.tiles.size(); i++) { + if (unitsXmlRules.tiles[i].hash == hash && unitsXmlRules.tiles[i].shape == shapeNum) { + static char hdTexturePath[2048]; + if (unitsXmlRules.tiles[i].frames.size() == 0) + return NULL; + + sprintf(hdTexturePath, "DATA/ART/TEXTURES/SRGB/RED_ALERT/UNITS/%s", unitsXmlRules.tiles[i].frames[frameNum].c_str()); + return &hdTexturePath[0]; + } + } + return NULL; +} + +int Units_GetNumFramesForTile(const char* shapeFileName, int shapeNum) { + char tmpFileName[2048]; + strcpy(tmpFileName, shapeFileName); + COM_SetExtension(tmpFileName, strlen(tmpFileName), ""); + int64_t hash = generateHashValue(tmpFileName, strlen(tmpFileName)); + for (int i = 0; i < unitsXmlRules.tiles.size(); i++) { + if (unitsXmlRules.tiles[i].hash == hash && unitsXmlRules.tiles[i].shape == shapeNum) { + return unitsXmlRules.tiles[i].frames.size(); + } + } + return 0; +} + +void Units_ParseTile(tinyxml2::XMLNode* tile, UnitsTileRule_t& tileRule) { + tinyxml2::XMLNode* KeyNode = tile->FirstChildElement("Key"); + tinyxml2::XMLNode* NameNode = KeyNode->FirstChildElement("Name"); + tinyxml2::XMLNode* ShapeNode = KeyNode->FirstChildElement("Shape"); + tinyxml2::XMLNode* ValueNode = tile->FirstChildElement("Value"); + tinyxml2::XMLNode* FramesNode = ValueNode->FirstChildElement("Frames"); + tinyxml2::XMLNode* FrameNode = FramesNode->FirstChildElement("Frame"); + + tileRule.name = NameNode->FirstChild()->ToText()->Value(); + tileRule.hash = generateHashValue(tileRule.name.c_str(), tileRule.name.size()); + tileRule.shape = atoi(ShapeNode->FirstChild()->ToText()->Value()); + + while (FrameNode != NULL) { + if (FrameNode->FirstChild() != NULL) { + tileRule.frames.push_back(FrameNode->FirstChild()->ToText()->Value()); + } + FrameNode = FrameNode->NextSiblingElement("Frame"); + } +} + +void Units_LoadRuleXML(const char* path, UnitsXMLInfo_t& info) { + tinyxml2::XMLDocument doc; + doc.LoadFile(path); + + tinyxml2::XMLElement* root = doc.FirstChildElement(); + if (root == NULL) + return; + + tinyxml2::XMLNode* tilesetTypeClassNode = root->FirstChild(); + + tinyxml2::XMLNode* tilesParent = tilesetTypeClassNode->FirstChildElement("Tiles"); + tinyxml2::XMLNode* tile = tilesParent->FirstChildElement("Tile"); + while (tile != NULL) { + UnitsTileRule_t tileRule; + Units_ParseTile(tile, tileRule); + info.tiles.push_back(tileRule); + tile = tile->NextSiblingElement("Tile"); + } +} + +void Units_LoadRules(void) { + Units_LoadRuleXML("data/xml/tilesets/RA_UNITS.XML", unitsXmlRules); +} \ No newline at end of file diff --git a/code/REDALERT/WIN32LIB/DRAWBUFF.H b/code/REDALERT/WIN32LIB/DRAWBUFF.H index 0ae21ca..8f5ff9e 100644 --- a/code/REDALERT/WIN32LIB/DRAWBUFF.H +++ b/code/REDALERT/WIN32LIB/DRAWBUFF.H @@ -64,7 +64,7 @@ extern "C" { struct Image_t; Image_t* Load_Stamp(const char* name, const void* icondata); -void Get_Stamp_Size(const void* icondata, int &width, int &height); +void Get_Stamp_Size(const void* icondata, int *width, int *height); Image_t* Load_StampHD(int theater, const char* iconName, const void *icondata); extern GraphicViewPortClass *LogicPage; diff --git a/code/REDALERT/WINSTUB.CPP b/code/REDALERT/WINSTUB.CPP index a2f1d88..132ccbf 100644 --- a/code/REDALERT/WINSTUB.CPP +++ b/code/REDALERT/WINSTUB.CPP @@ -241,14 +241,17 @@ static bool Image_loadHDImage(Image_t *image, const char* name, int houseid, int else image->HouseImages[houseid].image[animid][frameId] = texture; image->namehash = hash; - image->renderwidth = image->width = Width; - image->renderheight = image->height = Height; + image->renderwidth[animid] = image->width = Width; + image->renderheight[animid] = image->height = Height; //image->buffer[houseid][animid] = new unsigned char[Width * Height * Bpp]; //memcpy(image->buffer[houseid][animid], Data, Width * Height * Bpp); if (!writeGenerated && Bpp == 4 && houseid >= 0) { char* generatedImageName = Image_GetGeneratedName(image, name, houseid, animid, frameId, hash); Image_WriteTGA(generatedImageName, Data, Width, Height, false); + + Console_Printf("Writing %s to cache %s\n", image->name, name); + Sleep(0); } ilDeleteImages(1, &ImageName); @@ -376,8 +379,8 @@ Image_t* Image_CreateImageFrom8Bit(const char* name, int Width, int Height, unsi image->HouseImages[0].image[0][0] = texture; image->numAnimFrames = -1; image->namehash = hash; - image->renderwidth = image->width = Width; - image->renderheight = image->height = Height; + image->renderwidth[0] = image->width = Width; + image->renderheight[0] = image->height = Height; loaded_images.push_back(image); delete buffer; return image; @@ -431,8 +434,8 @@ void Image_Add8BitImage(Image_t *image, int HouseId, int ShapeID, int Width, int image->HouseImages[HouseId].image[ShapeID][0] = texture; image->numAnimFrames = -1; - image->renderwidth = image->width = Width; - image->renderheight = image->height = Height; + image->renderwidth[ShapeID] = image->width = Width; + image->renderheight[ShapeID] = image->height = Height; delete buffer; } diff --git a/code/TIBERIANDAWN/UDATA.CPP b/code/TIBERIANDAWN/UDATA.CPP index 50f52db..80cffb5 100644 --- a/code/TIBERIANDAWN/UDATA.CPP +++ b/code/TIBERIANDAWN/UDATA.CPP @@ -1684,7 +1684,7 @@ void UnitTypeClass::One_Time(void) } #endif //PETROGLYPH_EXAMPLE_MOD - ((void const *&)uclass.ImageData) = ptr; + ((void const *&)uclass.ImageData) = ptr; if (ptr) { if (index == UNIT_MLRS || index == UNIT_MSAM) {