Nimbin[12]?SDL & Graphics / sdl_runtime_compiler / commits / 8657672

sdl_runtime_compiler git · main

SDL3 game for running and compiling code at runtime

sdl3 c++ compiler dlopen cmake · first commit 2026-04-19 · last commit 2026-07-03 (3 months ago) · synced 3 days ago · upstream: git.ide3.de/hsnr/sdl-runtime-compiler

C++ 72.3% C 26.2%
git clone https://git.christianimmanuel.de/sdl-graphics/sdl_runtime_compiler.gitwget https://git.christianimmanuel.de/sdl-graphics/sdl_runtime_compiler/archive/sdl_runtime_compiler.tar.gz

Cleanup

Christian Immanuel · 2026-05-30 21:03 · 8657672c49af28b7097499d69d95d104b411bc03

 CMakeLists.txt                  |  5 ----
 assets/sandbox.c                |  5 ++--
 assets/sandbox.c.last_ok        |  3 +--
 src/core/game.cpp               | 16 +++++++++++++
 src/entities/player.cpp         |  6 ++---
 src/entities/player.hpp         |  4 ++++
 src/states/game_state.cpp       | 16 ++++++++++++-
 src/systems/compiler_system.cpp | 51 ++++-----------------------------------
 src/systems/mod_loader.cpp      |  4 +++-
 src/utils/ascii.hpp             | 53 +++++++++++++++++++++++++++++++++++++++++
 10 files changed, 101 insertions(+), 62 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7b138ec..38dedb8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -135,11 +135,6 @@ add_custom_target(compile_commands_link ALL
     DEPENDS SDL3_RuntimeCompiler
 )
 
-add_custom_command(TARGET SDL3_RuntimeCompiler POST_BUILD
-    COMMAND ${CMAKE_COMMAND} -E make_directory /tmp/game_mod_include
-    COMMAND ${CMAKE_COMMAND} -E copy
-        ${CMAKE_SOURCE_DIR}/src/systems/game_mod_abi.h
-        /tmp/game_mod_include/game_mod_abi.h)
 
 # ─────────────────────────────────────────────────────────────────────────────
 # Benchmarks
diff --git a/assets/sandbox.c b/assets/sandbox.c
index e596933..5e72631 100644
--- a/assets/sandbox.c
+++ b/assets/sandbox.c
@@ -1,4 +1,4 @@
-#include "game_mod_abi.h"
+# include "game_mod_abi.h"
 static int n ;
 static ModObject * o ;
 static void box ( double x , double y , double z , double hx , double hy , double hz ) {
@@ -19,10 +19,9 @@ n = n + 1 ;
 }
 int game_build ( ModObject * out , int max ) {
 ( void ) max ;
-
 o = out ; n = 0 ;
 box ( 0 , - 16 , 5 , 1 , 1 , 1 ) ;
 text ( 0 , - 15 , 5 , "hi" ) ;
-box ( 3 , - 16 , 5 , 1 , 2 , 1 ) ;
+box ( 3 , - 16 , 5 , 1 , 6 , 1 ) ;
 return n ;
 }
diff --git a/assets/sandbox.c.last_ok b/assets/sandbox.c.last_ok
index b966a3c..5e72631 100644
--- a/assets/sandbox.c.last_ok
+++ b/assets/sandbox.c.last_ok
@@ -22,7 +22,6 @@ int game_build ( ModObject * out , int max ) {
 o = out ; n = 0 ;
 box ( 0 , - 16 , 5 , 1 , 1 , 1 ) ;
 text ( 0 , - 15 , 5 , "hi" ) ;
-box(6,-16,5,1,3,1);
-box ( 3 , - 16 , 7 , 1 , 2 , 1 ) ;
+box ( 3 , - 16 , 5 , 1 , 6 , 1 ) ;
 return n ;
 }
diff --git a/src/core/game.cpp b/src/core/game.cpp
index af565aa..fbcd20e 100644
--- a/src/core/game.cpp
+++ b/src/core/game.cpp
@@ -1,3 +1,6 @@
+#include <filesystem>
+#include <system_error>
+
 #include "game.hpp"
 #include "utils/config.hpp"
 #include "entities/world.hpp"
@@ -14,6 +17,19 @@ Game::~Game() = default;
 bool
 Game::init()
 {
+    {
+        std::error_code ec;
+        std::filesystem::create_directories("/tmp/game_mod_include", ec);
+        std::filesystem::copy_file(
+            "src/systems/game_mod_abi.h",
+            "/tmp/game_mod_include/game_mod_abi.h",
+            std::filesystem::copy_options::overwrite_existing, ec);
+        if (ec)
+            SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
+                        "Could not stage game_mod_abi.h: %s", ec.message().c_str());
+    }
+
+
     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
     SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
