luciusDXL / TheForceEngine

Modern "Jedi Engine" replacement supporting Dark Forces, mods, and in the future Outlaws.
https://TheForceEngine.github.io
GNU General Public License v2.0
995 stars 73 forks source link

Add support for compiling on macOS #473

Open apancik opened 4 days ago

apancik commented 4 days ago

This pull request introduces changes to enable compiling The Force Engine on macOS. It's a cleanup of #472 (thank you @mlauss2 for your help!)

Hardware: Intel Mac / macOS Sequoia 15.1 / XCode 16.1 SDL2: version 2.30.9, SDL2_image: version 2.8.2, RtMidi: version 6.0.0

Screenshot 2024-11-19 at 5 57 22 PM Screenshot 2024-11-19 at 5 57 44 PM Screenshot 2024-11-19 at 5 58 06 PM

mlauss2 commented 4 days ago

I like it (obviously). As a next step, some of the #ifdef APPLE could be replaced with a runtime test for OSX. SDL provides SDL_GetPlatform():

bool isosx = (0 == strcmp(SDL_GetPlatform(), "Mac OS X"));

OpenGL_caps.cpp and renderbackend::createwindow come to mind.

This way your code gets compiler coverage on windows/linux too.

mlauss2 commented 4 days ago

something like this:

diff --git a/TheForceEngine/TFE_RenderBackend/Win32OpenGL/openGL_Caps.cpp b/TheForceEngine/TFE_RenderBackend/Win32OpenGL/openGL_Caps.cpp
index 1fe52b54..e74d95b6 100644
--- a/TheForceEngine/TFE_RenderBackend/Win32OpenGL/openGL_Caps.cpp
+++ b/TheForceEngine/TFE_RenderBackend/Win32OpenGL/openGL_Caps.cpp
@@ -1,3 +1,4 @@
+#include <TFE_System/system.h>
 #include "openGL_Caps.h"
 #include "gl.h"
 #include <assert.h>
@@ -39,8 +40,12 @@ namespace OpenGL_Caps
        glGetIntegerv(GL_MAJOR_VERSION, &gl_maj);
        glGetIntegerv(GL_MINOR_VERSION, &gl_min);

