Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 35 additions & 10 deletions .github/workflows/build-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,33 @@ on:

jobs:
build-windows:
name: GeneralsMD x86
name: ${{ matrix.game.id }} x86
runs-on: windows-2022
timeout-minutes: 45
strategy:
fail-fast: false
matrix:
game:
- id: generalsxzh
name: Zero Hour
target: z_generals
folder: GeneralsMD
exe: GeneralsXZH.exe
pdb: GeneralsXZH.pdb
build_zh: "ON"
build_generals: "OFF"
artifact_name: generalsxzh-windows-x86
ci_artifact_name: generalsxzh-windows-x86-replay-test-only
- id: generalsx
name: Generals Base
target: g_generals
folder: Generals
exe: GeneralsX.exe
pdb: GeneralsX.pdb
build_zh: "OFF"
build_generals: "ON"
artifact_name: generalsx-windows-x86
ci_artifact_name: generalsx-windows-x86-ci-only

steps:
- name: Checkout
Expand All @@ -28,27 +52,28 @@ jobs:
run: |
$env:VCPKG_ROOT = $env:VCPKG_INSTALLATION_ROOT
cmake --preset win32-vcpkg `
-DRTS_BUILD_GENERALS=OFF `
-DRTS_BUILD_ZEROHOUR=ON `
-DRTS_BUILD_GENERALS=${{ matrix.game.build_generals }} `
-DRTS_BUILD_ZEROHOUR=${{ matrix.game.build_zh }} `
-DRTS_BUILD_CORE_TOOLS=OFF `
-DRTS_BUILD_ZEROHOUR_TOOLS=OFF `
-DRTS_BUILD_GENERALS_TOOLS=OFF `
-DRTS_BUILD_OPTION_SAGE_PATCH=OFF `
-DSAGE_USE_DX8=ON `
-DSAGE_USE_DETERMINISTIC_MATH=ON

- name: Build
shell: pwsh
run: cmake --build --preset win32-vcpkg
run: cmake --build --preset win32-vcpkg --target ${{ matrix.game.target }}

- name: Collect runtime
shell: pwsh
run: |
New-Item -ItemType Directory -Force artifacts | Out-Null
New-Item -ItemType Directory -Force ci-artifacts | Out-Null
Copy-Item build/win32-vcpkg/GeneralsMD/Release/GeneralsXZH.exe artifacts/
Copy-Item build/win32-vcpkg/GeneralsMD/Release/GeneralsXZH.pdb artifacts/
Copy-Item build/win32-vcpkg/${{ matrix.game.folder }}/Release/${{ matrix.game.exe }} artifacts/
Copy-Item build/win32-vcpkg/${{ matrix.game.folder }}/Release/${{ matrix.game.pdb }} artifacts/
Copy-Item build/win32-vcpkg/vcpkg_installed/x86-windows/bin/zlib1.dll artifacts/
Copy-Item build/win32-vcpkg/GeneralsMD/Release/GeneralsXZH.exe ci-artifacts/
Copy-Item build/win32-vcpkg/${{ matrix.game.folder }}/Release/${{ matrix.game.exe }} ci-artifacts/
Copy-Item build/win32-vcpkg/vcpkg_installed/x86-windows/bin/zlib1.dll ci-artifacts/

foreach ($name in @("binkw32.dll", "mss32.dll")) {
Expand All @@ -61,21 +86,21 @@ jobs:
}

@"
Copy these files into an existing licensed Zero Hour installation.
Copy these files into an existing licensed ${{ matrix.game.name }} installation.
Keep the installation's original binkw32.dll and mss32.dll; the build-time
stub DLLs do not provide retail video or audio playback.
"@ | Set-Content artifacts/INSTALL.txt

- name: Upload runtime
uses: actions/upload-artifact@v7
with:
name: generalsxzh-windows-x86
name: ${{ matrix.game.artifact_name }}
path: artifacts
retention-days: 7

- name: Upload replay-test runtime
uses: actions/upload-artifact@v7
with:
name: generalsxzh-windows-x86-replay-test-only
name: ${{ matrix.game.ci_artifact_name }}
path: ci-artifacts
retention-days: 1
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ jobs:
build-windows:
name: Build Windows
needs: detect-changes
if: needs.detect-changes.outputs.zh-should-build == 'true' || github.event_name == 'workflow_dispatch'
if: needs.detect-changes.outputs.zh-should-build == 'true' || needs.detect-changes.outputs.base-should-build == 'true' || github.event_name == 'workflow_dispatch'
uses: ./.github/workflows/build-windows.yml
secrets: inherit