diff --git a/src/entities/player.cpp b/src/entities/player.cpp
index 5ec4508..179db30 100644
--- a/src/entities/player.cpp
+++ b/src/entities/player.cpp
@@ -56,10 +56,8 @@ Player::compute_Movement(const FrameInput& input)
 
     if (n != 0) {
         double inv = 1.0 / SDL_sqrt(n);
-        double mult = 60.0;
-
-        acc_x = mult * ( c*dirX + s*dirZ) * inv;
-        acc_z = mult * (-s*dirX + c*dirZ) * inv;
+        acc_x = MOVE_ACCEL * ( c*dirX + s*dirZ) * inv;
+        acc_z = MOVE_ACCEL * (-s*dirX + c*dirZ) * inv;
     }
 }
 
diff --git a/src/entities/player.hpp b/src/entities/player.hpp
index e7ce60a..27fbff5 100644
--- a/src/entities/player.hpp
+++ b/src/entities/player.hpp
@@ -32,6 +32,10 @@ public:
     float    radius   {0.5f};
     float    height   {1.5f};
     bool     on_ground{false};
+    static constexpr double
+             JUMP_VELOCITY = 8.4375;
+    static constexpr double
+             MOVE_ACCEL    = 60.0;
 
     void   compute_Movement(const FrameInput& input);
     void   add_Look(int dx, int dy);
diff --git a/src/states/game_state.cpp b/src/states/game_state.cpp
index dc15ac0..906f29b 100644
--- a/src/states/game_state.cpp
+++ b/src/states/game_state.cpp
@@ -338,7 +338,7 @@ void
 GameState::on_Jump()
 {
     if (ctx.player->on_ground) {
-        ctx.player->vel.y     = 8.4375;
+        ctx.player->vel.y     = Player::JUMP_VELOCITY;
         ctx.player->on_ground = false;
     }
 }
@@ -880,8 +880,22 @@ GameState::scene_Teardown()
             ctx.scenery.end());
     }
 
+    // Also drop any dynamic-lib spawned objects (boxes in scenery, text in words).
+    if (!mod_scenery.empty()) {
+        std::unordered_set<GameObject*> mod_set(mod_scenery.begin(), mod_scenery.end());
+        ctx.scenery.erase(
+            std::remove_if(ctx.scenery.begin(), ctx.scenery.end(),
+                [&mod_set](const GameObjectPtr& sp){ return mod_set.count(sp.get()) > 0; }),
+            ctx.scenery.end());
+        ctx.words.erase(
+            std::remove_if(ctx.words.begin(), ctx.words.end(),
+                [&mod_set](const Text3dPtr& wp){ return mod_set.count(wp.get()) > 0; }),
+            ctx.words.end());
+    }
+
     step_scenery.clear();
     step_plates.clear();
+    mod_scenery.clear();
 }
 
 
diff --git a/src/systems/compiler_system.cpp b/src/systems/compiler_system.cpp
index 4e4e3dc..a0375fe 100644
--- a/src/systems/compiler_system.cpp
+++ b/src/systems/compiler_system.cpp
@@ -1,49 +1,8 @@
-#include "systems/compiler_system.hpp"
-#include "text_3d/text_3d.hpp"
 #include <SDL3/SDL.h>
 
-
-
-
-static std::string
-sanitize_Ascii(const std::string& in)
-{
-    std::string out;
-    out.reserve(in.size());
-
-    size_t i = 0;
-    while (i < in.size()) {
-        unsigned char c = static_cast<unsigned char>(in[i]);
-
-        if (c < 0x80) {
-            // Plain ASCII — keep as-is
-            out += static_cast<char>(c);
-            i++;
-        }
-        else if (c == 0xE2 && i+2 < in.size()
-              && static_cast<unsigned char>(in[i+1]) == 0x80) {
-            // Common Unicode punctuation block U+2000–U+20FF
-            unsigned char c3 = static_cast<unsigned char>(in[i+2]);
-            switch (c3) {
-                case 0x98: case 0x99: out += '\''; break; // ' '
-                case 0x9C: case 0x9D: out += '"';  break; // " "
-                case 0x93: case 0x94: out += '"';  break; // " "
-                case 0xA2:            out += '-';  break; // –
-                case 0xA6:            out += '-';  break; // —
-                default:              out += '?';  break;
-            }
-            i += 3;
-        }
-        else {
-            // Skip other multi-byte sequences
-            out += '?';
-            while (i < in.size() && (static_cast<unsigned char>(in[i]) & 0xC0) == 0x80)
-                i++;
-            if (i < in.size()) i++;
-        }
-    }
-    return out;
-}
+#include "systems/compiler_system.hpp"
+#include "text_3d/text_3d.hpp"
+#include "utils/ascii.hpp"
 
 
 
