From 647519138b008977cfba12c4c846209b38c62400 Mon Sep 17 00:00:00 2001 From: Justin Marshall Date: Thu, 18 Jun 2020 16:45:01 -0700 Subject: [PATCH] Switched in game rendering to OpenGL. --- code/REDALERT/CELL.CPP | 17 +- code/REDALERT/CONQUER.CPP | 62 +++--- code/REDALERT/DISPLAY.H | 5 +- code/REDALERT/DLLInterface.cpp | 56 +++--- code/REDALERT/FUNCTION.H | 4 +- code/REDALERT/GSCREEN.CPP | 2 +- code/REDALERT/Image.h | 2 +- code/REDALERT/POWER.CPP | 7 +- code/REDALERT/STARTUP.CPP | 4 +- code/REDALERT/Shape.cpp | 224 +++++++++++----------- code/REDALERT/TILESET.CPP | 141 +++++++++----- code/REDALERT/VORTEX.CPP | 4 +- code/REDALERT/WIN32LIB/GBUFFER.H | 58 +++--- code/REDALERT/WINSTUB.CPP | 42 ++-- textures/{afv01.sno.png => afv01.tem.png} | Bin textures/afv02.tem.png | Bin 0 -> 18679 bytes textures/afv03.tem.png | Bin 0 -> 19767 bytes 17 files changed, 353 insertions(+), 275 deletions(-) rename textures/{afv01.sno.png => afv01.tem.png} (100%) create mode 100644 textures/afv02.tem.png create mode 100644 textures/afv03.tem.png diff --git a/code/REDALERT/CELL.CPP b/code/REDALERT/CELL.CPP index a8e0ed6..6d776c7 100644 --- a/code/REDALERT/CELL.CPP +++ b/code/REDALERT/CELL.CPP @@ -84,6 +84,11 @@ */ #include "SidebarGlyphx.h" +std::vector renderedFrameObjects; + +bool HasRenderedObject(const ObjectClass* technoClass) { + return std::find(renderedFrameObjects.begin(), renderedFrameObjects.end(), technoClass) != renderedFrameObjects.end(); +} /*********************************************************************************************** * CellClass::CellClass -- Constructor for cell objects. * @@ -993,8 +998,6 @@ bool CellClass::Get_Template_Info(char *template_name, int &icon, void *&image_d return false; } - - /*********************************************************************************************** * CellClass::Draw_It -- Draws the cell imagery at the location specified. * * * @@ -1088,7 +1091,7 @@ 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->Get_Image_Data(), icon, x, y, NULL, WINDOW_TACTICAL); + LogicPage->Draw_Stamp(ttype, icon, x, y, NULL, WINDOW_TACTICAL); if (remap) { LogicPage->Remap(x+Map.TacPixelX, y+Map.TacPixelY, ICON_PIXEL_W, ICON_PIXEL_H, remap); } @@ -1210,7 +1213,9 @@ 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; - LogicPage->Draw_Stamp(tptr->Get_Image_Data(), icon, x, y, NULL, WINDOW_TACTICAL); +// jmarshall - pass in raw tptr + LogicPage->Draw_Stamp(tptr, icon, x, y, NULL, WINDOW_TACTICAL); +// jmarshall end } break; @@ -1334,6 +1339,10 @@ void CellClass::Draw_It(int x, int y, bool objects) const */ for (int index = 0; index < count; index++) { object = optr[index]; + if (HasRenderedObject(object)) { + continue; + } + renderedFrameObjects.push_back(object); int xx,yy; if (object->IsToDisplay && (!object->Is_Techno() || ((TechnoClass *)object)->Visual_Character() == VISUAL_NORMAL) && Map.Coord_To_Pixel(object->Render_Coord(), xx, yy)) { if (_Calc_Partial_Window(x, y, xx, yy)) { diff --git a/code/REDALERT/CONQUER.CPP b/code/REDALERT/CONQUER.CPP index f8aaa77..b110b37 100644 --- a/code/REDALERT/CONQUER.CPP +++ b/code/REDALERT/CONQUER.CPP @@ -2121,8 +2121,8 @@ static void Sync_Delay(void) ** Delay until the frame timer expires. This forces the game loop to be regulated to a ** speed controlled by the game options slider. */ - while (FrameTimer) { - Color_Cycle(); + while (FrameTimer) { + Color_Cycle(); Call_Back(); if (SpecialDialog == SDLG_NONE) { @@ -2136,10 +2136,12 @@ static void Sync_Delay(void) Keyboard_Process(input); } Map.Render(); - } + } + } + if (!FrameTimer) { + Color_Cycle(); + Call_Back(); } - Color_Cycle(); - Call_Back(); } @@ -2321,8 +2323,7 @@ Mono_Set_Cursor(0,0); ** Keep track of elapsed time in the game. */ Score.ElapsedTime += TIMER_SECOND / TICKS_PER_SECOND; - - Call_Back(); + //Call_Back(); /* ** Check for player wins or loses according to global event flag. @@ -3580,24 +3581,21 @@ void CC_Draw_Shape(Image_t* image, int shapenum, int x, int y, WindowNumberType // predoffset = -predoffset; //} - x = x + WindowList[window][WINDOWX] + LogicPage->Get_XPos(); - y = y + WindowList[window][WINDOWY] + LogicPage->Get_YPos(); - Buffer_Enable_HD_Texture(true); //if (draw_window.Lock()) { if ((flags & (SHAPE_GHOST | SHAPE_FADING)) == (SHAPE_GHOST | SHAPE_FADING)) { - Buffer_Frame_To_Page(x, y, width, height, image, HiddenPage, flags | SHAPE_TRANS, ghostdata, fadingdata, 1, predoffset); + Buffer_Frame_To_Page(x, y, width, height, image, window, flags | SHAPE_TRANS, ghostdata, fadingdata, 1, predoffset); } else { if (flags & SHAPE_FADING) { - Buffer_Frame_To_Page(x, y, width, height, image, HiddenPage, flags | SHAPE_TRANS, fadingdata, 1, predoffset); + Buffer_Frame_To_Page(x, y, width, height, image, window, flags | SHAPE_TRANS, fadingdata, 1, predoffset); } else { if (flags & SHAPE_PREDATOR) { - Buffer_Frame_To_Page(x, y, width, height, image, HiddenPage, flags | SHAPE_TRANS, predoffset); + Buffer_Frame_To_Page(x, y, width, height, image, window, flags | SHAPE_TRANS, predoffset); } else { - Buffer_Frame_To_Page(x, y, width, height, image, HiddenPage, flags | SHAPE_TRANS, ghostdata, predoffset); + Buffer_Frame_To_Page(x, y, width, height, image, window, flags | SHAPE_TRANS, ghostdata, predoffset); } } } @@ -3698,13 +3696,16 @@ void CC_Draw_Shape(void const * shapefile, int shapenum, int x, int y, WindowNum /* ** In WIn95, build shape returns a pointer to the shape not its size */ + + Image_t* shape_image = NULL; shape_pointer = Build_Frame(shapefile, shapenum, _ShapeBuffer); + if (shape_pointer) { - GraphicViewPortClass draw_window(LogicPage->Get_Graphic_Buffer(), - WindowList[window][WINDOWX] + LogicPage->Get_XPos(), - WindowList[window][WINDOWY] + LogicPage->Get_YPos(), - WindowList[window][WINDOWWIDTH], - WindowList[window][WINDOWHEIGHT]); + //GraphicViewPortClass draw_window(LogicPage->Get_Graphic_Buffer(), + // WindowList[window][WINDOWX] + LogicPage->Get_XPos(), + // WindowList[window][WINDOWY] + LogicPage->Get_YPos(), + // WindowList[window][WINDOWWIDTH], + // WindowList[window][WINDOWHEIGHT]); unsigned char * buffer = (unsigned char *) shape_pointer; //Get_Shape_Header_Data((void*)shape_pointer); #else //WIN32 @@ -3755,6 +3756,18 @@ void CC_Draw_Shape(void const * shapefile, int shapenum, int x, int y, WindowNum } } + { + char tmp[512]; + sprintf(tmp, "s%d%d%d%d%d", shapefile, shapenum, rotation, fadingdata, flags); + + if (flags & SHAPE_FADING) { + shape_image = Image_CreateImageFrom8Bit(tmp, width, height, (unsigned char*)shape_pointer, (unsigned char*)fadingdata); + } + else { + shape_image = Image_CreateImageFrom8Bit(tmp, width, height, (unsigned char*)shape_pointer, NULL); + } + } + /* ** Special shadow drawing code (used for aircraft and bullets). */ @@ -3770,21 +3783,20 @@ void CC_Draw_Shape(void const * shapefile, int shapenum, int x, int y, WindowNum // predoffset = -predoffset; //} - if (draw_window.Lock()) { + { if ((flags & (SHAPE_GHOST|SHAPE_FADING)) == (SHAPE_GHOST|SHAPE_FADING)) { - Buffer_Frame_To_Page(x, y, width, height, buffer, draw_window, flags | SHAPE_TRANS, ghostdata, fadingdata, 1, predoffset); + Buffer_Frame_To_Page(x, y, width, height, shape_image, window, flags | SHAPE_TRANS, ghostdata, fadingdata, 1, predoffset); } else { if (flags & SHAPE_FADING) { - Buffer_Frame_To_Page(x, y, width, height, buffer, draw_window, flags | SHAPE_TRANS, fadingdata, 1, predoffset); + Buffer_Frame_To_Page(x, y, width, height, shape_image, window, flags | SHAPE_TRANS, fadingdata, 1, predoffset); } else { if (flags & SHAPE_PREDATOR) { - Buffer_Frame_To_Page(x, y, width, height, buffer, draw_window, flags | SHAPE_TRANS, predoffset); + Buffer_Frame_To_Page(x, y, width, height, shape_image, window, flags | SHAPE_TRANS, predoffset); } else { - Buffer_Frame_To_Page(x, y, width, height, buffer, draw_window, flags | SHAPE_TRANS, ghostdata, predoffset); + Buffer_Frame_To_Page(x, y, width, height, shape_image, window, flags | SHAPE_TRANS, ghostdata, predoffset); } } } - draw_window.Unlock(); } } } diff --git a/code/REDALERT/DISPLAY.H b/code/REDALERT/DISPLAY.H index e2fae5b..73c37b0 100644 --- a/code/REDALERT/DISPLAY.H +++ b/code/REDALERT/DISPLAY.H @@ -189,8 +189,9 @@ class DisplayClass: public MapClass void Repair_Mode_Control(int control); virtual void Flag_Cell(CELL cell); - bool Is_Cell_Flagged(CELL cell) const {return CellRedraw.Is_True(cell);}; - +// jmarshall + bool Is_Cell_Flagged(CELL cell) const { return true; } +// jmarshall end /* ** Computes starting position based on player's units' Coords. */ diff --git a/code/REDALERT/DLLInterface.cpp b/code/REDALERT/DLLInterface.cpp index 1d71c02..48daa36 100644 --- a/code/REDALERT/DLLInterface.cpp +++ b/code/REDALERT/DLLInterface.cpp @@ -1474,33 +1474,35 @@ bool Debug_Write_Shape(const char *file_name, void const * shapefile, int shapen /* ** Build frame returns a pointer now instead of the shapes length */ - char *shape_pointer = (char*) Build_Frame(shapefile , shapenum , _ShapeBuffer); - if (shape_pointer == NULL) { - return false;; - } - if (Get_Last_Frame_Length() > _ShapeBufferSize) { - return false;; - } - - int width = Get_Build_Frame_Width(shapefile); - int height = Get_Build_Frame_Height(shapefile); - - GraphicBufferClass temp_gbuffer(width, height); - GraphicViewPortClass temp_viewport(&temp_gbuffer, 0, 0, width, height); - - WindowList[WINDOW_CUSTOM][WINDOWX] = 0; - WindowList[WINDOW_CUSTOM][WINDOWY] = 0; - WindowList[WINDOW_CUSTOM][WINDOWWIDTH] = width; - WindowList[WINDOW_CUSTOM][WINDOWHEIGHT] = height; - - static const char _shape_trans = 0x40; - - if (flags == 0) { - Buffer_Frame_To_Page(0, 0, width, height, shape_pointer, temp_viewport, SHAPE_NORMAL|SHAPE_WIN_REL|_shape_trans); //, ghostdata, predoffset); - } else { - Buffer_Frame_To_Page(0, 0, width, height, shape_pointer, temp_viewport, flags, ghostdata); - } - Write_PCX_File((char*)file_name, temp_viewport, (unsigned char*)GamePalette.Get_Data()); +// jmarshall - do we need this? + //char *shape_pointer = (char*) Build_Frame(shapefile , shapenum , _ShapeBuffer); + //if (shape_pointer == NULL) { + // return false;; + //} + //if (Get_Last_Frame_Length() > _ShapeBufferSize) { + // return false;; + //} + // + //int width = Get_Build_Frame_Width(shapefile); + //int height = Get_Build_Frame_Height(shapefile); + // + //GraphicBufferClass temp_gbuffer(width, height); + //GraphicViewPortClass temp_viewport(&temp_gbuffer, 0, 0, width, height); + // + //WindowList[WINDOW_CUSTOM][WINDOWX] = 0; + //WindowList[WINDOW_CUSTOM][WINDOWY] = 0; + //WindowList[WINDOW_CUSTOM][WINDOWWIDTH] = width; + //WindowList[WINDOW_CUSTOM][WINDOWHEIGHT] = height; + // + //static const char _shape_trans = 0x40; + // + //if (flags == 0) { + // Buffer_Frame_To_Page(0, 0, width, height, shape_pointer, temp_viewport, SHAPE_NORMAL|SHAPE_WIN_REL|_shape_trans); //, ghostdata, predoffset); + //} else { + // Buffer_Frame_To_Page(0, 0, width, height, shape_pointer, temp_viewport, flags, ghostdata); + //} + //Write_PCX_File((char*)file_name, temp_viewport, (unsigned char*)GamePalette.Get_Data()); +// jmarshall end return true; } diff --git a/code/REDALERT/FUNCTION.H b/code/REDALERT/FUNCTION.H index 90fe9ba..6c4decc 100644 --- a/code/REDALERT/FUNCTION.H +++ b/code/REDALERT/FUNCTION.H @@ -710,9 +710,7 @@ void Buffer_Enable_HD_Texture(bool hdTextureEnabled); /* ** KEYFBUFF.ASM */ -extern "C" { - long __cdecl Buffer_Frame_To_Page(int x, int y, int w, int h, void *Buffer, GraphicViewPortClass &view, int flags, ...); -} +long __cdecl Buffer_Frame_To_Page(int x, int y, int w, int h, Image_t* image, unsigned int Window, int flags, ...); /* ** KEYFRAME.CPP diff --git a/code/REDALERT/GSCREEN.CPP b/code/REDALERT/GSCREEN.CPP index 4ddf2a1..e315b54 100644 --- a/code/REDALERT/GSCREEN.CPP +++ b/code/REDALERT/GSCREEN.CPP @@ -397,7 +397,7 @@ void GScreenClass::Render(void) //if (Buttons && Buttons->Is_List_To_Redraw()) { // IsToRedraw = true; //} - + IsToRedraw = true; if (IsToUpdate || IsToRedraw) { BStart(BENCH_GSCREEN_RENDER); diff --git a/code/REDALERT/Image.h b/code/REDALERT/Image.h index 57b88bf..8ca0c14 100644 --- a/code/REDALERT/Image.h +++ b/code/REDALERT/Image.h @@ -24,4 +24,4 @@ __forceinline Image_t::~Image_t() { } Image_t* Image_LoadImage(const char* name); -Image_t* Image_CreateImageFrom8Bit(const char* name, int Width, int Height, char* data); \ No newline at end of file +Image_t* Image_CreateImageFrom8Bit(const char* name, int Width, int Height, unsigned char* data, unsigned char *remap = NULL); \ No newline at end of file diff --git a/code/REDALERT/POWER.CPP b/code/REDALERT/POWER.CPP index 5e1fc0d..1f55d49 100644 --- a/code/REDALERT/POWER.CPP +++ b/code/REDALERT/POWER.CPP @@ -166,6 +166,10 @@ void PowerClass::Draw_It(bool complete) 0, -1, 0, 1, 0, -1, -2, -1, 0, 1, 2, 1 ,0 }; +// jmarshall - render the world before the power bar. + RadarClass::Draw_It(complete); +// jmarshall end + { BStart(BENCH_POWER); @@ -244,8 +248,7 @@ void PowerClass::Draw_It(bool complete) LogicPage->Unlock(); } BEnd(BENCH_POWER); - } - RadarClass::Draw_It(complete); + } } diff --git a/code/REDALERT/STARTUP.CPP b/code/REDALERT/STARTUP.CPP index 8e6c472..f5febf1 100644 --- a/code/REDALERT/STARTUP.CPP +++ b/code/REDALERT/STARTUP.CPP @@ -924,8 +924,8 @@ void Read_Setup_Options( RawFileClass *config_file ) VideoBackBufferAllowed = ini.Get_Bool("Options", "VideoBackBuffer", true); AllowHardwareBlitFills = ini.Get_Bool("Options", "HardwareFills", true); - ScreenWidth = 1024; - ScreenHeight = 768; + ScreenWidth = 1280; + ScreenHeight = 720; /* ** See if an alternative socket number has been specified diff --git a/code/REDALERT/Shape.cpp b/code/REDALERT/Shape.cpp index 0cfd6c2..9c2480e 100644 --- a/code/REDALERT/Shape.cpp +++ b/code/REDALERT/Shape.cpp @@ -28,6 +28,14 @@ * A full copy of the GNU General Public License can be found in * LICENSE */ +/* +============================ + +This file has been heavily modified by IceColdDuke(Justin Marshall) to render with OpenGL. + +============================ +*/ + #include "FUNCTION.H" #include #include @@ -1388,7 +1396,7 @@ static void Single_Line_Flagger( } } -long Buffer_Frame_To_Page(int x, int y, int width, int height, void* shape, GraphicViewPortClass& viewport, int flags, ...) +long Buffer_Frame_To_Page(int x, int y, int width, int height, struct Image_t * shape_image, unsigned int Window, int flags, ...) { BOOL use_old_drawer = false; int fade_count = 0; @@ -1397,30 +1405,10 @@ long Buffer_Frame_To_Page(int x, int y, int width, int height, void* shape, Grap uint8_t* ghost_table = nullptr; uint8_t* ghost_lookup = nullptr; - if (!shape) { + if (!shape_image) { return 0; } - uint8_t* frame_data = static_cast(shape); - - if (!renderHDTexture) - { - if (UseOldShapeDraw) { - use_old_drawer = true; - } - else if (UseBigShapeBuffer) { - draw_header = static_cast(shape); - uint8_t* shape_buff = reinterpret_cast(BigShapeBufferStart); - - if (draw_header->m_IsTheaterShape) { - shape_buff = reinterpret_cast(TheaterShapeBufferStart); - } - - frame_data = shape_buff + draw_header->m_FrameOffset; - use_old_drawer = false; - } - } - va_list ap; va_start(ap, flags); @@ -1447,12 +1435,6 @@ long Buffer_Frame_To_Page(int x, int y, int width, int height, void* shape, Grap use_old_drawer = true; } - if (!renderHDTexture) { - if (use_old_drawer != true && (draw_header->m_DrawFlags == 0xFFFFFFFF || draw_header->m_DrawFlags != (flags & 0x1340))) { - Single_Line_Flagger(width, height, frame_data, draw_header, flags, ghost_table, ghost_lookup); - } - } - // Sets for BF_Fading functions if (flags & SHAPE_FADING) { fade_table = va_arg(ap, uint8_t*); @@ -1474,18 +1456,18 @@ long Buffer_Frame_To_Page(int x, int y, int width, int height, void* shape, Grap } // Sets for BF_Predator functions - if (flags & SHAPE_PREDATOR) { - int current_frame = va_arg(ap, uint32_t); - blit_style |= 8; - - g_PredFrame = ((unsigned)current_frame) % 8; - g_PartialCount = 0; - g_PartialPred = 256; - - // Calculates the end of the visible display buffer, hopefully prevent crashes from predator effect. - // Unused by default in RA, but would be nice on the phase tank in Aftermath. - g_PredatorLimit = (uint8_t*)(viewport.Get_Offset()) + viewport.Get_Full_Pitch() * viewport.Get_Height(); - } + //if (flags & SHAPE_PREDATOR) { + // int current_frame = va_arg(ap, uint32_t); + // blit_style |= 8; + // + // g_PredFrame = ((unsigned)current_frame) % 8; + // g_PartialCount = 0; + // g_PartialPred = 256; + // + // // Calculates the end of the visible display buffer, hopefully prevent crashes from predator effect. + // // Unused by default in RA, but would be nice on the phase tank in Aftermath. + // g_PredatorLimit = (uint8_t*)(viewport.Get_Offset()) + viewport.Get_Full_Pitch() * viewport.Get_Height(); + //} if (flags & SHAPE_PARTIAL) { g_PartialPred = va_arg(ap, int) & 0xFF; @@ -1500,97 +1482,105 @@ long Buffer_Frame_To_Page(int x, int y, int width, int height, void* shape, Grap int ms_img_offset = 0; // If we aren't drawing within the viewport, return. - if (xstart >= viewport.Get_Width() || ystart >= viewport.Get_Height() || xend <= 0 || yend <= 0) { - return 0; - } + //if (xstart >= viewport.Get_Width() || ystart >= viewport.Get_Height() || xend <= 0 || yend <= 0) { + // return 0; + //} // Do any needed clipping. - if (xstart < 0) { - ms_img_offset = -xstart; - xstart = 0; - use_old_drawer = true; - } + //if (xstart < 0) { + // ms_img_offset = -xstart; + // xstart = 0; + // use_old_drawer = true; + //} + // + //if (ystart < 0) { + // //frame_data += width * (-ystart); + // ystart = 0; + // use_old_drawer = true; + //} - if (ystart < 0) { - frame_data += width * (-ystart); - ystart = 0; - use_old_drawer = true; - } + if (xstart + width < 0 || ystart + height < 0) + return 0; - if (xend >= viewport.Get_Width() - 1) { - xend = viewport.Get_Width() - 1; - use_old_drawer = true; - } - - if (yend >= viewport.Get_Height() - 1) { - yend = viewport.Get_Height() - 1; - use_old_drawer = true; - } + // if (xend >= viewport.Get_Width() - 1) { + // xend = viewport.Get_Width() - 1; + // use_old_drawer = true; + // } + // + // if (yend >= viewport.Get_Height() - 1) { + // yend = viewport.Get_Height() - 1; + // use_old_drawer = true; + // } int blit_width = xend - xstart + 1; int blit_height = yend - ystart + 1; - int pitch = viewport.Get_Full_Pitch(); - uint8_t* dst = (ystart * pitch * 4) + (xstart * 4) + (uint8_t*)(viewport.Get_Offset()); - uint8_t* src = frame_data + ms_img_offset; - if (renderHDTexture) { - Image_t* image = (Image_t*)shape; - src = image->buffer + (ms_img_offset * 4); - } + //int pitch = viewport.Get_Full_Pitch(); + //uint8_t* dst = (ystart * pitch * 4) + (xstart * 4) + (uint8_t*)(viewport.Get_Offset()); + //uint8_t* src = frame_data + ms_img_offset; + //if (renderHDTexture) { + // Image_t* image = (Image_t*)shape; + // src = image->buffer + (ms_img_offset * 4); + //} - int dst_pitch = pitch - blit_width; - int src_pitch = width - blit_width; + //int dst_pitch = pitch - blit_width; + //int src_pitch = width - blit_width; // Use "new" line drawing routines that appear to have been added during the windows port. - if (use_old_drawer != true && !renderHDTexture) { - // DEBUG_SAY("Drawing with Single_Line draw functions\n"); - - // Here we can use the individual line drawing routines - // Means we can skip drawing some lines all together or avoid using - // more expensive routines on some lines. - uint8_t* line_flags = reinterpret_cast(draw_header + 1); - - for (int i = 0; i < blit_height; ++i) { - NewShapeJumpTable[line_flags[i] & 0x1F](blit_width, dst, src, ghost_lookup, ghost_table, fade_table, fade_count); - src += width; - dst += pitch * 4; - } - - return 0; - } + //if (use_old_drawer != true && !renderHDTexture) { + // // DEBUG_SAY("Drawing with Single_Line draw functions\n"); + // + // // Here we can use the individual line drawing routines + // // Means we can skip drawing some lines all together or avoid using + // // more expensive routines on some lines. + // uint8_t* line_flags = reinterpret_cast(draw_header + 1); + // + // for (int i = 0; i < blit_height; ++i) { + // NewShapeJumpTable[line_flags[i] & 0x1F](blit_width, dst, src, ghost_lookup, ghost_table, fade_table, fade_count); + // src += width; + // dst += pitch * 4; + // } + // + // return 0; + //} + xstart = xstart + WindowList[Window][WINDOWX];// + LogicPage->Get_XPos(); + ystart = ystart + WindowList[Window][WINDOWY];// + LogicPage->Get_YPos(); + //GL_SetClipRect(WindowList[Window][WINDOWX], WindowList[Window][WINDOWY], WindowList[Window][WINDOWWIDTH], WindowList[Window][WINDOWWIDTH]); + GL_RenderImage(shape_image, xstart, ystart, width, height); + // Here we just use the function that will blit the entire frame // using the appropriate effects. - if (blit_height > 0 && blit_width > 0) { - // DEBUG_SAY("Drawing with BF draw functions\n"); - if (!renderHDTexture) - { - OldShapeJumpTable[blit_style & 0xF](blit_width, blit_height, dst, src, dst_pitch, src_pitch, ghost_lookup, ghost_table, fade_table, fade_count); - } - else - { - int src_index = 0; - for (int f = 0; f < height; f++) - { - for (int i = width; i > 0; --i) { - //if (src_index >= ((f + 1) * blit_height * 4)) - // break; - - if (src[src_index + 3] > 0) { - dst[0] = ChannelBlend_Alpha(src[(src_index) + 0], dst[0], src[(src_index) + 3]); - dst[1] = ChannelBlend_Alpha(src[(src_index) + 1], dst[1], src[(src_index) + 3]); - dst[2] = ChannelBlend_Alpha(src[(src_index) + 2], dst[2], src[(src_index) + 3]); - dst[3] = 255; - } - src_index += 4; - dst += 4; - } - - src_index += src_pitch * 4; - dst += dst_pitch * 4; - } - } - } + //if (blit_height > 0 && blit_width > 0) { + // // DEBUG_SAY("Drawing with BF draw functions\n"); + // if (!renderHDTexture) + // { + // OldShapeJumpTable[blit_style & 0xF](blit_width, blit_height, dst, src, dst_pitch, src_pitch, ghost_lookup, ghost_table, fade_table, fade_count); + // } + // else + // { + // int src_index = 0; + // for (int f = 0; f < height; f++) + // { + // for (int i = width; i > 0; --i) { + // //if (src_index >= ((f + 1) * blit_height * 4)) + // // break; + // + // if (src[src_index + 3] > 0) { + // dst[0] = ChannelBlend_Alpha(src[(src_index) + 0], dst[0], src[(src_index) + 3]); + // dst[1] = ChannelBlend_Alpha(src[(src_index) + 1], dst[1], src[(src_index) + 3]); + // dst[2] = ChannelBlend_Alpha(src[(src_index) + 2], dst[2], src[(src_index) + 3]); + // dst[3] = 255; + // } + // src_index += 4; + // dst += 4; + // } + // + // src_index += src_pitch * 4; + // dst += dst_pitch * 4; + // } + // } + //} return 0; } diff --git a/code/REDALERT/TILESET.CPP b/code/REDALERT/TILESET.CPP index 1b34281..95f639e 100644 --- a/code/REDALERT/TILESET.CPP +++ b/code/REDALERT/TILESET.CPP @@ -13,8 +13,17 @@ * A full copy of the GNU General Public License can be found in * LICENSE */ + /* + ============================ + + This file has been heavily modified by IceColdDuke(Justin Marshall) to render with OpenGL. + + ============================ + */ + #include "FUNCTION.H" #include "gbuffer.h" +#include "Image.h" #include using std::memcpy; @@ -23,6 +32,8 @@ 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. */ @@ -93,6 +104,7 @@ 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); @@ -181,8 +193,17 @@ void __cdecl Buffer_Draw_Stamp2(GraphicViewPortClass& viewport, IconControlType* } } -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) +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; } @@ -192,7 +213,7 @@ void __cdecl Buffer_Draw_Stamp_Clip2(GraphicViewPortClass& viewport, IconControl } int icon_index = MapPtr != nullptr ? MapPtr[icon] : icon; - + if (icon_index < IconCount) { int blit_height = IconHeight; int blit_width = IconWidth; @@ -202,83 +223,103 @@ void __cdecl Buffer_Draw_Stamp_Clip2(GraphicViewPortClass& viewport, IconControl 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; 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 * 4) + (ystart * 4) * 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[0] = backbuffer_data_raw[(cur_byte * 3) + 0]; + // dst[1] = backbuffer_data_raw[(cur_byte * 3) + 1]; + // dst[2] = backbuffer_data_raw[(cur_byte * 3) + 2]; + // dst[3] = 255; + // } + // + // dst += 4; + // } + // dst += dst_pitch * 4; + // } + // + //} + //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[0] = backbuffer_data_raw[(cur_byte * 3) + 0]; + // dst[1] = backbuffer_data_raw[(cur_byte * 3) + 1]; + // dst[2] = backbuffer_data_raw[(cur_byte * 3) + 2]; + // dst[3] = 255; + // } + // + // dst += 4; + // } + // src += src_pitch; + // dst += dst_pitch * 4; + // } + // + //} + //else { + { + //for (int i = 0; i < blit_height; ++i) { + // FastScanlinePaletteBlit(dst, src, blit_width); + // dst += full_pitch * 4; + // src += IconWidth; + //} - 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[0] = backbuffer_data_raw[(cur_byte * 3) + 0]; - dst[1] = backbuffer_data_raw[(cur_byte * 3) + 1]; - dst[2] = backbuffer_data_raw[(cur_byte * 3) + 2]; - dst[3] = 255; - } - - dst += 4; - } - dst += dst_pitch * 4; - } - - } - 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[0] = backbuffer_data_raw[(cur_byte * 3) + 0]; - dst[1] = backbuffer_data_raw[(cur_byte * 3) + 1]; - dst[2] = backbuffer_data_raw[(cur_byte * 3) + 2]; - dst[3] = 255; - } - - dst += 4; - } - src += src_pitch; - dst += dst_pitch * 4; - } - - } - else { - for (int i = 0; i < blit_height; ++i) { - FastScanlinePaletteBlit(dst, src, blit_width); - dst += full_pitch * 4; - src += IconWidth; - } + GL_SetClipRect(xstart, ystart, blit_width, blit_height); + GL_RenderImage(tileset_icon_cache[icon_index], xstart, ystart, blit_width, blit_height); + GL_ResetClipRect(); } } } } 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); + if (icondata == NULL) + return; + + Buffer_Draw_Stamp_Clip2(*((GraphicViewPortClass*)this_object), 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) { diff --git a/code/REDALERT/VORTEX.CPP b/code/REDALERT/VORTEX.CPP index bdf455a..da3dbe9 100644 --- a/code/REDALERT/VORTEX.CPP +++ b/code/REDALERT/VORTEX.CPP @@ -935,7 +935,9 @@ void ChronalVortexClass::Render (void) ** Draw the template */ if (ttype->Get_Image_Data()) { - RenderBuffer->Draw_Stamp(ttype->Get_Image_Data(), icon, x*CELL_PIXEL_W, y*CELL_PIXEL_H, NULL, WINDOW_MAIN); +// jmarshall - send down the raw ttype + RenderBuffer->Draw_Stamp(ttype, icon, x*CELL_PIXEL_W, y*CELL_PIXEL_H, NULL, WINDOW_MAIN); +// jmarshall end } /* diff --git a/code/REDALERT/WIN32LIB/GBUFFER.H b/code/REDALERT/WIN32LIB/GBUFFER.H index 3bdf860..ec7fb5d 100644 --- a/code/REDALERT/WIN32LIB/GBUFFER.H +++ b/code/REDALERT/WIN32LIB/GBUFFER.H @@ -1122,28 +1122,28 @@ inline void GraphicViewPortClass::Draw_Stamp(void const * icondata, int icon, in int cache_index=-1; int drewit = 0; - if (IconCacheAllowed){ - if (IsDirectDraw){ - if (!remap){ - cache_index = Is_Icon_Cached(icondata,icon); - } - - if (cache_index != -1){ - if (CachedIcons[cache_index].Get_Is_Cached() ){ - CachedIcons[cache_index].Draw_It (GraphicBuff->Get_DD_Surface() , x_pixel, y_pixel, - WindowList[clip_window][WINDOWX] + XPos, - WindowList[clip_window][WINDOWY] +YPos, - WindowList[clip_window][WINDOWWIDTH], - WindowList[clip_window][WINDOWHEIGHT]); - CachedIconsDrawn++; - drewit = 1; - } - } - } - } + //if (IconCacheAllowed){ + // if (IsDirectDraw){ + // if (!remap){ + // cache_index = Is_Icon_Cached(icondata,icon); + // } + // + // if (cache_index != -1){ + // if (CachedIcons[cache_index].Get_Is_Cached() ){ + // CachedIcons[cache_index].Draw_It (GraphicBuff->Get_DD_Surface() , x_pixel, y_pixel, + // WindowList[clip_window][WINDOWX] + XPos, + // WindowList[clip_window][WINDOWY] +YPos, + // WindowList[clip_window][WINDOWWIDTH], + // WindowList[clip_window][WINDOWHEIGHT]); + // CachedIconsDrawn++; + // drewit = 1; + // } + // } + // } + //} - if (drewit == 0) { + { if (Lock()){ UnCachedIconsDrawn++; extern int ScreenHeight, ScreenWidth; @@ -1173,7 +1173,10 @@ inline VOID GraphicViewPortClass::Draw_Line(int sx, int sy, int dx, int dy, unsi // Buffer_Draw_Line(this, sx, sy, dx, dy, color); //} //Unlock(); - + sx += XPos; + sy += YPos; + dx += XPos; + dy += YPos; GL_DrawLine(color, sx, sy, dx, dy); } @@ -1191,14 +1194,11 @@ inline VOID GraphicViewPortClass::Draw_Line(int sx, int sy, int dx, int dy, unsi *=========================================================================*/ inline VOID GraphicViewPortClass::Fill_Rect(int sx, int sy, int dx, int dy, unsigned char color) { -// jmarshall - // Still needed for gameplay. - if (Lock()) { - Buffer_Fill_Rect(this, sx, sy, dx, dy, color); - Unlock(); - } - //GL_FillRect(color, sx, sy, dx - sx, dy - sy); -// jmarshall end + sx += XPos; + sy += YPos; + dx += XPos; + dy += YPos; + GL_FillRect(color, sx - 1, sy - 1, (dx - sx) + 1, ((dy - sy) + 1)); } diff --git a/code/REDALERT/WINSTUB.CPP b/code/REDALERT/WINSTUB.CPP index e9dbb29..52c105d 100644 --- a/code/REDALERT/WINSTUB.CPP +++ b/code/REDALERT/WINSTUB.CPP @@ -73,6 +73,8 @@ SDL_Window* game_window; SDL_GLContext game_context; int OverlappedVideoBlits = 0; +extern std::vector renderedFrameObjects; + bool renderConsole = false; void (*Misc_Focus_Loss_Function)(void) = nullptr; @@ -127,8 +129,8 @@ Image_t* Image_LoadImage(const char* name) { assert(!"Unknown BPP in image!"); } - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); Image_t* image = new Image_t(); strcpy(image->name, name); @@ -144,7 +146,7 @@ Image_t* Image_LoadImage(const char* name) { return image; } -Image_t* Image_CreateImageFrom8Bit(const char* name, int Width, int Height, char *data) { +Image_t* Image_CreateImageFrom8Bit(const char* name, int Width, int Height, unsigned char *data, unsigned char* remap) { // Check to see if the image is already loaded. for (int i = 0; i < loaded_images.size(); i++) { if (!strcmp(loaded_images[i]->name, name)) { @@ -152,21 +154,37 @@ Image_t* Image_CreateImageFrom8Bit(const char* name, int Width, int Height, char } } + unsigned char* ccpalete = (unsigned char*)CCPalette.Get_Data(); + Image_t* image = new Image_t(); image->buffer = new unsigned char[Width * Height * 4]; for (int i = 0; i < Width * Height; i++) { - char c = data[i]; + unsigned char c = data[i]; + if (remap) { + c = remap[c]; + } - image->buffer[(i * 4) + 0] = backbuffer_palette[(c * 3) + 0]; - image->buffer[(i * 4) + 1] = backbuffer_palette[(c * 3) + 1]; - image->buffer[(i * 4) + 2] = backbuffer_palette[(c * 3) + 2]; - if (c == 0) { - image->buffer[(i * 4) + 3] = 0; + 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 { - image->buffer[(i * 4) + 3] = 255; + else if (c != 0) { + a = 255; } + + + image->buffer[(i * 4) + 0] = r; + image->buffer[(i * 4) + 1] = g; + image->buffer[(i * 4) + 2] = b; + image->buffer[(i * 4) + 3] = a; } @@ -228,6 +246,8 @@ void ImGui_NewFrame(void) { ImGui::NewFrame(show_oldframebuffer); ImGui_ImplSDL2_NewFrame(game_window); + + renderedFrameObjects.clear(); } void Device_Present(void) { diff --git a/textures/afv01.sno.png b/textures/afv01.tem.png similarity index 100% rename from textures/afv01.sno.png rename to textures/afv01.tem.png diff --git a/textures/afv02.tem.png b/textures/afv02.tem.png new file mode 100644 index 0000000000000000000000000000000000000000..5c9433cd88269d7254556f547d562bc9d995001d GIT binary patch literal 18679 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 literal 0 HcmV?d00001 diff --git a/textures/afv03.tem.png b/textures/afv03.tem.png new file mode 100644 index 0000000000000000000000000000000000000000..2019cb7f71c7bbed366e7a7b5473ef5ad0851c52 GIT binary patch literal 19767 zcmbTd1ymf*)-MVK86>#t;OlC`7j;#+_b9|DFfcIh738Hg->x=qrw#z|?YE8dtHs*| z*;U@a0|o{a=bsZ6COv}?1_lA&UR&Q&UqxBS%EgJz!rH|W#OCYd`i6#q5f<}xwXkvk zc>*m#w)V~!yhW#{SX zD#Xt2=LAF|FK|2ET`!PtE*T-iCssFdgK(04UfDC%} z&ekqI9*qA(1CX?ZCrE_qpI&3-;A7?F*XHCE;t>?$jJpU8)ZOB+#cv}2#!PZtnHZJZ?7HP z|IhYn?)GmkXyN#OOy?iR{AcV4$=iFp^{U^$T}KP#_V1FTJ@8+{MaaVHA2$%8vihh0 zLDp3Ner*4LY=QqG>thFcBl`a_F8&MV;bPj+4rF))EX zf5CD4Yb`A+3)1oS_R?AKoK&7f>l+`IX|HD5{tJu-#0afg_nYAFBFN%T&&h%GR&{*5 z-VR($2@N(X0*Qf@qq3tokc7B7q4}q*@25XcEB}<2k4MLj4=2%Y_dgDO881yI@?Pj# zhx+aK{rTB0J-GKYadz_@7)&qRIer644OGJ$rt2&rJUy{c>>1Je0iSG_ YZOFVgt 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 nrQjgVm}rfpK