Expand Down
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ Docker is the recommended build method on Linux hosts to ensure all toolchain re
- **SDL3 from source**: Fetched via CMake FetchContent. No system package needed.
- **Manual memory**: Always delete/delete[]. Use STLPort for VC6 legacy builds.
- **Debug options break replays**: Use `RTS_BUILD_OPTION_DEBUG=OFF` for replay tests.
- **Windows executable icons (.ico)**: Windows builds embed `Generals/Code/Main/Generals.ico` and `GeneralsMD/Code/Main/Generals.ico` via `RTS.RC`. If source PNG icon assets (`assets/generalsx_icon.png` or `assets/generalsx-zh_icon.png`) are updated, regenerate the multi-resolution `.ico` files (sizes 16, 24, 32, 48, 64, 128, 256) to keep Windows executables in sync.

## Testing & Validation
### Smoke test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,11 @@
//----------------------------------------------------------------------------

#include "GameClient/VideoPlayer.h"
// GeneralsX @TheSuperHackers @build BenderAI 11/02/2026 Stub Bink for Phase 1 (proprietary SDK)
// TODO Phase 3: Replace with FFmpeg or skip videos gracefully
// #include "bink.h"

// Bink type stubs (proprietary SDK not available)
#ifdef _WIN32
#include "bink.h"
#else
typedef struct BINK* HBINK;
#endif

//----------------------------------------------------------------------------
// Forward References
Expand Down
4 changes: 3 additions & 1 deletion Generals/Code/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ add_library(gi_always_no_pch INTERFACE) # Use this for Shared Libs with MFC AFX
target_include_directories(gi_gameengine_include INTERFACE "GameEngine/Include")
target_include_directories(gi_libraries_source_wwvegas INTERFACE "Libraries/Source/WWVegas")
target_include_directories(gi_main INTERFACE "Main")
target_include_directories(gi_always INTERFACE "CompatLib/Include")
if(UNIX)
target_include_directories(gi_always INTERFACE "CompatLib/Include")
endif()

