From f13de68efe45a7a5d1db9a791faef0368ba51903 Mon Sep 17 00:00:00 2001 From: stm <14291421+stephanmeesters@users.noreply.github.com> Date: Sun, 25 Oct 2026 22:16:26 +0100 Subject: [PATCH 1/9] test: Change every example rendering test to demonstrate the rendering comparison Co-Authored-By: Claude Opus 5.5 --- .../Rendering/EXAMPLE_TEMPORARY_ClearTest.cpp | 2 +- .../Rendering/EXAMPLE_TEMPORARY_LaserTest.cpp | 8 ++++---- .../EXAMPLE_TEMPORARY_ParticlesTest.cpp | 6 +++--- .../EXAMPLE_TEMPORARY_Render2DBlendingTest.cpp | 12 ++++++------ .../EXAMPLE_TEMPORARY_Render2DShapesTest.cpp | 16 ++++++++-------- .../EXAMPLE_TEMPORARY_Render2DTextureTest.cpp | 10 +++++----- .../Rendering/EXAMPLE_TEMPORARY_TextTest.cpp | 8 ++++---- .../Rendering/EXAMPLE_TEMPORARY_TracerTest.cpp | 6 +++--- .../Rendering/EXAMPLE_TEMPORARY_TriangleTest.cpp | 8 ++++---- 9 files changed, 38 insertions(+), 38 deletions(-) diff --git a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_ClearTest.cpp b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_ClearTest.cpp index 1f67e37de62..d703672e1b5 100644 --- a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_ClearTest.cpp +++ b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_ClearTest.cpp @@ -21,7 +21,7 @@ // Clearing the render target fills it with the clear color from corner to corner. TEST_F(RenderingTest, Clear) { - const DWORD color = 0x102030; + const DWORD color = 0x603010; clear(color); capture("clear.png"); EXPECT_EQ(pixel(0, 0), color); diff --git a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_LaserTest.cpp b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_LaserTest.cpp index b09a03dc7d3..b6469e70354 100644 --- a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_LaserTest.cpp +++ b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_LaserTest.cpp @@ -31,20 +31,20 @@ TEST_F(RenderingTest, Laser) return 0xFF000000 | brightness << 16 | brightness << 8 | brightness; }); - // A red beam from west to east and a blue one that crosses it on the way up. + // A green beam from west to east and a magenta one that crosses it on the way up. Vector3 eastWest[] = {Vector3(-6.0f, 0.0f, 0.0f), Vector3(6.0f, 0.0f, 0.0f)}; Vector3 diagonal[] = {Vector3(-5.0f, -3.0f, 0.0f), Vector3(5.0f, 3.0f, 2.0f)}; SegmentedLineClass *red = NEW_REF(SegmentedLineClass, ()); red->Set_Points(2, eastWest); - red->Set_Color(Vector3(1.0f, 0.2f, 0.1f)); + red->Set_Color(Vector3(0.2f, 1.0f, 0.2f)); SegmentedLineClass *blue = NEW_REF(SegmentedLineClass, ()); blue->Set_Points(2, diagonal); - blue->Set_Color(Vector3(0.2f, 0.4f, 1.0f)); + blue->Set_Color(Vector3(1.0f, 0.2f, 1.0f)); for (SegmentedLineClass *laser : {red, blue}) { laser->Set_Texture(glow); laser->Set_Shader(ShaderClass::_PresetAdditiveShader); - laser->Set_Width(0.8f); + laser->Set_Width(1.2f); } render({red, blue}); diff --git a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_ParticlesTest.cpp b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_ParticlesTest.cpp index aed0a621f44..d3db097f13b 100644 --- a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_ParticlesTest.cpp +++ b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_ParticlesTest.cpp @@ -37,7 +37,7 @@ TEST_F(RenderingTest, Particles) return 0xFF000000 | brightness << 16 | brightness << 8 | brightness; }); - // A ring of particles on the ground that turn from red to yellow and grow, around one in the middle. + // A ring of particles on the ground that turn from blue to cyan and grow, around one in the middle. constexpr int Count = 13; ShareBufferClass *locations = NEW_REF(ShareBufferClass, (Count, "ParticlesTest")); ShareBufferClass *colors = NEW_REF(ShareBufferClass, (Count, "ParticlesTest")); @@ -45,9 +45,9 @@ TEST_F(RenderingTest, Particles) for (int i = 0; i < Count; ++i) { const float angle = i * WWMATH_PI * 2.0f / (Count - 1); - const float radius = i == 0 ? 0.0f : 4.0f; + const float radius = i == 0 ? 0.0f : 3.0f; locations->Get_Array()[i] = Vector3(radius * cosf(angle), radius * sinf(angle), 0.0f); - colors->Get_Array()[i] = Vector4(1.0f, static_cast(i) / Count, 0.1f, 1.0f); + colors->Get_Array()[i] = Vector4(0.1f, static_cast(i) / Count, 1.0f, 1.0f); sizes->Get_Array()[i] = 1.0f + i * 0.1f; } diff --git a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_Render2DBlendingTest.cpp b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_Render2DBlendingTest.cpp index e6c9175ac4b..604c51569db 100644 --- a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_Render2DBlendingTest.cpp +++ b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_Render2DBlendingTest.cpp @@ -29,22 +29,22 @@ TEST_F(RenderingTest, Render2DBlending) renderer.Set_Coordinate_Range(RectClass(0.0f, 0.0f, Width, Height)); renderer.Enable_Texturing(false); - // Half transparent red. + // Half transparent blue. renderer.Enable_Alpha(true); - renderer.Add_Quad(RectClass(16.0f, 16.0f, 112.0f, 240.0f), 0x80FF0000); + renderer.Add_Quad(RectClass(16.0f, 16.0f, 112.0f, 240.0f), 0x800000FF); renderer.Render(); - // Green added on top, partly over the red. + // Red added on top, partly over the blue. renderer.Reset(); renderer.Enable_Additive(true); - renderer.Add_Quad(RectClass(80.0f, 16.0f, 176.0f, 240.0f), 0xFF006000); + renderer.Add_Quad(RectClass(80.0f, 16.0f, 176.0f, 240.0f), 0xFF600000); renderer.Render(); - // Blue multiplied with what is below, partly over the green. + // Yellow multiplied with what is below, partly over the red. renderer.Reset(); *renderer.Get_Shader() = ShaderClass::_PresetMultiplicative2DShader; renderer.Enable_Texturing(false); - renderer.Add_Quad(RectClass(144.0f, 16.0f, 240.0f, 240.0f), 0xFF4080FF); + renderer.Add_Quad(RectClass(144.0f, 16.0f, 240.0f, 240.0f), 0xFFFFFF40); renderer.Render(); capture("render2d_blending.png"); diff --git a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_Render2DShapesTest.cpp b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_Render2DShapesTest.cpp index 4f0790c2c48..4c68d7c9f2b 100644 --- a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_Render2DShapesTest.cpp +++ b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_Render2DShapesTest.cpp @@ -27,17 +27,17 @@ TEST_F(RenderingTest, Render2DShapes) renderer.Set_Coordinate_Range(RectClass(0.0f, 0.0f, Width, Height)); renderer.Enable_Texturing(false); - // A blue rectangle with a white border, an orange outline, a green line and a red to blue gradient. - renderer.Add_Rect(RectClass(16.0f, 16.0f, 112.0f, 112.0f), 4.0f, 0xFFFFFFFF, 0xFF2040C0); - renderer.Add_Outline(RectClass(144.0f, 16.0f, 240.0f, 112.0f), 2.0f, 0xFFFFC000); - renderer.Add_Line(Vector2(16.0f, 136.0f), Vector2(240.0f, 184.0f), 3.0f, 0xFF40FF40); - renderer.Add_Quad_HGradient(RectClass(16.0f, 208.0f, 240.0f, 240.0f), 0xFFFF0000, 0xFF0000FF); + // An orange rectangle with a green border, a cyan outline, a yellow line and a green to magenta gradient. + renderer.Add_Rect(RectClass(16.0f, 16.0f, 112.0f, 112.0f), 4.0f, 0xFF40FF40, 0xFFC04020); + renderer.Add_Outline(RectClass(144.0f, 16.0f, 240.0f, 112.0f), 2.0f, 0xFF00C0FF); + renderer.Add_Line(Vector2(16.0f, 136.0f), Vector2(240.0f, 184.0f), 3.0f, 0xFFFFFF40); + renderer.Add_Quad_HGradient(RectClass(16.0f, 208.0f, 240.0f, 240.0f), 0xFF00FF00, 0xFFFF00FF); renderer.Render(); capture("render2d_shapes.png"); // The fill and the border of the rectangle, and the inside and the edge of the outline. - EXPECT_EQ(pixel(64, 64), 0x2040C0); - EXPECT_EQ(pixel(17, 64), 0xFFFFFF); + EXPECT_EQ(pixel(64, 64), 0xC04020); + EXPECT_EQ(pixel(17, 64), 0x40FF40); EXPECT_EQ(pixel(192, 64), 0x000000); - EXPECT_EQ(pixel(145, 64), 0xFFC000); + EXPECT_EQ(pixel(145, 64), 0x00C0FF); } diff --git a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_Render2DTextureTest.cpp b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_Render2DTextureTest.cpp index ed34827d4bf..99d8eb9b4d4 100644 --- a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_Render2DTextureTest.cpp +++ b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_Render2DTextureTest.cpp @@ -24,14 +24,14 @@ // linear filtering blends them, and transparent texels let the background show through. TEST_F(RenderingTest, Render2DTexture) { - const DWORD background = 0x204060; + const DWORD background = 0x402060; clear(background); - // A red and white checkerboard with a transparent top left quarter. + // A blue and white checkerboard with a transparent top left quarter. const auto checkerboard = [](UINT x, UINT y) -> DWORD { const DWORD alpha = (x < 4 && y < 4) ? 0x00000000 : 0xFF000000; - return alpha | (((x ^ y) & 1) ? 0xFFFFFF : 0xC02020); + return alpha | (((x ^ y) & 1) ? 0xFFFFFF : 0x2080C0); }; TextureClass *sharp = createTexture(8, 8, checkerboard); sharp->Get_Filter().Set_Min_Filter(TextureFilterClass::FILTER_TYPE_NONE); @@ -53,8 +53,8 @@ TEST_F(RenderingTest, Render2DTexture) REF_PTR_RELEASE(smooth); capture("render2d_texture.png"); - // Each texel covers 12 by 12 pixels. These are the centers of texel (5, 5), which is red, and texel (1, 1), + // Each texel covers 12 by 12 pixels. These are the centers of texel (5, 5), which is blue, and texel (1, 1), // which is transparent. - EXPECT_EQ(pixel(16 + 5 * 12 + 6, 64 + 5 * 12 + 6), 0xC02020); + EXPECT_EQ(pixel(16 + 5 * 12 + 6, 64 + 5 * 12 + 6), 0x2080C0); EXPECT_EQ(pixel(16 + 1 * 12 + 6, 64 + 1 * 12 + 6), background); } diff --git a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_TextTest.cpp b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_TextTest.cpp index f2de7a934f5..c844dfab4d8 100644 --- a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_TextTest.cpp +++ b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_TextTest.cpp @@ -23,7 +23,7 @@ // including the drop shadow below the text. TEST_F(RenderingTest, Text) { - const DWORD background = 0x204060; + const DWORD background = 0x302020; clear(background); FontCharsClass *font = NEW_REF(FontCharsClass, ()); @@ -33,12 +33,12 @@ TEST_F(RenderingTest, Text) REF_PTR_RELEASE(font); // The black shadow first, then the text over it. - const WCHAR *text = L"Command & Conquer"; + const WCHAR *text = L"Generals Zero Hour"; sentence.Build_Sentence(text, nullptr, nullptr); sentence.Set_Location(Vector2(18.0f, 18.0f)); sentence.Draw_Sentence(0xFF000000); sentence.Set_Location(Vector2(16.0f, 16.0f)); - sentence.Draw_Sentence(0xFFFFC000); + sentence.Draw_Sentence(0xFF40C0FF); sentence.Render(); const Vector2 extents = sentence.Get_Text_Extents(text); @@ -48,7 +48,7 @@ TEST_F(RenderingTest, Text) bool found = false; for (UINT x = 16; x < 16 + extents.X; ++x) { - found |= pixel(x, 16 + static_cast(extents.Y) / 2) == 0xFFC000; + found |= pixel(x, 16 + static_cast(extents.Y) / 2) == 0x40C0FF; } EXPECT_TRUE(found); } diff --git a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_TracerTest.cpp b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_TracerTest.cpp index 27bcb9ba40b..ec6ee941f9c 100644 --- a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_TracerTest.cpp +++ b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_TracerTest.cpp @@ -22,9 +22,9 @@ // Tracers are 3D lines, which W3DTracerDraw fades out by lowering their opacity. TEST_F(RenderingTest, Tracer) { - // A solid yellow tracer, crossed by a red one at half opacity. - Line3DClass *solid = NEW_REF(Line3DClass, (Vector3(-6.0f, -2.0f, 0.0f), Vector3(6.0f, 2.0f, 0.0f), 0.2f, 1.0f, 0.9f, 0.2f)); - Line3DClass *faded = NEW_REF(Line3DClass, (Vector3(-6.0f, 2.0f, 0.0f), Vector3(6.0f, -2.0f, 0.0f), 0.2f, 1.0f, 0.3f, 0.2f, 0.5f)); + // A solid cyan tracer, crossed by a magenta one at half opacity. + Line3DClass *solid = NEW_REF(Line3DClass, (Vector3(-6.0f, -2.0f, 0.0f), Vector3(6.0f, 2.0f, 0.0f), 0.3f, 0.2f, 0.9f, 1.0f)); + Line3DClass *faded = NEW_REF(Line3DClass, (Vector3(-6.0f, 2.0f, 0.0f), Vector3(6.0f, -2.0f, 0.0f), 0.3f, 1.0f, 0.2f, 1.0f, 0.5f)); render({solid, faded}); REF_PTR_RELEASE(solid); diff --git a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_TriangleTest.cpp b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_TriangleTest.cpp index 9e39fda6166..62c7c8d5188 100644 --- a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_TriangleTest.cpp +++ b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_TriangleTest.cpp @@ -21,12 +21,12 @@ // A triangle with a red, a green and a blue corner blends the corner colors across its area. TEST_F(RenderingTest, Triangle) { - const DWORD background = 0x102030; + const DWORD background = 0x301020; clear(background); drawTriangles({ - {128.0f, 32.0f, 0xff0000}, - {224.0f, 224.0f, 0x00ff00}, - {32.0f, 224.0f, 0x0000ff}, + {128.0f, 32.0f, 0x0000ff}, + {224.0f, 224.0f, 0xff0000}, + {32.0f, 224.0f, 0x00ff00}, }); capture("triangle.png"); // GPUs round the blended colors differently, so the exact colors are left to the image comparison of CI. From c1dfa88db57c9c6cbeb1aa7bbc5cedef2225a951 Mon Sep 17 00:00:00 2001 From: stm <14291421+stephanmeesters@users.noreply.github.com> Date: Sun, 25 Oct 2026 22:21:47 +0100 Subject: [PATCH 2/9] ci: Show the rendering differences with Resemble.js Co-Authored-By: Claude Opus 5.5 --- .../workflows/reusable-check-rendering.yml | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/.github/workflows/reusable-check-rendering.yml b/.github/workflows/reusable-check-rendering.yml index 197fb4d7a4e..e719a9b762e 100644 --- a/.github/workflows/reusable-check-rendering.yml +++ b/.github/workflows/reusable-check-rendering.yml @@ -142,25 +142,32 @@ jobs: "changes=$changes" >> $env:GITHUB_OUTPUT "message=$(if ($changes) { $changes } else { 'No changes' }) $since" >> $env:GITHUB_OUTPUT "### $env:GAME Rendering`n`n$(($images | Group-Object State | ForEach-Object { "$($_.Count) $($_.Name)" }) -join ', ') $since.`n" >> $env:GITHUB_STEP_SUMMARY - # One page with the images inline, so the browser opens the artifact without unzipping. The difference - # blends the new image over the base and brightens the result, so only changed pixels show. + # One page with the images inline, so the browser opens the artifact without unzipping. Resemble.js marks + # the pixels of each changed image that differ from the base. $rows = foreach ($image in $images | Sort-Object State, Name) { - $diff = if ($image.State -eq 'changed') { "
$($image.Old)$($image.New)
" } - "$($image.Name)
$($image.State)$($image.Old)$($image.New)$diff" + $diff = if ($image.State -eq 'changed') { ' class=diff' } + "$($image.Name)
$($image.State)$($image.Old)$($image.New)" } @" $env:GAME rendering $since - + +

