From b996fff6fa87e95913856acc6de5cdf82be3c147 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Wed, 10 Jan 2024 23:34:32 +0100 Subject: [PATCH] Support building isle with modern MSVC + msys2 (#421) * cmake: detect older MSVC and define ENABLE_DECOMP_ASSERTS to enable decomp asserts * Add /Zc:__cplusplus to define __cplusplus with c++ version number * Silence deprecated CRT releated warnings * LegoCameraController overrids some methods that are not defined in its parent(s) * Tgl::Device::GetDrawnTriangleCount does not exist (FIXME: INCORRECT FIX -> Tgl::Device should be updated instead) * Remove copy/pasted APP_ICON from lego1 resource.h header * Implement empty ViewLODList::Dump method * Also enable "compat mode" for newer MSVC compilers * Only do decomp assertions when using older MSVC compilers * msys2 mingw compat (cannot pass reference of rvalue) * Fix msys2 mingw warning: declaration 'class Tgl::Group' does not declare anything * Add FIXME comment to LEgo3DView::m_previousRenderTime * LegoView1 is 16 bytes bigger then LegoView ==> 4 32-bit pointers * include string.h for strlen * Fix overrides * Fix constness of method * Fixes * Formatting * Add size assert for MxFrequencyMeter * ci: build isle with msys2 + msvc on GitHub actions * Set vcvars for msvc * msys2 needs the msys2 shell * Build in default shell * isle is not 64-bit yet (I think) * Print bitness * Use amd64_x64 cross tools * Minor updates * Add more names --------- Co-authored-by: Christian Semmler --- .github/workflows/analyze.yml | 2 + .github/workflows/build.yml | 54 +++++++++++++++++-- CMakeLists.txt | 41 +++++++++++++- .../legoomni/include/legocameracontroller.h | 14 ++--- LEGO1/lego/legoomni/include/legoentity.h | 16 +++--- .../include/legopointofviewcontroller.h | 1 + .../src/common/legoactioncontrolpresenter.cpp | 7 +++ .../src/entity/legocameracontroller.cpp | 2 +- LEGO1/lego/legoomni/src/entity/legoentity.cpp | 2 +- .../legoomni/src/video/legovideomanager.cpp | 1 + LEGO1/lego/sources/3dmanager/lego3dmanager.h | 8 ++- LEGO1/lego/sources/3dmanager/lego3dview.h | 6 +-- LEGO1/lego/sources/3dmanager/legoview1.h | 6 ++- LEGO1/lego/sources/3dmanager/tglsurface.cpp | 5 ++ LEGO1/lego/sources/3dmanager/tglsurface.h | 11 ++-- LEGO1/omni/include/mxutil.h | 2 + LEGO1/res/resource.h | 2 - LEGO1/viewmanager/viewlodlist.h | 7 +++ util/compat.h | 4 +- util/decomp.h | 2 +- 20 files changed, 157 insertions(+), 36 deletions(-) diff --git a/.github/workflows/analyze.yml b/.github/workflows/analyze.yml index e139b8bf..01b85f47 100644 --- a/.github/workflows/analyze.yml +++ b/.github/workflows/analyze.yml @@ -4,6 +4,7 @@ on: [push, pull_request] jobs: decomplint-isle: + name: 'ISLE annotations' runs-on: ubuntu-latest steps: @@ -18,6 +19,7 @@ jobs: python3 tools/decomplint/decomplint.py ISLE --module ISLE --warnfail decomplint-lego1: + name: 'LEGO1 annotations' runs-on: ubuntu-latest steps: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2c285836..419033cc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,7 +3,53 @@ name: Build on: [push, pull_request] jobs: + build-current-toolchain: + name: 'Current ${{ matrix.toolchain.name }}' + runs-on: windows-latest + defaults: + run: + shell: ${{ matrix.toolchain.shell }} + strategy: + fail-fast: false + matrix: + toolchain: + - { name: 'MSVC', shell: 'sh', setup-cmake: true, setup-ninja: true, setup-msvc: true } + - { name: 'msys2 mingw32', shell: 'msys2 {0}', setup-msys2: true } + + steps: + - name: Set up MSYS2 + if: matrix.toolchain.setup-msys2 + uses: msys2/setup-msys2@v2 + with: + msystem: mingw32 + install: >- + mingw-w64-i686-cc + mingw-w64-i686-cmake + mingw-w64-i686-ninja + + - name: Setup cmake + if: matrix.toolchain.setup-cmake + uses: jwlawson/actions-setup-cmake@v1.13 + + - name: Setup ninja + if: matrix.toolchain.setup-ninja + uses: ashutoshvarma/setup-ninja@master + + - name: Setup vcvars + if: matrix.toolchain.setup-msvc + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: amd64_x86 # Use the 64-bit x64-native cross tools to build 32-bit x86 code + + - uses: actions/checkout@v3 + + - name: Build + run: | + cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -GNinja -Werror=dev + cmake --build build + build: + name: 'MSVC 4.20' runs-on: windows-latest steps: @@ -28,10 +74,8 @@ jobs: shell: cmd run: | call .\msvc420\bin\VCVARS32.BAT x86 - mkdir build - cd build - cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo -G "NMake Makefiles" - cmake --build . + cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo -G "NMake Makefiles" + cmake --build build - name: Upload Artifact uses: actions/upload-artifact@master @@ -44,6 +88,7 @@ jobs: build/LEGO1.PDB compare: + name: 'Compare with master' needs: build runs-on: windows-latest steps: @@ -109,6 +154,7 @@ jobs: LEGO1PROGRESS.* upload: + name: 'Upload artifacts' needs: [build, compare] runs-on: ubuntu-latest if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'isledecomp/isle' }} diff --git a/CMakeLists.txt b/CMakeLists.txt index 483ba9db..6378a2b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,8 +2,24 @@ cmake_minimum_required(VERSION 3.13 FATAL_ERROR) project(isle CXX) +math(EXPR bits "8 * ${CMAKE_SIZEOF_VOID_P}") +message(STATUS "Building ${bits}-bit LEGO Island") +if (NOT bits EQUAL 32) + message(WARNING "Only 32-bit executables are supported") +endif() + +set(MSVC_FOR_DECOMP FALSE) +if (MSVC) + # Visual C++ 4.2 -> cl version 10.2.0 + if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "11.0") + set(MSVC_FOR_DECOMP TRUE) + endif() +endif() + +message(STATUS "MSVC for decompilation: ${MSVC_FOR_DECOMP}") + option(ISLE_BUILD_APP "Build ISLE.EXE application" ON) -option(ISLE_USE_SMARTHEAP "Build with SmartHeap" ${MSVC}) +option(ISLE_USE_SMARTHEAP "Build with SmartHeap" ${MSVC_FOR_DECOMP}) option(ISLE_USE_DX5 "Build with internal DirectX 5 SDK" ON) add_library(lego1 SHARED @@ -300,6 +316,29 @@ if (ISLE_BUILD_APP) endif() if (MSVC) + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "15") + target_compile_definitions(lego1 PRIVATE _CRT_SECURE_NO_WARNINGS) + if (ISLE_BUILD_APP) + target_compile_definitions(isle PRIVATE "_CRT_SECURE_NO_WARNINGS") + endif() + endif() + # Visual Studio 2017 version 15.7 needs "/Zc:__cplusplus" for __cplusplus + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "19.14.26428") + target_compile_options(lego1 PRIVATE "-Zc:__cplusplus") + if (ISLE_BUILD_APP) + target_compile_options(isle PRIVATE "-Zc:__cplusplus") + endif() + endif() +endif() + +if (MSVC_FOR_DECOMP) + target_compile_definitions(lego1 PRIVATE "ENABLE_DECOMP_ASSERTS") + if (ISLE_BUILD_APP) + target_compile_definitions(isle PRIVATE "ENABLE_DECOMP_ASSERTS") + endif() +endif() + +if (MSVC_FOR_DECOMP) # These flags have been taken from the defaults for a Visual C++ 4.20 project (the compiler the # game was originally built with) and tweaked slightly to produce more debugging info for reccmp. # They ensure a recompilation that can be byte/instruction accurate to the original binaries. diff --git a/LEGO1/lego/legoomni/include/legocameracontroller.h b/LEGO1/lego/legoomni/include/legocameracontroller.h index 05c974a3..ba66461a 100644 --- a/LEGO1/lego/legoomni/include/legocameracontroller.h +++ b/LEGO1/lego/legoomni/include/legocameracontroller.h @@ -29,14 +29,14 @@ public: return !strcmp(p_name, ClassName()) || MxCore::IsA(p_name); } - virtual void OnLButtonDown(MxPoint32 p_point) override; // vtable+0x30 - virtual void OnLButtonUp(MxPoint32 p_point) override; // vtable+0x34 - virtual void OnRButtonDown(MxPoint32 p_point) override; // vtable+0x38 - virtual void OnRButtonUp(MxPoint32 p_point) override; // vtable+0x3c - virtual void OnMouseMove(MxU8 p_modifier, MxPoint32 p_point) override; // vtable+0x40 - virtual MxResult Create(); // vtable+0x44 + virtual void OnLButtonDown(MxPoint32 p_point); // vtable+0x30 + virtual void OnLButtonUp(MxPoint32 p_point); // vtable+0x34 + virtual void OnRButtonDown(MxPoint32 p_point); // vtable+0x38 + virtual void OnRButtonUp(MxPoint32 p_point); // vtable+0x3c + virtual void OnMouseMove(MxU8 p_modifier, MxPoint32 p_point); // vtable+0x40 + virtual MxResult Create(); // vtable+0x44 - void SetWorldTransform(Vector3Impl& p_at, Vector3Impl& p_dir, Vector3Impl& p_up); + void SetWorldTransform(const Vector3Impl& p_at, const Vector3Impl& p_dir, const Vector3Impl& p_up); void FUN_100123e0(Matrix4Data& p_transform, MxU32); Vector3Data& FUN_10012740(); Vector3Data& FUN_100127f0(); diff --git a/LEGO1/lego/legoomni/include/legoentity.h b/LEGO1/lego/legoomni/include/legoentity.h index ba0e1a7b..d911457c 100644 --- a/LEGO1/lego/legoomni/include/legoentity.h +++ b/LEGO1/lego/legoomni/include/legoentity.h @@ -32,12 +32,16 @@ public: return !strcmp(p_name, LegoEntity::ClassName()) || MxEntity::IsA(p_name); } - virtual MxResult Create(MxDSObject& p_dsObject); // vtable+0x18 - virtual void Destroy(MxBool p_fromDestructor); // vtable+0x1c - virtual void ParseAction(char*); // vtable+0x20 - virtual void SetROI(LegoROI* p_roi, MxBool p_bool1, MxBool p_bool2); // vtable+0x24 - virtual void SetWorldTransform(Vector3Impl& p_loc, Vector3Impl& p_dir, Vector3Impl& p_up); // vtable+0x28 - virtual void ResetWorldTransform(MxBool p_inVehicle); // vtable+0x2c + virtual MxResult Create(MxDSObject& p_dsObject); // vtable+0x18 + virtual void Destroy(MxBool p_fromDestructor); // vtable+0x1c + virtual void ParseAction(char*); // vtable+0x20 + virtual void SetROI(LegoROI* p_roi, MxBool p_bool1, MxBool p_bool2); // vtable+0x24 + virtual void SetWorldTransform( + const Vector3Impl& p_loc, + const Vector3Impl& p_dir, + const Vector3Impl& p_up + ); // vtable+0x28 + virtual void ResetWorldTransform(MxBool p_inVehicle); // vtable+0x2c // FUNCTION: LEGO1 0x10001090 virtual void SetWorldSpeed(MxFloat p_worldSpeed) { m_worldSpeed = p_worldSpeed; } // vtable+0x30 virtual void VTable0x34(); // vtable+0x34 diff --git a/LEGO1/lego/legoomni/include/legopointofviewcontroller.h b/LEGO1/lego/legoomni/include/legopointofviewcontroller.h index a7e92e97..444a08ad 100644 --- a/LEGO1/lego/legoomni/include/legopointofviewcontroller.h +++ b/LEGO1/lego/legoomni/include/legopointofviewcontroller.h @@ -3,6 +3,7 @@ #include "decomp.h" #include "mxcore.h" +#include "mxpoint32.h" #include diff --git a/LEGO1/lego/legoomni/src/common/legoactioncontrolpresenter.cpp b/LEGO1/lego/legoomni/src/common/legoactioncontrolpresenter.cpp index 953aef36..3649bb50 100644 --- a/LEGO1/lego/legoomni/src/common/legoactioncontrolpresenter.cpp +++ b/LEGO1/lego/legoomni/src/common/legoactioncontrolpresenter.cpp @@ -39,7 +39,14 @@ void LegoActionControlPresenter::RepeatingTickle() ParseExtra(); } +#ifdef COMPAT_MODE + { + MxAtomId atom(m_unk0x54.GetData(), LookupMode_LowerCase2); + InvokeAction(m_unk0x50, atom, m_unk0x64, NULL); + } +#else InvokeAction(m_unk0x50, MxAtomId(m_unk0x54.GetData(), LookupMode_LowerCase2), m_unk0x64, NULL); +#endif m_previousTickleStates |= 1 << (unsigned char) m_currentTickleState; m_currentTickleState = TickleState_Done; } diff --git a/LEGO1/lego/legoomni/src/entity/legocameracontroller.cpp b/LEGO1/lego/legoomni/src/entity/legocameracontroller.cpp index 34afaac0..d339b104 100644 --- a/LEGO1/lego/legoomni/src/entity/legocameracontroller.cpp +++ b/LEGO1/lego/legoomni/src/entity/legocameracontroller.cpp @@ -71,7 +71,7 @@ void LegoCameraController::OnMouseMove(MxU8 p_modifier, MxPoint32 p_point) } // FUNCTION: LEGO1 0x10012260 -void LegoCameraController::SetWorldTransform(Vector3Impl& p_at, Vector3Impl& p_dir, Vector3Impl& p_up) +void LegoCameraController::SetWorldTransform(const Vector3Impl& p_at, const Vector3Impl& p_dir, const Vector3Impl& p_up) { CalcLocalTransform(p_at, p_dir, p_up, m_matrix1); m_matrix2 = m_matrix1; diff --git a/LEGO1/lego/legoomni/src/entity/legoentity.cpp b/LEGO1/lego/legoomni/src/entity/legoentity.cpp index 0f813029..b000da96 100644 --- a/LEGO1/lego/legoomni/src/entity/legoentity.cpp +++ b/LEGO1/lego/legoomni/src/entity/legoentity.cpp @@ -36,7 +36,7 @@ void LegoEntity::ResetWorldTransform(MxBool p_inVehicle) } // STUB: LEGO1 0x10010790 -void LegoEntity::SetWorldTransform(Vector3Impl& p_loc, Vector3Impl& p_dir, Vector3Impl& p_up) +void LegoEntity::SetWorldTransform(const Vector3Impl& p_loc, const Vector3Impl& p_dir, const Vector3Impl& p_up) { // TODO } diff --git a/LEGO1/lego/legoomni/src/video/legovideomanager.cpp b/LEGO1/lego/legoomni/src/video/legovideomanager.cpp index 1db16c2c..4d3dd304 100644 --- a/LEGO1/lego/legoomni/src/video/legovideomanager.cpp +++ b/LEGO1/lego/legoomni/src/video/legovideomanager.cpp @@ -10,6 +10,7 @@ DECOMP_SIZE_ASSERT(LegoVideoManager, 0x590); DECOMP_SIZE_ASSERT(MxStopWatch, 0x18); +DECOMP_SIZE_ASSERT(MxFrequencyMeter, 0x20); // FUNCTION: LEGO1 0x1007aa20 LegoVideoManager::LegoVideoManager() diff --git a/LEGO1/lego/sources/3dmanager/lego3dmanager.h b/LEGO1/lego/sources/3dmanager/lego3dmanager.h index 8445800b..ab2bdefc 100644 --- a/LEGO1/lego/sources/3dmanager/lego3dmanager.h +++ b/LEGO1/lego/sources/3dmanager/lego3dmanager.h @@ -4,8 +4,12 @@ #include "assert.h" #include "lego3dview.h" -class Tgl::Renderer; -class Tgl::Group; +namespace Tgl +{ +class Renderer; +class Group; +} // namespace Tgl + class ViewROI; // ??? for now diff --git a/LEGO1/lego/sources/3dmanager/lego3dview.h b/LEGO1/lego/sources/3dmanager/lego3dview.h index 986d652c..f02e7d31 100644 --- a/LEGO1/lego/sources/3dmanager/lego3dview.h +++ b/LEGO1/lego/sources/3dmanager/lego3dview.h @@ -36,10 +36,8 @@ public: private: ViewManager* m_pViewManager; // 0x88 double m_previousRenderTime; // 0x8c - - ViewROI* m_pPointOfView; // 0x90 - - undefined m_unk0x94[0x0c]; // 0x94 + ViewROI* m_pPointOfView; // 0x94 + undefined m_unk0x98[0x0c]; // 0x98 }; // SYNTHETIC: LEGO1 0x100aaf10 diff --git a/LEGO1/lego/sources/3dmanager/legoview1.h b/LEGO1/lego/sources/3dmanager/legoview1.h index 20ccadfa..bfee4e3d 100644 --- a/LEGO1/lego/sources/3dmanager/legoview1.h +++ b/LEGO1/lego/sources/3dmanager/legoview1.h @@ -2,9 +2,13 @@ #define _LegoView1_h #include "compat.h" +#include "decomp.h" #include "tglsurface.h" -class Tgl::Camera; +namespace Tgl +{ +class Camera; +} ///////////////////////////////////////////////////////////////////////////// // LegoView diff --git a/LEGO1/lego/sources/3dmanager/tglsurface.cpp b/LEGO1/lego/sources/3dmanager/tglsurface.cpp index 2493e00c..394e03e5 100644 --- a/LEGO1/lego/sources/3dmanager/tglsurface.cpp +++ b/LEGO1/lego/sources/3dmanager/tglsurface.cpp @@ -195,7 +195,12 @@ double TglSurface::Render() #ifdef _DEBUG { +#if 0 + // FIXME: Tgl::Device::GetDrawnTriangleCount does not exist unsigned long triangleCount = m_pDevice->GetDrawnTriangleCount(); +#else + unsigned long triangleCount = 0; +#endif m_triangleRateMeter.IncreaseOperationCount(triangleCount - m_triangleCount - 1); m_triangleCount = triangleCount; diff --git a/LEGO1/lego/sources/3dmanager/tglsurface.h b/LEGO1/lego/sources/3dmanager/tglsurface.h index 2ea4cf12..2b97db50 100644 --- a/LEGO1/lego/sources/3dmanager/tglsurface.h +++ b/LEGO1/lego/sources/3dmanager/tglsurface.h @@ -4,10 +4,13 @@ #include "mxdirectx/mxstopwatch.h" #include "tgl/tgl.h" -class Tgl::Renderer; -class Tgl::Device; -class Tgl::View; -class Tgl::Group; +namespace Tgl +{ +class Renderer; +class Device; +class View; +class Group; +} // namespace Tgl ///////////////////////////////////////////////////////////////////////////// // TglSurface diff --git a/LEGO1/omni/include/mxutil.h b/LEGO1/omni/include/mxutil.h index f9febef1..ca2ab867 100644 --- a/LEGO1/omni/include/mxutil.h +++ b/LEGO1/omni/include/mxutil.h @@ -3,6 +3,8 @@ #include "mxtypes.h" +#include + class MxDSFile; class MxDSObject; diff --git a/LEGO1/res/resource.h b/LEGO1/res/resource.h index 5a51e019..2402acad 100644 --- a/LEGO1/res/resource.h +++ b/LEGO1/res/resource.h @@ -8,5 +8,3 @@ #define LEGO1_LEAF5 108 #define LEGO1_LEAF3 109 #define LEGO1_BUSY 111 - -#define APP_ICON 105 diff --git a/LEGO1/viewmanager/viewlodlist.h b/LEGO1/viewmanager/viewlodlist.h index 9dc06d7b..0fc35d07 100644 --- a/LEGO1/viewmanager/viewlodlist.h +++ b/LEGO1/viewmanager/viewlodlist.h @@ -119,4 +119,11 @@ inline int ViewLODList::Release() return m_refCount; } +#ifdef _DEBUG +inline void ViewLODList::Dump(void (*pTracer)(const char*, ...)) const +{ + // FIXME: dump something +} +#endif + #endif // VIEWLODLIST_H diff --git a/util/compat.h b/util/compat.h index 3c83def6..b38a1c7c 100644 --- a/util/compat.h +++ b/util/compat.h @@ -3,13 +3,13 @@ // Various macros to enable compiling with other/newer compilers. -#ifdef __MINGW32__ +#if defined(__MINGW32__) || (defined(_MSC_VER) && _MSC_VER >= 1100) #define COMPAT_MODE #endif // Use `COMPAT_CONST` where something ought to be 'const', and a newer compiler would complain if it // wasn't, but we know it isn't 'const' in the original code. -#ifdef __MINGW32__ +#if defined(__MINGW32__) || (defined(_MSC_VER) && _MSC_VER >= 1100) #define COMPAT_CONST const #else #define COMPAT_CONST diff --git a/util/decomp.h b/util/decomp.h index 4e539eaf..3470fcc3 100644 --- a/util/decomp.h +++ b/util/decomp.h @@ -1,7 +1,7 @@ #ifndef DECOMP_H #define DECOMP_H -#if defined(_MSC_VER) +#if defined(ENABLE_DECOMP_ASSERTS) #define DECOMP_STATIC_ASSERT(V) \ namespace \ { \