-#ifdef __APPLE__
-       if (gl_maj >= 4) {
+       
+       if (PLAT_OSX == TFE_System::getPlatform())
+       {
+           if (gl_maj < 4)
+               return;
+       
            m_supportFlags = CAP_PBO | CAP_VBO | CAP_FBO | CAP_UBO | CAP_NON_POW_2 | CAP_TEXTURE_ARRAY;

            if (SDL_GL_ExtensionSupported("GL_EXT_texture_filter_anisotropic")) {
@@ -61,9 +66,9 @@ namespace OpenGL_Caps
            if (m_textureBufferMaxSize >= GLSPEC_MAX_TEXTURE_BUFFER_SIZE_MIN) {
                m_deviceTier = DEV_TIER_2;
            }
+           return;
        }
-       return;
-#endif
+
        if (SDL_GL_ExtensionSupported("GL_ARB_pixel_buffer_object"))
            m_supportFlags |= CAP_PBO | CAP_NON_POW_2;
        if (SDL_GL_ExtensionSupported("GL_ARB_vertex_buffer_object"))
diff --git a/TheForceEngine/TFE_RenderBackend/Win32OpenGL/renderBackend.cpp b/TheForceEngine/TFE_RenderBackend/Win32OpenGL/renderBackend.cpp
index 4fed0683..33432c9c 100644
--- a/TheForceEngine/TFE_RenderBackend/Win32OpenGL/renderBackend.cpp
+++ b/TheForceEngine/TFE_RenderBackend/Win32OpenGL/renderBackend.cpp
@@ -71,9 +71,7 @@ namespace TFE_RenderBackend
    void drawVirtualDisplay();
    void setupPostEffectChain(bool useDynamicTexture, bool useBloom);

-#ifdef __APPLE__
    static GLuint s_globalVAO = 0;
-#endif

    static void printGLInfo(void)
    {
@@ -91,6 +89,7 @@ namespace TFE_RenderBackend
    {
        u32 windowFlags = SDL_WINDOW_OPENGL;
        bool windowed = !(state.flags & WINFLAG_FULLSCREEN);
+       bool isosx = (PLAT_OSX == TFE_System::getPlatform());

        TFE_Settings_Window* windowSettings = TFE_Settings::getWindowSettings();

@@ -116,13 +115,14 @@ namespace TFE_RenderBackend

        SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, true);

-#ifdef __APPLE__
-       // macOS specific OpenGL context setup
-       SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
-       SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
-       SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
-       SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
-#endif
+       if (isosx)
+       {
+           // macOS specific OpenGL context setup
+           SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
+           SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
+           SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
+           SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
+       }

        TFE_System::logWrite(LOG_MSG, "RenderBackend", "SDL Videodriver: %s", SDL_GetCurrentVideoDriver());
        SDL_Window* window = SDL_CreateWindow(state.name, x, y, state.width, state.height, windowFlags);
@@ -177,26 +177,27 @@ namespace TFE_RenderBackend
            uiScale = 150;
        }

-#ifdef __APPLE__
-       // macOS specific setup:
-       // Create and bind a global VAO for macOS
-       glGenVertexArrays(1, &s_globalVAO);
-       if (!s_globalVAO)
+       if (isosx)
        {
-           TFE_System::logWrite(LOG_ERROR, "RenderBackend", "Failed to create global VAO");
-           SDL_DestroyWindow(window);
-           return nullptr;
-       }
-       glBindVertexArray(s_globalVAO);
+           // macOS specific setup:
+           // Create and bind a global VAO for macOS
+           glGenVertexArrays(1, &s_globalVAO);
+           if (!s_globalVAO)
+           {
+               TFE_System::logWrite(LOG_ERROR, "RenderBackend", "Failed to create global VAO");
+               SDL_DestroyWindow(window);
+               return nullptr;
+           }
+           glBindVertexArray(s_globalVAO);

-       // handle Retina displays
-       s32 drawableWidth, drawableHeight;
-       SDL_GL_GetDrawableSize(window, &drawableWidth, &drawableHeight);
-       if (drawableWidth > state.width)
-       {
-           uiScale = (uiScale * drawableWidth) / state.width;
+           // handle Retina displays
+           s32 drawableWidth, drawableHeight;
+           SDL_GL_GetDrawableSize(window, &drawableWidth, &drawableHeight);
+           if (drawableWidth > state.width)
+           {
+               uiScale = (uiScale * drawableWidth) / state.width;
+           }
        }
-#endif

 #ifndef _WIN32
        SDL_SetWindowFullscreen(window, windowed ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP);
@@ -1066,9 +1067,8 @@ namespace TFE_RenderBackend

    void bindGlobalVAO(void)
    {
-#ifdef __APPLE__
-       glBindVertexArray(s_globalVAO);
-#endif
+       if (s_globalVAO)
+           glBindVertexArray(s_globalVAO);
    }

 }  // namespace
diff --git a/TheForceEngine/TFE_System/system.cpp b/TheForceEngine/TFE_System/system.cpp
index 4ce39dce..00985577 100644
--- a/TheForceEngine/TFE_System/system.cpp
+++ b/TheForceEngine/TFE_System/system.cpp
@@ -45,6 +45,7 @@ namespace TFE_System
    static s32 s_missedFrameCount = 0;

    static char s_versionString[64];
+   static TFE_Platform s_platform;     // win/lin/osx

    void init(f32 refreshRate, bool synced, const char* versionString)
    {
@@ -62,6 +63,17 @@ namespace TFE_System

        TFE_COUNTER(s_missedFrameCount, "Miss-Predicted Vysnc Intervals");
        strcpy(s_versionString, versionString);
+
+       const char *sdlplat = SDL_GetPlatform();
+       if (0 == strcmp(sdlplat, "Windows"))
+           s_platform = PLAT_WIN;
+       else if (0 == strcmp(sdlplat, "Mac OS X"))
+           s_platform = PLAT_OSX;
+       else if (0 == strcmp(sdlplat, "Linux"))
+           s_platform = PLAT_LIN;
+       else
+           s_platform = PLAT_UNK;
+       TFE_System::logWrite(LOG_MSG, "Startup", "SDL Platform: '%s' (%u)", sdlplat, s_platform);
    }

    void shutdown()
@@ -102,6 +114,11 @@ namespace TFE_System
        return dt;
    }