$env:GAME rendering $since

$($rows -join "`n")
BaseThis commitDifference
+ "@ | Set-Content "build/$env:GAME-rendering-report.html" # A single file is uploaded unzipped, so its link opens it in the browser. From 6338974ea1b9656c99271d67e1f5ac42ed6f8fd7 Mon Sep 17 00:00:00 2001 From: stm <14291421+stephanmeesters@users.noreply.github.com> Date: Mon, 26 Oct 2026 12:28:31 +0100 Subject: [PATCH 3/9] test: Change one detail per example rendering test instead of whole images Co-Authored-By: Claude Opus 5.5 --- .../Core/Rendering/EXAMPLE_TEMPORARY_ClearTest.cpp | 2 +- .../Core/Rendering/EXAMPLE_TEMPORARY_LaserTest.cpp | 10 +++++----- .../Rendering/EXAMPLE_TEMPORARY_ParticlesTest.cpp | 8 ++++---- .../EXAMPLE_TEMPORARY_Render2DBlendingTest.cpp | 12 ++++++------ .../EXAMPLE_TEMPORARY_Render2DShapesTest.cpp | 12 ++++++------ .../EXAMPLE_TEMPORARY_Render2DTextureTest.cpp | 12 ++++++------ .../Core/Rendering/EXAMPLE_TEMPORARY_TextTest.cpp | 8 ++++---- .../Core/Rendering/EXAMPLE_TEMPORARY_TracerTest.cpp | 6 +++--- .../Rendering/EXAMPLE_TEMPORARY_TriangleTest.cpp | 10 +++++----- 9 files changed, 40 insertions(+), 40 deletions(-) diff --git a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_ClearTest.cpp b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_ClearTest.cpp index d703672e1b5..1f67e37de62 100644 --- a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_ClearTest.cpp +++ b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_ClearTest.cpp @@ -21,7 +21,7 @@ // Clearing the render target fills it with the clear color from corner to corner. TEST_F(RenderingTest, Clear) { - const DWORD color = 0x603010; + const DWORD color = 0x102030; clear(color); capture("clear.png"); EXPECT_EQ(pixel(0, 0), color); diff --git a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_LaserTest.cpp b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_LaserTest.cpp index b6469e70354..9772f470c32 100644 --- a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_LaserTest.cpp +++ b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_LaserTest.cpp @@ -31,20 +31,20 @@ TEST_F(RenderingTest, Laser) return 0xFF000000 | brightness << 16 | brightness << 8 | brightness; }); - // A green beam from west to east and a magenta one that crosses it on the way up. + // A red beam from west to east and a blue one that crosses it on the way up. Vector3 eastWest[] = {Vector3(-6.0f, 0.0f, 0.0f), Vector3(6.0f, 0.0f, 0.0f)}; - Vector3 diagonal[] = {Vector3(-5.0f, -3.0f, 0.0f), Vector3(5.0f, 3.0f, 2.0f)}; + Vector3 diagonal[] = {Vector3(-5.0f, -3.0f, 0.0f), Vector3(5.0f, 3.0f, 4.0f)}; SegmentedLineClass *red = NEW_REF(SegmentedLineClass, ()); red->Set_Points(2, eastWest); - red->Set_Color(Vector3(0.2f, 1.0f, 0.2f)); + red->Set_Color(Vector3(1.0f, 0.2f, 0.1f)); SegmentedLineClass *blue = NEW_REF(SegmentedLineClass, ()); blue->Set_Points(2, diagonal); - blue->Set_Color(Vector3(1.0f, 0.2f, 1.0f)); + blue->Set_Color(Vector3(0.2f, 0.4f, 1.0f)); for (SegmentedLineClass *laser : {red, blue}) { laser->Set_Texture(glow); laser->Set_Shader(ShaderClass::_PresetAdditiveShader); - laser->Set_Width(1.2f); + laser->Set_Width(0.8f); } render({red, blue}); diff --git a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_ParticlesTest.cpp b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_ParticlesTest.cpp index d3db097f13b..7069f54950b 100644 --- a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_ParticlesTest.cpp +++ b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_ParticlesTest.cpp @@ -37,7 +37,7 @@ TEST_F(RenderingTest, Particles) return 0xFF000000 | brightness << 16 | brightness << 8 | brightness; }); - // A ring of particles on the ground that turn from blue to cyan and grow, around one in the middle. + // A ring of particles on the ground that turn from red to yellow and grow, around a larger one in the middle. constexpr int Count = 13; ShareBufferClass *locations = NEW_REF(ShareBufferClass, (Count, "ParticlesTest")); ShareBufferClass *colors = NEW_REF(ShareBufferClass, (Count, "ParticlesTest")); @@ -45,10 +45,10 @@ TEST_F(RenderingTest, Particles) for (int i = 0; i < Count; ++i) { const float angle = i * WWMATH_PI * 2.0f / (Count - 1); - const float radius = i == 0 ? 0.0f : 3.0f; + const float radius = i == 0 ? 0.0f : 4.0f; locations->Get_Array()[i] = Vector3(radius * cosf(angle), radius * sinf(angle), 0.0f); - colors->Get_Array()[i] = Vector4(0.1f, static_cast(i) / Count, 1.0f, 1.0f); - sizes->Get_Array()[i] = 1.0f + i * 0.1f; + colors->Get_Array()[i] = Vector4(1.0f, static_cast(i) / Count, 0.1f, 1.0f); + sizes->Get_Array()[i] = i == 0 ? 2.0f : 1.0f + i * 0.1f; } // Set up as W3DParticleSystemManager sets up its batches. diff --git a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_Render2DBlendingTest.cpp b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_Render2DBlendingTest.cpp index 604c51569db..184c1f68be8 100644 --- a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_Render2DBlendingTest.cpp +++ b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_Render2DBlendingTest.cpp @@ -29,22 +29,22 @@ TEST_F(RenderingTest, Render2DBlending) renderer.Set_Coordinate_Range(RectClass(0.0f, 0.0f, Width, Height)); renderer.Enable_Texturing(false); - // Half transparent blue. + // Half transparent red. renderer.Enable_Alpha(true); - renderer.Add_Quad(RectClass(16.0f, 16.0f, 112.0f, 240.0f), 0x800000FF); + renderer.Add_Quad(RectClass(16.0f, 16.0f, 112.0f, 240.0f), 0x80FF0000); renderer.Render(); - // Red added on top, partly over the blue. + // Green added on top, partly over the red. renderer.Reset(); renderer.Enable_Additive(true); - renderer.Add_Quad(RectClass(80.0f, 16.0f, 176.0f, 240.0f), 0xFF600000); + renderer.Add_Quad(RectClass(80.0f, 16.0f, 176.0f, 240.0f), 0xFF006000); renderer.Render(); - // Yellow multiplied with what is below, partly over the red. + // Orange multiplied with what is below, partly over the green. renderer.Reset(); *renderer.Get_Shader() = ShaderClass::_PresetMultiplicative2DShader; renderer.Enable_Texturing(false); - renderer.Add_Quad(RectClass(144.0f, 16.0f, 240.0f, 240.0f), 0xFFFFFF40); + renderer.Add_Quad(RectClass(144.0f, 16.0f, 240.0f, 240.0f), 0xFFFF8040); renderer.Render(); capture("render2d_blending.png"); diff --git a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_Render2DShapesTest.cpp b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_Render2DShapesTest.cpp index 4c68d7c9f2b..13b48de279c 100644 --- a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_Render2DShapesTest.cpp +++ b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_Render2DShapesTest.cpp @@ -27,17 +27,17 @@ TEST_F(RenderingTest, Render2DShapes) renderer.Set_Coordinate_Range(RectClass(0.0f, 0.0f, Width, Height)); renderer.Enable_Texturing(false); - // An orange rectangle with a green border, a cyan outline, a yellow line and a green to magenta gradient. - renderer.Add_Rect(RectClass(16.0f, 16.0f, 112.0f, 112.0f), 4.0f, 0xFF40FF40, 0xFFC04020); + // A blue rectangle with a white border, a cyan outline, a green line and a red to blue gradient. + renderer.Add_Rect(RectClass(16.0f, 16.0f, 112.0f, 112.0f), 4.0f, 0xFFFFFFFF, 0xFF2040C0); renderer.Add_Outline(RectClass(144.0f, 16.0f, 240.0f, 112.0f), 2.0f, 0xFF00C0FF); - renderer.Add_Line(Vector2(16.0f, 136.0f), Vector2(240.0f, 184.0f), 3.0f, 0xFFFFFF40); - renderer.Add_Quad_HGradient(RectClass(16.0f, 208.0f, 240.0f, 240.0f), 0xFF00FF00, 0xFFFF00FF); + renderer.Add_Line(Vector2(16.0f, 136.0f), Vector2(240.0f, 184.0f), 3.0f, 0xFF40FF40); + renderer.Add_Quad_HGradient(RectClass(16.0f, 208.0f, 240.0f, 240.0f), 0xFFFF0000, 0xFF0000FF); renderer.Render(); capture("render2d_shapes.png"); // The fill and the border of the rectangle, and the inside and the edge of the outline. - EXPECT_EQ(pixel(64, 64), 0xC04020); - EXPECT_EQ(pixel(17, 64), 0x40FF40); + EXPECT_EQ(pixel(64, 64), 0x2040C0); + EXPECT_EQ(pixel(17, 64), 0xFFFFFF); EXPECT_EQ(pixel(192, 64), 0x000000); EXPECT_EQ(pixel(145, 64), 0x00C0FF); } diff --git a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_Render2DTextureTest.cpp b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_Render2DTextureTest.cpp index 99d8eb9b4d4..4ab510539dd 100644 --- a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_Render2DTextureTest.cpp +++ b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_Render2DTextureTest.cpp @@ -24,14 +24,14 @@ // linear filtering blends them, and transparent texels let the background show through. TEST_F(RenderingTest, Render2DTexture) { - const DWORD background = 0x402060; + const DWORD background = 0x204060; clear(background); - // A blue and white checkerboard with a transparent top left quarter. + // A red and white checkerboard with a transparent top left corner. const auto checkerboard = [](UINT x, UINT y) -> DWORD { - const DWORD alpha = (x < 4 && y < 4) ? 0x00000000 : 0xFF000000; - return alpha | (((x ^ y) & 1) ? 0xFFFFFF : 0x2080C0); + const DWORD alpha = (x < 2 && y < 2) ? 0x00000000 : 0xFF000000; + return alpha | (((x ^ y) & 1) ? 0xFFFFFF : 0xC02020); }; TextureClass *sharp = createTexture(8, 8, checkerboard); sharp->Get_Filter().Set_Min_Filter(TextureFilterClass::FILTER_TYPE_NONE); @@ -53,8 +53,8 @@ TEST_F(RenderingTest, Render2DTexture) REF_PTR_RELEASE(smooth); capture("render2d_texture.png"); - // Each texel covers 12 by 12 pixels. These are the centers of texel (5, 5), which is blue, and texel (1, 1), + // Each texel covers 12 by 12 pixels. These are the centers of texel (5, 5), which is red, and texel (1, 1), // which is transparent. - EXPECT_EQ(pixel(16 + 5 * 12 + 6, 64 + 5 * 12 + 6), 0x2080C0); + EXPECT_EQ(pixel(16 + 5 * 12 + 6, 64 + 5 * 12 + 6), 0xC02020); EXPECT_EQ(pixel(16 + 1 * 12 + 6, 64 + 1 * 12 + 6), background); } diff --git a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_TextTest.cpp b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_TextTest.cpp index c844dfab4d8..310281ae3b7 100644 --- a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_TextTest.cpp +++ b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_TextTest.cpp @@ -23,7 +23,7 @@ // including the drop shadow below the text. TEST_F(RenderingTest, Text) { - const DWORD background = 0x302020; + const DWORD background = 0x204060; clear(background); FontCharsClass *font = NEW_REF(FontCharsClass, ()); @@ -33,12 +33,12 @@ TEST_F(RenderingTest, Text) REF_PTR_RELEASE(font); // The black shadow first, then the text over it. - const WCHAR *text = L"Generals Zero Hour"; + const WCHAR *text = L"Command + Conquer"; sentence.Build_Sentence(text, nullptr, nullptr); sentence.Set_Location(Vector2(18.0f, 18.0f)); sentence.Draw_Sentence(0xFF000000); sentence.Set_Location(Vector2(16.0f, 16.0f)); - sentence.Draw_Sentence(0xFF40C0FF); + sentence.Draw_Sentence(0xFFFFC000); sentence.Render(); const Vector2 extents = sentence.Get_Text_Extents(text); @@ -48,7 +48,7 @@ TEST_F(RenderingTest, Text) bool found = false; for (UINT x = 16; x < 16 + extents.X; ++x) { - found |= pixel(x, 16 + static_cast(extents.Y) / 2) == 0x40C0FF; + found |= pixel(x, 16 + static_cast(extents.Y) / 2) == 0xFFC000; } EXPECT_TRUE(found); } diff --git a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_TracerTest.cpp b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_TracerTest.cpp index ec6ee941f9c..3ef9d1106ac 100644 --- a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_TracerTest.cpp +++ b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_TracerTest.cpp @@ -22,9 +22,9 @@ // Tracers are 3D lines, which W3DTracerDraw fades out by lowering their opacity. TEST_F(RenderingTest, Tracer) { - // A solid cyan tracer, crossed by a magenta one at half opacity. - Line3DClass *solid = NEW_REF(Line3DClass, (Vector3(-6.0f, -2.0f, 0.0f), Vector3(6.0f, 2.0f, 0.0f), 0.3f, 0.2f, 0.9f, 1.0f)); - Line3DClass *faded = NEW_REF(Line3DClass, (Vector3(-6.0f, 2.0f, 0.0f), Vector3(6.0f, -2.0f, 0.0f), 0.3f, 1.0f, 0.2f, 1.0f, 0.5f)); + // A solid yellow tracer, crossed by a blue one at half opacity. + Line3DClass *solid = NEW_REF(Line3DClass, (Vector3(-6.0f, -2.0f, 0.0f), Vector3(6.0f, 2.0f, 0.0f), 0.2f, 1.0f, 0.9f, 0.2f)); + Line3DClass *faded = NEW_REF(Line3DClass, (Vector3(-6.0f, 2.0f, 0.0f), Vector3(6.0f, -2.0f, 0.0f), 0.2f, 0.2f, 0.4f, 1.0f, 0.5f)); render({solid, faded}); REF_PTR_RELEASE(solid); diff --git a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_TriangleTest.cpp b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_TriangleTest.cpp index 62c7c8d5188..cff97f8c765 100644 --- a/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_TriangleTest.cpp +++ b/Tests/Google/Core/Rendering/EXAMPLE_TEMPORARY_TriangleTest.cpp @@ -18,15 +18,15 @@ #include "RenderingTestFixture.h" -// A triangle with a red, a green and a blue corner blends the corner colors across its area. +// A triangle with a red, a green and a white corner blends the corner colors across its area. TEST_F(RenderingTest, Triangle) { - const DWORD background = 0x301020; + const DWORD background = 0x102030; clear(background); drawTriangles({ - {128.0f, 32.0f, 0x0000ff}, - {224.0f, 224.0f, 0xff0000}, - {32.0f, 224.0f, 0x00ff00}, + {128.0f, 32.0f, 0xff0000}, + {224.0f, 224.0f, 0x00ff00}, + {32.0f, 224.0f, 0xffffff}, }); capture("triangle.png"); // GPUs round the blended colors differently, so the exact colors are left to the image comparison of CI. From 0d9b172a16a2212cb401056f319eac0e5f202b5c Mon Sep 17 00:00:00 2001 From: stm <14291421+stephanmeesters@users.noreply.github.com> Date: Mon, 26 Oct 2026 12:28:31 +0100 Subject: [PATCH 4/9] ci: Style the rendering report with Tailwind and show the share of changed pixels beside the state Co-Authored-By: Claude Opus 5.5 --- .../workflows/reusable-check-rendering.yml | 38 +++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/.github/workflows/reusable-check-rendering.yml b/.github/workflows/reusable-check-rendering.yml index e719a9b762e..da1623ab867 100644 --- a/.github/workflows/reusable-check-rendering.yml +++ b/.github/workflows/reusable-check-rendering.yml @@ -141,30 +141,54 @@ jobs: $changes = ($images | Where-Object State -in 'changed', 'removed' | ForEach-Object { "$($_.Name) $($_.State)" }) -join ', ' "changes=$changes" >> $env:GITHUB_OUTPUT "message=$(if ($changes) { $changes } else { 'No changes' }) $since" >> $env:GITHUB_OUTPUT - "### $env:GAME Rendering`n`n$(($images | Group-Object State | ForEach-Object { "$($_.Count) $($_.Name)" }) -join ', ') $since.`n" >> $env:GITHUB_STEP_SUMMARY + $counts = ($images | Group-Object State | ForEach-Object { "$($_.Count) $($_.Name)" }) -join ', ' + "### $env:GAME Rendering`n`n$counts $since.`n" >> $env:GITHUB_STEP_SUMMARY # One page with the images inline, so the browser opens the artifact without unzipping. Resemble.js marks # the pixels of each changed image that differ from the base. $rows = foreach ($image in $images | Sort-Object State, Name) { $diff = if ($image.State -eq 'changed') { ' class=diff' } - "$($image.Name)
$($image.State)$($image.Old)$($image.New)" + "$($image.Name)$($image.State)$($image.Old)$($image.New)" } @" $env:GAME rendering $since - + -