@@ -67,7 +26,7 @@ CompilerSystem::compile(TextWallList& texts, const std::string& src)
 
     // Open gcc pipe — stderr redirected to stdout so we get errors too
     if (pipe) { pclose(pipe); pipe = nullptr; }
-    pipe = popen("gcc /tmp/game_prog.c -o /tmp/game_prog 2>&1", "r");
+    pipe = popen("LC_ALL=C gcc /tmp/game_prog.c -o /tmp/game_prog 2>&1", "r");
     if (!pipe) SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "CompilerSystem: popen failed");
 }
 
@@ -109,7 +68,7 @@ CompilerSystem::push_Line(TextWallList& texts, const std::string& line, float wo
 {
     if (line == "OK") last_compile_ok = true;
 
-    std::string clean = sanitize_Ascii(line);
+    std::string clean = ascii_Sanitize(line);
 
     for (TextWallPtr& wt : texts)
         if (wt->role == Wall::Role::Compiler)
diff --git a/src/systems/mod_loader.cpp b/src/systems/mod_loader.cpp
index f0e8d53..9adcd93 100644
--- a/src/systems/mod_loader.cpp
+++ b/src/systems/mod_loader.cpp
@@ -6,6 +6,7 @@
 
 #include "systems/mod_loader.hpp"
 #include "text_3d/text_3d.hpp"
+#include "utils/ascii.hpp"
 
 
 // Where game_mod_abi.h is installed at runtime, and the build scratch dir.
@@ -151,7 +152,8 @@ ModLoader::push_Line(TextWallList& texts, const std::string& line, float world_s
     Vec3 pos = tf.position;
     pos.y = start_y;
 
-    Text3dPtr t = make_Text3d(line, Text3d::depth_compiler, 0.003f,
+    std::string clean = ascii_Sanitize(line);
+    Text3dPtr t = make_Text3d(clean, Text3d::depth_compiler, 0.003f,
                               pos, Text3d::color_compiler);
     t->yaw = tf.yaw;
 
diff --git a/src/utils/ascii.hpp b/src/utils/ascii.hpp
new file mode 100644
index 0000000..bc5a66a
--- /dev/null
+++ b/src/utils/ascii.hpp
@@ -0,0 +1,53 @@
+#pragma once
+#include <string>
+
+// ─────────────────────────────────────────────────────────────────────────
+// ascii_Sanitize — collapse non-ASCII bytes to safe ASCII for wall display.
+//
+// gcc diagnostics use Unicode directional quotes (U+2018/2019 ‘ ’, U+201C/201D
+// “ ”) which the text renderer can't draw. This maps the common ones to plain
+// ' and ", and replaces any other multibyte sequence with '?'. Used by both
+// CompilerSystem and ModLoader so their wall output stays renderable.
+//
+// Note: also set LC_ALL=C on the gcc invocation to make gcc emit ASCII quotes
+// at the source; this function is the belt-and-suspenders fallback.
+// ─────────────────────────────────────────────────────────────────────────
+inline std::string
+ascii_Sanitize(const std::string& in)
+{
+    std::string out;
+    out.reserve(in.size());
+
+    size_t i = 0;
+    while (i < in.size()) {
+        const unsigned char c = static_cast<unsigned char>(in[i]);
+
+        if (c < 0x80) {
+            out += static_cast<char>(c);
+            ++i;
+            continue;
+        }
+
+        // U+2000–U+20FF punctuation block: E2 80 xx
+        if (c == 0xE2 && i + 2 < in.size() &&
+            static_cast<unsigned char>(in[i + 1]) == 0x80) {
+            const unsigned char c3 = static_cast<unsigned char>(in[i + 2]);
+            switch (c3) {
+                case 0x98: case 0x99: out += '\''; break;  // ‘ ’
+                case 0x9C: case 0x9D: out += '"';  break;  // “ ”
+                case 0x93: case 0x94: out += '-';  break;  // – —
+                default:              out += '\''; break;
+            }
+            i += 3;
+            continue;
+        }
+
+        // Any other multibyte sequence: one '?', skip continuation bytes.
+        out += '?';
+        ++i;
+        while (i < in.size() &&
+               (static_cast<unsigned char>(in[i]) & 0xC0) == 0x80)
+            ++i;
+    }
+    return out;
+}