+   TFE_Platform getPlatform(void)
+   {
+       return s_platform;
+   }
+
    void update()
    {
        // This assumes that SDL_GetPerformanceCounter() is monotonic.
diff --git a/TheForceEngine/TFE_System/system.h b/TheForceEngine/TFE_System/system.h
index 6d2e558d..d39e52fe 100644
--- a/TheForceEngine/TFE_System/system.h
+++ b/TheForceEngine/TFE_System/system.h
@@ -28,6 +28,14 @@ enum LogWriteType
    LOG_COUNT
 };

+enum TFE_Platform
+{
+   PLAT_WIN = 0,
+   PLAT_LIN,
+   PLAT_OSX,
+   PLAT_UNK
+};
+
 namespace TFE_System
 {
    void init(f32 refreshRate, bool synced, const char* versionString);
@@ -39,6 +47,8 @@ namespace TFE_System
    void update();
    f64 updateThreadLocal(u64* localTime);

+   TFE_Platform getPlatform(void);
+
    // Timing
    // --- The current time and delta time are determined once per frame, during the update() function.
    //     In other words an entire frame operates on a single instance of time.
apancik commented 4 days ago

I pushed my initial draft in commit 34d29a9 just before you sent your changes. I'll take a look at how to merge them.

A bigger issue is that shooting weapons no longer works. I’m not sure yet how or where I broke it, especially since I didn’t touch the game logic.

mlauss2 commented 4 days ago

I pushed my initial draft in commit 34d29a9 just before you sent your changes. I'll take a look at how to merge them.

Oh i meant this is something for later, but yeah like this.

A bigger issue is that shooting weapons no longer works. I’m not sure yet how or where I broke it, especially since I didn’t touch the game logic.

you need this:

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 80398f03..9a2030dd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -81,6 +81,7 @@ if(ENABLE_TFE)
                # the necessary support file directories into the build env.
                execute_process(COMMAND ln -sf ${CMAKE_SOURCE_DIR}/TheForceEngine/Captions)
                execute_process(COMMAND ln -sf ${CMAKE_SOURCE_DIR}/TheForceEngine/Documentation)
+               execute_process(COMMAND ln -sf  ${CMAKE_SOURCE_DIR}/TheForceEngine/ExternalData)
                execute_process(COMMAND ln -sf ${CMAKE_SOURCE_DIR}/TheForceEngine/Fonts)
                execute_process(COMMAND ln -sf ${CMAKE_SOURCE_DIR}/TheForceEngine/Mods)
                execute_process(COMMAND ln -sf ${CMAKE_SOURCE_DIR}/TheForceEngine/Shaders)
@@ -137,6 +138,7 @@ if(ENABLE_TFE)
        install(DIRECTORY
                "${CMAKE_CURRENT_SOURCE_DIR}/TheForceEngine/Captions"
                "${CMAKE_CURRENT_SOURCE_DIR}/TheForceEngine/Documentation"
+               "${CMAKE_CURRENT_SOURCE_DIR}/TheForceEngine/ExternalData"
                "${CMAKE_CURRENT_SOURCE_DIR}/TheForceEngine/UI_Text"
                "${CMAKE_CURRENT_SOURCE_DIR}/TheForceEngine/UI_Images"
                "${CMAKE_CURRENT_SOURCE_DIR}/TheForceEngine/EditorDef"
mlauss2 commented 3 days ago

erm, please just keep the first patch for this PR; the others were just ideas for a new PR after this has been merged, and the patch you need to get projectiles again, which is not at all material for this pr.