target_compile_definitions(gi_always INTERFACE
RTS_GENERALS=1
Expand Down
13 changes: 0 additions & 13 deletions Generals/Code/CompatLib/Include/comip.h

This file was deleted.

12 changes: 0 additions & 12 deletions Generals/Code/CompatLib/Include/comutil.h

This file was deleted.

14 changes: 14 additions & 0 deletions Generals/Code/CompatLib/Include/d3dx8math.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,20 @@ extern "C"
typedef struct D3DXMATRIX : D3DMATRIX
{
#ifdef __cplusplus
D3DXMATRIX() = default;

D3DXMATRIX(
FLOAT m00, FLOAT m01, FLOAT m02, FLOAT m03,
FLOAT m10, FLOAT m11, FLOAT m12, FLOAT m13,
FLOAT m20, FLOAT m21, FLOAT m22, FLOAT m23,
FLOAT m30, FLOAT m31, FLOAT m32, FLOAT m33)
{
m[0][0] = m00; m[0][1] = m01; m[0][2] = m02; m[0][3] = m03;
m[1][0] = m10; m[1][1] = m11; m[1][2] = m12; m[1][3] = m13;
m[2][0] = m20; m[2][1] = m21; m[2][2] = m22; m[2][3] = m23;
m[3][0] = m30; m[3][1] = m31; m[3][2] = m32; m[3][3] = m33;
}

D3DXMATRIX operator *(const D3DXMATRIX &other) const;
D3DXMATRIX operator *= (const D3DXMATRIX& other);
#endif
Expand Down
7 changes: 2 additions & 5 deletions Generals/Code/CompatLib/Include/windows.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,8 @@
// Our types take precedence via PCH (PreRTS.h includes windows_compat.h early).

#ifdef _WIN32
// Windows: use real Windows.h from SDK (will be found in system paths first)
// This header is only reached if no SDK windows.h exists
#include "windows_compat.h"
#include <windows.h>
#else
// Linux: Our compatibility layer only (NO DXVK headers here!)
// DXVK's windows_base.h will be included by d3d8.h when needed
// Linux/macOS: Our compatibility layer only (prevents DXVK unknwn.h redefinition)
#include "windows_compat.h"
#endif
2 changes: 1 addition & 1 deletion Generals/Code/CompatLib/Include/windows_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#ifdef _WIN32
// Windows: use real Windows.h from SDK (will be found in system paths first)
// This header is only reached if no SDK windows.h exists
#include "windows_compat.h"
#include <windows.h>
#else
// Linux: Our compatibility layer only (NO DXVK headers here!)
// DXVK's windows_base.h will be included by d3d8.h when needed
Expand Down
12 changes: 12 additions & 0 deletions Generals/Code/GameEngine/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1079,6 +1079,17 @@ target_sources(g_gameengine PRIVATE ${GAMEENGINE_SRC})
target_include_directories(g_gameengine PUBLIC
Include
)
if(UNIX)
target_include_directories(g_gameengine PUBLIC ../CompatLib/Include)
endif()

# Ensure DXVK headers are available when building on Linux
if(NOT SAGE_USE_DX8 AND dxvk_SOURCE_DIR)
target_include_directories(g_gameengine PUBLIC
${dxvk_SOURCE_DIR}/usr/include
${dxvk_SOURCE_DIR}/usr/include/dxvk
)
endif()

target_include_directories(g_gameengine PRIVATE
Include/Precompiled
Expand All @@ -1092,6 +1103,7 @@ target_link_libraries(g_gameengine PRIVATE
target_link_libraries(g_gameengine PUBLIC
corei_gameengine_public
g_wwvegas
d3d8lib # Ensure DirectX8 headers available (Windows SDK or DXVK)
)

target_precompile_headers(g_gameengine PRIVATE
Expand Down
11 changes: 11 additions & 0 deletions Generals/Code/GameEngine/Source/Common/GameEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1159,3 +1159,14 @@ void updateTGAtoDDS()

system(CONVERT_EXEC1);
}

// If we're using the Wide character version of MessageBox, then there's no additional
// processing necessary. Please note that this is a sleazy way to get this information,
// but pending a better one, this'll have to do.
// TheSuperHackers @build fighter19 11/02/2026 MessageBox detection (Windows-only)
#ifdef _WIN32
extern const Bool TheSystemIsUnicode = (((void*) (::MessageBox)) == ((void*) (::MessageBoxW)));
#else
extern const Bool TheSystemIsUnicode = true; // Linux: Always Unicode (UTF-8)
#endif

2 changes: 1 addition & 1 deletion Generals/Code/GameEngine/Source/Common/System/registry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine

#include "Common/Registry.h"
#include "registryini.h"
#include "WWLib/registryini.h"

// TheSuperHackers @build felipebraz 11/02/2026 Phase 1.5 - Linux port
// Windows Registry types not available on Linux - define stub types
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
#include "Common/GameLOD.h"
#include "Common/GameState.h"

#if DEEP_CRC_TO_MEMORY
#if DEEP_CRC_TO_MEMORY && !defined(_WIN32)
#include <sys/utsname.h>
#include <SDL3/SDL.h>
#endif
Expand Down Expand Up @@ -5065,6 +5065,9 @@ void GameLogic::writeCRCBuffersToDisk(UnsignedInt frame) const
AsciiString str;
// GeneralsX: Generate OS/Arch header
AsciiString headerStr;
#ifdef _WIN32
headerStr = "GeneralsX: Windows x86\n\n";
#else
struct utsname sysInfo;
if (uname(&sysInfo) == 0) {
headerStr.format("GeneralsX: %s %s (%s)\nArch: %s\nCPU Cores: %d\nRAM: %d MB\n\n",
Expand All @@ -5073,6 +5076,7 @@ void GameLogic::writeCRCBuffersToDisk(UnsignedInt frame) const
} else {
headerStr = "GeneralsX: Unknown OS/Arch\n\n";
}
#endif

// Format filename as deep_crc_YYYY-MM-DD-HH-MM-SS.bin inside user data Debug dir
time_t t = time(nullptr);
Expand Down
10 changes: 5 additions & 5 deletions Generals/Code/GameEngineDevice/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -175,13 +175,13 @@ if(WIN32)
list(APPEND GAMEENGINEDEVICE_SRC
# Source/Win32Device/Common/Win32BIGFile.cpp
# Source/Win32Device/Common/Win32BIGFileSystem.cpp
Source/Win32Device/Common/Win32CDManager.cpp
Source/Win32Device/Common/Win32GameEngine.cpp
${CMAKE_SOURCE_DIR}/Core/GameEngineDevice/Source/Win32Device/Common/Win32GameEngine.cpp
# Source/Win32Device/Common/Win32LocalFile.cpp
# Source/Win32Device/Common/Win32LocalFileSystem.cpp
Source/Win32Device/Common/Win32OSDisplay.cpp
Source/Win32Device/GameClient/Win32DIKeyboard.cpp
Source/Win32Device/GameClient/Win32Mouse.cpp
${CMAKE_SOURCE_DIR}/Core/GameEngineDevice/Source/Win32Device/Common/Win32OSDisplay.cpp
${CMAKE_SOURCE_DIR}/Core/GameEngineDevice/Source/Win32Device/GameClient/Win32DIKeyboard.cpp
# Source/Win32Device/GameClient/Win32DIMouse.cpp
${CMAKE_SOURCE_DIR}/Core/GameEngineDevice/Source/Win32Device/GameClient/Win32Mouse.cpp
)
else()
# Linux-specific files (SDL3, DXVK)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2111,7 +2111,6 @@ void W3DProjectedShadow::init()

if (m_type & SHADOW_PROJECTION)
{
float minx,maxx;
m_shadowProjector = NEW_REF(TexProjectClass,());
m_shadowProjector->Set_Intensity(0.4f,true);
m_shadowProjector->Set_Texture(m_shadowTexture[0]->getTexture());
Expand Down
Binary file modified Generals/Code/Main/Generals.ico
Binary file not shown.
14 changes: 14 additions & 0 deletions GeneralsMD/Code/CompatLib/Include/windows.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#pragma once

// Linux/Unix compatibility shim for Windows.h
// GeneralsX @build BenderAI 11/02/2026 Windows API compatibility layer
// STRATEGY: Provide our own complete Windows types/functions FIRST.
// DXVK headers (d3d8.h) will include their own windows_base.h later.
// Our types take precedence via PCH (PreRTS.h includes windows_compat.h early).

#ifdef _WIN32
#include <windows.h>
#else
// Linux/macOS: Our compatibility layer only (prevents DXVK unknwn.h redefinition)
#include "windows_compat.h"
#endif
Binary file modified GeneralsMD/Code/Main/Generals.ico
Binary file not shown.
2 changes: 1 addition & 1 deletion GeneralsMD/Code/Main/RTS.RC
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ END

// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ApplicationIcon ICON DISCARDABLE "GENERALS.ICO"
IDI_ApplicationIcon ICON DISCARDABLE "Generals.ico"
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////

Expand Down
9 changes: 9 additions & 0 deletions docs/WORKLOG/2026-08-DIARY.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
# August 2026

## 19/08/2026
### Enable Windows Build Matrix for Generals Base Game
- Backported native MSVC Windows build support to the Generals base game (`Generals/`):
- Pointed Win32 device sources to shared `Core/GameEngineDevice/Source/Win32Device/` implementations (`Win32GameEngine.cpp`, `Win32OSDisplay.cpp`, `Win32DIKeyboard.cpp`, `Win32Mouse.cpp`).
- Synced include guards and `d3d8lib` linkage across `Generals/Code/GameEngine/CMakeLists.txt` and `Generals/Code/CMakeLists.txt`.
- Removed obsolete shadowing CompatLib headers (`comip.h`, `comutil.h`, `windows.h`) and synced `windows_wrapper.h` / `d3dx8math.h`.
- Expanded `.github/workflows/build-windows.yml` to a matrix building both `generalsxzh` (`GeneralsMD` -> `GeneralsXZH.exe`) and `generalsx` (`Generals` -> `GeneralsX.exe`).
- Updated `ci.yml` to trigger `build-windows` when either Zero Hour or Generals base game changes are detected.
- Converted `assets/generalsx_icon.png` and `assets/generalsx-zh_icon.png` into high-resolution multi-size Windows icon files (`Generals.ico`), packaging crisp icons (16x16 to 256x256) into Windows executables.

### Independent Windows CI Asset Cache & Executable Standardization
- Decoupled Windows replay tests from Linux build/replay workflows by establishing dedicated Windows asset caching (`game-assets-cache-windows-v1`) with self-contained fallback extraction.
- Passed `ASSETS_KEY` secret directly to the Windows replay test workflow.
Expand Down
Loading