From 83fba9ae31e89badaef2e75682e13eb07ab6a01c Mon Sep 17 00:00:00 2001 From: Robert Middleton Date: Thu, 18 Jun 2026 21:32:47 -0400 Subject: [PATCH 1/6] build wwlib on linux --- .github/workflows/openw3d.yml | 1 + CMakeLists.txt | 1 + Code/wwlib/CMakeLists.txt | 9 +- Code/wwlib/always.h | 71 ++++++++ Code/wwlib/cpudetect.cpp | 52 +++++- Code/wwlib/critsection.h | 8 + Code/wwlib/mixfile.cpp | 6 +- Code/wwlib/msgloop.cpp | 3 + Code/wwlib/msgloop.h | 4 + Code/wwlib/refcount.cpp | 2 + Code/wwlib/registry.cpp | 4 +- Code/wwlib/registry.h | 5 +- Code/wwlib/registry_linux.cpp | 303 ++++++++++++++++++++++++++++++++++ Code/wwlib/thread.cpp | 4 + Code/wwlib/verchk.cpp | 14 +- Code/wwlib/verchk.h | 13 +- Code/wwlib/win.cpp | 10 +- Code/wwlib/win.h | 5 +- cmake/dx9.cmake | 6 + 19 files changed, 497 insertions(+), 24 deletions(-) create mode 100644 Code/wwlib/registry_linux.cpp diff --git a/.github/workflows/openw3d.yml b/.github/workflows/openw3d.yml index dce2c6023..fe0d6f3c9 100644 --- a/.github/workflows/openw3d.yml +++ b/.github/workflows/openw3d.yml @@ -77,6 +77,7 @@ jobs: wwdebug wwbitpack wwtranslatedb + wwlib shell: bash steps: diff --git a/CMakeLists.txt b/CMakeLists.txt index 726a12036..1d3433ff7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,6 +72,7 @@ if(NOT WIN32) add_compile_definitions(strnicmp=strncasecmp) add_compile_definitions(wcsnicmp=wcsncasecmp) add_compile_definitions(wcsicmp=wcscasecmp) + add_compile_definitions(DebugBreak=__builtin_trap) endif() include(FetchContent) diff --git a/Code/wwlib/CMakeLists.txt b/Code/wwlib/CMakeLists.txt index 1e8bc455f..8f1e8f0e0 100644 --- a/Code/wwlib/CMakeLists.txt +++ b/Code/wwlib/CMakeLists.txt @@ -39,7 +39,6 @@ set(WWLIB_SRC readline.cpp realcrc.cpp refcount.cpp - registry.cpp rndstrng.cpp slnode.cpp straw.cpp @@ -53,7 +52,6 @@ set(WWLIB_SRC verchk.cpp widestring.cpp win.cpp - WWCOMUtil.cpp wwfile.cpp wwstring.cpp xpipe.cpp @@ -139,7 +137,6 @@ set(WWLIB_SRC verchk.h widestring.h win.h - WWCOMUtil.h wwdialog.cpp wwdialog.h wwfile.h @@ -149,6 +146,12 @@ set(WWLIB_SRC xstraw.h ) +if(WIN32) + list(APPEND WWLIB_SRC registry.cpp) +else() + list(APPEND WWLIB_SRC registry_linux.cpp) +endif() + if(TARGET ffmpeg) list(APPEND WWLIB_SRC FFmpegFile.cpp FFmpegFile.h) endif() diff --git a/Code/wwlib/always.h b/Code/wwlib/always.h index 3dd4ba898..10835962e 100644 --- a/Code/wwlib/always.h +++ b/Code/wwlib/always.h @@ -154,6 +154,77 @@ __forceinline unsigned int _byteswap_ulong(unsigned int value) #ifndef _alloca #define _alloca(size) alloca(size) #endif + +#ifndef OutputDebugStringA +#define OutputDebugStringA(s) ((void)(s)) +#endif + +// Windows BOOL type +#ifndef BOOL +typedef int BOOL; +#endif +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +// Windows path constant equivalents +#ifndef _MAX_DRIVE +#define _MAX_DRIVE 3 +#endif +#ifndef _MAX_DIR +#define _MAX_DIR 260 +#endif +#ifndef _MAX_PATH +#define _MAX_PATH 260 +#endif +#ifndef _MAX_FNAME +#define _MAX_FNAME 256 +#endif +#ifndef _MAX_EXT +#define _MAX_EXT 256 +#endif + +// Windows file operation equivalents +#ifndef DeleteFileA +#define DeleteFileA(f) (remove(f) == 0) +#endif +#ifndef MoveFileA +#define MoveFileA(src, dst) (rename(src, dst) == 0) +#endif + +// _splitpath: split a path into drive/dir/fname/ext components +static inline void _splitpath(const char *path, char *drive, char *dir, char *fname, char *ext) +{ + if (drive) drive[0] = '\0'; // no drive letters on Linux + const char *last_slash = strrchr(path, '/'); + const char *name_start = last_slash ? last_slash + 1 : path; + const char *last_dot = strrchr(name_start, '.'); + if (dir) { + if (last_slash) { + size_t n = (size_t)(last_slash - path) + 1; + std::memcpy(dir, path, n); + dir[n] = '\0'; + } else { + dir[0] = '\0'; + } + } + if (fname) { + size_t n = last_dot ? (size_t)(last_dot - name_start) : std::strlen(name_start); + std::memcpy(fname, name_start, n); + fname[n] = '\0'; + } + if (ext) { + if (last_dot) { + std::strcpy(ext, last_dot); + } else { + ext[0] = '\0'; + } + } +} + #endif // !_WIN32 #endif diff --git a/Code/wwlib/cpudetect.cpp b/Code/wwlib/cpudetect.cpp index 793432037..acf2fcef4 100644 --- a/Code/wwlib/cpudetect.cpp +++ b/Code/wwlib/cpudetect.cpp @@ -21,11 +21,27 @@ #include "wwdebug.h" #include "thread.h" #include "mpu.h" +#if defined(_WIN32) #include +#else +#include +#include +#include +// Stub out Windows OS version platform IDs; Linux Init_OS sets OSVersionPlatformId=3 +// so all switch statements on OSVersionPlatformId fall through to the default case. +#define VER_PLATFORM_WIN32s 0 +#define VER_PLATFORM_WIN32_WINDOWS 1 +#define VER_PLATFORM_WIN32_NT 2 +#endif #include "systimer.h" #if CPU_X86 || CPU_X86_64 +#if defined(_MSC_VER) #include +#else +#include +#include +#endif #endif #if CPU_X86 || CPU_X86_64 @@ -890,6 +906,7 @@ void CPUDetectClass::Init_Processor_Features() void CPUDetectClass::Init_Memory() { +#if defined(_WIN32) MEMORYSTATUS mem; GlobalMemoryStatus(&mem); TotalPhysicalMemory=mem.dwTotalPhys; @@ -898,10 +915,22 @@ void CPUDetectClass::Init_Memory() AvailablePageMemory=mem.dwAvailPageFile; TotalVirtualMemory=mem.dwTotalVirtual; AvailableVirtualMemory=mem.dwAvailVirtual; +#else + struct sysinfo si = {}; + if (sysinfo(&si) == 0) { + TotalPhysicalMemory = (unsigned)(si.totalram * si.mem_unit); + AvailablePhysicalMemory = (unsigned)(si.freeram * si.mem_unit); + TotalPageMemory = (unsigned)(si.totalswap * si.mem_unit); + AvailablePageMemory = (unsigned)(si.freeswap * si.mem_unit); + TotalVirtualMemory = (unsigned)((si.totalram + si.totalswap) * si.mem_unit); + AvailableVirtualMemory = (unsigned)((si.freeram + si.freeswap) * si.mem_unit); + } +#endif } void CPUDetectClass::Init_OS() { +#if defined(_WIN32) // GetVersionEx only returns the version of Windows it was manifested for since Windows 8. // RtlGetVersion returns the correct information at least at the time of writing. typedef LONG(WINAPI * RtlGetVersionFuncPtr)(PRTL_OSVERSIONINFOW); @@ -927,6 +956,17 @@ void CPUDetectClass::Init_OS() OSVersionBuildNumber = 0; OSVersionPlatformId = 2; OSVersionExtraInfo = ""; +#else + struct utsname uts = {}; + if (uname(&uts) == 0) { + OSVersionExtraInfo = uts.release; + sscanf(uts.release, "%u.%u.%u", + &OSVersionNumberMajor, + &OSVersionNumberMinor, + &OSVersionBuildNumber); + } + OSVersionPlatformId = 3; // No Windows platform match; switches fall to default +#endif } bool CPUDetectClass::CPUID( @@ -940,17 +980,19 @@ bool CPUDetectClass::CPUID( if (!Has_CPUID_Instruction()) { return false; // Most processors since 486 have CPUID... } +#if defined(_MSC_VER) int cpuInfo[4]; __cpuid(cpuInfo, cpuid_type); - u_eax_=cpuInfo[0]; u_ebx_=cpuInfo[1]; u_ecx_=cpuInfo[2]; u_edx_=cpuInfo[3]; - +#else + __cpuid(cpuid_type, u_eax_, u_ebx_, u_ecx_, u_edx_); +#endif return true; #else - return false + return false; #endif } @@ -1059,9 +1101,13 @@ void CPUDetectClass::Init_Compact_Log() { StringClass work(0,true); +#if defined(_WIN32) TIME_ZONE_INFORMATION time_zone; GetTimeZoneInformation(&time_zone); COMPACTLOG(("%d\t",time_zone.Bias)); +#else + COMPACTLOG(("0\t")); +#endif OSInfoStruct os_info; Get_OS_Info(os_info,OSVersionPlatformId,OSVersionNumberMajor,OSVersionNumberMinor,OSVersionBuildNumber); diff --git a/Code/wwlib/critsection.h b/Code/wwlib/critsection.h index dab884f15..2ba31ca49 100644 --- a/Code/wwlib/critsection.h +++ b/Code/wwlib/critsection.h @@ -45,7 +45,11 @@ #include "always.h" #include "wwdebug.h" +#if defined(_WIN32) #include +#else +#include +#endif class CriticalSectionClass { @@ -67,7 +71,11 @@ class CriticalSectionClass friend LockClass; private: +#if defined(_WIN32) CRITICAL_SECTION Bar; +#else + std::mutex Bar; +#endif bool inside; void Enter(); void Exit(); diff --git a/Code/wwlib/mixfile.cpp b/Code/wwlib/mixfile.cpp index 20f5f6175..f65497b6b 100644 --- a/Code/wwlib/mixfile.cpp +++ b/Code/wwlib/mixfile.cpp @@ -365,8 +365,8 @@ MixFileFactoryClass::Flush_Changes (void) // // Delete the old mix file and rename the new one // - ::DeleteFileA (MixFilename); - ::MoveFileA (full_path, MixFilename); + DeleteFileA (MixFilename); + MoveFileA (full_path, MixFilename); // // Reset the lists @@ -595,6 +595,7 @@ void MixFileCreator::Add_File( const char * filename, FileClass *file ) /* ** */ +#if defined(_WIN32) void Add_Files( const char * dir, MixFileCreator & mix ) { BOOL bcontinue = true; @@ -637,3 +638,4 @@ void Setup_Mix_File( void ) } } +#endif // _WIN32 diff --git a/Code/wwlib/msgloop.cpp b/Code/wwlib/msgloop.cpp index 535e5bbcf..bb6355c7f 100644 --- a/Code/wwlib/msgloop.cpp +++ b/Code/wwlib/msgloop.cpp @@ -43,6 +43,7 @@ #include "vector.h" #include "win.h" +#if defined(_WIN32) /* ** Tracks modeless dialog box messages by keeping a record of all active modeless dialog @@ -252,3 +253,5 @@ void Remove_Accelerator(HACCEL accelerator) } } } + +#endif // _WIN32 diff --git a/Code/wwlib/msgloop.h b/Code/wwlib/msgloop.h index 4fd233219..b8a75a3b7 100644 --- a/Code/wwlib/msgloop.h +++ b/Code/wwlib/msgloop.h @@ -40,6 +40,8 @@ #ifndef MSGLOOP_H #define MSGLOOP_H +#if defined(_WIN32) + #include // Main message handler. @@ -56,4 +58,6 @@ void Remove_Accelerator(HACCEL accelerator); // General purpose message intercept handler. extern bool (*Message_Intercept_Handler)(MSG &msg); +#endif // _WIN32 + #endif diff --git a/Code/wwlib/refcount.cpp b/Code/wwlib/refcount.cpp index 47aadf5d5..ba0d65da1 100644 --- a/Code/wwlib/refcount.cpp +++ b/Code/wwlib/refcount.cpp @@ -40,7 +40,9 @@ #include "refcount.h" +#if defined(_WIN32) #include +#endif #ifndef NDEBUG diff --git a/Code/wwlib/registry.cpp b/Code/wwlib/registry.cpp index 2cac809f9..52d8dd15f 100644 --- a/Code/wwlib/registry.cpp +++ b/Code/wwlib/registry.cpp @@ -33,6 +33,8 @@ *---------------------------------------------------------------------------------------------* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +#if defined(_WIN32) + #include "registry.h" #include "rawfile.h" #include "ini.h" @@ -733,7 +735,7 @@ void RegistryClass::Delete_Registry_Tree(char *path) } } - +#endif // _WIN32 diff --git a/Code/wwlib/registry.h b/Code/wwlib/registry.h index 5b958711b..bd53c2239 100644 --- a/Code/wwlib/registry.h +++ b/Code/wwlib/registry.h @@ -110,10 +110,11 @@ class RegistryClass { private: +#if defined(_WIN32) static void Delete_Registry_Values(HKEY key); - static void Save_Registry_Tree(char *path, INIClass *ini); static void Save_Registry_Values(HKEY key, char *path, INIClass *ini); - +#endif + static void Save_Registry_Tree(char *path, INIClass *ini); void * Key; bool IsValid; diff --git a/Code/wwlib/registry_linux.cpp b/Code/wwlib/registry_linux.cpp new file mode 100644 index 000000000..0da11349e --- /dev/null +++ b/Code/wwlib/registry_linux.cpp @@ -0,0 +1,303 @@ +/* +** Command & Conquer Renegade(tm) +** Copyright 2025 Electronic Arts Inc. +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +*/ + +/* +** Linux implementation of RegistryClass backed by an INI file. +** Persists settings to $HOME/.config/renegade/registry.ini. +*/ + +#if !defined(_WIN32) + +#include "registry.h" +#include "ini.h" +#include "inisup.h" +#include "rawfile.h" + +#include +#include +#include +#include +#include +#include + +bool RegistryClass::IsLocked = false; + +static const char *Registry_File_Path() +{ + static char path[512] = {}; + if (path[0] == '\0') { + const char *home = getenv("HOME"); + if (home) { + snprintf(path, sizeof(path), "%s/.config/renegade/registry.ini", home); + } else { + strncpy(path, "registry.ini", sizeof(path) - 1); + } + } + return path; +} + +static void Ensure_Registry_Dir() +{ + const char *home = getenv("HOME"); + if (!home) return; + char dir[512]; + snprintf(dir, sizeof(dir), "%s/.config", home); + mkdir(dir, 0755); + snprintf(dir, sizeof(dir), "%s/.config/renegade", home); + mkdir(dir, 0755); +} + +static INIClass &Registry_INI() +{ + static INIClass ini; + static bool loaded = false; + if (!loaded) { + loaded = true; + RawFileClass file(Registry_File_Path()); + if (file.Is_Available()) { + ini.Load(file); + } + } + return ini; +} + +static void Save_Registry_INI() +{ + Ensure_Registry_Dir(); + RawFileClass file(Registry_File_Path()); + Registry_INI().Save(file); +} + +static const char *Key_Section(void *key) +{ + return reinterpret_cast(key); +} + +bool RegistryClass::Exists(const char *sub_key) +{ + return Registry_INI().Section_Present(sub_key); +} + +RegistryClass::RegistryClass(const char *sub_key, bool create) : + IsValid(false), + Key(NULL) +{ + if (sub_key) { + Key = strdup(sub_key); + if (create && !IsLocked) { + IsValid = true; + } else { + IsValid = Registry_INI().Section_Present(sub_key); + } + } +} + +RegistryClass::~RegistryClass() +{ + if (Key) { + free(Key); + Key = NULL; + } + IsValid = false; +} + +int RegistryClass::Get_Int(const char *name, int def_value) +{ + assert(IsValid); + return Registry_INI().Get_Int(Key_Section(Key), name, def_value); +} + +void RegistryClass::Set_Int(const char *name, int value) +{ + assert(IsValid); + if (IsLocked) return; + Registry_INI().Put_Int(Key_Section(Key), name, value); + Save_Registry_INI(); +} + +bool RegistryClass::Get_Bool(const char *name, bool def_value) +{ + return (Get_Int(name, def_value ? 1 : 0) != 0); +} + +void RegistryClass::Set_Bool(const char *name, bool value) +{ + Set_Int(name, value ? 1 : 0); +} + +float RegistryClass::Get_Float(const char *name, float def_value) +{ + assert(IsValid); + return Registry_INI().Get_Float(Key_Section(Key), name, def_value); +} + +void RegistryClass::Set_Float(const char *name, float value) +{ + assert(IsValid); + if (IsLocked) return; + Registry_INI().Put_Float(Key_Section(Key), name, value); + Save_Registry_INI(); +} + +char *RegistryClass::Get_String(const char *name, char *value, int value_size, const char *default_string) +{ + assert(IsValid); + const char *def = (default_string != NULL) ? default_string : ""; + Registry_INI().Get_String(Key_Section(Key), name, def, value, value_size); + return value; +} + +void RegistryClass::Get_String(const char *name, StringClass &string, const char *default_string) +{ + assert(IsValid); + const char *def = (default_string != NULL) ? default_string : ""; + Registry_INI().Get_String(string, Key_Section(Key), name, def); +} + +void RegistryClass::Set_String(const char *name, const char *value) +{ + assert(IsValid); + if (IsLocked) return; + Registry_INI().Put_String(Key_Section(Key), name, value); + Save_Registry_INI(); +} + +int RegistryClass::Get_Bin_Size(const char *name) +{ + assert(IsValid); + unsigned char buf[8192]; + return Registry_INI().Get_UUBlock(Key_Section(Key), name, buf, sizeof(buf)); +} + +void RegistryClass::Get_Bin(const char *name, void *buffer, int buffer_size) +{ + assert(IsValid); + assert(buffer != NULL); + assert(buffer_size > 0); + Registry_INI().Get_UUBlock(Key_Section(Key), name, buffer, buffer_size); +} + +void RegistryClass::Set_Bin(const char *name, const void *buffer, int buffer_size) +{ + assert(IsValid); + assert(buffer != NULL); + assert(buffer_size > 0); + if (IsLocked) return; + Registry_INI().Put_UUBlock(Key_Section(Key), name, buffer, buffer_size); + Save_Registry_INI(); +} + +void RegistryClass::Get_Value_List(DynamicVectorClass &list) +{ + const char *section = Key_Section(Key); + int index = 0; + const char *entry = NULL; + while ((entry = Registry_INI().Get_Entry(section, index++)) != NULL) { + list.Add(StringClass(entry)); + } +} + +void RegistryClass::Delete_Value(const char *name) +{ + if (IsLocked) return; + Registry_INI().Clear(Key_Section(Key), name); + Save_Registry_INI(); +} + +void RegistryClass::Deleta_All_Values() +{ + if (IsLocked) return; + Registry_INI().Clear(Key_Section(Key)); + Save_Registry_INI(); +} + +void RegistryClass::Delete_Registry_Tree(char *path) +{ + if (IsLocked) return; + Registry_INI().Clear(path); + Save_Registry_INI(); +} + +void RegistryClass::Save_Registry_Tree(char *path, INIClass *ini) +{ + const char *section = path; + int index = 0; + const char *entry = NULL; + char buf[1024]; + while ((entry = Registry_INI().Get_Entry(section, index++)) != NULL) { + Registry_INI().Get_String(section, entry, "", buf, sizeof(buf)); + ini->Put_String(section, entry, buf); + } +} + +void RegistryClass::Save_Registry(const char *filename, char *path) +{ + RawFileClass file(filename); + INIClass ini; + Save_Registry_Tree(path, &ini); + ini.Save(file); +} + +void RegistryClass::Load_Registry(const char *filename, char *old_path, char *new_path) +{ + if (IsLocked) return; + + RawFileClass file(filename); + INIClass ini; + ini.Load(file); + + const size_t old_path_len = ::strlen(old_path); + char path[1024]; + char string[1024]; + unsigned char buffer[8192]; + + List §ion_list = ini.Get_Section_List(); + + for (INISection *section = section_list.First(); section != NULL; section = section->Next_Valid()) { + char *section_name = section->Section; + strcpy(path, new_path); + char *cut = strstr(section_name, old_path); + if (cut) { + strcat(path, cut + old_path_len); + } + + RegistryClass reg(path); + if (reg.Is_Valid()) { + char *entry = (char*)1; + int index = 0; + + while (entry) { + entry = (char*)ini.Get_Entry(section_name, index++); + if (entry) { + if (strncmp(entry, "BIN_", 4) == 0) { + int len = ini.Get_UUBlock(section_name, entry, buffer, sizeof(buffer)); + reg.Set_Bin(entry + 4, buffer, len); + } else if (strncmp(entry, "DWORD_", 6) == 0) { + int temp = ini.Get_Int(section_name, entry, 0); + reg.Set_Int(entry + 6, temp); + } else if (strncmp(entry, "STRING_", 7) == 0) { + ini.Get_String(section_name, entry, "", string, sizeof(string)); + reg.Set_String(entry + 7, string); + } + } + } + } + } +} + +#endif // !_WIN32 diff --git a/Code/wwlib/thread.cpp b/Code/wwlib/thread.cpp index 1ac1a0f01..7629b16a5 100644 --- a/Code/wwlib/thread.cpp +++ b/Code/wwlib/thread.cpp @@ -67,7 +67,9 @@ ThreadClass::InternalThreadFunctionReturnType INTERNAL_THREAD_FUNCTION_CALL_CONV assert(0); #endif +#ifdef _WIN32 Register_Thread_ID(tc->mThreadID, tc->ThreadName); +#endif #ifdef _MSC_VER __try { @@ -78,7 +80,9 @@ ThreadClass::InternalThreadFunctionReturnType INTERNAL_THREAD_FUNCTION_CALL_CONV tc->Thread_Function(); #endif +#ifdef _WIN32 Unregister_Thread_ID(tc->mThreadID, tc->ThreadName); +#endif tc->mThreadID = 0; tc->mRunning = false; return 0; diff --git a/Code/wwlib/verchk.cpp b/Code/wwlib/verchk.cpp index 80f7b8b43..16d60006d 100644 --- a/Code/wwlib/verchk.cpp +++ b/Code/wwlib/verchk.cpp @@ -38,14 +38,13 @@ #include "verchk.h" #include "rawfile.h" #include "ffactory.h" -#if defined(OPENW3D_WIN32) +#if defined(_WIN32) #include -#elif defined(OPENW3D_SDL3) -#include -#include #endif +#if defined(_WIN32) + /****************************************************************************** * * NAME @@ -93,6 +92,9 @@ bool GetVersionInfo(char* filename, VS_FIXEDFILEINFO* fileInfo) { } +#endif // _WIN32 + + bool GetFileCreationTime(const char* filename, FileCreationTime* createTime) { if (filename && createTime) @@ -119,6 +121,8 @@ bool GetFileCreationTime(const char* filename, FileCreationTime* createTime) } +#if defined(_WIN32) + //////////////////////////////////////////////////////////////////////// // // Get_Image_File_Header @@ -230,3 +234,5 @@ Compare_EXE_Version (HINSTANCE app_instance, const char *filename) return retval; } + +#endif // _WIN32 diff --git a/Code/wwlib/verchk.h b/Code/wwlib/verchk.h index 38c40744c..ddf7087f0 100644 --- a/Code/wwlib/verchk.h +++ b/Code/wwlib/verchk.h @@ -42,8 +42,6 @@ #ifndef __VERCHK_H #define __VERCHK_H -#include - struct FileCreationTime { int year; int month; @@ -53,12 +51,16 @@ struct FileCreationTime { int second; }; -// Obtain version information from the specified file. -bool GetVersionInfo(char* filename, VS_FIXEDFILEINFO* fileInfo); - // Retreive creation time of specified file. bool GetFileCreationTime(const char* filename, FileCreationTime* createTime); +#if defined(_WIN32) + +#include + +// Obtain version information from the specified file. +bool GetVersionInfo(char* filename, VS_FIXEDFILEINFO* fileInfo); + //////////////////////////////////////////////////////////////////////// // // Compare_EXE_Version @@ -73,6 +75,7 @@ bool GetFileCreationTime(const char* filename, FileCreationTime* createTime); //////////////////////////////////////////////////////////////////////// int Compare_EXE_Version (HINSTANCE app_instance, const char *filename); +#endif // _WIN32 #endif //__VERCHK_H diff --git a/Code/wwlib/win.cpp b/Code/wwlib/win.cpp index 1b22ef7ec..de1b9bfc4 100644 --- a/Code/wwlib/win.cpp +++ b/Code/wwlib/win.cpp @@ -20,6 +20,8 @@ #include "win.h" #include "wwdebug.h" +#if defined(_WIN32) + HINSTANCE ProgramInstance; HWND MainWindow; bool GameInFocus = false; @@ -47,5 +49,11 @@ void __cdecl Print_Win32Error(unsigned int win32Error) WWDEBUG_SAY(("Win32 Error: %s\n", (const char*)lpMsgBuf)); LocalFree(lpMsgBuf); } -#endif +#endif // _DEBUG + +#else // !_WIN32 + +bool GameInFocus = false; + +#endif // _WIN32 diff --git a/Code/wwlib/win.h b/Code/wwlib/win.h index c232d52e7..9dffa4a38 100644 --- a/Code/wwlib/win.h +++ b/Code/wwlib/win.h @@ -57,10 +57,11 @@ //#include //#include +extern bool GameInFocus; + #ifdef _WIN32 extern HINSTANCE ProgramInstance; extern HWND MainWindow; -extern bool GameInFocus; #ifdef _DEBUG @@ -72,8 +73,6 @@ void __cdecl Print_Win32Error(unsigned int win32Error); #endif // _DEBUG -#else // _WIN32 -//#include #endif // _WIN32 #endif // WIN_H diff --git a/cmake/dx9.cmake b/cmake/dx9.cmake index f7b6ca5db..56bc331be 100644 --- a/cmake/dx9.cmake +++ b/cmake/dx9.cmake @@ -11,6 +11,12 @@ if(WIN32) add_library(d3d9lib INTERFACE) target_link_libraries(d3d9lib INTERFACE d3d9 d3dx9) endif() +elseif(LINUX) + find_package(PkgConfig REQUIRED) + + pkg_check_modules(dxvk REQUIRED IMPORTED_TARGET dxvk-d3d9) + add_library(d3d9lib INTERFACE) + target_link_libraries(d3d9lib INTERFACE PkgConfig::dxvk) else() find_path(DXVK_INCLUDE_PATH NAMES "dxvk/d3d9.h" REQUIRED) find_library(DXVK_D3D9_LIBRARY NAMES "dxvk_d3d9" REQUIRED) From 14a250b3415992c5816ef1c127e2cd03b09a31bc Mon Sep 17 00:00:00 2001 From: Robert Middleton Date: Fri, 19 Jun 2026 18:34:04 -0400 Subject: [PATCH 2/6] clean up claude work --- Code/wwlib/CMakeLists.txt | 6 ++++-- Code/wwlib/always.h | 6 ------ Code/wwlib/msgloop.cpp | 4 ---- Code/wwlib/registry.cpp | 4 ---- Code/wwlib/registry_linux.cpp | 29 +++++++++-------------------- 5 files changed, 13 insertions(+), 36 deletions(-) diff --git a/Code/wwlib/CMakeLists.txt b/Code/wwlib/CMakeLists.txt index 8f1e8f0e0..12eb34563 100644 --- a/Code/wwlib/CMakeLists.txt +++ b/Code/wwlib/CMakeLists.txt @@ -24,7 +24,6 @@ set(WWLIB_SRC mixfile.cpp mpmath.cpp mpu.cpp - msgloop.cpp multilist.cpp mutex.cpp nstrdup.cpp @@ -147,7 +146,10 @@ set(WWLIB_SRC ) if(WIN32) - list(APPEND WWLIB_SRC registry.cpp) + list(APPEND WWLIB_SRC + registry.cpp + msgloop.cpp + ) else() list(APPEND WWLIB_SRC registry_linux.cpp) endif() diff --git a/Code/wwlib/always.h b/Code/wwlib/always.h index 10835962e..be22df018 100644 --- a/Code/wwlib/always.h +++ b/Code/wwlib/always.h @@ -163,12 +163,6 @@ __forceinline unsigned int _byteswap_ulong(unsigned int value) #ifndef BOOL typedef int BOOL; #endif -#ifndef TRUE -#define TRUE 1 -#endif -#ifndef FALSE -#define FALSE 0 -#endif // Windows path constant equivalents #ifndef _MAX_DRIVE diff --git a/Code/wwlib/msgloop.cpp b/Code/wwlib/msgloop.cpp index bb6355c7f..cdf9ff30d 100644 --- a/Code/wwlib/msgloop.cpp +++ b/Code/wwlib/msgloop.cpp @@ -43,8 +43,6 @@ #include "vector.h" #include "win.h" -#if defined(_WIN32) - /* ** Tracks modeless dialog box messages by keeping a record of all active modeless dialog ** box handles and then determining if the windows message applies to the dialog box. If it @@ -253,5 +251,3 @@ void Remove_Accelerator(HACCEL accelerator) } } } - -#endif // _WIN32 diff --git a/Code/wwlib/registry.cpp b/Code/wwlib/registry.cpp index 52d8dd15f..2390aafd6 100644 --- a/Code/wwlib/registry.cpp +++ b/Code/wwlib/registry.cpp @@ -33,8 +33,6 @@ *---------------------------------------------------------------------------------------------* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ -#if defined(_WIN32) - #include "registry.h" #include "rawfile.h" #include "ini.h" @@ -735,8 +733,6 @@ void RegistryClass::Delete_Registry_Tree(char *path) } } -#endif // _WIN32 - diff --git a/Code/wwlib/registry_linux.cpp b/Code/wwlib/registry_linux.cpp index 0da11349e..f3796d7b3 100644 --- a/Code/wwlib/registry_linux.cpp +++ b/Code/wwlib/registry_linux.cpp @@ -1,6 +1,6 @@ /* ** Command & Conquer Renegade(tm) -** Copyright 2025 Electronic Arts Inc. +** Copyright 2026 OpenW3D ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by @@ -27,6 +27,7 @@ #include "ini.h" #include "inisup.h" #include "rawfile.h" +#include "openw3d.h" #include #include @@ -37,20 +38,6 @@ bool RegistryClass::IsLocked = false; -static const char *Registry_File_Path() -{ - static char path[512] = {}; - if (path[0] == '\0') { - const char *home = getenv("HOME"); - if (home) { - snprintf(path, sizeof(path), "%s/.config/renegade/registry.ini", home); - } else { - strncpy(path, "registry.ini", sizeof(path) - 1); - } - } - return path; -} - static void Ensure_Registry_Dir() { const char *home = getenv("HOME"); @@ -68,7 +55,7 @@ static INIClass &Registry_INI() static bool loaded = false; if (!loaded) { loaded = true; - RawFileClass file(Registry_File_Path()); + RawFileClass file(OpenW3D::Get_Config_File_Path()); if (file.Is_Available()) { ini.Load(file); } @@ -79,7 +66,7 @@ static INIClass &Registry_INI() static void Save_Registry_INI() { Ensure_Registry_Dir(); - RawFileClass file(Registry_File_Path()); + RawFileClass file(OpenW3D::Get_Config_File_Path()); Registry_INI().Save(file); } @@ -263,17 +250,19 @@ void RegistryClass::Load_Registry(const char *filename, char *old_path, char *ne const size_t old_path_len = ::strlen(old_path); char path[1024]; + char path_tmp[1024]; char string[1024]; unsigned char buffer[8192]; List §ion_list = ini.Get_Section_List(); for (INISection *section = section_list.First(); section != NULL; section = section->Next_Valid()) { - char *section_name = section->Section; - strcpy(path, new_path); + char *section_name = section->Section; + snprintf(path, sizeof(path), "%s", new_path); char *cut = strstr(section_name, old_path); if (cut) { - strcat(path, cut + old_path_len); + memcpy(path_tmp, path, sizeof(path)); + snprintf(path, sizeof(path), "%s%s", path_tmp, cut + old_path_len); } RegistryClass reg(path); From 11319a51515999e36da4709a1726b527e9140c79 Mon Sep 17 00:00:00 2001 From: Robert Middleton Date: Fri, 19 Jun 2026 20:39:16 -0400 Subject: [PATCH 3/6] remove files that have whitespace-only changes --- Code/wwlib/msgloop.cpp | 1 + Code/wwlib/registry.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Code/wwlib/msgloop.cpp b/Code/wwlib/msgloop.cpp index cdf9ff30d..535e5bbcf 100644 --- a/Code/wwlib/msgloop.cpp +++ b/Code/wwlib/msgloop.cpp @@ -43,6 +43,7 @@ #include "vector.h" #include "win.h" + /* ** Tracks modeless dialog box messages by keeping a record of all active modeless dialog ** box handles and then determining if the windows message applies to the dialog box. If it diff --git a/Code/wwlib/registry.cpp b/Code/wwlib/registry.cpp index 2390aafd6..2cac809f9 100644 --- a/Code/wwlib/registry.cpp +++ b/Code/wwlib/registry.cpp @@ -743,3 +743,5 @@ void RegistryClass::Delete_Registry_Tree(char *path) + + From 36cfa2410b260c0ad4cb1d31830b5426bd6bc439 Mon Sep 17 00:00:00 2001 From: Robert Middleton Date: Sat, 20 Jun 2026 20:18:02 -0400 Subject: [PATCH 4/6] update with PR comments --- CMakeLists.txt | 1 - Code/wwlib/always.h | 8 ---- Code/wwlib/critsection.cpp | 83 ------------------------------------- Code/wwlib/critsection.h | 85 -------------------------------------- Code/wwlib/ini.cpp | 8 ++-- Code/wwlib/mixfile.cpp | 4 +- Code/wwlib/refcount.cpp | 16 ------- 7 files changed, 6 insertions(+), 199 deletions(-) delete mode 100644 Code/wwlib/critsection.cpp delete mode 100644 Code/wwlib/critsection.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d3433ff7..726a12036 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,7 +72,6 @@ if(NOT WIN32) add_compile_definitions(strnicmp=strncasecmp) add_compile_definitions(wcsnicmp=wcsncasecmp) add_compile_definitions(wcsicmp=wcscasecmp) - add_compile_definitions(DebugBreak=__builtin_trap) endif() include(FetchContent) diff --git a/Code/wwlib/always.h b/Code/wwlib/always.h index be22df018..c2342d8f2 100644 --- a/Code/wwlib/always.h +++ b/Code/wwlib/always.h @@ -181,14 +181,6 @@ typedef int BOOL; #define _MAX_EXT 256 #endif -// Windows file operation equivalents -#ifndef DeleteFileA -#define DeleteFileA(f) (remove(f) == 0) -#endif -#ifndef MoveFileA -#define MoveFileA(src, dst) (rename(src, dst) == 0) -#endif - // _splitpath: split a path into drive/dir/fname/ext components static inline void _splitpath(const char *path, char *drive, char *dir, char *fname, char *ext) { diff --git a/Code/wwlib/critsection.cpp b/Code/wwlib/critsection.cpp deleted file mode 100644 index 90e32737e..000000000 --- a/Code/wwlib/critsection.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* -** Command & Conquer Renegade(tm) -** Copyright 2025 Electronic Arts Inc. -** -** This program is free software: you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation, either version 3 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program. If not, see . -*/ - -/*********************************************************************************************** - *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** - *********************************************************************************************** - * * - * Project Name : critsection.cpp * - * * - * $Archive:: /Commando/Code/wwlib/critsection.cpp $* - * * - * Original Author:: Hector Yee * - * * - * $Author:: Hector_y $* - * * - * $Modtime:: 3/14/01 4:04p $* - * * - * $Revision:: 1 $* - * * - *---------------------------------------------------------------------------------------------* - * Functions: * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - -#include "critsection.h" - -CriticalSectionClass::CriticalSectionClass(): -inside(false) -{ -#ifndef _UNIX - InitializeCriticalSection(&Bar); -#endif -} - -CriticalSectionClass::~CriticalSectionClass() -{ -#ifndef _UNIX - DeleteCriticalSection(&Bar); -#endif -} - -void CriticalSectionClass::Enter() -{ - WWASSERT(inside==false); -#ifndef _UNIX - EnterCriticalSection(&Bar); - inside=true; -#endif -} - -void CriticalSectionClass::Exit() -{ - WWASSERT(inside==true); -#ifndef _UNIX - inside=false; - LeaveCriticalSection(&Bar); -#endif -} - -CriticalSectionClass::LockClass::LockClass(CriticalSectionClass &c): -crit(c) -{ - crit.Enter(); -} - -CriticalSectionClass::LockClass::~LockClass() -{ - crit.Exit(); -} diff --git a/Code/wwlib/critsection.h b/Code/wwlib/critsection.h deleted file mode 100644 index 2ba31ca49..000000000 --- a/Code/wwlib/critsection.h +++ /dev/null @@ -1,85 +0,0 @@ -/* -** Command & Conquer Renegade(tm) -** Copyright 2025 Electronic Arts Inc. -** -** This program is free software: you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation, either version 3 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program. If not, see . -*/ - -/*********************************************************************************************** - *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** - *********************************************************************************************** - * * - * Project Name : critsection.h * - * * - * $Archive:: /Commando/Code/wwlib/critsection.h $* - * * - * Original Author:: Hector Yee * - * * - * $Author:: Hector_y $* - * * - * $Modtime:: 3/14/01 4:04p $* - * * - * $Revision:: 1 $* - * * - *---------------------------------------------------------------------------------------------* - * Functions: * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - -#ifndef CRIT_SECTION -#define CRIT_SECTION - -#if defined(_MSC_VER) -#pragma once -#endif - -#include "always.h" -#include "wwdebug.h" -#if defined(_WIN32) -#include -#else -#include -#endif - -class CriticalSectionClass -{ -public: - CriticalSectionClass(); - ~CriticalSectionClass(); - - class LockClass - { - CriticalSectionClass& crit; - public: - // In order to enter a critical section create a local - // instance of LockClass with critical section as a parameter. - LockClass(CriticalSectionClass& c); - ~LockClass(); - private: - LockClass &operator=(const LockClass&) { return(*this); } - }; - friend LockClass; - -private: -#if defined(_WIN32) - CRITICAL_SECTION Bar; -#else - std::mutex Bar; -#endif - bool inside; - void Enter(); - void Exit(); -}; - - -#endif diff --git a/Code/wwlib/ini.cpp b/Code/wwlib/ini.cpp index 6cc76c1fa..4924b522c 100644 --- a/Code/wwlib/ini.cpp +++ b/Code/wwlib/ini.cpp @@ -1647,9 +1647,9 @@ bool INIClass::Put_String(char const * section, char const * entry, char const * if (strcmp(entryptr->Entry, entry)) { DuplicateCRCError("INIClass::Put_String", section, entry); } else { - OutputDebugStringA("INIClass::Put_String - Duplicate Entry \""); - OutputDebugStringA(entry); - OutputDebugStringA("\"\n"); + printf("INIClass::Put_String - Duplicate Entry \""); + printf("%s", entry); + printf("\"\n"); } secptr->EntryIndex.Remove_Index(entryptr->Index_ID()); delete entryptr; @@ -2360,7 +2360,7 @@ void INIClass::DuplicateCRCError(const char *message, const char *section, const snprintf(buffer, sizeof(buffer), "%s - Duplicate Entry \"%s\" in section \"%s\" (%s)\n", message, entry, section, Filename); - OutputDebugStringA(buffer); + printf(buffer); assert(0); #ifdef NDEBUG diff --git a/Code/wwlib/mixfile.cpp b/Code/wwlib/mixfile.cpp index f65497b6b..60265732f 100644 --- a/Code/wwlib/mixfile.cpp +++ b/Code/wwlib/mixfile.cpp @@ -365,8 +365,8 @@ MixFileFactoryClass::Flush_Changes (void) // // Delete the old mix file and rename the new one // - DeleteFileA (MixFilename); - MoveFileA (full_path, MixFilename); + remove (MixFilename); + rename (full_path, MixFilename); // // Reset the lists diff --git a/Code/wwlib/refcount.cpp b/Code/wwlib/refcount.cpp index ba0d65da1..c487c22ca 100644 --- a/Code/wwlib/refcount.cpp +++ b/Code/wwlib/refcount.cpp @@ -40,9 +40,6 @@ #include "refcount.h" -#if defined(_WIN32) -#include -#endif #ifndef NDEBUG @@ -165,19 +162,11 @@ void RefCountClass::Inc_Total_Refs([[maybe_unused]] RefCountClass * obj) } -// SKB 7/21/99 Set BreakOnRefernce to a pointer and it will break when called. -// This is used for debugging, please do not deleted. -RefCountClass* BreakOnReference = 0; - #ifndef NDEBUG void RefCountClass::Add_Ref(void) { NumRefs++; - // See if programmer set break on for a specific address. - if (this == BreakOnReference) { - DebugBreak(); // trigger the debugger - } Inc_Total_Refs(this); } #endif @@ -200,11 +189,6 @@ void RefCountClass::Dec_Total_Refs(RefCountClass * obj) assert(Validate_Active_Ref(obj)); #endif TotalRefs--; - - // See if programmer set break on for a specific address. - if (obj == BreakOnReference) { - DebugBreak(); // trigger the debugger - } } From 4ada1c6b8a6c4bbe2bcac3f2860e2f80abb3ac4b Mon Sep 17 00:00:00 2001 From: Robert Middleton Date: Sat, 20 Jun 2026 20:28:49 -0400 Subject: [PATCH 5/6] add cstdio to includes --- Code/wwlib/mixfile.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Code/wwlib/mixfile.cpp b/Code/wwlib/mixfile.cpp index 60265732f..e080c2548 100644 --- a/Code/wwlib/mixfile.cpp +++ b/Code/wwlib/mixfile.cpp @@ -44,6 +44,8 @@ #include "win.h" #include "bittype.h" +#include + /* ** */ From 0f8cf5cc99700f1ce1ee325a9e55b54315875ae7 Mon Sep 17 00:00:00 2001 From: Robert Middleton Date: Sat, 11 Jul 2026 20:36:00 -0400 Subject: [PATCH 6/6] fix warning --- Code/wwlib/ini.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/wwlib/ini.cpp b/Code/wwlib/ini.cpp index 4924b522c..513d4b5b9 100644 --- a/Code/wwlib/ini.cpp +++ b/Code/wwlib/ini.cpp @@ -2360,7 +2360,7 @@ void INIClass::DuplicateCRCError(const char *message, const char *section, const snprintf(buffer, sizeof(buffer), "%s - Duplicate Entry \"%s\" in section \"%s\" (%s)\n", message, entry, section, Filename); - printf(buffer); + printf("%s", buffer); assert(0); #ifdef NDEBUG