$env:GAME rendering $since

+ +

$env:GAME rendering

+

$counts $since

- + + $($rows -join "`n") +
BaseThis commitDifference
BaseThis commitDifference
From 0530b21a6b68b6f4a3b97731f851f6f523780485 Mon Sep 17 00:00:00 2001 From: stm <14291421+stephanmeesters@users.noreply.github.com> Date: Mon, 26 Oct 2026 12:47:26 +0100 Subject: [PATCH 5/9] ci: List the changed rendering images first and tint them red Co-Authored-By: Claude Opus 5.5 --- .github/workflows/reusable-check-rendering.yml | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/workflows/reusable-check-rendering.yml b/.github/workflows/reusable-check-rendering.yml index da1623ab867..e6b59098615 100644 --- a/.github/workflows/reusable-check-rendering.yml +++ b/.github/workflows/reusable-check-rendering.yml @@ -145,9 +145,11 @@ jobs: "### $env:GAME Rendering`n`n$counts $since.`n" >> $env:GITHUB_STEP_SUMMARY # One page with the images inline, so the browser opens the artifact without unzipping. Resemble.js marks # the pixels of each changed image that differ from the base. - $rows = foreach ($image in $images | Sort-Object State, Name) { + # Changes first. + $order = 'changed', 'removed', 'new', 'unchanged' + $rows = foreach ($image in $images | Sort-Object { $order.IndexOf($_.State) }, Name) { $diff = if ($image.State -eq 'changed') { ' class=diff' } - "$($image.Name)$($image.State)$($image.Old)$($image.New)" + "$($image.Name)$($image.State)$($image.Old)$($image.New)" } @" @@ -162,15 +164,17 @@ jobs: table { @apply mt-4 border-separate border-spacing-y-3; } thead th { @apply px-4 text-left text-sm font-medium text-slate-500; } tbody tr { @apply bg-white shadow-sm; } + tbody tr.changed { @apply bg-rose-50 shadow-rose-200; } + tr.changed td:nth-child(3) img { @apply ring-2 ring-rose-400; } tbody th, tbody td { @apply p-4 text-left align-top; } tbody th { @apply rounded-l-xl font-mono text-sm font-medium; } tbody td:last-child { @apply rounded-r-xl; } img { @apply rounded-md; } .state { @apply mt-2 block w-fit rounded-full px-2 py-0.5 font-sans text-xs; } - .changed { @apply bg-amber-100 text-amber-800; } - .new { @apply bg-sky-100 text-sky-800; } - .removed { @apply bg-rose-100 text-rose-800; } - .unchanged { @apply bg-emerald-100 text-emerald-800; } + .state.changed { @apply bg-rose-200 text-rose-900; } + .state.new { @apply bg-sky-100 text-sky-800; } + .state.removed { @apply bg-slate-200 text-slate-700; } + .state.unchanged { @apply bg-emerald-100 text-emerald-800; } .percent { @apply mt-1 block font-sans text-xs font-normal text-slate-500; }

