From 95048af484f59b2686629524f2e386e5102d9135 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sat, 10 Jan 2026 21:32:52 +0100 Subject: [PATCH 1/4] fix(radar): Fix Radar pixel color format for non A8R8B8G8 surfaces --- .../Include/W3DDevice/Common/W3DRadar.h | 1 + .../W3DDevice/Common/System/W3DRadar.cpp | 44 ++++++--- .../Source/WWVegas/WW3D2/ww3dformat.cpp | 96 +++++++++++++++++++ .../Source/WWVegas/WW3D2/ww3dformat.h | 2 + 4 files changed, 128 insertions(+), 15 deletions(-) diff --git a/Core/GameEngineDevice/Include/W3DDevice/Common/W3DRadar.h b/Core/GameEngineDevice/Include/W3DDevice/Common/W3DRadar.h index 38d650e6a09..81d15815268 100644 --- a/Core/GameEngineDevice/Include/W3DDevice/Common/W3DRadar.h +++ b/Core/GameEngineDevice/Include/W3DDevice/Common/W3DRadar.h @@ -110,6 +110,7 @@ class W3DRadar : public Radar SurfaceClass *m_shroudSurface; ///< surface to shroud texture void *m_shroudSurfaceBits; ///< shroud surface bits int m_shroudSurfacePitch; ///< shroud surface pitch + WW3DFormat m_shroudSurfaceFormat; ///< shroud surface format UnsignedInt m_shroudSurfacePixelSize; ///< shroud surface pixel size Int m_textureWidth; ///< width for all radar textures diff --git a/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp b/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp index 065d725184d..4feafc4164c 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp @@ -700,9 +700,11 @@ void W3DRadar::renderObjectList( const RadarObject *listHead, TextureClass *text Player *player = rts::getObservedOrLocalPlayer(); + SurfaceClass::SurfaceDescription surfaceDesc; + surface->Get_Description(surfaceDesc); int pitch; void *pBits = surface->Lock(&pitch); - const unsigned int bytesPerPixel = surface->Get_Bytes_Per_Pixel(); + const unsigned int bytesPerPixel = Get_Bytes_Per_Pixel(surfaceDesc.Format); for( const RadarObject *rObj = listHead; rObj; rObj = rObj->friend_getNext() ) { @@ -718,7 +720,7 @@ void W3DRadar::renderObjectList( const RadarObject *listHead, TextureClass *text radarPoint.y = pos->y / (m_mapExtent.height() / RADAR_CELL_HEIGHT); // get the color we're going to draw in - Color c = rObj->getColor(); + Color color = rObj->getColor(); // adjust the alpha for stealth units so they "fade/blink" on the radar for the controller // if( obj->getRadarPriority() == RADAR_PRIORITY_LOCAL_UNIT_ONLY ) @@ -727,7 +729,7 @@ void W3DRadar::renderObjectList( const RadarObject *listHead, TextureClass *text if( obj->testStatus( OBJECT_STATUS_STEALTHED ) ) { UnsignedByte r, g, b, a; - GameGetColorComponents( c, &r, &g, &b, &a ); + GameGetColorComponents( color, &r, &g, &b, &a ); const UnsignedInt framesForTransition = LOGICFRAMES_PER_SECOND; const UnsignedByte minAlpha = 32; @@ -737,25 +739,27 @@ void W3DRadar::renderObjectList( const RadarObject *listHead, TextureClass *text a = REAL_TO_UNSIGNEDBYTE( ((alphaScale - 1.0f) * (255.0f - minAlpha)) + minAlpha ); else a = REAL_TO_UNSIGNEDBYTE( (alphaScale * (255.0f - minAlpha)) + minAlpha ); - c = GameMakeColor( r, g, b, a ); + color = GameMakeColor( r, g, b, a ); } + color = ARGB_Color_To_WW3D_Color(surfaceDesc.Format, color); + // draw the blip, but make sure the points are legal if( legalRadarPoint( radarPoint.x, radarPoint.y ) ) - surface->Draw_Pixel( radarPoint.x, radarPoint.y, c, bytesPerPixel, pBits, pitch ); + surface->Draw_Pixel( radarPoint.x, radarPoint.y, color, bytesPerPixel, pBits, pitch ); radarPoint.y++; if( legalRadarPoint( radarPoint.x, radarPoint.y ) ) - surface->Draw_Pixel( radarPoint.x, radarPoint.y, c, bytesPerPixel, pBits, pitch ); + surface->Draw_Pixel( radarPoint.x, radarPoint.y, color, bytesPerPixel, pBits, pitch ); radarPoint.x++; if( legalRadarPoint( radarPoint.x, radarPoint.y ) ) - surface->Draw_Pixel( radarPoint.x, radarPoint.y, c, bytesPerPixel, pBits, pitch ); + surface->Draw_Pixel( radarPoint.x, radarPoint.y, color, bytesPerPixel, pBits, pitch ); radarPoint.y--; if( legalRadarPoint( radarPoint.x, radarPoint.y ) ) - surface->Draw_Pixel( radarPoint.x, radarPoint.y, c, bytesPerPixel, pBits, pitch ); + surface->Draw_Pixel( radarPoint.x, radarPoint.y, color, bytesPerPixel, pBits, pitch ); } @@ -860,6 +864,7 @@ W3DRadar::W3DRadar( void ) m_shroudSurface = nullptr; m_shroudSurfaceBits = nullptr; m_shroudSurfacePitch = 0; + m_shroudSurfaceFormat = WW3D_FORMAT_UNKNOWN; m_shroudSurfacePixelSize = 0; m_textureWidth = RADAR_CELL_WIDTH; @@ -1078,9 +1083,11 @@ void W3DRadar::buildTerrainTexture( TerrainLogic *terrain ) Coord3D worldPoint; Bridge *bridge; + SurfaceClass::SurfaceDescription surfaceDesc; + surface->Get_Description(surfaceDesc); int pitch; void *pBits = surface->Lock(&pitch); - const unsigned int bytesPerPixel = surface->Get_Bytes_Per_Pixel(); + const unsigned int bytesPerPixel = Get_Bytes_Per_Pixel(surfaceDesc.Format); for( y = 0; y < m_textureHeight; y++ ) { @@ -1270,6 +1277,7 @@ void W3DRadar::buildTerrainTexture( TerrainLogic *terrain ) // draw the pixel for the terrain at this point, note that because of the orientation // of our world we draw it with positive y in the "up" direction Color pixelColor = GameMakeColor( color.red * 255, color.green * 255, color.blue * 255, 255 ); + pixelColor = ARGB_Color_To_WW3D_Color(surfaceDesc.Format, pixelColor); surface->Draw_Pixel( x, y, pixelColor, bytesPerPixel, pBits, pitch ); } @@ -1364,10 +1372,13 @@ void W3DRadar::setShroudLevel(Int shroudX, Int shroudY, CellShroudStatus setting // This is expensive. SurfaceClass* surface = m_shroudTexture->Get_Surface_Level(); DEBUG_ASSERTCRASH( surface, ("W3DRadar: Can't get surface for Shroud texture") ); + SurfaceClass::SurfaceDescription surfaceDesc; + surface->Get_Description(surfaceDesc); int pitch; void *pBits = surface->Lock(&pitch); - const unsigned int bytesPerPixel = surface->Get_Bytes_Per_Pixel(); - const Color color = GameMakeColor( 0, 0, 0, alpha ); + const unsigned int bytesPerPixel = Get_Bytes_Per_Pixel(surfaceDesc.Format); + Color color = GameMakeColor( 0, 0, 0, alpha ); + color = ARGB_Color_To_WW3D_Color(surfaceDesc.Format, color); for( Int y = radarMinY; y <= radarMaxY; ++y ) { @@ -1384,8 +1395,10 @@ void W3DRadar::setShroudLevel(Int shroudX, Int shroudY, CellShroudStatus setting { // This is cheap. DEBUG_ASSERTCRASH(m_shroudSurfaceBits != nullptr, ("W3DRadar::setShroudLevel: m_shroudSurfaceBits is not expected null")); + DEBUG_ASSERTCRASH(m_shroudSurfaceFormat != WW3D_FORMAT_UNKNOWN, ("W3DRadar::setShroudLevel: m_shroudSurfaceFormat is not expected UNKNOWN")); DEBUG_ASSERTCRASH(m_shroudSurfacePixelSize != 0, ("W3DRadar::setShroudLevel: m_shroudSurfacePixelSize is not expected 0")); - const Color color = GameMakeColor( 0, 0, 0, alpha ); + Color color = GameMakeColor( 0, 0, 0, alpha ); + color = ARGB_Color_To_WW3D_Color(m_shroudSurfaceFormat, color); for( Int y = radarMinY; y <= radarMaxY; ++y ) { @@ -1403,10 +1416,11 @@ void W3DRadar::beginSetShroudLevel() m_shroudSurface = m_shroudTexture->Get_Surface_Level(); DEBUG_ASSERTCRASH( m_shroudSurface != nullptr, ("W3DRadar::beginSetShroudLevel: Can't get surface for Shroud texture") ); - SurfaceClass::SurfaceDescription sd; - m_shroudSurface->Get_Description(sd); + SurfaceClass::SurfaceDescription surfaceDesc; + m_shroudSurface->Get_Description(surfaceDesc); m_shroudSurfaceBits = m_shroudSurface->Lock(&m_shroudSurfacePitch); - m_shroudSurfacePixelSize = Get_Bytes_Per_Pixel(sd.Format); + m_shroudSurfaceFormat = surfaceDesc.Format; + m_shroudSurfacePixelSize = Get_Bytes_Per_Pixel(surfaceDesc.Format); } void W3DRadar::endSetShroudLevel() diff --git a/Core/Libraries/Source/WWVegas/WW3D2/ww3dformat.cpp b/Core/Libraries/Source/WWVegas/WW3D2/ww3dformat.cpp index accec5da22b..0c867868458 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/ww3dformat.cpp +++ b/Core/Libraries/Source/WWVegas/WW3D2/ww3dformat.cpp @@ -422,6 +422,102 @@ unsigned Get_Bytes_Per_Pixel(WW3DFormat format) return 0; } +unsigned ARGB_Color_To_WW3D_Color(WW3DFormat format, unsigned argb) +{ + unsigned a = (argb >> 24) & 0xFF; + unsigned r = (argb >> 16) & 0xFF; + unsigned g = (argb >> 8) & 0xFF; + unsigned b = (argb >> 0) & 0xFF; + + switch (format) + { + case WW3D_FORMAT_R8G8B8: + return (r << 16) | (g << 8) | b; + + case WW3D_FORMAT_A8R8G8B8: + return (a << 24) | (r << 16) | (g << 8) | b; + + case WW3D_FORMAT_X8R8G8B8: + return (0xFF << 24) | (r << 16) | (g << 8) | b; + + case WW3D_FORMAT_R5G6B5: + return ((r >> 3) << 11) | + ((g >> 2) << 5) | + ((b >> 3) << 0); + + case WW3D_FORMAT_X1R5G5B5: + return ( 1 << 15) | + ((r >> 3) << 10) | + ((g >> 3) << 5) | + ((b >> 3) << 0); + + case WW3D_FORMAT_A1R5G5B5: + return ((a >> 7) << 15) | + ((r >> 3) << 10) | + ((g >> 3) << 5) | + ((b >> 3) << 0); + + case WW3D_FORMAT_A4R4G4B4: + return ((a >> 4) << 12) | + ((r >> 4) << 8) | + ((g >> 4) << 4) | + ((b >> 4) << 0); + + case WW3D_FORMAT_R3G3B2: + return ((r >> 5) << 5) | + ((g >> 5) << 2) | + ((b >> 6) << 0); + + case WW3D_FORMAT_A8: + return a; + + case WW3D_FORMAT_A8R3G3B2: + return ( a << 8) | + ((r >> 5) << 5) | + ((g >> 5) << 2) | + ((b >> 6) << 0); + + case WW3D_FORMAT_X4R4G4B4: + return ( 0xF << 12) | + ((r >> 4) << 8) | + ((g >> 4) << 4) | + ((b >> 4) << 0); + + case WW3D_FORMAT_L8: + { + unsigned l = (r * 77 + g * 150 + b * 29) >> 8; + return l; + } + + case WW3D_FORMAT_A8L8: + { + unsigned l = (r * 77 + g * 150 + b * 29) >> 8; + return (a << 8) | l; + } + + case WW3D_FORMAT_A4L4: + { + unsigned l = (r * 77 + g * 150 + b * 29) >> 8; + return ((a >> 4) << 4) | (l >> 4); + } + + // Palettized, bump-map, and compressed formats + // cannot be represented by a single ARGB color + case WW3D_FORMAT_P8: + case WW3D_FORMAT_A8P8: + case WW3D_FORMAT_U8V8: + case WW3D_FORMAT_L6V5U5: + case WW3D_FORMAT_X8L8V8U8: + case WW3D_FORMAT_DXT1: + case WW3D_FORMAT_DXT2: + case WW3D_FORMAT_DXT3: + case WW3D_FORMAT_DXT4: + case WW3D_FORMAT_DXT5: + default: + return 0; + } +} + unsigned Get_Num_Depth_Bits(WW3DZFormat zformat) { switch (zformat) diff --git a/Core/Libraries/Source/WWVegas/WW3D2/ww3dformat.h b/Core/Libraries/Source/WWVegas/WW3D2/ww3dformat.h index e9f9d898742..ade7aa7cbc7 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/ww3dformat.h +++ b/Core/Libraries/Source/WWVegas/WW3D2/ww3dformat.h @@ -195,6 +195,8 @@ WW3DFormat Get_Valid_Texture_Format(WW3DFormat format,bool is_compression_allowe unsigned Get_Bytes_Per_Pixel(WW3DFormat format); +unsigned ARGB_Color_To_WW3D_Color(WW3DFormat format, unsigned argb); + void Get_WW3D_Format_Name(WW3DFormat format, StringClass& name); void Get_WW3D_ZFormat_Name(WW3DZFormat format, StringClass& name); From bcffca5eef929af06982430801d22bca93549614 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Thu, 22 Jan 2026 23:19:30 +0100 Subject: [PATCH 2/4] Set m_shroudSurfaceFormat to unknown --- .../GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp b/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp index 4feafc4164c..676bc37bd27 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp @@ -1431,6 +1431,7 @@ void W3DRadar::endSetShroudLevel() m_shroudSurface->Unlock(); m_shroudSurfaceBits = nullptr; m_shroudSurfacePitch = 0; + m_shroudSurfaceFormat = WW3D_FORMAT_UNKNOWN; m_shroudSurfacePixelSize = 0; } REF_PTR_RELEASE(m_shroudSurface); From 64d1bf012fbdcf2f89dc4812cdfcaf9bada9b068 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Wed, 28 Jan 2026 22:27:14 +0100 Subject: [PATCH 3/4] Rename color names --- .../W3DDevice/Common/System/W3DRadar.cpp | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp b/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp index 676bc37bd27..d8a9f812486 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp @@ -743,23 +743,23 @@ void W3DRadar::renderObjectList( const RadarObject *listHead, TextureClass *text } - color = ARGB_Color_To_WW3D_Color(surfaceDesc.Format, color); + const unsigned int pixelColor = ARGB_Color_To_WW3D_Color(surfaceDesc.Format, color); // draw the blip, but make sure the points are legal if( legalRadarPoint( radarPoint.x, radarPoint.y ) ) - surface->Draw_Pixel( radarPoint.x, radarPoint.y, color, bytesPerPixel, pBits, pitch ); + surface->Draw_Pixel( radarPoint.x, radarPoint.y, pixelColor, bytesPerPixel, pBits, pitch ); radarPoint.y++; if( legalRadarPoint( radarPoint.x, radarPoint.y ) ) - surface->Draw_Pixel( radarPoint.x, radarPoint.y, color, bytesPerPixel, pBits, pitch ); + surface->Draw_Pixel( radarPoint.x, radarPoint.y, pixelColor, bytesPerPixel, pBits, pitch ); radarPoint.x++; if( legalRadarPoint( radarPoint.x, radarPoint.y ) ) - surface->Draw_Pixel( radarPoint.x, radarPoint.y, color, bytesPerPixel, pBits, pitch ); + surface->Draw_Pixel( radarPoint.x, radarPoint.y, pixelColor, bytesPerPixel, pBits, pitch ); radarPoint.y--; if( legalRadarPoint( radarPoint.x, radarPoint.y ) ) - surface->Draw_Pixel( radarPoint.x, radarPoint.y, color, bytesPerPixel, pBits, pitch ); + surface->Draw_Pixel( radarPoint.x, radarPoint.y, pixelColor, bytesPerPixel, pBits, pitch ); } @@ -1276,8 +1276,8 @@ void W3DRadar::buildTerrainTexture( TerrainLogic *terrain ) // draw the pixel for the terrain at this point, note that because of the orientation // of our world we draw it with positive y in the "up" direction - Color pixelColor = GameMakeColor( color.red * 255, color.green * 255, color.blue * 255, 255 ); - pixelColor = ARGB_Color_To_WW3D_Color(surfaceDesc.Format, pixelColor); + const Color argbColor = GameMakeColor( color.red * 255, color.green * 255, color.blue * 255, 255 ); + const unsigned int pixelColor = ARGB_Color_To_WW3D_Color(surfaceDesc.Format, argbColor); surface->Draw_Pixel( x, y, pixelColor, bytesPerPixel, pBits, pitch ); } @@ -1377,14 +1377,14 @@ void W3DRadar::setShroudLevel(Int shroudX, Int shroudY, CellShroudStatus setting int pitch; void *pBits = surface->Lock(&pitch); const unsigned int bytesPerPixel = Get_Bytes_Per_Pixel(surfaceDesc.Format); - Color color = GameMakeColor( 0, 0, 0, alpha ); - color = ARGB_Color_To_WW3D_Color(surfaceDesc.Format, color); + const Color argbColor = GameMakeColor( 0, 0, 0, alpha ); + const unsigned int pixelColor = ARGB_Color_To_WW3D_Color(surfaceDesc.Format, argbColor); for( Int y = radarMinY; y <= radarMaxY; ++y ) { for( Int x = radarMinX; x <= radarMaxX; ++x ) { - surface->Draw_Pixel( x, y, color, bytesPerPixel, pBits, pitch ); + surface->Draw_Pixel( x, y, pixelColor, bytesPerPixel, pBits, pitch ); } } @@ -1397,14 +1397,14 @@ void W3DRadar::setShroudLevel(Int shroudX, Int shroudY, CellShroudStatus setting DEBUG_ASSERTCRASH(m_shroudSurfaceBits != nullptr, ("W3DRadar::setShroudLevel: m_shroudSurfaceBits is not expected null")); DEBUG_ASSERTCRASH(m_shroudSurfaceFormat != WW3D_FORMAT_UNKNOWN, ("W3DRadar::setShroudLevel: m_shroudSurfaceFormat is not expected UNKNOWN")); DEBUG_ASSERTCRASH(m_shroudSurfacePixelSize != 0, ("W3DRadar::setShroudLevel: m_shroudSurfacePixelSize is not expected 0")); - Color color = GameMakeColor( 0, 0, 0, alpha ); - color = ARGB_Color_To_WW3D_Color(m_shroudSurfaceFormat, color); + const Color argbColor = GameMakeColor( 0, 0, 0, alpha ); + const unsigned int pixelColor = ARGB_Color_To_WW3D_Color(m_shroudSurfaceFormat, argbColor); for( Int y = radarMinY; y <= radarMaxY; ++y ) { for( Int x = radarMinX; x <= radarMaxX; ++x ) { - m_shroudSurface->Draw_Pixel( x, y, color, m_shroudSurfacePixelSize, m_shroudSurfaceBits, m_shroudSurfacePitch ); + m_shroudSurface->Draw_Pixel( x, y, pixelColor, m_shroudSurfacePixelSize, m_shroudSurfaceBits, m_shroudSurfacePitch ); } } } From 07b5b358941941c9ca66793fa6e9d789ac8b2a9b Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Thu, 29 Jan 2026 18:52:05 +0100 Subject: [PATCH 4/4] Rename color names 2 --- .../Source/W3DDevice/Common/System/W3DRadar.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp b/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp index d8a9f812486..62ffaea09b2 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp @@ -720,7 +720,7 @@ void W3DRadar::renderObjectList( const RadarObject *listHead, TextureClass *text radarPoint.y = pos->y / (m_mapExtent.height() / RADAR_CELL_HEIGHT); // get the color we're going to draw in - Color color = rObj->getColor(); + Color argbColor = rObj->getColor(); // adjust the alpha for stealth units so they "fade/blink" on the radar for the controller // if( obj->getRadarPriority() == RADAR_PRIORITY_LOCAL_UNIT_ONLY ) @@ -729,7 +729,7 @@ void W3DRadar::renderObjectList( const RadarObject *listHead, TextureClass *text if( obj->testStatus( OBJECT_STATUS_STEALTHED ) ) { UnsignedByte r, g, b, a; - GameGetColorComponents( color, &r, &g, &b, &a ); + GameGetColorComponents( argbColor, &r, &g, &b, &a ); const UnsignedInt framesForTransition = LOGICFRAMES_PER_SECOND; const UnsignedByte minAlpha = 32; @@ -739,11 +739,11 @@ void W3DRadar::renderObjectList( const RadarObject *listHead, TextureClass *text a = REAL_TO_UNSIGNEDBYTE( ((alphaScale - 1.0f) * (255.0f - minAlpha)) + minAlpha ); else a = REAL_TO_UNSIGNEDBYTE( (alphaScale * (255.0f - minAlpha)) + minAlpha ); - color = GameMakeColor( r, g, b, a ); + argbColor = GameMakeColor( r, g, b, a ); } - const unsigned int pixelColor = ARGB_Color_To_WW3D_Color(surfaceDesc.Format, color); + const unsigned int pixelColor = ARGB_Color_To_WW3D_Color(surfaceDesc.Format, argbColor); // draw the blip, but make sure the points are legal if( legalRadarPoint( radarPoint.x, radarPoint.y ) )