From 3c67c936c5609845c2b313e2e009daa8cc9fe795 Mon Sep 17 00:00:00 2001 From: githubawn <115191165+githubawn@users.noreply.github.com> Date: Mon, 30 Mar 2026 22:55:40 +0200 Subject: [PATCH 01/20] perf(gui): Implement batched GUI rendering for improved performance --- .../GameEngine/Include/GameClient/Display.h | 5 + .../GameClient/GUI/GameWindowManager.cpp | 4 + .../Include/W3DDevice/GameClient/W3DDisplay.h | 9 + .../W3DDevice/GameClient/W3DDisplay.cpp | 290 +++++++++++++++--- .../W3DDevice/GameClient/W3DDisplayString.cpp | 6 + 5 files changed, 264 insertions(+), 50 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/Display.h b/GeneralsMD/Code/GameEngine/Include/GameClient/Display.h index 319b15dc651..0803cc8b8fa 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/Display.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/Display.h @@ -113,6 +113,10 @@ class Display : public SubsystemInterface virtual Bool isClippingEnabled() = 0; virtual void enableClipping( Bool onoff ) = 0; + virtual void beginBatch() { } + virtual void endBatch() { } + virtual Bool isBatching() { return m_isBatching; } + virtual void step() {}; ///< Do one fixed time step virtual void draw() override; ///< Redraw the entire display virtual void setTimeOfDay( TimeOfDay tod ) = 0; ///< Set the time of day for this display @@ -187,6 +191,7 @@ class Display : public SubsystemInterface UnsignedInt m_width, m_height; ///< Dimensions of the display UnsignedInt m_bitDepth; ///< bit depth of the display Bool m_windowed; ///< TRUE when windowed, FALSE when fullscreen + Bool m_isBatching; View *m_viewList; ///< All of the views into the world // Cinematic text data diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GameWindowManager.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GameWindowManager.cpp index 773c22dd94e..b2da74cbbef 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GameWindowManager.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GameWindowManager.cpp @@ -1269,6 +1269,8 @@ void GameWindowManager::winRepaint() { GameWindow *window, *next; + TheDisplay->beginBatch(); + // draw below windows for( window = m_windowTail; window; window = next ) { @@ -1299,6 +1301,8 @@ void GameWindowManager::winRepaint() if(TheTransitionHandler) TheTransitionHandler->draw(); + + TheDisplay->endBatch(); } //------------------------------------------------------------------------------------------------- diff --git a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DDisplay.h b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DDisplay.h index 9372d69136f..09c77f98f07 100644 --- a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DDisplay.h +++ b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DDisplay.h @@ -45,6 +45,7 @@ class Render2DClass; class RTS3DScene; class RTS2DScene; class RTS3DInterfaceScene; +class TextureClass; //============================================================================= @@ -81,6 +82,9 @@ class W3DDisplay : public Display virtual void step() override; ///< Do one fixed time step virtual void draw() override; ///< redraw the entire display + virtual void beginBatch(); + virtual void endBatch(); + /// @todo Replace these light management routines with a LightManager singleton virtual void createLightPulse( const Coord3D *pos, const RGBColor *color, Real innerRadius,Real outerRadius, UnsignedInt increaseFrameTime, UnsignedInt decayFrameTime//, Bool donut = FALSE @@ -168,6 +172,11 @@ class W3DDisplay : public Display Bool m_isClippedEnabled; ///Reset(); + m_2DRender->Enable_Texturing(FALSE); + m_2DRender->Enable_Alpha(TRUE); + } +} + +void W3DDisplay::endBatch() +{ + if (m_isBatching) + { + if (m_2DRender) + { + m_2DRender->Render(); + m_2DRender->Reset(); + } + m_isBatching = FALSE; + } +} + // W3DDisplay::initAssets ===================================================== /** */ //============================================================================= @@ -2148,14 +2179,32 @@ void W3DDisplay::drawLine( Int startX, Int startY, Real lineWidth, UnsignedInt lineColor ) { + if (m_isBatching) + { + if (m_batchTexture != nullptr || m_batchMode != DRAW_IMAGE_SOLID) + { + m_2DRender->Render(); + m_2DRender->Reset(); + m_batchTexture = nullptr; + m_batchMode = DRAW_IMAGE_SOLID; + m_2DRender->Enable_Texturing(FALSE); + m_2DRender->Enable_Alpha(TRUE); + } + } + else + { + m_2DRender->Reset(); + m_2DRender->Enable_Texturing( FALSE ); + m_2DRender->Enable_Alpha(TRUE); + } - /// @todo we need to consider the efficiency of the 2D renderer - m_2DRender->Reset(); - m_2DRender->Enable_Texturing( FALSE ); m_2DRender->Add_Line( Vector2( startX, startY ), Vector2( endX, endY ), lineWidth, lineColor ); - m_2DRender->Render(); + if (!m_isBatching) + { + m_2DRender->Render(); + } } // W3DDisplay::drawLine ======================================================= @@ -2166,13 +2215,32 @@ void W3DDisplay::drawLine( Int startX, Int startY, Real lineWidth, UnsignedInt lineColor1,UnsignedInt lineColor2 ) { + if (m_isBatching) + { + if (m_batchTexture != nullptr || m_batchMode != DRAW_IMAGE_SOLID) + { + m_2DRender->Render(); + m_2DRender->Reset(); + m_batchTexture = nullptr; + m_batchMode = DRAW_IMAGE_SOLID; + m_2DRender->Enable_Texturing(FALSE); + m_2DRender->Enable_Alpha(TRUE); + } + } + else + { + m_2DRender->Reset(); + m_2DRender->Enable_Texturing( FALSE ); + m_2DRender->Enable_Alpha(TRUE); + } - /// @todo we need to consider the efficiency of the 2D renderer - m_2DRender->Reset(); - m_2DRender->Enable_Texturing( FALSE ); m_2DRender->Add_Line( Vector2( startX, startY ), Vector2( endX, endY ), lineWidth, lineColor1, lineColor2 ); - m_2DRender->Render(); + + if (!m_isBatching) + { + m_2DRender->Render(); + } } @@ -2215,16 +2283,34 @@ void W3DDisplay::drawOpenRect( Int startX, Int startY, Int width, Int height, } else { - /// @todo we need to consider the efficiency of the 2D renderer - m_2DRender->Reset(); - m_2DRender->Enable_Texturing( FALSE ); + if (m_isBatching) + { + if (m_batchTexture != nullptr || m_batchMode != DRAW_IMAGE_SOLID) + { + m_2DRender->Render(); + m_2DRender->Reset(); + m_batchTexture = nullptr; + m_batchMode = DRAW_IMAGE_SOLID; + m_2DRender->Enable_Texturing(FALSE); + m_2DRender->Enable_Alpha(TRUE); + } + } + else + { + m_2DRender->Reset(); + m_2DRender->Enable_Texturing( FALSE ); + m_2DRender->Enable_Alpha(TRUE); + } m_2DRender->Add_Outline( RectClass( startX, startY, startX + width, startY + height ), lineWidth, lineColor ); // render it now! - m_2DRender->Render(); + if (!m_isBatching) + { + m_2DRender->Render(); + } } } @@ -2234,17 +2320,34 @@ void W3DDisplay::drawOpenRect( Int startX, Int startY, Int width, Int height, void W3DDisplay::drawFillRect( Int startX, Int startY, Int width, Int height, UnsignedInt color ) { + if (m_isBatching) + { + if (m_batchTexture != nullptr || m_batchMode != DRAW_IMAGE_SOLID) + { + m_2DRender->Render(); + m_2DRender->Reset(); + m_batchTexture = nullptr; + m_batchMode = DRAW_IMAGE_SOLID; + m_2DRender->Enable_Texturing(FALSE); + m_2DRender->Enable_Alpha(TRUE); + } + } + else + { + m_2DRender->Reset(); + m_2DRender->Enable_Texturing( FALSE ); + m_2DRender->Enable_Alpha(TRUE); + } - /// @todo we need to consider the efficiency of the 2D renderer - m_2DRender->Reset(); - m_2DRender->Enable_Texturing( FALSE ); m_2DRender->Add_Rect( RectClass( startX, startY, startX + width, startY + height ), 0, 0, color ); // render it now! - m_2DRender->Render(); - + if (!m_isBatching) + { + m_2DRender->Render(); + } } void W3DDisplay::drawRectClock(Int startX, Int startY, Int width, Int height, Int percent, UnsignedInt color) @@ -2253,8 +2356,24 @@ void W3DDisplay::drawRectClock(Int startX, Int startY, Int width, Int height, In if(percent < 1 || percent > 100) return; - m_2DRender->Reset(); - m_2DRender->Enable_Texturing( FALSE ); + if (m_isBatching) + { + if (m_batchTexture != nullptr || m_batchMode != DRAW_IMAGE_SOLID) + { + m_2DRender->Render(); + m_2DRender->Reset(); + m_batchTexture = nullptr; + m_batchMode = DRAW_IMAGE_SOLID; + m_2DRender->Enable_Texturing(FALSE); + m_2DRender->Enable_Alpha(TRUE); + } + } + else + { + m_2DRender->Reset(); + m_2DRender->Enable_Texturing( FALSE ); + m_2DRender->Enable_Alpha(TRUE); + } // The rectangles are numberd as follows //(x,y) |---------| @@ -2400,8 +2519,10 @@ void W3DDisplay::drawRectClock(Int startX, Int startY, Int width, Int height, In } // render it now! - m_2DRender->Render(); - + if (!m_isBatching) + { + m_2DRender->Render(); + } } @@ -2417,8 +2538,24 @@ void W3DDisplay::drawRemainingRectClock(Int startX, Int startY, Int width, Int h if( percent < 0 || percent > 99 ) return; - m_2DRender->Reset(); - m_2DRender->Enable_Texturing( FALSE ); + if (m_isBatching) + { + if (m_batchTexture != nullptr || m_batchMode != DRAW_IMAGE_SOLID) + { + m_2DRender->Render(); + m_2DRender->Reset(); + m_batchTexture = nullptr; + m_batchMode = DRAW_IMAGE_SOLID; + m_2DRender->Enable_Texturing(FALSE); + m_2DRender->Enable_Alpha(TRUE); + } + } + else + { + m_2DRender->Reset(); + m_2DRender->Enable_Texturing( FALSE ); + m_2DRender->Enable_Alpha(TRUE); + } // The rectangles are numbered as follows //(x,y) |---------| @@ -2579,7 +2716,10 @@ void W3DDisplay::drawRemainingRectClock(Int startX, Int startY, Int width, Int h } // render it now! - m_2DRender->Render(); + if (!m_isBatching) + { + m_2DRender->Render(); + } } @@ -2603,37 +2743,71 @@ void W3DDisplay::drawImage( const Image *image, Int startX, Int startY, const Region2D *uv = image->getUV(); - m_2DRender->Reset(); - m_2DRender->Enable_Texturing( TRUE ); - - Bool doAlphaReset=FALSE; + TextureClass *tex = nullptr; + if (BitIsSet(image->getStatus(), IMAGE_STATUS_RAW_TEXTURE)) + tex = (TextureClass *)(image->getRawTextureData()); + else + tex = WW3DAssetManager::Get_Instance()->Get_Texture(image->getFilename().str(), MIP_LEVELS_1); + Bool grayscale = (mode == DRAW_IMAGE_GRAYSCALE); ///@todo: Why are we alpha blending all images? Reduces our fillrate. -MW - switch (mode) + if (m_isBatching) + { + if (m_batchTexture != tex || m_batchMode != mode || m_batchGrayscale != grayscale) + { + m_2DRender->Render(); + m_2DRender->Reset(); + m_batchTexture = tex; + m_batchMode = mode; + m_batchGrayscale = grayscale; + + m_2DRender->Enable_Texturing(TRUE); + m_2DRender->Set_Texture(tex); + switch (mode) + { + case DRAW_IMAGE_ALPHA: + m_2DRender->Enable_Alpha(TRUE); + break; + case DRAW_IMAGE_GRAYSCALE: + m_2DRender->Enable_Grayscale(true); + break; + case DRAW_IMAGE_ADDITIVE: + m_2DRender->Enable_Additive(true); + break; + case DRAW_IMAGE_SOLID: + m_2DRender->Enable_Additive(false); + m_2DRender->Enable_Alpha(false); + break; + } + } + } + else { - case DRAW_IMAGE_ALPHA: //nothing to do since alpha is the default state + m_2DRender->Reset(); + m_2DRender->Enable_Texturing(TRUE); + m_2DRender->Set_Texture(tex); + switch (mode) + { + case DRAW_IMAGE_ALPHA: + m_2DRender->Enable_Alpha(TRUE); break; case DRAW_IMAGE_GRAYSCALE: - m_2DRender->Enable_Grayscale(true); + m_2DRender->Enable_Grayscale(TRUE); break; case DRAW_IMAGE_ADDITIVE: - m_2DRender->Enable_Additive(true); - doAlphaReset = TRUE; + m_2DRender->Enable_Additive(TRUE); break; case DRAW_IMAGE_SOLID: - m_2DRender->Enable_Additive(false); - m_2DRender->Enable_Alpha(false); - doAlphaReset = TRUE; - break; - default: + m_2DRender->Enable_Additive(FALSE); + m_2DRender->Enable_Alpha(FALSE); break; + } } - // if we have raw texture data we will use it, otherwise we are referencing filenames - if( BitIsSet( image->getStatus(), IMAGE_STATUS_RAW_TEXTURE ) ) - m_2DRender->Set_Texture( (TextureClass *)(image->getRawTextureData()) ); - else - m_2DRender->Set_Texture( image->getFilename().str() ); + if (tex != nullptr && !BitIsSet(image->getStatus(), IMAGE_STATUS_RAW_TEXTURE)) + { + tex->Release_Ref(); + } RectClass screen_rect(startX,startY,endX,endY); RectClass uv_rect(uv->lo.x,uv->lo.y,uv->hi.x,uv->hi.y); @@ -2748,12 +2922,12 @@ void W3DDisplay::drawImage( const Image *image, Int startX, Int startY, } - m_2DRender->Render(); - - //reset to default states for next time this method is called. - m_2DRender->Enable_Grayscale(false); //never leave it in this mode - if (doAlphaReset) + if (!m_isBatching) + { + m_2DRender->Render(); + m_2DRender->Enable_Grayscale(false); m_2DRender->Enable_Alpha(true); + } } @@ -2855,12 +3029,28 @@ void W3DDisplay::drawVideoBuffer( VideoBuffer *buffer, Int startX, Int startY, I { W3DVideoBuffer *vbuffer = (W3DVideoBuffer*) buffer; - m_2DRender->Reset(); + if (m_isBatching) + { + m_2DRender->Render(); + m_2DRender->Reset(); + m_batchTexture = vbuffer->texture(); + m_batchMode = DRAW_IMAGE_ALPHA; + m_batchGrayscale = FALSE; + } + else + { + m_2DRender->Reset(); + } + m_2DRender->Enable_Texturing( TRUE ); m_2DRender->Set_Texture( vbuffer->texture() ); m_2DRender->Add_Quad( RectClass( startX, startY, endX, endY ), vbuffer->Rect( 0, 0, 1, 1) ); - m_2DRender->Render(); + + if (!m_isBatching) + { + m_2DRender->Render(); + } } diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplayString.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplayString.cpp index 12c7c8dbeeb..247556a8cf6 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplayString.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplayString.cpp @@ -49,6 +49,7 @@ #include // USER INCLUDES ////////////////////////////////////////////////////////////// +#include "GameClient/Display.h" #include "GameClient/GameClient.h" #include "W3DDevice/GameClient/W3DDisplayString.h" #include "GameClient/HotKey.h" @@ -227,6 +228,11 @@ void W3DDisplayString::draw( Int x, Int y, Color color, Color dropColor, Int xDr } // render the text + if (TheDisplay->isBatching()) + { + TheDisplay->endBatch(); + TheDisplay->beginBatch(); + } m_textRenderer.Render(); // we are for sure using display resources now From dd7e82227e2e777fa8a8de44bee8582306ced1e3 Mon Sep 17 00:00:00 2001 From: githubawn <115191165+githubawn@users.noreply.github.com> Date: Mon, 30 Mar 2026 23:30:14 +0200 Subject: [PATCH 02/20] centralized logic into setup2DRenderState --- .../GameEngine/Include/GameClient/Display.h | 3 +- .../Include/W3DDevice/GameClient/W3DDisplay.h | 1 + .../W3DDevice/GameClient/W3DDisplay.cpp | 272 ++++++------------ 3 files changed, 92 insertions(+), 184 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/Display.h b/GeneralsMD/Code/GameEngine/Include/GameClient/Display.h index 0803cc8b8fa..b1175da0a41 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/Display.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/Display.h @@ -58,7 +58,8 @@ class Display : public SubsystemInterface DRAW_IMAGE_SOLID, DRAW_IMAGE_GRAYSCALE, //draw image without blending and ignoring alpha DRAW_IMAGE_ALPHA, //alpha blend the image into frame buffer - DRAW_IMAGE_ADDITIVE //additive blend the image into frame buffer + DRAW_IMAGE_ADDITIVE, //additive blend the image into frame buffer + DRAW_IMAGE_PRIMITIVE //non-textured primitive (lines, rects) }; typedef void (DebugDisplayCallback)( DebugDisplayInterface *debugDisplay, void *userData, FILE *fp ); diff --git a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DDisplay.h b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DDisplay.h index 09c77f98f07..e052a6862a0 100644 --- a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DDisplay.h +++ b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DDisplay.h @@ -164,6 +164,7 @@ class W3DDisplay : public Display void calculateTerrainLOD(); ///< Calculate terrain LOD. void renderLetterBox(UnsignedInt time); ///< draw letter box border void updateAverageFPS(); ///< calculate the average fps over the last 30 frames. + void setup2DRenderState(TextureClass *tex, DrawImageMode mode, Bool grayscale); Byte m_initialized; ///< TRUE when system is initialized LightClass *m_myLight[LightEnvironmentClass::MAX_LIGHTS]; ///< light hack for now diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index b0f0b65aee6..6a71c369cd1 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -591,15 +591,11 @@ void W3DDisplay::setHeight( UnsignedInt height ) void W3DDisplay::beginBatch() { m_isBatching = TRUE; - m_batchTexture = nullptr; - m_batchGrayscale = FALSE; + m_batchTexture = (TextureClass*)-1; m_batchMode = DRAW_IMAGE_ALPHA; - if (m_2DRender) - { - m_2DRender->Reset(); - m_2DRender->Enable_Texturing(FALSE); - m_2DRender->Enable_Alpha(TRUE); - } + m_batchGrayscale = FALSE; + + setup2DRenderState(nullptr, DRAW_IMAGE_PRIMITIVE, FALSE); } void W3DDisplay::endBatch() @@ -612,6 +608,79 @@ void W3DDisplay::endBatch() m_2DRender->Reset(); } m_isBatching = FALSE; + m_batchTexture = nullptr; + m_batchMode = DRAW_IMAGE_ALPHA; + m_batchGrayscale = FALSE; + } +} + +void W3DDisplay::setup2DRenderState(TextureClass *tex, DrawImageMode mode, Bool grayscale) +{ + if (m_isBatching) + { + if (m_batchTexture == tex && m_batchMode == mode && m_batchGrayscale == grayscale) + { + return; + } + + if (m_2DRender) + { + // if m_batchTexture == -1, this is the very first setup in a batch, we don't render/reset yet + if (m_batchTexture != (TextureClass*)-1) + { + m_2DRender->Render(); + m_2DRender->Reset(); + } + } + m_batchTexture = tex; + m_batchMode = mode; + m_batchGrayscale = grayscale; + } + else + { + if (m_2DRender) + { + m_2DRender->Reset(); + } + } + + if (m_2DRender) + { + if (tex) + { + m_2DRender->Enable_Texturing(TRUE); + m_2DRender->Set_Texture(tex); + } + else + { + m_2DRender->Enable_Texturing(FALSE); + } + + // Strictly mirroring original commit's state setting logic per mode + switch (mode) + { + case DRAW_IMAGE_ALPHA: + m_2DRender->Enable_Alpha(TRUE); + m_2DRender->Enable_Grayscale(grayscale); + break; + case DRAW_IMAGE_GRAYSCALE: + m_2DRender->Enable_Grayscale(TRUE); + break; + case DRAW_IMAGE_ADDITIVE: + m_2DRender->Enable_Additive(TRUE); + m_2DRender->Enable_Grayscale(grayscale); + break; + case DRAW_IMAGE_SOLID: + m_2DRender->Enable_Additive(FALSE); + m_2DRender->Enable_Alpha(FALSE); + m_2DRender->Enable_Grayscale(grayscale); + break; + case DRAW_IMAGE_PRIMITIVE: + m_2DRender->Enable_Additive(FALSE); + m_2DRender->Enable_Alpha(TRUE); + m_2DRender->Enable_Grayscale(FALSE); + break; + } } } @@ -2179,24 +2248,7 @@ void W3DDisplay::drawLine( Int startX, Int startY, Real lineWidth, UnsignedInt lineColor ) { - if (m_isBatching) - { - if (m_batchTexture != nullptr || m_batchMode != DRAW_IMAGE_SOLID) - { - m_2DRender->Render(); - m_2DRender->Reset(); - m_batchTexture = nullptr; - m_batchMode = DRAW_IMAGE_SOLID; - m_2DRender->Enable_Texturing(FALSE); - m_2DRender->Enable_Alpha(TRUE); - } - } - else - { - m_2DRender->Reset(); - m_2DRender->Enable_Texturing( FALSE ); - m_2DRender->Enable_Alpha(TRUE); - } + setup2DRenderState(nullptr, DRAW_IMAGE_PRIMITIVE, FALSE); m_2DRender->Add_Line( Vector2( startX, startY ), Vector2( endX, endY ), lineWidth, lineColor ); @@ -2215,24 +2267,7 @@ void W3DDisplay::drawLine( Int startX, Int startY, Real lineWidth, UnsignedInt lineColor1,UnsignedInt lineColor2 ) { - if (m_isBatching) - { - if (m_batchTexture != nullptr || m_batchMode != DRAW_IMAGE_SOLID) - { - m_2DRender->Render(); - m_2DRender->Reset(); - m_batchTexture = nullptr; - m_batchMode = DRAW_IMAGE_SOLID; - m_2DRender->Enable_Texturing(FALSE); - m_2DRender->Enable_Alpha(TRUE); - } - } - else - { - m_2DRender->Reset(); - m_2DRender->Enable_Texturing( FALSE ); - m_2DRender->Enable_Alpha(TRUE); - } + setup2DRenderState(nullptr, DRAW_IMAGE_PRIMITIVE, FALSE); m_2DRender->Add_Line( Vector2( startX, startY ), Vector2( endX, endY ), lineWidth, lineColor1, lineColor2 ); @@ -2283,24 +2318,7 @@ void W3DDisplay::drawOpenRect( Int startX, Int startY, Int width, Int height, } else { - if (m_isBatching) - { - if (m_batchTexture != nullptr || m_batchMode != DRAW_IMAGE_SOLID) - { - m_2DRender->Render(); - m_2DRender->Reset(); - m_batchTexture = nullptr; - m_batchMode = DRAW_IMAGE_SOLID; - m_2DRender->Enable_Texturing(FALSE); - m_2DRender->Enable_Alpha(TRUE); - } - } - else - { - m_2DRender->Reset(); - m_2DRender->Enable_Texturing( FALSE ); - m_2DRender->Enable_Alpha(TRUE); - } + setup2DRenderState(nullptr, DRAW_IMAGE_PRIMITIVE, FALSE); m_2DRender->Add_Outline( RectClass( startX, startY, startX + width, startY + height ), @@ -2320,24 +2338,7 @@ void W3DDisplay::drawOpenRect( Int startX, Int startY, Int width, Int height, void W3DDisplay::drawFillRect( Int startX, Int startY, Int width, Int height, UnsignedInt color ) { - if (m_isBatching) - { - if (m_batchTexture != nullptr || m_batchMode != DRAW_IMAGE_SOLID) - { - m_2DRender->Render(); - m_2DRender->Reset(); - m_batchTexture = nullptr; - m_batchMode = DRAW_IMAGE_SOLID; - m_2DRender->Enable_Texturing(FALSE); - m_2DRender->Enable_Alpha(TRUE); - } - } - else - { - m_2DRender->Reset(); - m_2DRender->Enable_Texturing( FALSE ); - m_2DRender->Enable_Alpha(TRUE); - } + setup2DRenderState(nullptr, DRAW_IMAGE_PRIMITIVE, FALSE); m_2DRender->Add_Rect( RectClass( startX, startY, startX + width, startY + height ), @@ -2356,24 +2357,7 @@ void W3DDisplay::drawRectClock(Int startX, Int startY, Int width, Int height, In if(percent < 1 || percent > 100) return; - if (m_isBatching) - { - if (m_batchTexture != nullptr || m_batchMode != DRAW_IMAGE_SOLID) - { - m_2DRender->Render(); - m_2DRender->Reset(); - m_batchTexture = nullptr; - m_batchMode = DRAW_IMAGE_SOLID; - m_2DRender->Enable_Texturing(FALSE); - m_2DRender->Enable_Alpha(TRUE); - } - } - else - { - m_2DRender->Reset(); - m_2DRender->Enable_Texturing( FALSE ); - m_2DRender->Enable_Alpha(TRUE); - } + setup2DRenderState(nullptr, DRAW_IMAGE_PRIMITIVE, FALSE); // The rectangles are numberd as follows //(x,y) |---------| @@ -2538,24 +2522,7 @@ void W3DDisplay::drawRemainingRectClock(Int startX, Int startY, Int width, Int h if( percent < 0 || percent > 99 ) return; - if (m_isBatching) - { - if (m_batchTexture != nullptr || m_batchMode != DRAW_IMAGE_SOLID) - { - m_2DRender->Render(); - m_2DRender->Reset(); - m_batchTexture = nullptr; - m_batchMode = DRAW_IMAGE_SOLID; - m_2DRender->Enable_Texturing(FALSE); - m_2DRender->Enable_Alpha(TRUE); - } - } - else - { - m_2DRender->Reset(); - m_2DRender->Enable_Texturing( FALSE ); - m_2DRender->Enable_Alpha(TRUE); - } + setup2DRenderState(nullptr, DRAW_IMAGE_PRIMITIVE, FALSE); // The rectangles are numbered as follows //(x,y) |---------| @@ -2751,58 +2718,7 @@ void W3DDisplay::drawImage( const Image *image, Int startX, Int startY, Bool grayscale = (mode == DRAW_IMAGE_GRAYSCALE); ///@todo: Why are we alpha blending all images? Reduces our fillrate. -MW - if (m_isBatching) - { - if (m_batchTexture != tex || m_batchMode != mode || m_batchGrayscale != grayscale) - { - m_2DRender->Render(); - m_2DRender->Reset(); - m_batchTexture = tex; - m_batchMode = mode; - m_batchGrayscale = grayscale; - - m_2DRender->Enable_Texturing(TRUE); - m_2DRender->Set_Texture(tex); - switch (mode) - { - case DRAW_IMAGE_ALPHA: - m_2DRender->Enable_Alpha(TRUE); - break; - case DRAW_IMAGE_GRAYSCALE: - m_2DRender->Enable_Grayscale(true); - break; - case DRAW_IMAGE_ADDITIVE: - m_2DRender->Enable_Additive(true); - break; - case DRAW_IMAGE_SOLID: - m_2DRender->Enable_Additive(false); - m_2DRender->Enable_Alpha(false); - break; - } - } - } - else - { - m_2DRender->Reset(); - m_2DRender->Enable_Texturing(TRUE); - m_2DRender->Set_Texture(tex); - switch (mode) - { - case DRAW_IMAGE_ALPHA: - m_2DRender->Enable_Alpha(TRUE); - break; - case DRAW_IMAGE_GRAYSCALE: - m_2DRender->Enable_Grayscale(TRUE); - break; - case DRAW_IMAGE_ADDITIVE: - m_2DRender->Enable_Additive(TRUE); - break; - case DRAW_IMAGE_SOLID: - m_2DRender->Enable_Additive(FALSE); - m_2DRender->Enable_Alpha(FALSE); - break; - } - } + setup2DRenderState(tex, mode, grayscale); if (tex != nullptr && !BitIsSet(image->getStatus(), IMAGE_STATUS_RAW_TEXTURE)) { @@ -2926,7 +2842,10 @@ void W3DDisplay::drawImage( const Image *image, Int startX, Int startY, { m_2DRender->Render(); m_2DRender->Enable_Grayscale(false); - m_2DRender->Enable_Alpha(true); + if (mode == DRAW_IMAGE_ADDITIVE || mode == DRAW_IMAGE_SOLID) + { + m_2DRender->Enable_Alpha(true); + } } } @@ -3029,21 +2948,8 @@ void W3DDisplay::drawVideoBuffer( VideoBuffer *buffer, Int startX, Int startY, I { W3DVideoBuffer *vbuffer = (W3DVideoBuffer*) buffer; - if (m_isBatching) - { - m_2DRender->Render(); - m_2DRender->Reset(); - m_batchTexture = vbuffer->texture(); - m_batchMode = DRAW_IMAGE_ALPHA; - m_batchGrayscale = FALSE; - } - else - { - m_2DRender->Reset(); - } + setup2DRenderState(vbuffer->texture(), DRAW_IMAGE_ALPHA, FALSE); - m_2DRender->Enable_Texturing( TRUE ); - m_2DRender->Set_Texture( vbuffer->texture() ); m_2DRender->Add_Quad( RectClass( startX, startY, endX, endY ), vbuffer->Rect( 0, 0, 1, 1) ); From bfd6c1e6c73031094588e2f602e28246fda639f1 Mon Sep 17 00:00:00 2001 From: githubawn <115191165+githubawn@users.noreply.github.com> Date: Tue, 31 Mar 2026 00:44:35 +0200 Subject: [PATCH 03/20] prevent some possible state leakage --- .../GameEngine/Include/GameClient/Display.h | 8 ++- .../GameEngine/Source/GameClient/Display.cpp | 20 ++++++++ .../Include/W3DDevice/GameClient/W3DDisplay.h | 7 +-- .../W3DDevice/GameClient/W3DDisplay.cpp | 49 ++++++++++--------- .../W3DDevice/GameClient/W3DDisplayString.cpp | 21 ++++---- 5 files changed, 67 insertions(+), 38 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/Display.h b/GeneralsMD/Code/GameEngine/Include/GameClient/Display.h index b1175da0a41..6fba1d36d45 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/Display.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/Display.h @@ -114,8 +114,9 @@ class Display : public SubsystemInterface virtual Bool isClippingEnabled() = 0; virtual void enableClipping( Bool onoff ) = 0; - virtual void beginBatch() { } - virtual void endBatch() { } + virtual void beginBatch(); + virtual void endBatch(); + virtual void flush(); virtual Bool isBatching() { return m_isBatching; } virtual void step() {}; ///< Do one fixed time step @@ -187,6 +188,9 @@ class Display : public SubsystemInterface virtual Int getLastFrameDrawCalls() = 0; ///< returns the number of draw calls issued in the previous frame protected: + virtual void onBeginBatch() { } + virtual void onEndBatch() { } + virtual void onFlush() { } virtual void deleteViews(); ///< delete all views UnsignedInt m_width, m_height; ///< Dimensions of the display diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/Display.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/Display.cpp index 9b7bbeaadd8..e009d2b9635 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/Display.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/Display.cpp @@ -66,6 +66,7 @@ Display::Display() m_currentlyPlayingMovie.clear(); m_letterBoxFadeStartTime = 0; + m_isBatching = FALSE; } /** @@ -387,3 +388,22 @@ Display::DebugDisplayCallback *Display::getDebugDisplayCallback() { return m_debugDisplayCallback; } + +void Display::beginBatch() +{ + if (m_isBatching) return; + m_isBatching = TRUE; + onBeginBatch(); +} + +void Display::endBatch() +{ + if (!m_isBatching) return; + onEndBatch(); + m_isBatching = FALSE; +} + +void Display::flush() +{ + onFlush(); +} diff --git a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DDisplay.h b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DDisplay.h index e052a6862a0..476fc14342c 100644 --- a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DDisplay.h +++ b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DDisplay.h @@ -82,9 +82,6 @@ class W3DDisplay : public Display virtual void step() override; ///< Do one fixed time step virtual void draw() override; ///< redraw the entire display - virtual void beginBatch(); - virtual void endBatch(); - /// @todo Replace these light management routines with a LightManager singleton virtual void createLightPulse( const Coord3D *pos, const RGBColor *color, Real innerRadius,Real outerRadius, UnsignedInt increaseFrameTime, UnsignedInt decayFrameTime//, Bool donut = FALSE @@ -165,6 +162,9 @@ class W3DDisplay : public Display void renderLetterBox(UnsignedInt time); ///< draw letter box border void updateAverageFPS(); ///< calculate the average fps over the last 30 frames. void setup2DRenderState(TextureClass *tex, DrawImageMode mode, Bool grayscale); + virtual void onBeginBatch() override; + virtual void onEndBatch() override; + virtual void onFlush() override; Byte m_initialized; ///< TRUE when system is initialized LightClass *m_myLight[LightEnvironmentClass::MAX_LIGHTS]; ///< light hack for now @@ -177,6 +177,7 @@ class W3DDisplay : public Display TextureClass *m_batchTexture; DrawImageMode m_batchMode; Bool m_batchGrayscale; + Bool m_batchNeedsInit; #if defined(RTS_DEBUG) Int64 m_timerAtCumuFPSStart; diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index 6a71c369cd1..ddd2f9a902b 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -588,29 +588,34 @@ void W3DDisplay::setHeight( UnsignedInt height ) } -void W3DDisplay::beginBatch() +void W3DDisplay::onBeginBatch() { - m_isBatching = TRUE; - m_batchTexture = (TextureClass*)-1; + m_batchTexture = nullptr; m_batchMode = DRAW_IMAGE_ALPHA; m_batchGrayscale = FALSE; + m_batchNeedsInit = FALSE; + + if (m_2DRender) + { + m_2DRender->Reset(); + } setup2DRenderState(nullptr, DRAW_IMAGE_PRIMITIVE, FALSE); } -void W3DDisplay::endBatch() +void W3DDisplay::onEndBatch() { - if (m_isBatching) + onFlush(); + m_batchTexture = nullptr; +} + +void W3DDisplay::onFlush() +{ + if (m_2DRender && !m_batchNeedsInit) { - if (m_2DRender) - { - m_2DRender->Render(); - m_2DRender->Reset(); - } - m_isBatching = FALSE; - m_batchTexture = nullptr; - m_batchMode = DRAW_IMAGE_ALPHA; - m_batchGrayscale = FALSE; + m_2DRender->Render(); + m_2DRender->Reset(); + m_batchNeedsInit = TRUE; } } @@ -618,23 +623,20 @@ void W3DDisplay::setup2DRenderState(TextureClass *tex, DrawImageMode mode, Bool { if (m_isBatching) { - if (m_batchTexture == tex && m_batchMode == mode && m_batchGrayscale == grayscale) + if (!m_batchNeedsInit && m_batchTexture == tex && m_batchMode == mode && m_batchGrayscale == grayscale) { return; } if (m_2DRender) { - // if m_batchTexture == -1, this is the very first setup in a batch, we don't render/reset yet - if (m_batchTexture != (TextureClass*)-1) - { - m_2DRender->Render(); - m_2DRender->Reset(); - } + m_2DRender->Render(); + m_2DRender->Reset(); } m_batchTexture = tex; m_batchMode = mode; m_batchGrayscale = grayscale; + m_batchNeedsInit = FALSE; } else { @@ -656,17 +658,20 @@ void W3DDisplay::setup2DRenderState(TextureClass *tex, DrawImageMode mode, Bool m_2DRender->Enable_Texturing(FALSE); } - // Strictly mirroring original commit's state setting logic per mode switch (mode) { case DRAW_IMAGE_ALPHA: + m_2DRender->Enable_Additive(FALSE); m_2DRender->Enable_Alpha(TRUE); m_2DRender->Enable_Grayscale(grayscale); break; case DRAW_IMAGE_GRAYSCALE: + m_2DRender->Enable_Additive(FALSE); + m_2DRender->Enable_Alpha(FALSE); m_2DRender->Enable_Grayscale(TRUE); break; case DRAW_IMAGE_ADDITIVE: + m_2DRender->Enable_Alpha(FALSE); m_2DRender->Enable_Additive(TRUE); m_2DRender->Enable_Grayscale(grayscale); break; diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplayString.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplayString.cpp index 247556a8cf6..409295faffa 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplayString.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplayString.cpp @@ -217,22 +217,21 @@ void W3DDisplayString::draw( Int x, Int y, Color color, Color dropColor, Int xDr m_textRenderer.Set_Location( Vector2( m_textPos.x, m_textPos.y ) ); m_textRenderer.Draw_Sentence( m_currTextColor ); - if(m_useHotKey) - { - m_textRendererHotKey.Reset_Polys(); - m_textRendererHotKey.Set_Location( Vector2( m_textPos.x + m_hotKeyPos.x , m_textPos.y +m_hotKeyPos.y) ); - m_textRendererHotKey.Draw_Sentence( m_hotKeyColor ); - m_textRendererHotKey.Render(); - } - } - // render the text if (TheDisplay->isBatching()) { - TheDisplay->endBatch(); - TheDisplay->beginBatch(); + TheDisplay->flush(); } + + if(m_useHotKey) + { + m_textRendererHotKey.Reset_Polys(); + m_textRendererHotKey.Set_Location( Vector2( m_textPos.x + m_hotKeyPos.x , m_textPos.y +m_hotKeyPos.y) ); + m_textRendererHotKey.Draw_Sentence( m_hotKeyColor ); + m_textRendererHotKey.Render(); + } + m_textRenderer.Render(); // we are for sure using display resources now From f02e944c42e392e2b37f10db363d64ece4862e27 Mon Sep 17 00:00:00 2001 From: githubawn <115191165+githubawn@users.noreply.github.com> Date: Tue, 31 Mar 2026 02:54:58 +0200 Subject: [PATCH 04/20] fix batch execution order and texture lifetime bug --- .../Source/W3DDevice/GameClient/W3DDisplay.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index ddd2f9a902b..de2895d8886 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -606,7 +606,11 @@ void W3DDisplay::onBeginBatch() void W3DDisplay::onEndBatch() { onFlush(); - m_batchTexture = nullptr; + if (m_batchTexture) + { + m_batchTexture->Release_Ref(); + m_batchTexture = nullptr; + } } void W3DDisplay::onFlush() @@ -633,7 +637,14 @@ void W3DDisplay::setup2DRenderState(TextureClass *tex, DrawImageMode mode, Bool m_2DRender->Render(); m_2DRender->Reset(); } - m_batchTexture = tex; + + if (tex != m_batchTexture) + { + if (tex) tex->Add_Ref(); + if (m_batchTexture) m_batchTexture->Release_Ref(); + m_batchTexture = tex; + } + m_batchMode = mode; m_batchGrayscale = grayscale; m_batchNeedsInit = FALSE; From b40f7bdd8b02dbf23f666144f539021781c94785 Mon Sep 17 00:00:00 2001 From: githubawn <115191165+githubawn@users.noreply.github.com> Date: Tue, 31 Mar 2026 04:05:28 +0200 Subject: [PATCH 05/20] initialize m_batchNeedsInit in constructor --- .../GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index de2895d8886..e52fbe1e684 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -408,6 +408,7 @@ W3DDisplay::W3DDisplay() m_batchTexture = nullptr; m_batchMode = DRAW_IMAGE_ALPHA; m_batchGrayscale = FALSE; + m_batchNeedsInit = TRUE; } // W3DDisplay::~W3DDisplay ==================================================== From 6d17889c35ac2423d5e221617c8766cdfc2d2318 Mon Sep 17 00:00:00 2001 From: githubawn <115191165+githubawn@users.noreply.github.com> Date: Tue, 31 Mar 2026 04:20:48 +0200 Subject: [PATCH 06/20] defer Release_Ref until after m_2DRender->Render(): split single line IF --- .../W3DDevice/GameClient/W3DDisplay.cpp | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index e52fbe1e684..c778aeb3f62 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -641,8 +641,14 @@ void W3DDisplay::setup2DRenderState(TextureClass *tex, DrawImageMode mode, Bool if (tex != m_batchTexture) { - if (tex) tex->Add_Ref(); - if (m_batchTexture) m_batchTexture->Release_Ref(); + if (tex) + { + tex->Add_Ref(); + } + if (m_batchTexture) + { + m_batchTexture->Release_Ref(); + } m_batchTexture = tex; } @@ -2737,11 +2743,6 @@ void W3DDisplay::drawImage( const Image *image, Int startX, Int startY, ///@todo: Why are we alpha blending all images? Reduces our fillrate. -MW setup2DRenderState(tex, mode, grayscale); - if (tex != nullptr && !BitIsSet(image->getStatus(), IMAGE_STATUS_RAW_TEXTURE)) - { - tex->Release_Ref(); - } - RectClass screen_rect(startX,startY,endX,endY); RectClass uv_rect(uv->lo.x,uv->lo.y,uv->hi.x,uv->hi.y); @@ -2865,6 +2866,11 @@ void W3DDisplay::drawImage( const Image *image, Int startX, Int startY, } } + if (tex != nullptr && !BitIsSet(image->getStatus(), IMAGE_STATUS_RAW_TEXTURE)) + { + tex->Release_Ref(); + } + } //============================================================================ From f52030ac5ed94f34a2af39a69ca58b958cfaf23a Mon Sep 17 00:00:00 2001 From: githubawn <115191165+githubawn@users.noreply.github.com> Date: Tue, 31 Mar 2026 04:33:14 +0200 Subject: [PATCH 07/20] resolve texture leak optimize clipping check --- .../Source/W3DDevice/GameClient/W3DDisplay.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index c778aeb3f62..87b0e9dce61 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -2753,8 +2753,14 @@ void W3DDisplay::drawImage( const Image *image, Int startX, Int startY, // Check for completely clipped // if ( endX <= m_clipRegion.lo.x || - endY <= m_clipRegion.lo.y) + endY <= m_clipRegion.lo.y || + startX >= m_clipRegion.hi.x || + startY >= m_clipRegion.hi.y) { + if (tex != nullptr && !BitIsSet(image->getStatus(), IMAGE_STATUS_RAW_TEXTURE)) + { + tex->Release_Ref(); + } return; //nothing to render } else { RectClass clipped_rect; From b4ddceb8b851f011a75f0b4a3b3c934dc484d424 Mon Sep 17 00:00:00 2001 From: githubawn <115191165+githubawn@users.noreply.github.com> Date: Tue, 31 Mar 2026 04:45:40 +0200 Subject: [PATCH 08/20] move off screen clipping after the null check remove obsolete else --- .../W3DDevice/GameClient/W3DDisplay.cpp | 29 ++++++++----------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index 87b0e9dce61..7d4fa118245 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -598,10 +598,8 @@ void W3DDisplay::onBeginBatch() if (m_2DRender) { - m_2DRender->Reset(); + setup2DRenderState(nullptr, DRAW_IMAGE_PRIMITIVE, FALSE); } - - setup2DRenderState(nullptr, DRAW_IMAGE_PRIMITIVE, FALSE); } void W3DDisplay::onEndBatch() @@ -2725,6 +2723,17 @@ void W3DDisplay::drawImage( const Image *image, Int startX, Int startY, if( image == nullptr ) return; + if (m_isClippedEnabled) + { + if ( endX <= m_clipRegion.lo.x || + endY <= m_clipRegion.lo.y || + startX >= m_clipRegion.hi.x || + startY >= m_clipRegion.hi.y) + { + return; //nothing to render + } + } + // !! // Remember to update the GUIEditDisplay::drawImage when you make // changes to this, it technically uses W3D code to render itself, @@ -2748,21 +2757,7 @@ void W3DDisplay::drawImage( const Image *image, Int startX, Int startY, if (m_isClippedEnabled) { //need to clip this quad to clip rectangle - - // - // Check for completely clipped - // - if ( endX <= m_clipRegion.lo.x || - endY <= m_clipRegion.lo.y || - startX >= m_clipRegion.hi.x || - startY >= m_clipRegion.hi.y) { - if (tex != nullptr && !BitIsSet(image->getStatus(), IMAGE_STATUS_RAW_TEXTURE)) - { - tex->Release_Ref(); - } - return; //nothing to render - } else { RectClass clipped_rect; RectClass clipped_uv_rect; From 2497ea1291d74360194c6c7ea02ad469b2fd1a20 Mon Sep 17 00:00:00 2001 From: githubawn <115191165+githubawn@users.noreply.github.com> Date: Tue, 31 Mar 2026 18:20:21 +0200 Subject: [PATCH 09/20] fix order call in draw_image_additive return statement on seperate line --- .../Code/GameEngine/Source/GameClient/Display.cpp | 10 ++++++++-- .../Source/W3DDevice/GameClient/W3DDisplay.cpp | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/Display.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/Display.cpp index e009d2b9635..32ac78f3e05 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/Display.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/Display.cpp @@ -391,14 +391,20 @@ Display::DebugDisplayCallback *Display::getDebugDisplayCallback() void Display::beginBatch() { - if (m_isBatching) return; + if (m_isBatching) + { + return; + } m_isBatching = TRUE; onBeginBatch(); } void Display::endBatch() { - if (!m_isBatching) return; + if (!m_isBatching) + { + return; + } onEndBatch(); m_isBatching = FALSE; } diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index 7d4fa118245..55baca18bcd 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -687,8 +687,8 @@ void W3DDisplay::setup2DRenderState(TextureClass *tex, DrawImageMode mode, Bool m_2DRender->Enable_Grayscale(TRUE); break; case DRAW_IMAGE_ADDITIVE: - m_2DRender->Enable_Alpha(FALSE); m_2DRender->Enable_Additive(TRUE); + m_2DRender->Enable_Alpha(FALSE); m_2DRender->Enable_Grayscale(grayscale); break; case DRAW_IMAGE_SOLID: From aaaff88b6b027f273f35f68b7895f0bc783dab9c Mon Sep 17 00:00:00 2001 From: githubawn <115191165+githubawn@users.noreply.github.com> Date: Tue, 31 Mar 2026 18:35:59 +0200 Subject: [PATCH 10/20] remove unneeded DRAW_IMAGE centralized flush --- .../GameEngine/Include/GameClient/Display.h | 3 +-- .../W3DDevice/GameClient/W3DDisplay.cpp | 25 ++++++------------- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/Display.h b/GeneralsMD/Code/GameEngine/Include/GameClient/Display.h index 6fba1d36d45..6b035fc112e 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/Display.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/Display.h @@ -58,8 +58,7 @@ class Display : public SubsystemInterface DRAW_IMAGE_SOLID, DRAW_IMAGE_GRAYSCALE, //draw image without blending and ignoring alpha DRAW_IMAGE_ALPHA, //alpha blend the image into frame buffer - DRAW_IMAGE_ADDITIVE, //additive blend the image into frame buffer - DRAW_IMAGE_PRIMITIVE //non-textured primitive (lines, rects) + DRAW_IMAGE_ADDITIVE //additive blend the image into frame buffer }; typedef void (DebugDisplayCallback)( DebugDisplayInterface *debugDisplay, void *userData, FILE *fp ); diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index 55baca18bcd..313b149ba43 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -598,7 +598,7 @@ void W3DDisplay::onBeginBatch() if (m_2DRender) { - setup2DRenderState(nullptr, DRAW_IMAGE_PRIMITIVE, FALSE); + setup2DRenderState(nullptr, DRAW_IMAGE_ALPHA, FALSE); } } @@ -631,11 +631,7 @@ void W3DDisplay::setup2DRenderState(TextureClass *tex, DrawImageMode mode, Bool return; } - if (m_2DRender) - { - m_2DRender->Render(); - m_2DRender->Reset(); - } + onFlush(); if (tex != m_batchTexture) { @@ -696,11 +692,6 @@ void W3DDisplay::setup2DRenderState(TextureClass *tex, DrawImageMode mode, Bool m_2DRender->Enable_Alpha(FALSE); m_2DRender->Enable_Grayscale(grayscale); break; - case DRAW_IMAGE_PRIMITIVE: - m_2DRender->Enable_Additive(FALSE); - m_2DRender->Enable_Alpha(TRUE); - m_2DRender->Enable_Grayscale(FALSE); - break; } } } @@ -2269,7 +2260,7 @@ void W3DDisplay::drawLine( Int startX, Int startY, Real lineWidth, UnsignedInt lineColor ) { - setup2DRenderState(nullptr, DRAW_IMAGE_PRIMITIVE, FALSE); + setup2DRenderState(nullptr, DRAW_IMAGE_ALPHA, FALSE); m_2DRender->Add_Line( Vector2( startX, startY ), Vector2( endX, endY ), lineWidth, lineColor ); @@ -2288,7 +2279,7 @@ void W3DDisplay::drawLine( Int startX, Int startY, Real lineWidth, UnsignedInt lineColor1,UnsignedInt lineColor2 ) { - setup2DRenderState(nullptr, DRAW_IMAGE_PRIMITIVE, FALSE); + setup2DRenderState(nullptr, DRAW_IMAGE_ALPHA, FALSE); m_2DRender->Add_Line( Vector2( startX, startY ), Vector2( endX, endY ), lineWidth, lineColor1, lineColor2 ); @@ -2339,7 +2330,7 @@ void W3DDisplay::drawOpenRect( Int startX, Int startY, Int width, Int height, } else { - setup2DRenderState(nullptr, DRAW_IMAGE_PRIMITIVE, FALSE); + setup2DRenderState(nullptr, DRAW_IMAGE_ALPHA, FALSE); m_2DRender->Add_Outline( RectClass( startX, startY, startX + width, startY + height ), @@ -2359,7 +2350,7 @@ void W3DDisplay::drawOpenRect( Int startX, Int startY, Int width, Int height, void W3DDisplay::drawFillRect( Int startX, Int startY, Int width, Int height, UnsignedInt color ) { - setup2DRenderState(nullptr, DRAW_IMAGE_PRIMITIVE, FALSE); + setup2DRenderState(nullptr, DRAW_IMAGE_ALPHA, FALSE); m_2DRender->Add_Rect( RectClass( startX, startY, startX + width, startY + height ), @@ -2378,7 +2369,7 @@ void W3DDisplay::drawRectClock(Int startX, Int startY, Int width, Int height, In if(percent < 1 || percent > 100) return; - setup2DRenderState(nullptr, DRAW_IMAGE_PRIMITIVE, FALSE); + setup2DRenderState(nullptr, DRAW_IMAGE_ALPHA, FALSE); // The rectangles are numberd as follows //(x,y) |---------| @@ -2543,7 +2534,7 @@ void W3DDisplay::drawRemainingRectClock(Int startX, Int startY, Int width, Int h if( percent < 0 || percent > 99 ) return; - setup2DRenderState(nullptr, DRAW_IMAGE_PRIMITIVE, FALSE); + setup2DRenderState(nullptr, DRAW_IMAGE_ALPHA, FALSE); // The rectangles are numbered as follows //(x,y) |---------| From 6d28a5168719cc99a182fdad474525306cb8835f Mon Sep 17 00:00:00 2001 From: githubawn <115191165+githubawn@users.noreply.github.com> Date: Tue, 31 Mar 2026 21:49:07 +0200 Subject: [PATCH 11/20] properly initialize m_batchNeedsInit in constructor --- .../Source/W3DDevice/GameClient/W3DDisplay.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index 313b149ba43..43fd06213b0 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -408,7 +408,7 @@ W3DDisplay::W3DDisplay() m_batchTexture = nullptr; m_batchMode = DRAW_IMAGE_ALPHA; m_batchGrayscale = FALSE; - m_batchNeedsInit = TRUE; + m_batchNeedsInit = FALSE; } // W3DDisplay::~W3DDisplay ==================================================== @@ -594,12 +594,11 @@ void W3DDisplay::onBeginBatch() m_batchTexture = nullptr; m_batchMode = DRAW_IMAGE_ALPHA; m_batchGrayscale = FALSE; - m_batchNeedsInit = FALSE; - if (m_2DRender) { - setup2DRenderState(nullptr, DRAW_IMAGE_ALPHA, FALSE); + m_2DRender->Reset(); } + m_batchNeedsInit = TRUE; } void W3DDisplay::onEndBatch() @@ -614,9 +613,12 @@ void W3DDisplay::onEndBatch() void W3DDisplay::onFlush() { - if (m_2DRender && !m_batchNeedsInit) + if (m_2DRender) { - m_2DRender->Render(); + if (!m_batchNeedsInit) + { + m_2DRender->Render(); + } m_2DRender->Reset(); m_batchNeedsInit = TRUE; } From 8ddb66e401a78491628717fc1368e24a89e8d50c Mon Sep 17 00:00:00 2001 From: githubawn <115191165+githubawn@users.noreply.github.com> Date: Tue, 31 Mar 2026 22:10:56 +0200 Subject: [PATCH 12/20] fix DRAW_IMAGE_GRAYSCALE to explicitly call Enable_Alpha(TRUE) --- .../GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index 43fd06213b0..a870a01e548 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -681,7 +681,7 @@ void W3DDisplay::setup2DRenderState(TextureClass *tex, DrawImageMode mode, Bool break; case DRAW_IMAGE_GRAYSCALE: m_2DRender->Enable_Additive(FALSE); - m_2DRender->Enable_Alpha(FALSE); + m_2DRender->Enable_Alpha(TRUE); m_2DRender->Enable_Grayscale(TRUE); break; case DRAW_IMAGE_ADDITIVE: From b280e5bfd8bdfc5c7e2b0fe6136716acf09313c8 Mon Sep 17 00:00:00 2001 From: githubawn <115191165+githubawn@users.noreply.github.com> Date: Tue, 31 Mar 2026 22:25:01 +0200 Subject: [PATCH 13/20] optimize m_textRendererHotKey --- .../Source/W3DDevice/GameClient/W3DDisplayString.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplayString.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplayString.cpp index 409295faffa..a473bd6ca21 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplayString.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplayString.cpp @@ -217,6 +217,13 @@ void W3DDisplayString::draw( Int x, Int y, Color color, Color dropColor, Int xDr m_textRenderer.Set_Location( Vector2( m_textPos.x, m_textPos.y ) ); m_textRenderer.Draw_Sentence( m_currTextColor ); + if (m_useHotKey) + { + m_textRendererHotKey.Reset_Polys(); + m_textRendererHotKey.Set_Location( Vector2( m_textPos.x + m_hotKeyPos.x , m_textPos.y +m_hotKeyPos.y) ); + m_textRendererHotKey.Draw_Sentence( m_hotKeyColor ); + } + } if (TheDisplay->isBatching()) @@ -226,9 +233,6 @@ void W3DDisplayString::draw( Int x, Int y, Color color, Color dropColor, Int xDr if(m_useHotKey) { - m_textRendererHotKey.Reset_Polys(); - m_textRendererHotKey.Set_Location( Vector2( m_textPos.x + m_hotKeyPos.x , m_textPos.y +m_hotKeyPos.y) ); - m_textRendererHotKey.Draw_Sentence( m_hotKeyColor ); m_textRendererHotKey.Render(); } From 93132b41cc04be953cf81e9c55b0868d4be33cb3 Mon Sep 17 00:00:00 2001 From: githubawn <115191165+githubawn@users.noreply.github.com> Date: Tue, 31 Mar 2026 22:25:01 +0200 Subject: [PATCH 14/20] optimize m_textRendererHotKey endBatch() is re-entrant-safe Clipping fast-path in drawImage remove Redundant m_isBatching = FALSE --- .../Code/GameEngine/Source/GameClient/Display.cpp | 2 +- .../Source/W3DDevice/GameClient/W3DDisplay.cpp | 3 +-- .../Source/W3DDevice/GameClient/W3DDisplayString.cpp | 10 +++++++--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/Display.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/Display.cpp index 32ac78f3e05..ac42b86bc16 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/Display.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/Display.cpp @@ -405,8 +405,8 @@ void Display::endBatch() { return; } - onEndBatch(); m_isBatching = FALSE; + onEndBatch(); } void Display::flush() diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index a870a01e548..4c2018a5ded 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -404,7 +404,6 @@ W3DDisplay::W3DDisplay() for (i = 0; i < DisplayStringCount; i++) m_displayStrings[i] = nullptr; - m_isBatching = FALSE; m_batchTexture = nullptr; m_batchMode = DRAW_IMAGE_ALPHA; m_batchGrayscale = FALSE; @@ -2750,7 +2749,7 @@ void W3DDisplay::drawImage( const Image *image, Int startX, Int startY, if (m_isClippedEnabled) { //need to clip this quad to clip rectangle - { + if (screen_rect.Left < m_clipRegion.lo.x || screen_rect.Right > m_clipRegion.hi.x || screen_rect.Top < m_clipRegion.lo.y || screen_rect.Bottom > m_clipRegion.hi.y) RectClass clipped_rect; RectClass clipped_uv_rect; diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplayString.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplayString.cpp index 409295faffa..a473bd6ca21 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplayString.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplayString.cpp @@ -217,6 +217,13 @@ void W3DDisplayString::draw( Int x, Int y, Color color, Color dropColor, Int xDr m_textRenderer.Set_Location( Vector2( m_textPos.x, m_textPos.y ) ); m_textRenderer.Draw_Sentence( m_currTextColor ); + if (m_useHotKey) + { + m_textRendererHotKey.Reset_Polys(); + m_textRendererHotKey.Set_Location( Vector2( m_textPos.x + m_hotKeyPos.x , m_textPos.y +m_hotKeyPos.y) ); + m_textRendererHotKey.Draw_Sentence( m_hotKeyColor ); + } + } if (TheDisplay->isBatching()) @@ -226,9 +233,6 @@ void W3DDisplayString::draw( Int x, Int y, Color color, Color dropColor, Int xDr if(m_useHotKey) { - m_textRendererHotKey.Reset_Polys(); - m_textRendererHotKey.Set_Location( Vector2( m_textPos.x + m_hotKeyPos.x , m_textPos.y +m_hotKeyPos.y) ); - m_textRendererHotKey.Draw_Sentence( m_hotKeyColor ); m_textRendererHotKey.Render(); } From 0efede5ad31997f9b4f226bd86d419ffe19b0d2a Mon Sep 17 00:00:00 2001 From: githubawn <115191165+githubawn@users.noreply.github.com> Date: Tue, 31 Mar 2026 23:00:47 +0200 Subject: [PATCH 15/20] add missing curly bracket --- .../GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index 4c2018a5ded..224aa7d2a00 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -2750,6 +2750,7 @@ void W3DDisplay::drawImage( const Image *image, Int startX, Int startY, if (m_isClippedEnabled) { //need to clip this quad to clip rectangle if (screen_rect.Left < m_clipRegion.lo.x || screen_rect.Right > m_clipRegion.hi.x || screen_rect.Top < m_clipRegion.lo.y || screen_rect.Bottom > m_clipRegion.hi.y) + { RectClass clipped_rect; RectClass clipped_uv_rect; From 53badb9ebcb889b3b389153da7a7ce16f2d52f02 Mon Sep 17 00:00:00 2001 From: githubawn <115191165+githubawn@users.noreply.github.com> Date: Tue, 31 Mar 2026 23:34:04 +0200 Subject: [PATCH 16/20] simplify onflush --- .../Source/W3DDevice/GameClient/W3DDisplay.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index 224aa7d2a00..144606bcd29 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -612,12 +612,9 @@ void W3DDisplay::onEndBatch() void W3DDisplay::onFlush() { - if (m_2DRender) + if (m_2DRender && !m_batchNeedsInit) { - if (!m_batchNeedsInit) - { - m_2DRender->Render(); - } + m_2DRender->Render(); m_2DRender->Reset(); m_batchNeedsInit = TRUE; } From 5d9405ae1d25f935cdeb8e1154e62ee8b9b90ac5 Mon Sep 17 00:00:00 2001 From: githubawn <115191165+githubawn@users.noreply.github.com> Date: Wed, 1 Apr 2026 18:58:53 +0200 Subject: [PATCH 17/20] Move HUD batching from GameWindowManager to W3DInGameUI::draw() --- Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp | 3 +++ .../GameEngine/Source/GameClient/GUI/GameWindowManager.cpp | 4 ---- .../Source/W3DDevice/GameClient/W3DInGameUI.cpp | 3 +++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp index 1f913d2af82..f040941a6a5 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp @@ -1880,7 +1880,10 @@ void W3DView::draw() /// @todo we might want to consider wiping this iterate out if there is nothing to post draw // TheGameClient->resetRenderedObjectCount(); + + TheDisplay->beginBatch(); TheGameClient->iterateDrawablesInRegion( &axisAlignedRegion, drawablePostDraw, this ); + TheDisplay->endBatch(); TheGameClient->flushTextBearingDrawables(); diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GameWindowManager.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GameWindowManager.cpp index b2da74cbbef..773c22dd94e 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GameWindowManager.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GameWindowManager.cpp @@ -1269,8 +1269,6 @@ void GameWindowManager::winRepaint() { GameWindow *window, *next; - TheDisplay->beginBatch(); - // draw below windows for( window = m_windowTail; window; window = next ) { @@ -1301,8 +1299,6 @@ void GameWindowManager::winRepaint() if(TheTransitionHandler) TheTransitionHandler->draw(); - - TheDisplay->endBatch(); } //------------------------------------------------------------------------------------------------- diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DInGameUI.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DInGameUI.cpp index 8fd63a0c3fd..d1fb63d2af4 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DInGameUI.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DInGameUI.cpp @@ -387,6 +387,7 @@ void W3DInGameUI::reset() //------------------------------------------------------------------------------------------------- void W3DInGameUI::draw() { + TheDisplay->beginBatch(); preDraw(); // draw selection region if drag selecting @@ -439,6 +440,8 @@ void W3DInGameUI::draw() } #endif + TheDisplay->endBatch(); + } //------------------------------------------------------------------------------------------------- From 13fc7630f92dec6728cf088eed5f79e33c4e1cd6 Mon Sep 17 00:00:00 2001 From: githubawn <115191165+githubawn@users.noreply.github.com> Date: Sun, 5 Apr 2026 03:25:26 +0200 Subject: [PATCH 18/20] replicated to generals --- .../GameEngine/Include/GameClient/Display.h | 9 + .../GameEngine/Source/GameClient/Display.cpp | 26 ++ .../Include/W3DDevice/GameClient/W3DDisplay.h | 11 + .../W3DDevice/GameClient/W3DDisplay.cpp | 247 +++++++++++++----- .../W3DDevice/GameClient/W3DDisplayString.cpp | 15 +- .../W3DDevice/GameClient/W3DInGameUI.cpp | 3 + 6 files changed, 240 insertions(+), 71 deletions(-) diff --git a/Generals/Code/GameEngine/Include/GameClient/Display.h b/Generals/Code/GameEngine/Include/GameClient/Display.h index dab09f09c1a..37cdad97b0e 100644 --- a/Generals/Code/GameEngine/Include/GameClient/Display.h +++ b/Generals/Code/GameEngine/Include/GameClient/Display.h @@ -113,6 +113,11 @@ class Display : public SubsystemInterface virtual Bool isClippingEnabled() = 0; virtual void enableClipping( Bool onoff ) = 0; + virtual void beginBatch(); + virtual void endBatch(); + virtual void flush(); + virtual Bool isBatching() { return m_isBatching; } + virtual void step() {}; ///< Do one fixed time step virtual void draw() override; ///< Redraw the entire display virtual void setTimeOfDay( TimeOfDay tod ) = 0; ///< Set the time of day for this display @@ -182,11 +187,15 @@ class Display : public SubsystemInterface virtual Int getLastFrameDrawCalls() = 0; ///< returns the number of draw calls issued in the previous frame protected: + virtual void onBeginBatch() { } + virtual void onEndBatch() { } + virtual void onFlush() { } virtual void deleteViews(); ///< delete all views UnsignedInt m_width, m_height; ///< Dimensions of the display UnsignedInt m_bitDepth; ///< bit depth of the display Bool m_windowed; ///< TRUE when windowed, FALSE when fullscreen + Bool m_isBatching; View *m_viewList; ///< All of the views into the world // Cinematic text data diff --git a/Generals/Code/GameEngine/Source/GameClient/Display.cpp b/Generals/Code/GameEngine/Source/GameClient/Display.cpp index 770900814e1..6106deeed8c 100644 --- a/Generals/Code/GameEngine/Source/GameClient/Display.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/Display.cpp @@ -66,6 +66,7 @@ Display::Display() m_currentlyPlayingMovie.clear(); m_letterBoxFadeStartTime = 0; + m_isBatching = FALSE; } /** @@ -387,3 +388,28 @@ Display::DebugDisplayCallback *Display::getDebugDisplayCallback() { return m_debugDisplayCallback; } + +void Display::beginBatch() +{ + if (m_isBatching) + { + return; + } + m_isBatching = TRUE; + onBeginBatch(); +} + +void Display::endBatch() +{ + if (!m_isBatching) + { + return; + } + m_isBatching = FALSE; + onEndBatch(); +} + +void Display::flush() +{ + onFlush(); +} diff --git a/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DDisplay.h b/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DDisplay.h index 5f079d4324d..937e2d756ba 100644 --- a/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DDisplay.h +++ b/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DDisplay.h @@ -45,6 +45,7 @@ class Render2DClass; class RTS3DScene; class RTS2DScene; class RTS3DInterfaceScene; +class TextureClass; //============================================================================= @@ -160,6 +161,10 @@ class W3DDisplay : public Display void calculateTerrainLOD(); ///< Calculate terrain LOD. void renderLetterBox(UnsignedInt time); ///< draw letter box border void updateAverageFPS(); ///< calculate the average fps over the last 30 frames. + void setup2DRenderState(TextureClass *tex, DrawImageMode mode, Bool grayscale); + virtual void onBeginBatch() override; + virtual void onEndBatch() override; + virtual void onFlush() override; Byte m_initialized; ///< TRUE when system is initialized LightClass *m_myLight[LightEnvironmentClass::MAX_LIGHTS]; ///< light hack for now @@ -168,6 +173,12 @@ class W3DDisplay : public Display Bool m_isClippedEnabled; ///Reset(); + } + m_batchNeedsInit = TRUE; +} + +void W3DDisplay::onEndBatch() +{ + onFlush(); + if (m_batchTexture) + { + m_batchTexture->Release_Ref(); + m_batchTexture = nullptr; + } +} + +void W3DDisplay::onFlush() +{ + if (m_2DRender && !m_batchNeedsInit) + { + m_2DRender->Render(); + m_2DRender->Reset(); + m_batchNeedsInit = TRUE; + } +} + +void W3DDisplay::setup2DRenderState(TextureClass *tex, DrawImageMode mode, Bool grayscale) +{ + if (m_isBatching) + { + if (!m_batchNeedsInit && m_batchTexture == tex && m_batchMode == mode && m_batchGrayscale == grayscale) + { + return; + } + + onFlush(); + + if (tex != m_batchTexture) + { + if (tex) + { + tex->Add_Ref(); + } + if (m_batchTexture) + { + m_batchTexture->Release_Ref(); + } + m_batchTexture = tex; + } + + m_batchMode = mode; + m_batchGrayscale = grayscale; + m_batchNeedsInit = FALSE; + } + else + { + if (m_2DRender) + { + m_2DRender->Reset(); + } + } + + if (m_2DRender) + { + if (tex) + { + m_2DRender->Enable_Texturing(TRUE); + m_2DRender->Set_Texture(tex); + } + else + { + m_2DRender->Enable_Texturing(FALSE); + } + + switch (mode) + { + case DRAW_IMAGE_ALPHA: + m_2DRender->Enable_Additive(FALSE); + m_2DRender->Enable_Alpha(TRUE); + m_2DRender->Enable_Grayscale(grayscale); + break; + case DRAW_IMAGE_GRAYSCALE: + m_2DRender->Enable_Additive(FALSE); + m_2DRender->Enable_Alpha(TRUE); + m_2DRender->Enable_Grayscale(TRUE); + break; + case DRAW_IMAGE_ADDITIVE: + m_2DRender->Enable_Additive(TRUE); + m_2DRender->Enable_Alpha(FALSE); + m_2DRender->Enable_Grayscale(grayscale); + break; + case DRAW_IMAGE_SOLID: + m_2DRender->Enable_Additive(FALSE); + m_2DRender->Enable_Alpha(FALSE); + m_2DRender->Enable_Grayscale(grayscale); + break; + } + } +} + // W3DDisplay::initAssets ===================================================== /** */ //============================================================================= @@ -2039,13 +2149,14 @@ void W3DDisplay::drawLine( Int startX, Int startY, Real lineWidth, UnsignedInt lineColor ) { + setup2DRenderState(nullptr, DRAW_IMAGE_ALPHA, FALSE); - /// @todo we need to consider the efficiency of the 2D renderer - m_2DRender->Reset(); - m_2DRender->Enable_Texturing( FALSE ); m_2DRender->Add_Line( Vector2( startX, startY ), Vector2( endX, endY ), lineWidth, lineColor ); - m_2DRender->Render(); + if (!m_isBatching) + { + m_2DRender->Render(); + } } @@ -2057,13 +2168,15 @@ void W3DDisplay::drawLine( Int startX, Int startY, Real lineWidth, UnsignedInt lineColor1,UnsignedInt lineColor2 ) { + setup2DRenderState(nullptr, DRAW_IMAGE_ALPHA, FALSE); - /// @todo we need to consider the efficiency of the 2D renderer - m_2DRender->Reset(); - m_2DRender->Enable_Texturing( FALSE ); m_2DRender->Add_Line( Vector2( startX, startY ), Vector2( endX, endY ), lineWidth, lineColor1, lineColor2 ); - m_2DRender->Render(); + + if (!m_isBatching) + { + m_2DRender->Render(); + } } @@ -2106,16 +2219,17 @@ void W3DDisplay::drawOpenRect( Int startX, Int startY, Int width, Int height, } else { - /// @todo we need to consider the efficiency of the 2D renderer - m_2DRender->Reset(); - m_2DRender->Enable_Texturing( FALSE ); + setup2DRenderState(nullptr, DRAW_IMAGE_ALPHA, FALSE); m_2DRender->Add_Outline( RectClass( startX, startY, startX + width, startY + height ), lineWidth, lineColor ); // render it now! - m_2DRender->Render(); + if (!m_isBatching) + { + m_2DRender->Render(); + } } } @@ -2125,17 +2239,17 @@ void W3DDisplay::drawOpenRect( Int startX, Int startY, Int width, Int height, void W3DDisplay::drawFillRect( Int startX, Int startY, Int width, Int height, UnsignedInt color ) { + setup2DRenderState(nullptr, DRAW_IMAGE_ALPHA, FALSE); - /// @todo we need to consider the efficiency of the 2D renderer - m_2DRender->Reset(); - m_2DRender->Enable_Texturing( FALSE ); m_2DRender->Add_Rect( RectClass( startX, startY, startX + width, startY + height ), 0, 0, color ); // render it now! - m_2DRender->Render(); - + if (!m_isBatching) + { + m_2DRender->Render(); + } } void W3DDisplay::drawRectClock(Int startX, Int startY, Int width, Int height, Int percent, UnsignedInt color) @@ -2144,8 +2258,7 @@ void W3DDisplay::drawRectClock(Int startX, Int startY, Int width, Int height, In if(percent < 1 || percent > 100) return; - m_2DRender->Reset(); - m_2DRender->Enable_Texturing( FALSE ); + setup2DRenderState(nullptr, DRAW_IMAGE_ALPHA, FALSE); // The rectanges are numberd as follows //(x,y) |---------| @@ -2291,8 +2404,10 @@ void W3DDisplay::drawRectClock(Int startX, Int startY, Int width, Int height, In } // render it now! - m_2DRender->Render(); - + if (!m_isBatching) + { + m_2DRender->Render(); + } } @@ -2470,7 +2585,10 @@ void W3DDisplay::drawRemainingRectClock(Int startX, Int startY, Int width, Int h } // render it now! - m_2DRender->Render(); + if (!m_isBatching) + { + m_2DRender->Render(); + } } @@ -2486,6 +2604,17 @@ void W3DDisplay::drawImage( const Image *image, Int startX, Int startY, if( image == nullptr ) return; + if (m_isClippedEnabled) + { + if ( endX <= m_clipRegion.lo.x || + endY <= m_clipRegion.lo.y || + startX >= m_clipRegion.hi.x || + startY >= m_clipRegion.hi.y) + { + return; //nothing to render + } + } + // !! // Remember to update the GUIEditDisplay::drawImage when you make // changes to this, it technically uses W3D code to render itself, @@ -2494,52 +2623,23 @@ void W3DDisplay::drawImage( const Image *image, Int startX, Int startY, const Region2D *uv = image->getUV(); - m_2DRender->Reset(); - m_2DRender->Enable_Texturing( TRUE ); - - Bool doAlphaReset=FALSE; + TextureClass *tex = nullptr; + if (BitIsSet(image->getStatus(), IMAGE_STATUS_RAW_TEXTURE)) + tex = (TextureClass *)(image->getRawTextureData()); + else + tex = WW3DAssetManager::Get_Instance()->Get_Texture(image->getFilename().str(), MIP_LEVELS_1); + Bool grayscale = (mode == DRAW_IMAGE_GRAYSCALE); ///@todo: Why are we alpha blending all images? Reduces our fillrate. -MW - switch (mode) - { - case DRAW_IMAGE_ALPHA: //nothing to do since alpha is the default state - break; - case DRAW_IMAGE_GRAYSCALE: - m_2DRender->Enable_Grayscale(true); - break; - case DRAW_IMAGE_ADDITIVE: - m_2DRender->Enable_Additive(true); - doAlphaReset = TRUE; - break; - case DRAW_IMAGE_SOLID: - m_2DRender->Enable_Additive(false); - m_2DRender->Enable_Alpha(false); - doAlphaReset = TRUE; - break; - default: - break; - } - - // if we have raw texture data we will use it, otherwise we are referencing filenames - if( BitIsSet( image->getStatus(), IMAGE_STATUS_RAW_TEXTURE ) ) - m_2DRender->Set_Texture( (TextureClass *)(image->getRawTextureData()) ); - else - m_2DRender->Set_Texture( image->getFilename().str() ); + setup2DRenderState(tex, mode, grayscale); RectClass screen_rect(startX,startY,endX,endY); RectClass uv_rect(uv->lo.x,uv->lo.y,uv->hi.x,uv->hi.y); if (m_isClippedEnabled) { //need to clip this quad to clip rectangle - - // - // Check for completely clipped - // - if ( endX <= m_clipRegion.lo.x || - endY <= m_clipRegion.lo.y) + if (screen_rect.Left < m_clipRegion.lo.x || screen_rect.Right > m_clipRegion.hi.x || screen_rect.Top < m_clipRegion.lo.y || screen_rect.Bottom > m_clipRegion.hi.y) { - return; //nothing to render - } else { RectClass clipped_rect; RectClass clipped_uv_rect; @@ -2639,12 +2739,20 @@ void W3DDisplay::drawImage( const Image *image, Int startX, Int startY, } - m_2DRender->Render(); + if (!m_isBatching) + { + m_2DRender->Render(); + m_2DRender->Enable_Grayscale(false); + if (mode == DRAW_IMAGE_ADDITIVE || mode == DRAW_IMAGE_SOLID) + { + m_2DRender->Enable_Alpha(true); + } + } - //reset to default states for next time this method is called. - m_2DRender->Enable_Grayscale(false); //never leave it in this mode - if (doAlphaReset) - m_2DRender->Enable_Alpha(true); + if (tex != nullptr && !BitIsSet(image->getStatus(), IMAGE_STATUS_RAW_TEXTURE)) + { + tex->Release_Ref(); + } } @@ -2746,12 +2854,15 @@ void W3DDisplay::drawVideoBuffer( VideoBuffer *buffer, Int startX, Int startY, I { W3DVideoBuffer *vbuffer = (W3DVideoBuffer*) buffer; - m_2DRender->Reset(); - m_2DRender->Enable_Texturing( TRUE ); - m_2DRender->Set_Texture( vbuffer->texture() ); + setup2DRenderState(vbuffer->texture(), DRAW_IMAGE_ALPHA, FALSE); + m_2DRender->Add_Quad( RectClass( startX, startY, endX, endY ), vbuffer->Rect( 0, 0, 1, 1) ); - m_2DRender->Render(); + + if (!m_isBatching) + { + m_2DRender->Render(); + } } diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplayString.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplayString.cpp index 8b046b02ffd..b670f8c9103 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplayString.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplayString.cpp @@ -49,6 +49,7 @@ #include // USER INCLUDES ////////////////////////////////////////////////////////////// +#include "GameClient/Display.h" #include "GameClient/GameClient.h" #include "W3DDevice/GameClient/W3DDisplayString.h" #include "GameClient/HotKey.h" @@ -216,17 +217,25 @@ void W3DDisplayString::draw( Int x, Int y, Color color, Color dropColor, Int xDr m_textRenderer.Set_Location( Vector2( m_textPos.x, m_textPos.y ) ); m_textRenderer.Draw_Sentence( m_currTextColor ); - if(m_useHotKey) + if (m_useHotKey) { m_textRendererHotKey.Reset_Polys(); m_textRendererHotKey.Set_Location( Vector2( m_textPos.x + m_hotKeyPos.x , m_textPos.y +m_hotKeyPos.y) ); m_textRendererHotKey.Draw_Sentence( m_hotKeyColor ); - m_textRendererHotKey.Render(); } } - // render the text + if (TheDisplay->isBatching()) + { + TheDisplay->flush(); + } + + if(m_useHotKey) + { + m_textRendererHotKey.Render(); + } + m_textRenderer.Render(); // we are for sure using display resources now diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DInGameUI.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DInGameUI.cpp index dec0b3a473d..c85dd43ab0b 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DInGameUI.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DInGameUI.cpp @@ -387,6 +387,7 @@ void W3DInGameUI::reset() //------------------------------------------------------------------------------------------------- void W3DInGameUI::draw() { + TheDisplay->beginBatch(); preDraw(); // draw selection region if drag selecting @@ -439,6 +440,8 @@ void W3DInGameUI::draw() } #endif + TheDisplay->endBatch(); + } //------------------------------------------------------------------------------------------------- From 667d24d373a6e24ade5a02b032cda20885c15768 Mon Sep 17 00:00:00 2001 From: githubawn <115191165+githubawn@users.noreply.github.com> Date: Mon, 6 Apr 2026 20:58:46 +0200 Subject: [PATCH 19/20] implement review feedback --- .../GameEngine/Source/GameClient/Display.cpp | 5 +- .../W3DDevice/GameClient/W3DDisplay.cpp | 52 +++++++++---------- .../W3DDevice/GameClient/W3DDisplayString.cpp | 5 +- .../GameEngine/Source/GameClient/Display.cpp | 5 +- .../W3DDevice/GameClient/W3DDisplay.cpp | 52 +++++++++---------- .../W3DDevice/GameClient/W3DDisplayString.cpp | 5 +- 6 files changed, 60 insertions(+), 64 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameClient/Display.cpp b/Generals/Code/GameEngine/Source/GameClient/Display.cpp index 6106deeed8c..c75fcaa0399 100644 --- a/Generals/Code/GameEngine/Source/GameClient/Display.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/Display.cpp @@ -411,5 +411,8 @@ void Display::endBatch() void Display::flush() { - onFlush(); + if (m_isBatching) + { + onFlush(); + } } diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index 46eb7663f23..abd057eeaae 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -543,11 +543,12 @@ void W3DDisplay::onBeginBatch() m_batchTexture = nullptr; m_batchMode = DRAW_IMAGE_ALPHA; m_batchGrayscale = FALSE; + m_batchNeedsInit = TRUE; + if (m_2DRender) { m_2DRender->Reset(); } - m_batchNeedsInit = TRUE; } void W3DDisplay::onEndBatch() @@ -591,6 +592,7 @@ void W3DDisplay::setup2DRenderState(TextureClass *tex, DrawImageMode mode, Bool { m_batchTexture->Release_Ref(); } + m_batchTexture = tex; } @@ -598,12 +600,9 @@ void W3DDisplay::setup2DRenderState(TextureClass *tex, DrawImageMode mode, Bool m_batchGrayscale = grayscale; m_batchNeedsInit = FALSE; } - else + else if (m_2DRender) { - if (m_2DRender) - { - m_2DRender->Reset(); - } + m_2DRender->Reset(); } if (m_2DRender) @@ -620,26 +619,26 @@ void W3DDisplay::setup2DRenderState(TextureClass *tex, DrawImageMode mode, Bool switch (mode) { - case DRAW_IMAGE_ALPHA: - m_2DRender->Enable_Additive(FALSE); - m_2DRender->Enable_Alpha(TRUE); - m_2DRender->Enable_Grayscale(grayscale); - break; - case DRAW_IMAGE_GRAYSCALE: - m_2DRender->Enable_Additive(FALSE); - m_2DRender->Enable_Alpha(TRUE); - m_2DRender->Enable_Grayscale(TRUE); - break; - case DRAW_IMAGE_ADDITIVE: - m_2DRender->Enable_Additive(TRUE); - m_2DRender->Enable_Alpha(FALSE); - m_2DRender->Enable_Grayscale(grayscale); - break; - case DRAW_IMAGE_SOLID: - m_2DRender->Enable_Additive(FALSE); - m_2DRender->Enable_Alpha(FALSE); - m_2DRender->Enable_Grayscale(grayscale); - break; + case DRAW_IMAGE_ALPHA: + m_2DRender->Enable_Additive(FALSE); + m_2DRender->Enable_Alpha(TRUE); + m_2DRender->Enable_Grayscale(grayscale); + break; + case DRAW_IMAGE_GRAYSCALE: + m_2DRender->Enable_Additive(FALSE); + m_2DRender->Enable_Alpha(TRUE); + m_2DRender->Enable_Grayscale(TRUE); + break; + case DRAW_IMAGE_ADDITIVE: + m_2DRender->Enable_Additive(TRUE); + m_2DRender->Enable_Alpha(FALSE); + m_2DRender->Enable_Grayscale(grayscale); + break; + case DRAW_IMAGE_SOLID: + m_2DRender->Enable_Additive(FALSE); + m_2DRender->Enable_Alpha(FALSE); + m_2DRender->Enable_Grayscale(grayscale); + break; } } } @@ -2630,7 +2629,6 @@ void W3DDisplay::drawImage( const Image *image, Int startX, Int startY, tex = WW3DAssetManager::Get_Instance()->Get_Texture(image->getFilename().str(), MIP_LEVELS_1); Bool grayscale = (mode == DRAW_IMAGE_GRAYSCALE); - ///@todo: Why are we alpha blending all images? Reduces our fillrate. -MW setup2DRenderState(tex, mode, grayscale); RectClass screen_rect(startX,startY,endX,endY); diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplayString.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplayString.cpp index b670f8c9103..b2dd25e12ff 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplayString.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplayString.cpp @@ -226,10 +226,7 @@ void W3DDisplayString::draw( Int x, Int y, Color color, Color dropColor, Int xDr } - if (TheDisplay->isBatching()) - { - TheDisplay->flush(); - } + TheDisplay->flush(); if(m_useHotKey) { diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/Display.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/Display.cpp index ac42b86bc16..65422dcb50a 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/Display.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/Display.cpp @@ -411,5 +411,8 @@ void Display::endBatch() void Display::flush() { - onFlush(); + if (m_isBatching) + { + onFlush(); + } } diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index 144606bcd29..2c5bc23d57c 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -593,11 +593,12 @@ void W3DDisplay::onBeginBatch() m_batchTexture = nullptr; m_batchMode = DRAW_IMAGE_ALPHA; m_batchGrayscale = FALSE; + m_batchNeedsInit = TRUE; + if (m_2DRender) { m_2DRender->Reset(); } - m_batchNeedsInit = TRUE; } void W3DDisplay::onEndBatch() @@ -641,6 +642,7 @@ void W3DDisplay::setup2DRenderState(TextureClass *tex, DrawImageMode mode, Bool { m_batchTexture->Release_Ref(); } + m_batchTexture = tex; } @@ -648,12 +650,9 @@ void W3DDisplay::setup2DRenderState(TextureClass *tex, DrawImageMode mode, Bool m_batchGrayscale = grayscale; m_batchNeedsInit = FALSE; } - else + else if (m_2DRender) { - if (m_2DRender) - { - m_2DRender->Reset(); - } + m_2DRender->Reset(); } if (m_2DRender) @@ -670,26 +669,26 @@ void W3DDisplay::setup2DRenderState(TextureClass *tex, DrawImageMode mode, Bool switch (mode) { - case DRAW_IMAGE_ALPHA: - m_2DRender->Enable_Additive(FALSE); - m_2DRender->Enable_Alpha(TRUE); - m_2DRender->Enable_Grayscale(grayscale); - break; - case DRAW_IMAGE_GRAYSCALE: - m_2DRender->Enable_Additive(FALSE); - m_2DRender->Enable_Alpha(TRUE); - m_2DRender->Enable_Grayscale(TRUE); - break; - case DRAW_IMAGE_ADDITIVE: - m_2DRender->Enable_Additive(TRUE); - m_2DRender->Enable_Alpha(FALSE); - m_2DRender->Enable_Grayscale(grayscale); - break; - case DRAW_IMAGE_SOLID: - m_2DRender->Enable_Additive(FALSE); - m_2DRender->Enable_Alpha(FALSE); - m_2DRender->Enable_Grayscale(grayscale); - break; + case DRAW_IMAGE_ALPHA: + m_2DRender->Enable_Additive(FALSE); + m_2DRender->Enable_Alpha(TRUE); + m_2DRender->Enable_Grayscale(grayscale); + break; + case DRAW_IMAGE_GRAYSCALE: + m_2DRender->Enable_Additive(FALSE); + m_2DRender->Enable_Alpha(TRUE); + m_2DRender->Enable_Grayscale(TRUE); + break; + case DRAW_IMAGE_ADDITIVE: + m_2DRender->Enable_Additive(TRUE); + m_2DRender->Enable_Alpha(FALSE); + m_2DRender->Enable_Grayscale(grayscale); + break; + case DRAW_IMAGE_SOLID: + m_2DRender->Enable_Additive(FALSE); + m_2DRender->Enable_Alpha(FALSE); + m_2DRender->Enable_Grayscale(grayscale); + break; } } } @@ -2738,7 +2737,6 @@ void W3DDisplay::drawImage( const Image *image, Int startX, Int startY, tex = WW3DAssetManager::Get_Instance()->Get_Texture(image->getFilename().str(), MIP_LEVELS_1); Bool grayscale = (mode == DRAW_IMAGE_GRAYSCALE); - ///@todo: Why are we alpha blending all images? Reduces our fillrate. -MW setup2DRenderState(tex, mode, grayscale); RectClass screen_rect(startX,startY,endX,endY); diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplayString.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplayString.cpp index a473bd6ca21..55071200656 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplayString.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplayString.cpp @@ -226,10 +226,7 @@ void W3DDisplayString::draw( Int x, Int y, Color color, Color dropColor, Int xDr } - if (TheDisplay->isBatching()) - { - TheDisplay->flush(); - } + TheDisplay->flush(); if(m_useHotKey) { From 8bec2154d18f799918c22af56a7302aa8cc40eb6 Mon Sep 17 00:00:00 2001 From: githubawn <115191165+githubawn@users.noreply.github.com> Date: Mon, 6 Apr 2026 21:34:57 +0200 Subject: [PATCH 20/20] fix generals replication --- .../Source/W3DDevice/GameClient/W3DDisplay.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index abd057eeaae..9eaf819745c 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -2422,8 +2422,7 @@ void W3DDisplay::drawRemainingRectClock(Int startX, Int startY, Int width, Int h if( percent < 0 || percent > 99 ) return; - m_2DRender->Reset(); - m_2DRender->Enable_Texturing( FALSE ); + setup2DRenderState(nullptr, DRAW_IMAGE_ALPHA, FALSE); // The rectanges are numbered as follows //(x,y) |---------|