$env:GAME rendering

From 174fcfdbe78f66ed2e9aba49fa72ad1a582b1f63 Mon Sep 17 00:00:00 2001 From: stm <14291421+stephanmeesters@users.noreply.github.com> Date: Mon, 26 Oct 2026 12:51:17 +0100 Subject: [PATCH 6/9] ci: Show the rendering images by test, with all images of a test in one card Co-Authored-By: Claude Opus 5.5 --- .../workflows/reusable-check-rendering.yml | 49 ++++++++++--------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/.github/workflows/reusable-check-rendering.yml b/.github/workflows/reusable-check-rendering.yml index e6b59098615..1e112ee7514 100644 --- a/.github/workflows/reusable-check-rendering.yml +++ b/.github/workflows/reusable-check-rendering.yml @@ -143,13 +143,22 @@ jobs: "message=$(if ($changes) { $changes } else { 'No changes' }) $since" >> $env:GITHUB_OUTPUT $counts = ($images | Group-Object State | ForEach-Object { "$($_.Count) $($_.Name)" }) -join ', ' "### $env:GAME Rendering`n`n$counts $since.`n" >> $env:GITHUB_STEP_SUMMARY - # One page with the images inline, so the browser opens the artifact without unzipping. Resemble.js marks - # the pixels of each changed image that differ from the base. - # Changes first. + # One page with the images inline, so the browser opens the artifact without unzipping. Each test gets a card + # with its images, which capture() names _.png. Resemble.js marks the pixels of each changed image + # that differ from the base. Changes come first. $order = 'changed', 'removed', 'new', 'unchanged' - $rows = foreach ($image in $images | Sort-Object { $order.IndexOf($_.State) }, Name) { - $diff = if ($image.State -eq 'changed') { ' class=diff' } - "$($image.Name)$($image.State)$($image.Old)$($image.New)" + $tests = $images | Group-Object { $_.Name -replace '_\d+\.png$' } | ForEach-Object { + [pscustomobject]@{ Name = $_.Name; Images = $_.Group; State = $_.Group.State | Sort-Object { $order.IndexOf($_) } | Select-Object -First 1 } + } + $cards = foreach ($test in $tests | Sort-Object { $order.IndexOf($_.State) }, Name) { + $index = 0 + $rows = foreach ($image in $test.Images | Sort-Object { ($_.Name -replace '^.*_(\d+)\.png$', '$1') -as [int] }) { + $title = if ($index++ -eq 0) { "

$($test.Name)

" } + $number = if ($test.Images.Count -gt 1) { "$($image.Name -replace '^.*_(\d+)\.png$', '#$1')" } + $diff = if ($image.State -eq 'changed') { ' class=diff' } + "
$title$number$($image.State)
$($image.Old)
$($image.New)
" + } + "
$($rows -join '')
" } @" @@ -161,30 +170,26 @@ jobs: body { @apply bg-slate-100 p-8 font-sans text-slate-800; } h1 { @apply text-2xl font-semibold; } h1 + p { @apply mt-1 text-slate-500; } - table { @apply mt-4 border-separate border-spacing-y-3; } - thead th { @apply px-4 text-left text-sm font-medium text-slate-500; } - tbody tr { @apply bg-white shadow-sm; } - tbody tr.changed { @apply bg-rose-50 shadow-rose-200; } - tr.changed td:nth-child(3) img { @apply ring-2 ring-rose-400; } - tbody th, tbody td { @apply p-4 text-left align-top; } - tbody th { @apply rounded-l-xl font-mono text-sm font-medium; } - tbody td:last-child { @apply rounded-r-xl; } + .columns, .image { @apply grid gap-8; grid-template-columns: 12rem repeat(3, 256px); } + .columns { @apply mt-6 px-4 text-sm font-medium text-slate-500; } + section { @apply mt-3 w-fit rounded-xl bg-white p-4 shadow-sm; } + section.changed { @apply bg-rose-50 shadow-rose-200; } + .image + .image { @apply mt-4; } + .image.changed > :nth-child(3) img { @apply ring-2 ring-rose-400; } + h2 { @apply mb-2 font-mono text-sm font-medium; } img { @apply rounded-md; } - .state { @apply mt-2 block w-fit rounded-full px-2 py-0.5 font-sans text-xs; } + .number { @apply mr-2 text-xs text-slate-500; } + .state { @apply inline-block rounded-full px-2 py-0.5 text-xs; } .state.changed { @apply bg-rose-200 text-rose-900; } .state.new { @apply bg-sky-100 text-sky-800; } .state.removed { @apply bg-slate-200 text-slate-700; } .state.unchanged { @apply bg-emerald-100 text-emerald-800; } - .percent { @apply mt-1 block font-sans text-xs font-normal text-slate-500; } + .percent { @apply mt-1 block text-xs text-slate-500; }

$env:GAME rendering

$counts $since

- - - - $($rows -join "`n") - -
BaseThis commitDifference
+
Base
This commit
Difference
+ $($cards -join "`n") From 7b3d9dd9a416351bb766435e06f3e6b82bb753d0 Mon Sep 17 00:00:00 2001 From: stm <14291421+stephanmeesters@users.noreply.github.com> Date: Mon, 26 Oct 2026 13:25:15 +0100 Subject: [PATCH 8/9] ci: Build only the Zero Hour win32 preset for this demo Co-Authored-By: Claude Opus 5.5 --- .github/workflows/ci.yml | 173 ++------------------------------------- 1 file changed, 5 insertions(+), 168 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8fb05c29c1f..12c22dbf9ff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -61,105 +61,6 @@ jobs: # Note the build jobs are split into two jobs for vc6 and win32 because the replay checks # only require the vc6 build and compiling vc6 is much faster than win32, # and the rendering checks only require the win32 build. - build-generals-vc6: - name: Build Generals${{ matrix.preset && '' }} - needs: detect-changes - if: ${{ github.event_name == 'workflow_dispatch' || needs.detect-changes.outputs.generals == 'true' || needs.detect-changes.outputs.shared == 'true' }} - permissions: - contents: read - strategy: - matrix: - include: - - preset: "vc6" - tools: true - extras: true - - preset: "vc6-profile" - tools: true - extras: true - - preset: "vc6-debug" - tools: true - extras: true - - preset: "vc6-releaselog" - tools: true - extras: true - fail-fast: false - uses: ./.github/workflows/reusable-build-toolchain.yml - with: - game: "Generals" - preset: ${{ matrix.preset }} - tools: ${{ matrix.tools }} - extras: ${{ matrix.extras }} - secrets: inherit - - build-generals-win32: - name: Build Generals${{ matrix.preset && '' }} - needs: detect-changes - if: ${{ github.event_name == 'workflow_dispatch' || needs.detect-changes.outputs.generals == 'true' || needs.detect-changes.outputs.shared == 'true' }} - permissions: - contents: read - packages: write - strategy: - matrix: - include: - - preset: "win32" - tools: true - extras: true - - preset: "win32-profile" - tools: true - extras: true - - preset: "win32-debug" - tools: true - extras: true - - preset: "win32-vcpkg" - tools: true - extras: true - - preset: "win32-vcpkg-profile" - tools: true - extras: true - - preset: "win32-vcpkg-debug" - tools: true - extras: true - fail-fast: false - uses: ./.github/workflows/reusable-build-toolchain.yml - with: - game: "Generals" - preset: ${{ matrix.preset }} - tools: ${{ matrix.tools }} - extras: ${{ matrix.extras }} - tests: true - benchmarks: ${{ matrix.preset == 'win32' }} - secrets: inherit - - build-generalsmd-vc6: - name: Build GeneralsMD${{ matrix.preset && '' }} - needs: detect-changes - if: ${{ github.event_name == 'workflow_dispatch' || needs.detect-changes.outputs.generalsmd == 'true' || needs.detect-changes.outputs.shared == 'true' }} - permissions: - contents: read - strategy: - matrix: - include: - - preset: "vc6" - tools: true - extras: true - - preset: "vc6-profile" - tools: true - extras: true - - preset: "vc6-debug" - tools: true - extras: true - - preset: "vc6-releaselog" - tools: true - extras: true - fail-fast: false - uses: ./.github/workflows/reusable-build-toolchain.yml - with: - game: "GeneralsMD" - preset: ${{ matrix.preset }} - tools: ${{ matrix.tools }} - extras: ${{ matrix.extras }} - secrets: inherit - build-generalsmd-win32: name: Build GeneralsMD${{ matrix.preset && '' }} needs: detect-changes @@ -170,25 +71,10 @@ jobs: strategy: matrix: include: + # This demo only builds what the rendering check needs. - preset: "win32" - tools: true - extras: true - - preset: "win32-profile" - tools: true - extras: true - - preset: "win32-debug" - tools: true - extras: true - - preset: "win32-vcpkg" - tools: true - extras: true - ffmpeg: true - - preset: "win32-vcpkg-profile" - tools: true - extras: true - - preset: "win32-vcpkg-debug" - tools: true - extras: true + tools: false + extras: false fail-fast: false uses: ./.github/workflows/reusable-build-toolchain.yml with: @@ -196,60 +82,11 @@ jobs: preset: ${{ matrix.preset }} tools: ${{ matrix.tools }} extras: ${{ matrix.extras }} - ffmpeg: ${{ matrix.ffmpeg || false}} + ffmpeg: false tests: true - benchmarks: ${{ matrix.preset == 'win32' }} - secrets: inherit - - replaycheck-generals: - name: Replay Check Generals${{ matrix.preset && '' }} - needs: [detect-changes, build-generals-vc6] - if: ${{ github.event_name == 'workflow_dispatch' || needs.detect-changes.outputs.generals == 'true' || needs.detect-changes.outputs.shared == 'true' }} - permissions: - contents: read - strategy: - matrix: - include: - - preset: "vc6+t+e" - - preset: "vc6-releaselog+t+e" # optimized build with logging and crashing enabled should be compatible, so we test that here. - fail-fast: false - uses: ./.github/workflows/reusable-check-replays.yml - with: - game: "Generals" - userdata: "GeneralsReplays/Generals/1.08" - preset: ${{ matrix.preset }} + benchmarks: false secrets: inherit - replaycheck-generalsmd: - name: Replay Check GeneralsMD${{ matrix.preset && '' }} - needs: [detect-changes, build-generalsmd-vc6] - if: ${{ github.event_name == 'workflow_dispatch' || needs.detect-changes.outputs.generalsmd == 'true' || needs.detect-changes.outputs.shared == 'true' }} - permissions: - contents: read - strategy: - matrix: - include: - - preset: "vc6+t+e" - - preset: "vc6-releaselog+t+e" # optimized build with logging and crashing enabled should be compatible, so we test that here. - fail-fast: false - uses: ./.github/workflows/reusable-check-replays.yml - with: - game: "GeneralsMD" - userdata: "GeneralsReplays/GeneralsZH/1.04" - preset: ${{ matrix.preset }} - secrets: inherit - - renderingcheck-generals: - name: Rendering Check Generals - needs: [detect-changes, build-generals-win32] - if: ${{ github.event_name == 'workflow_dispatch' || needs.detect-changes.outputs.generals == 'true' || needs.detect-changes.outputs.shared == 'true' }} - permissions: - contents: read - actions: read - uses: ./.github/workflows/reusable-check-rendering.yml - with: - game: "Generals" - renderingcheck-generalsmd: name: Rendering Check GeneralsMD needs: [detect-changes, build-generalsmd-win32] From e39b4f8ea51bd83209f039c4fc71026761650b00 Mon Sep 17 00:00:00 2001 From: stm <14291421+stephanmeesters@users.noreply.github.com> Date: Mon, 26 Oct 2026 13:33:35 +0100 Subject: [PATCH 9/9] ci: Build the core tools in this demo, which the artifact step collects Co-Authored-By: Claude Opus 5.5 --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 12c22dbf9ff..976d43b1538 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -73,7 +73,8 @@ jobs: include: # This demo only builds what the rendering check needs. - preset: "win32" - tools: false + # The artifact step collects the core tools, so they are built as well. + tools: true extras: false fail-fast: false uses: ./.github/workflows/reusable-build-toolchain.yml