sdl_runtime_compiler git · main
SDL3 game for running and compiling code at runtime
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.gzRefractor prefix private member vars
src/core/game.cpp | 50 ++- src/core/game.hpp | 9 +- src/entities/plate.hpp | 8 +- src/entities/player.cpp | 8 +- src/entities/player.hpp | 20 +- src/entities/world.cpp | 36 +-- src/entities/world.hpp | 16 +- src/rendering/floor_mandelbrot.cpp | 44 +-- src/rendering/floor_mandelbrot.hpp | 6 +- src/rendering/gl_renderer.cpp | 440 +++++++++++++------------- src/rendering/gl_renderer.hpp | 152 ++++----- src/states/game_state.cpp | 614 ++++++++++++++++++------------------ src/states/game_state.hpp | 77 +++-- src/states/menu_state.cpp | 154 ++++----- src/states/menu_state.hpp | 48 ++- src/systems/celebration_system.cpp | 38 +-- src/systems/celebration_system.hpp | 10 +- src/systems/compiler_system.cpp | 33 +- src/systems/compiler_system.hpp | 25 +- src/systems/freelook_system.hpp | 4 +- src/systems/hint_system.cpp | 22 +- src/systems/hint_system.hpp | 16 +- src/systems/input_system.cpp | 4 +- src/systems/level_runner_system.cpp | 4 +- src/systems/level_runner_system.hpp | 20 +- src/systems/mod_loader_system.cpp | 46 +-- src/systems/mod_loader_system.hpp | 43 +-- src/systems/particle_system.cpp | 18 +- src/systems/particle_system.hpp | 6 +- src/systems/physics_system.cpp | 16 +- src/systems/physics_system.hpp | 19 +- src/systems/plate_system.hpp | 7 +- src/systems/pult_system.cpp | 12 +- src/systems/pult_system.hpp | 4 +- src/systems/word_ai_system.cpp | 4 +- src/systems/word_ai_system.hpp | 31 +- src/systems/word_anim.hpp | 10 +- src/text_3d/text_label.cpp | 116 +++---- src/text_3d/text_label.hpp | 59 ++-- src/wall/editor_wall.cpp | 20 +- src/wall/editor_wall.hpp | 6 +- src/wall/wall_surfaces.cpp | 14 +- src/wall/wall_surfaces.hpp | 7 +- 43 files changed, 1133 insertions(+), 1163 deletions(-) diff --git a/src/core/game.cpp b/src/core/game.cpp index fbcd20e..adeae78 100644 --- a/src/core/game.cpp +++ b/src/core/game.cpp @@ -9,7 +9,6 @@ #include "states/menu_state.hpp" #include "systems/input_system.hpp" #include "systems/physics_system.hpp" -#include "rendering/gl_renderer.hpp" Game::~Game() = default; @@ -17,17 +16,13 @@ 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, + 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); @@ -38,60 +33,53 @@ Game::init() SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4); - window = SDL_CreateWindow("game", 640, 480, - SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL); - if (!window) { + _window = SDL_CreateWindow("game", 640, 480, SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL); + if (!_window) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateWindow failed: %s", SDL_GetError()); return false; } - SDL_SetWindowRelativeMouseMode(window, true); + SDL_SetWindowRelativeMouseMode(_window, true); - gl_renderer = cpputils::make_unique<GlRenderer>(); - if (!gl_renderer->init(window)) - return false; + _gl_renderer = cpputils::make_unique<GlRenderer>(); + if (!_gl_renderer->init(_window)) return false; - SDL_StartTextInput(window); + SDL_StartTextInput(_window); - changeState(cpputils::make_unique<MenuState>()); + change_State(cpputils::make_unique<MenuState>()); return true; } void -Game::changeState(cpputils::unique_ptr<IState> next) +Game::change_State(cpputils::unique_ptr<IState> next) { - if (m_state) - m_state->on_Exit(*this); + if (m_state) m_state->on_Exit(*this); m_state = std::move(next); - if (m_state) - m_state->on_Enter(*this); + if (m_state) m_state->on_Enter(*this); } void Game::handle_Event(const SDL_Event& event) { - if (m_state) - m_state->handle_Event(*this, event); + if (m_state) m_state->handle_Event(*this, event); } void Game::update(double dt_ns) { - if (m_state) - m_state->update(dt_ns * 1e-9); + if (m_state) m_state->update(dt_ns * 1e-9); } void Game::render() { - if (m_state) - m_state->render(*window, *gl_renderer); + if (m_state) m_state->render(*_window, *_gl_renderer); } diff --git a/src/core/game.hpp b/src/core/game.hpp index b11eeb1..0845c02 100644 --- a/src/core/game.hpp +++ b/src/core/game.hpp @@ -6,20 +6,19 @@ #include "states/istate.hpp" #include "utils/globals.hpp" +#include "rendering/gl_renderer.hpp" -class GlRenderer; - class Game { - GlRendererPtr gl_renderer{}; - SDL_Window* window{}; + GlRendererPtr _gl_renderer{}; + SDL_Window* _window {}; cpputils::unique_ptr<IState> m_state; public: ~Game(); bool init(); - void changeState(cpputils::unique_ptr<IState> next); + void change_State(cpputils::unique_ptr<IState> next); void handle_Event(const SDL_Event& event); void update(double dt_ns); diff --git a/src/entities/plate.hpp b/src/entities/plate.hpp index 188d5da..1b1b043 100644 --- a/src/entities/plate.hpp +++ b/src/entities/plate.hpp @@ -14,9 +14,9 @@ class GlRenderer; // when stepped on. struct Plate final : public SolidBox { - static constexpr float HALF_W = 0.6f; // plate is wide and short - static constexpr float HALF_H = 0.05f; - static constexpr float HALF_D = 0.6f; + static constexpr float _HALF_W = 0.6f; // plate is wide and short + static constexpr float _HALF_H = 0.05f; + static constexpr float _HALF_D = 0.6f; bool active { false }; // player currently standing on it bool was_active{ false }; // for edge detection @@ -27,7 +27,7 @@ struct Plate final : public SolidBox Plate(Vec3 world_pos) : SolidBox( world_pos, - Vec3{ HALF_W, HALF_H, HALF_D }, + Vec3{ _HALF_W, _HALF_H, _HALF_D }, SDL_FColor{ 0.3f, 1.0f, 0.6f, 1.0f }, // bright cyan-green SDL_FColor{ 0.6f, 1.0f, 0.8f, 1.0f }, false) // not interactable like a pult diff --git a/src/entities/player.cpp b/src/entities/player.cpp index 179db30..61c08c9 100644 --- a/src/entities/player.cpp +++ b/src/entities/player.cpp @@ -51,13 +51,13 @@ Player::compute_Movement(const FrameInput& input) double n = dirX * dirX + dirZ * dirZ; - acc_x = 0; - acc_z = 0; + _acc_x = 0; + _acc_z = 0; if (n != 0) { double inv = 1.0 / SDL_sqrt(n); - acc_x = MOVE_ACCEL * ( c*dirX + s*dirZ) * inv; - acc_z = MOVE_ACCEL * (-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 ddee694..7dd0a3e 100644 --- a/src/entities/player.hpp +++ b/src/entities/player.hpp @@ -19,6 +19,8 @@ struct PlayerCollision struct Player { + double _acc_x{}; + double _acc_z{}; public: Player(); @@ -37,18 +39,10 @@ public: MOVE_ACCEL = 60.0; void compute_Movement(const FrameInput& input); - void add_Look(int dx, int dy); - - void apply_Collision(const PlayerCollision& col); - + void add_Look (int dx, int dy); + void apply_Collision (const PlayerCollision& col); Vec3 interpolated_Pos(double alpha) const; - - double get_AccX() const { return acc_x; } - double get_AccZ() const { return acc_z; } - - void respawn(const Vec3& spawn_pos); - -private: - double acc_x{}; - double acc_z{}; + double get_AccX () const { return _acc_x; } + double get_AccZ () const { return _acc_z; } + void respawn (const Vec3& spawn_pos); }; diff --git a/src/entities/world.cpp b/src/entities/world.cpp index 485ea5c..9d7adda 100644 --- a/src/entities/world.cpp +++ b/src/entities/world.cpp @@ -3,14 +3,14 @@ World::World() { initEdges(); - wall_surfaces.generate(world_scale); + _wall_surfaces.generate(_world_scale); } void World::initEdges() { - const float r = world_scale; + const float r = _world_scale; const int map[24] = { 0,1 , 1,3 , 3,2 , 2,0 , @@ -30,21 +30,21 @@ World::initEdges() if (j == 2) { a.z = va; b.z = vb; } } - edges[i] = { a, b }; + _edges[i] = { a, b }; } - size_t scale = static_cast<size_t>(world_scale); + size_t scale = static_cast<size_t>(_world_scale); for (size_t i = 0; i < scale; i++) { - float d = static_cast<float>(i * 2) - world_scale; + float d = static_cast<float>(i * 2) - _world_scale; // line z axis - edges[12 + i] = { + _edges[12 + i] = { { -r, -r, d }, { r, -r, d } }; // line x axis - edges[12 + scale + i] = { + _edges[12 + scale + i] = { { d, -r, -r }, { d, -r, r } }; @@ -76,11 +76,11 @@ World::resolvePlayer(const Player& player) const PlayerCollision out; out.vel = player.vel; - const double min = -world_scale + player.radius; - const double max = world_scale - player.radius; + const double min = -_world_scale + player.radius; + const double max = _world_scale - player.radius; - const double minY = player.height - world_scale; - const double maxY = world_scale; + const double minY = player.height - _world_scale; + const double maxY = _world_scale; out.pos.x = sweepAxis(player.pos.x, min, max, out.hit_x); out.pos.y = sweepAxis(player.pos.y, minY, maxY, out.hit_y); @@ -102,12 +102,12 @@ World::draw(GlRenderer& gl, const Camera& camera, const Light& light) const Mat4 model = Mat4::identity(); Mat4 mvp = Mat4::mul(proj, Mat4::mul(view, model)); - // Box edges: dark grey + // Box _edges: dark grey if (show_wireframe) { DynArray<float> pts; - pts.reserve(map_box_edges_len * 6); - for (size_t k = 0; k < map_box_edges_len; k++) { - const Edge& e = edges[k]; + pts.reserve(_map_box_edges_len * 6); + for (size_t k = 0; k < _map_box_edges_len; k++) { + const Edge& e = _edges[k]; pts.push_back((float)e.a.x); pts.push_back((float)e.a.y); pts.push_back((float)e.a.z); pts.push_back((float)e.b.x); pts.push_back((float)e.b.y); pts.push_back((float)e.b.z); } @@ -117,7 +117,7 @@ World::draw(GlRenderer& gl, const Camera& camera, const Light& light) const } // Crosshair: 2D overlay in NDC. Uses identity MVP, then restores the - // world MVP so subsequent draws (wall_surfaces) aren't affected. + // world MVP so subsequent draws (_wall_surfaces) aren't affected. { Mat4 ident = Mat4::identity(); gl.set_MVP(model, ident); @@ -137,7 +137,7 @@ World::draw(GlRenderer& gl, const Camera& camera, const Light& light) const } // ── Solid wall surfaces ───────────────────────────────────────────── - wall_surfaces.draw(gl, camera, light); + _wall_surfaces.draw(gl, camera, light); } @@ -148,4 +148,4 @@ World::spawnPoint() const float World::scale() const -{ return world_scale; } +{ return _world_scale; } diff --git a/src/entities/world.hpp b/src/entities/world.hpp index ca06547..4e21969 100644 --- a/src/entities/world.hpp +++ b/src/entities/world.hpp @@ -22,23 +22,25 @@ struct SweepResult { class World { static inline constexpr int - map_box_scale{static_cast<int>(WORLD_BOX_SCALE)}; + _map_box_scale {static_cast<int>(WORLD_BOX_SCALE)}; static inline constexpr int - map_box_edges_len{12 + map_box_scale * 2}; + _map_box_edges_len {12 + _map_box_scale * 2}; float - world_scale{WORLD_BOX_SCALE}; + _world_scale {WORLD_BOX_SCALE}; - WallSurfaces wall_surfaces; + WallSurfaces + _wall_surfaces; - std::array<Edge, map_box_edges_len> - edges{}; + std::array<Edge, _map_box_edges_len> + _edges {}; void initEdges(); public: - bool show_wireframe { false }; + bool + show_wireframe { false }; World(); diff --git a/src/rendering/floor_mandelbrot.cpp b/src/rendering/floor_mandelbrot.cpp index 78ddb99..f5836a9 100644 --- a/src/rendering/floor_mandelbrot.cpp +++ b/src/rendering/floor_mandelbrot.cpp @@ -13,8 +13,8 @@ FloorMandelbrot::generate(float world_scale, double center_y, double width) { - verts_.clear(); - indices_.clear(); + _verts.clear(); + _indices.clear(); // Single quad covering the floor. We use the existing 9-floats-per-vertex // layout: [pos(3) | normal(3) | color(3)], but here we *abuse* the color @@ -34,33 +34,33 @@ FloorMandelbrot::generate(float world_scale, }; for (const V& v : corners) { - verts_.push_back(v.x); - verts_.push_back(v.y); - verts_.push_back(v.z); + _verts.push_back(v.x); + _verts.push_back(v.y); + _verts.push_back(v.z); // Normal — flat up. - verts_.push_back(0.0f); - verts_.push_back(1.0f); - verts_.push_back(0.0f); + _verts.push_back(0.0f); + _verts.push_back(1.0f); + _verts.push_back(0.0f); // "Color" slot carries the complex-plane coord. - verts_.push_back(static_cast<float>(v.cx)); - verts_.push_back(static_cast<float>(v.cy)); - verts_.push_back(0.0f); + _verts.push_back(static_cast<float>(v.cx)); + _verts.push_back(static_cast<float>(v.cy)); + _verts.push_back(0.0f); } // Two triangles: BL,BR,TR + BL,TR,TL - indices_.push_back(0); - indices_.push_back(1); - indices_.push_back(2); - indices_.push_back(0); - indices_.push_back(2); - indices_.push_back(3); + _indices.push_back(0); + _indices.push_back(1); + _indices.push_back(2); + _indices.push_back(0); + _indices.push_back(2); + _indices.push_back(3); } void FloorMandelbrot::draw(GlRenderer& gl, const Camera& cam, const Light& light) const { - if (verts_.empty()) return; + if (_verts.empty()) return; Mat4 view = buildViewMat4(cam); Mat4 proj = gl.projection(); @@ -74,9 +74,9 @@ FloorMandelbrot::draw(GlRenderer& gl, const Camera& cam, const Light& light) con gl.enable_MandelbrotMode(true); gl.set_ColorUseVertex(false); - gl.draw_MeshColored(verts_.data(), - static_cast<int>(verts_.size() / 9), - indices_.data(), - static_cast<int>(indices_.size())); + gl.draw_MeshColored(_verts.data(), + static_cast<int>(_verts.size() / 9), + _indices.data(), + static_cast<int>(_indices.size())); gl.enable_MandelbrotMode(false); } diff --git a/src/rendering/floor_mandelbrot.hpp b/src/rendering/floor_mandelbrot.hpp index c223ee2..b8424c1 100644 --- a/src/rendering/floor_mandelbrot.hpp +++ b/src/rendering/floor_mandelbrot.hpp @@ -16,6 +16,8 @@ class Camera; // transitions and clear "ring" regions around the set boundary. Inside // the set is a near-black indigo. class FloorMandelbrot { + DynArray<float> _verts; + DynArray<int> _indices; public: void generate(float world_scale, float floor_y, @@ -24,8 +26,4 @@ public: double width = 3.0); void draw(GlRenderer& gl, const Camera& cam, const Light& light) const; - -private: - DynArray<float> verts_; - DynArray<int> indices_; }; diff --git a/src/rendering/gl_renderer.cpp b/src/rendering/gl_renderer.cpp index 50290df..4d5c6ce 100644 --- a/src/rendering/gl_renderer.cpp +++ b/src/rendering/gl_renderer.cpp @@ -408,9 +408,9 @@ Mat4 buildModelMat4(const Vec3& pos, float yaw, float pitch) // ───────────────────────────────────────────────────────────────────────────── bool GlRenderer::init(SDL_Window* window) { - m_ctx = SDL_GL_CreateContext(window); - if (!m_ctx) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "GL context creation failed: %s", SDL_GetError()); return false; } - SDL_GL_MakeCurrent(window, m_ctx); + _ctx = SDL_GL_CreateContext(window); + if (!_ctx) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "GL context creation failed: %s", SDL_GetError()); return false; } + SDL_GL_MakeCurrent(window, _ctx); SDL_GL_SetSwapInterval(0); int samples = 0; @@ -429,55 +429,55 @@ bool GlRenderer::init(SDL_Window* window) glDeleteShader(vert); glDeleteShader(frag); - m_uMVP = glGetUniformLocation(m_prog, "u_MVP"); - m_uNormalMat = glGetUniformLocation(m_prog, "u_NormalMat"); - m_uColor = glGetUniformLocation(m_prog, "u_Color"); - m_uBodyColor = glGetUniformLocation(m_prog, "u_BodyColor"); - m_uBackDim = glGetUniformLocation(m_prog, "u_BackDim"); - m_uUseFront = glGetUniformLocation(m_prog, "u_UseFront"); - m_uLightDir = glGetUniformLocation(m_prog, "u_LightDir"); - m_uAmbient = glGetUniformLocation(m_prog, "u_Ambient"); - m_uIntensity = glGetUniformLocation(m_prog, "u_Intensity"); - m_uWireframe = glGetUniformLocation(m_prog, "u_Wireframe"); - m_uUseVertexColor = glGetUniformLocation(m_prog, "u_UseVertexColor"); - m_uMandelbrot = glGetUniformLocation(m_prog, "u_Mandelbrot"); - m_uWallPaper = glGetUniformLocation(m_prog, "u_WallPaper"); - m_uTextLineSpacing= glGetUniformLocation(m_prog, "u_TextLineSpacing"); - - - - m_uModel = glGetUniformLocation(m_prog, "u_Model"); - m_uSunColor = glGetUniformLocation(m_prog, "u_SunColor"); - m_uFlashPos = glGetUniformLocation(m_prog, "u_FlashPos"); - m_uFlashDir = glGetUniformLocation(m_prog, "u_FlashDir"); - m_uFlashColor = glGetUniformLocation(m_prog, "u_FlashColor"); - m_uFlashRange = glGetUniformLocation(m_prog, "u_FlashRange"); - m_uFlashInnerCos = glGetUniformLocation(m_prog, "u_FlashInnerCos"); - m_uFlashOuterCos = glGetUniformLocation(m_prog, "u_FlashOuterCos"); - m_uFlashIntensity = glGetUniformLocation(m_prog, "u_FlashIntensity"); - - glGenVertexArrays(1, &m_vao); glGenBuffers(1, &m_vbo); glGenBuffers(1, &m_ebo); - glBindVertexArray(m_vao); - glBindBuffer(GL_ARRAY_BUFFER, m_vbo); + _uMVP = glGetUniformLocation(_prog, "u_MVP"); + _uNormalMat = glGetUniformLocation(_prog, "u_NormalMat"); + _uColor = glGetUniformLocation(_prog, "u_Color"); + _uBodyColor = glGetUniformLocation(_prog, "u_BodyColor"); + _uBackDim = glGetUniformLocation(_prog, "u_BackDim"); + _uUseFront = glGetUniformLocation(_prog, "u_UseFront"); + _uLightDir = glGetUniformLocation(_prog, "u_LightDir"); + _uAmbient = glGetUniformLocation(_prog, "u_Ambient"); + _uIntensity = glGetUniformLocation(_prog, "u_Intensity"); + _uWireframe = glGetUniformLocation(_prog, "u_Wireframe"); + _uUseVertexColor = glGetUniformLocation(_prog, "u_UseVertexColor"); + _uMandelbrot = glGetUniformLocation(_prog, "u_Mandelbrot"); + _uWallPaper = glGetUniformLocation(_prog, "u_WallPaper"); + _uTextLineSpacing= glGetUniformLocation(_prog, "u_TextLineSpacing"); + + + + _uModel = glGetUniformLocation(_prog, "u_Model"); + _uSunColor = glGetUniformLocation(_prog, "u_SunColor"); + _uFlashPos = glGetUniformLocation(_prog, "u_FlashPos"); + _uFlashDir = glGetUniformLocation(_prog, "u_FlashDir"); + _uFlashColor = glGetUniformLocation(_prog, "u_FlashColor"); + _uFlashRange = glGetUniformLocation(_prog, "u_FlashRange"); + _uFlashInnerCos = glGetUniformLocation(_prog, "u_FlashInnerCos"); + _uFlashOuterCos = glGetUniformLocation(_prog, "u_FlashOuterCos"); + _uFlashIntensity = glGetUniformLocation(_prog, "u_FlashIntensity"); + + glGenVertexArrays(1, &_vao); glGenBuffers(1, &_vbo); glGenBuffers(1, &_ebo); + glBindVertexArray(_vao); + glBindBuffer(GL_ARRAY_BUFFER, _vbo); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), (void*)0); glEnableVertexAttribArray(0); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), (void*)(3*sizeof(float))); glEnableVertexAttribArray(1); glBindVertexArray(0); - glGenVertexArrays(1, &m_line_vao); glGenBuffers(1, &m_line_vbo); - glBindVertexArray(m_line_vao); - glBindBuffer(GL_ARRAY_BUFFER, m_line_vbo); + glGenVertexArrays(1, &_line_vao); glGenBuffers(1, &_line_vbo); + glBindVertexArray(_line_vao); + glBindBuffer(GL_ARRAY_BUFFER, _line_vbo); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void*)0); glEnableVertexAttribArray(0); glVertexAttrib3f(1, 0.0f, 0.0f, 1.0f); glBindVertexArray(0); - glGenVertexArrays(1, &m_vao_c); - glGenBuffers (1, &m_vbo_c); - glGenBuffers (1, &m_ebo_c); - glBindVertexArray(m_vao_c); - glBindBuffer(GL_ARRAY_BUFFER, m_vbo_c); + glGenVertexArrays(1, &_vao_c); + glGenBuffers (1, &_vbo_c); + glGenBuffers (1, &_ebo_c); + glBindVertexArray(_vao_c); + glBindBuffer(GL_ARRAY_BUFFER, _vbo_c); // 9 floats per vertex: pos(3) + normal(3) + color(3) glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), (void*)0); @@ -502,8 +502,8 @@ bool GlRenderer::init(SDL_Window* window) create_CompositeProgram_(); // Lookup the new emissive uniforms on the main program. - m_uEmissiveColor = glGetUniformLocation(m_prog, "u_EmissiveColor"); - m_uEmissiveStrength = glGetUniformLocation(m_prog, "u_EmissiveStrength"); + _uEmissiveColor = glGetUniformLocation(_prog, "u_EmissiveColor"); + _uEmissiveStrength = glGetUniformLocation(_prog, "u_EmissiveStrength"); { // thats for the menu @@ -512,10 +512,10 @@ bool GlRenderer::init(SDL_Window* window) -0.5f,-0.5f, 0.0f, 0.5f,-0.5f, 0.0f }; - glGenVertexArrays(1, &m_menu_vao); - glGenBuffers(1, &m_menu_vbo); - glBindVertexArray(m_menu_vao); - glBindBuffer(GL_ARRAY_BUFFER, m_menu_vbo); + glGenVertexArrays(1, &_menu_vao); + glGenBuffers(1, &_menu_vbo); + glBindVertexArray(_menu_vao); + glBindBuffer(GL_ARRAY_BUFFER, _menu_vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(tri), tri, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void*)0); glEnableVertexAttribArray(0); @@ -531,29 +531,29 @@ bool GlRenderer::init(SDL_Window* window) void GlRenderer::begin_Frame(int w, int h) { - m_view_w = w; m_view_h = h; - m_aspect = (h != 0) ? (float)w/(float)h : 1.0f; + _view_w = w; _view_h = h; + _aspect = (h != 0) ? (float)w/(float)h : 1.0f; // Lazy-create or resize the FBO to match the window. - if (m_scene_fbo == 0) create_FBO_(w, h); + if (_scene_fbo == 0) create_FBO_(w, h); else resize_FBO_(w, h); // Bind the FBO as the render target. - glBindFramebuffer(GL_FRAMEBUFFER, m_scene_fbo); + glBindFramebuffer(GL_FRAMEBUFFER, _scene_fbo); glViewport(0, 0, w, h); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glUseProgram(m_prog); - glUniform1i(m_uMandelbrot, 0); - glUniform1i(m_uWallPaper, 0); - glUniform1i(m_uUseFront, 0); + glUseProgram(_prog); + glUniform1i(_uMandelbrot, 0); + glUniform1i(_uWallPaper, 0); + glUniform1i(_uUseFront, 0); Mat4 ident = Mat4::identity(); - glUniformMatrix4fv(m_uModel, 1, GL_FALSE, ident.m); - glUniform1i(m_uUseVertexColor, 0); - glUniform3f(m_uEmissiveColor, 0.0f, 0.0f, 0.0f); - glUniform1f(m_uEmissiveStrength, 0.0f); - m_proj = Mat4::perspective(SDL_PI_F/3.0f, m_aspect, 0.1f, 200.0f); + glUniformMatrix4fv(_uModel, 1, GL_FALSE, ident.m); + glUniform1i(_uUseVertexColor, 0); + glUniform3f(_uEmissiveColor, 0.0f, 0.0f, 0.0f); + glUniform1f(_uEmissiveStrength, 0.0f); + _proj = Mat4::perspective(SDL_PI_F/3.0f, _aspect, 0.1f, 200.0f); } void @@ -567,26 +567,26 @@ GlRenderer::end_Frame(SDL_Window* window) // Composite scene + bloom to screen. glBindFramebuffer(GL_FRAMEBUFFER, 0); - glViewport(0, 0, m_view_w, m_view_h); + glViewport(0, 0, _view_w, _view_h); glDisable(GL_DEPTH_TEST); - glUseProgram(m_composite_prog); + glUseProgram(_composite_prog); glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, m_scene_color_tex); - glUniform1i(m_uComposeScene, 0); + glBindTexture(GL_TEXTURE_2D, _scene_color_tex); + glUniform1i(_uComposeScene, 0); glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, m_blur_tex[1]); // final bloom - glUniform1i(m_uComposeBloom, 1); - glUniform1f(m_uComposeStrength, m_bloom_strength); + glBindTexture(GL_TEXTURE_2D, _blur_tex[1]); // final bloom + glUniform1i(_uComposeBloom, 1); + glUniform1f(_uComposeStrength, _bloom_strength); { FP_ZONE("end_Frame.composite"); - glBindVertexArray(m_fullscreen_vao); + glBindVertexArray(_fullscreen_vao); glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0); glActiveTexture(GL_TEXTURE0); // reset to default unit glEnable(GL_DEPTH_TEST); - glUseProgram(m_prog); + glUseProgram(_prog); } { FP_ZONE("end_Frame.swap"); @@ -599,8 +599,8 @@ GlRenderer::end_Frame(SDL_Window* window) // ───────────────────────────────────────────────────────────────────────────── void GlRenderer::set_MVP(const Mat4& model, const Mat4& mvp) { - glUniformMatrix4fv(m_uMVP, 1, GL_FALSE, mvp.m); - glUniformMatrix4fv(m_uModel, 1, GL_FALSE, model.m); + glUniformMatrix4fv(_uMVP, 1, GL_FALSE, mvp.m); + glUniformMatrix4fv(_uModel, 1, GL_FALSE, model.m); } void GlRenderer::set_NormalMat(const Mat4& model) @@ -614,73 +614,73 @@ void GlRenderer::set_NormalMat(const Mat4& model) model.m[4], model.m[5], model.m[6], model.m[8], model.m[9], model.m[10] }; - glUniformMatrix3fv(m_uNormalMat, 1, GL_FALSE, n); + glUniformMatrix3fv(_uNormalMat, 1, GL_FALSE, n); } void GlRenderer::set_Color(float r, float g, float b) -{ glUniform3f(m_uColor, r, g, b); } +{ glUniform3f(_uColor, r, g, b); } void GlRenderer::set_Light(const Light& light) { // Sun - glUniform3f(m_uLightDir, + glUniform3f(_uLightDir, (float)light.direction.x, (float)light.direction.y, (float)light.direction.z); - glUniform3f(m_uSunColor, + glUniform3f(_uSunColor, (float)light.sun_color.x, (float)light.sun_color.y, (float)light.sun_color.z); - glUniform1f(m_uIntensity, light.sun_intensity); + glUniform1f(_uIntensity, light.sun_intensity); // Ambient - glUniform3f(m_uAmbient, + glUniform3f(_uAmbient, (float)light.ambient.x, (float)light.ambient.y, (float)light.ambient.z); // Flashlight - glUniform3f(m_uFlashPos, + glUniform3f(_uFlashPos, (float)light.flashlight_pos.x, (float)light.flashlight_pos.y, (float)light.flashlight_pos.z); - glUniform3f(m_uFlashDir, + glUniform3f(_uFlashDir, (float)light.flashlight_dir.x, (float)light.flashlight_dir.y, (float)light.flashlight_dir.z); - glUniform3f(m_uFlashColor, + glUniform3f(_uFlashColor, (float)light.flashlight_color.x, (float)light.flashlight_color.y, (float)light.flashlight_color.z); - glUniform1f(m_uFlashRange, light.flashlight_range); - glUniform1f(m_uFlashInnerCos, light.flashlight_inner_cos); - glUniform1f(m_uFlashOuterCos, light.flashlight_outer_cos); - glUniform1f(m_uFlashIntensity, light.flashlight_intensity); + glUniform1f(_uFlashRange, light.flashlight_range); + glUniform1f(_uFlashInnerCos, light.flashlight_inner_cos); + glUniform1f(_uFlashOuterCos, light.flashlight_outer_cos); + glUniform1f(_uFlashIntensity, light.flashlight_intensity); } void GlRenderer::set_Wireframe(bool on) -{ glUniform1i(m_uWireframe, on ? 1 : 0); } +{ glUniform1i(_uWireframe, on ? 1 : 0); } void GlRenderer::set_ColorUseVertex(bool on) -{ glUniform1i(m_uUseVertexColor, on ? 1 : 0); } +{ glUniform1i(_uUseVertexColor, on ? 1 : 0); } void GlRenderer::set_TextLineSpacing(float m) -{ glUniform1f(m_uTextLineSpacing, m); } +{ glUniform1f(_uTextLineSpacing, m); } void GlRenderer::set_Emissive(float r, float g, float b, float strength) { - glUniform3f(m_uEmissiveColor, r, g, b); - glUniform1f(m_uEmissiveStrength, strength); + glUniform3f(_uEmissiveColor, r, g, b); + glUniform1f(_uEmissiveStrength, strength); } void GlRenderer::set_FaceShade(float r, float g, float b, float back_dim, bool use_front) { - glUniform3f(m_uBodyColor, r, g, b); - glUniform1f(m_uBackDim, back_dim); - glUniform1i(m_uUseFront, use_front ? 1 : 0); + glUniform3f(_uBodyColor, r, g, b); + glUniform1f(_uBackDim, back_dim); + glUniform1i(_uUseFront, use_front ? 1 : 0); } // ───────────────────────────────────────────────────────────────────────────── @@ -689,10 +689,10 @@ GlRenderer::set_FaceShade(float r, float g, float b, float back_dim, bool use_fr void GlRenderer::draw_Mesh(const float* verts, int vert_count, const int* indices, int index_count) { - glBindVertexArray(m_vao); - glBindBuffer(GL_ARRAY_BUFFER, m_vbo); + glBindVertexArray(_vao); + glBindBuffer(GL_ARRAY_BUFFER, _vbo); glBufferData(GL_ARRAY_BUFFER, static_cast<size_t>(vert_count)*6*sizeof(float), verts, GL_STREAM_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ebo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ebo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, static_cast<size_t>(index_count)*sizeof(int), indices, GL_STREAM_DRAW); glDrawElements(GL_TRIANGLES, index_count, GL_UNSIGNED_INT, nullptr); glBindVertexArray(0); @@ -703,19 +703,19 @@ void GlRenderer::draw_MeshColored(const float* verts, int vert_count, const int* indices, int index_count) { - glBindVertexArray(m_vao_c); - glBindBuffer(GL_ARRAY_BUFFER, m_vbo_c); + glBindVertexArray(_vao_c); + glBindBuffer(GL_ARRAY_BUFFER, _vbo_c); glBufferData(GL_ARRAY_BUFFER, static_cast<size_t>(vert_count) * 9 * sizeof(float), verts, GL_STATIC_DRAW); - // Re-point attributes at m_vbo_c — draw_MeshCached may have repointed + // Re-point attributes at _vbo_c — draw_MeshCached may have repointed // this shared VAO at a per-Text3d VBO. glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (void*)0); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (void*)(3*sizeof(float))); glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (void*)(6*sizeof(float))); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ebo_c); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ebo_c); glBufferData(GL_ELEMENT_ARRAY_BUFFER, static_cast<size_t>(index_count) * sizeof(int), indices, GL_STATIC_DRAW); @@ -730,7 +730,7 @@ GlRenderer::draw_MeshCached(unsigned int& vbo, unsigned int& ebo, int& index_cou const float* verts, int vert_count, const int* indices, int idx_count) { - glBindVertexArray(m_vao_c); // reuse the 9-float pos|normal|color layout + glBindVertexArray(_vao_c); // reuse the 9-float pos|normal|color layout if (vbo == 0) glGenBuffers(1, &vbo); if (ebo == 0) glGenBuffers(1, &ebo); @@ -748,7 +748,7 @@ GlRenderer::draw_MeshCached(unsigned int& vbo, unsigned int& ebo, int& index_cou index_count = idx_count; } - // m_vao_c's attribute pointers were bound to m_vbo_c at init; rebind to ours. + // _vao_c's attribute pointers were bound to _vbo_c at init; rebind to ours. glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (void*)0); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (void*)(3*sizeof(float))); glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (void*)(6*sizeof(float))); @@ -769,8 +769,8 @@ GlRenderer::free_MeshBuffers(unsigned int vbo, unsigned int ebo) void GlRenderer::draw_Lines(const float* points, int point_count) { - glBindVertexArray(m_line_vao); - glBindBuffer(GL_ARRAY_BUFFER, m_line_vbo); + glBindVertexArray(_line_vao); + glBindBuffer(GL_ARRAY_BUFFER, _line_vbo); glBufferData(GL_ARRAY_BUFFER, static_cast<size_t>(point_count)*3*sizeof(float), points, GL_STREAM_DRAW); glDrawArrays(GL_LINES, 0, point_count); glBindVertexArray(0); @@ -778,30 +778,30 @@ void GlRenderer::draw_Lines(const float* points, int point_count) void GlRenderer::draw_Menu() { - glUseProgram(m_prog); + glUseProgram(_prog); Mat4 identity = Mat4::identity(); - glUniformMatrix4fv(m_uMVP, 1, GL_FALSE, identity.m); + glUniformMatrix4fv(_uMVP, 1, GL_FALSE, identity.m); float n[9] = {1,0,0, 0,1,0, 0,0,1}; - glUniformMatrix3fv(m_uNormalMat, 1, GL_FALSE, n); - glUniform3f(m_uColor, 0.2f, 0.4f, 0.8f); - glUniform3f(m_uLightDir, 0.0f, 0.0f, 1.0f); - glUniform3f(m_uAmbient, 1.0f, 1.0f, 1.0f); // full ambient = flat colour - glUniform1f(m_uIntensity, 1.0f); - glUniform1i(m_uWireframe, 1); - glUniform3f(m_uSunColor, 1.0f, 1.0f, 1.0f); - glUniform1i(m_uMandelbrot, 0); - glUniform1i(m_uWallPaper, 0); - glUniform3f(m_uFlashPos, 0.0f, 0.0f, 0.0f); - glUniform3f(m_uFlashDir, 0.0f, 0.0f, -1.0f); - glUniform3f(m_uFlashColor, 0.0f, 0.0f, 0.0f); - glUniform1f(m_uFlashRange, 1.0f); - glUniform1f(m_uFlashInnerCos, 0.97f); - glUniform1f(m_uFlashOuterCos, 0.90f); - glUniform1f(m_uFlashIntensity, 0.0f); + glUniformMatrix3fv(_uNormalMat, 1, GL_FALSE, n); + glUniform3f(_uColor, 0.2f, 0.4f, 0.8f); + glUniform3f(_uLightDir, 0.0f, 0.0f, 1.0f); + glUniform3f(_uAmbient, 1.0f, 1.0f, 1.0f); // full ambient = flat colour + glUniform1f(_uIntensity, 1.0f); + glUniform1i(_uWireframe, 1); + glUniform3f(_uSunColor, 1.0f, 1.0f, 1.0f); + glUniform1i(_uMandelbrot, 0); + glUniform1i(_uWallPaper, 0); + glUniform3f(_uFlashPos, 0.0f, 0.0f, 0.0f); + glUniform3f(_uFlashDir, 0.0f, 0.0f, -1.0f); + glUniform3f(_uFlashColor, 0.0f, 0.0f, 0.0f); + glUniform1f(_uFlashRange, 1.0f); + glUniform1f(_uFlashInnerCos, 0.97f); + glUniform1f(_uFlashOuterCos, 0.90f); + glUniform1f(_uFlashIntensity, 0.0f); Mat4 ident_m = Mat4::identity(); - glUniformMatrix4fv(m_uModel, 1, GL_FALSE, ident_m.m); + glUniformMatrix4fv(_uModel, 1, GL_FALSE, ident_m.m); - glBindVertexArray(m_menu_vao); + glBindVertexArray(_menu_vao); glDrawArrays(GL_TRIANGLES, 0, 3); glBindVertexArray(0); } @@ -812,32 +812,32 @@ GlRenderer::draw_Emissive(const Camera& cam, const float* verts, int vert_count, const int* indices, int index_count, float r, float g, float b, float strength) { - if (!m_emissive_prog || vert_count == 0 || index_count == 0) return; + if (!_emissive_prog || vert_count == 0 || index_count == 0) return; // Push state: switch program, enable additive blending, disable depth // write (we still depth-TEST so halos respect occluders, but we don't // want halos blocking each other in the depth buffer). - glUseProgram(m_emissive_prog); + glUseProgram(_emissive_prog); // The vertex shader needs an MVP. We use the current proj * view * I — // verts are already in world space. Mat4 view = buildViewMat4(cam); - Mat4 mvp = Mat4::mul(m_proj, view); - glUniformMatrix4fv(m_uEmissiveMVP, 1, GL_FALSE, mvp.m); + Mat4 mvp = Mat4::mul(_proj, view); + glUniformMatrix4fv(_uEmissiveMVP, 1, GL_FALSE, mvp.m); - glUniform3f(m_uEmissiveColor, r, g, b); - glUniform1f(m_uEmissiveStrength, strength); + glUniform3f(_uEmissiveColor, r, g, b); + glUniform1f(_uEmissiveStrength, strength); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE); // additive glDepthMask(GL_FALSE); // no depth write - glBindVertexArray(m_emissive_vao); - glBindBuffer(GL_ARRAY_BUFFER, m_emissive_vbo); + glBindVertexArray(_emissive_vao); + glBindBuffer(GL_ARRAY_BUFFER, _emissive_vbo); glBufferData(GL_ARRAY_BUFFER, static_cast<size_t>(vert_count) * 5 * sizeof(float), verts, GL_STREAM_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_emissive_ebo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _emissive_ebo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, static_cast<size_t>(index_count) * sizeof(int), indices, GL_STREAM_DRAW); @@ -847,7 +847,7 @@ GlRenderer::draw_Emissive(const Camera& cam, // Pop state. glDisable(GL_BLEND); glDepthMask(GL_TRUE); - glUseProgram(m_prog); // restore main program + glUseProgram(_prog); // restore main program } // ───────────────────────────────────────────────────────────────────────────── @@ -869,26 +869,26 @@ GLuint GlRenderer::compileShader(GLenum type, const char* src) bool GlRenderer::linkProgram(GLuint vert, GLuint frag) { - m_prog = glCreateProgram(); - glAttachShader(m_prog, vert); glAttachShader(m_prog, frag); - glLinkProgram(m_prog); - GLint ok; glGetProgramiv(m_prog, GL_LINK_STATUS, &ok); + _prog = glCreateProgram(); + glAttachShader(_prog, vert); glAttachShader(_prog, frag); + glLinkProgram(_prog); + GLint ok; glGetProgramiv(_prog, GL_LINK_STATUS, &ok); if (!ok) { - char log[512]; glGetProgramInfoLog(m_prog,512,nullptr,log); + char log[512]; glGetProgramInfoLog(_prog,512,nullptr,log); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Program link error: %s", log); - glDeleteProgram(m_prog); m_prog=0; return false; + glDeleteProgram(_prog); _prog=0; return false; } return true; } -float GlRenderer::aspect() const { return m_aspect; } -const Mat4& GlRenderer::projection() const { return m_proj; } +float GlRenderer::aspect() const { return _aspect; } +const Mat4& GlRenderer::projection() const { return _proj; } void GlRenderer::enable_MandelbrotMode(bool on) -{ glUniform1i(m_uMandelbrot, on ? 1 : 0); } +{ glUniform1i(_uMandelbrot, on ? 1 : 0); } void GlRenderer::enable_WallPaperMode(bool on) -{ glUniform1i(m_uWallPaper, on ? 1 : 0); } +{ glUniform1i(_uWallPaper, on ? 1 : 0); } @@ -903,10 +903,10 @@ GlRenderer::create_FullscreenQuad_() 1.0f, 1.0f, -1.0f, 1.0f, }; - glGenVertexArrays(1, &m_fullscreen_vao); - glGenBuffers(1, &m_fullscreen_vbo); - glBindVertexArray(m_fullscreen_vao); - glBindBuffer(GL_ARRAY_BUFFER, m_fullscreen_vbo); + glGenVertexArrays(1, &_fullscreen_vao); + glGenBuffers(1, &_fullscreen_vbo); + glBindVertexArray(_fullscreen_vao); + glBindBuffer(GL_ARRAY_BUFFER, _fullscreen_vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(quad_verts), quad_verts, GL_STATIC_DRAW); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2*sizeof(float), (void*)0); glEnableVertexAttribArray(0); @@ -918,53 +918,53 @@ GlRenderer::create_BlitProgram_() { GLuint v = compileShader(GL_VERTEX_SHADER, kBlitVertSrc); GLuint f = compileShader(GL_FRAGMENT_SHADER, kBlitFragSrc); - m_blit_prog = glCreateProgram(); - glAttachShader(m_blit_prog, v); - glAttachShader(m_blit_prog, f); - glLinkProgram(m_blit_prog); - GLint ok=0; glGetProgramiv(m_blit_prog, GL_LINK_STATUS, &ok); + _blit_prog = glCreateProgram(); + glAttachShader(_blit_prog, v); + glAttachShader(_blit_prog, f); + glLinkProgram(_blit_prog); + GLint ok=0; glGetProgramiv(_blit_prog, GL_LINK_STATUS, &ok); if (!ok) { - char log[512]; glGetProgramInfoLog(m_blit_prog, 512, nullptr, log); + char log[512]; glGetProgramInfoLog(_blit_prog, 512, nullptr, log); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Blit program link error: %s", log); } glDeleteShader(v); glDeleteShader(f); - m_uBlitTex = glGetUniformLocation(m_blit_prog, "u_SceneTex"); + _uBlitTex = glGetUniformLocation(_blit_prog, "u_SceneTex"); } void GlRenderer::create_FBO_(int w, int h) { - glGenFramebuffers(1, &m_scene_fbo); - glBindFramebuffer(GL_FRAMEBUFFER, m_scene_fbo); + glGenFramebuffers(1, &_scene_fbo); + glBindFramebuffer(GL_FRAMEBUFFER, _scene_fbo); // Color attachment: RGBA8 texture (LDR for now; future HDR upgrade // would use GL_RGBA16F here). - glGenTextures(1, &m_scene_color_tex); - glBindTexture(GL_TEXTURE_2D, m_scene_color_tex); + glGenTextures(1, &_scene_color_tex); + glBindTexture(GL_TEXTURE_2D, _scene_color_tex); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, m_scene_color_tex, 0); + GL_TEXTURE_2D, _scene_color_tex, 0); // Depth attachment: renderbuffer (we don't sample depth in postprocess, // so renderbuffer is fine and slightly cheaper than a depth texture). - glGenRenderbuffers(1, &m_scene_depth_rbo); - glBindRenderbuffer(GL_RENDERBUFFER, m_scene_depth_rbo); + glGenRenderbuffers(1, &_scene_depth_rbo); + glBindRenderbuffer(GL_RENDERBUFFER, _scene_depth_rbo); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, w, h); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, - GL_RENDERBUFFER, m_scene_depth_rbo); + GL_RENDERBUFFER, _scene_depth_rbo); GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Scene FBO incomplete: 0x%x", status); glBindFramebuffer(GL_FRAMEBUFFER, 0); - m_fbo_w = w; - m_fbo_h = h; + _fbo_w = w; + _fbo_h = h; } void @@ -972,12 +972,12 @@ GlRenderer::create_ExtractProgram_() { GLuint v = compileShader(GL_VERTEX_SHADER, kBlitVertSrc); GLuint f = compileShader(GL_FRAGMENT_SHADER, kExtractFragSrc); - m_extract_prog = glCreateProgram(); - glAttachShader(m_extract_prog, v); - glAttachShader(m_extract_prog, f); - glLinkProgram(m_extract_prog); + _extract_prog = glCreateProgram(); + glAttachShader(_extract_prog, v); + glAttachShader(_extract_prog, f); + glLinkProgram(_extract_prog); glDeleteShader(v); glDeleteShader(f); - m_uExtractTex = glGetUniformLocation(m_extract_prog, "u_SceneTex"); + _uExtractTex = glGetUniformLocation(_extract_prog, "u_SceneTex"); } void @@ -985,14 +985,14 @@ GlRenderer::create_BlurProgram_() { GLuint v = compileShader(GL_VERTEX_SHADER, kBlitVertSrc); GLuint f = compileShader(GL_FRAGMENT_SHADER, kBlurFragSrc); - m_blur_prog = glCreateProgram(); - glAttachShader(m_blur_prog, v); - glAttachShader(m_blur_prog, f); - glLinkProgram(m_blur_prog); + _blur_prog = glCreateProgram(); + glAttachShader(_blur_prog, v); + glAttachShader(_blur_prog, f); + glLinkProgram(_blur_prog); glDeleteShader(v); glDeleteShader(f); - m_uBlurTex = glGetUniformLocation(m_blur_prog, "u_BlurTex"); - m_uBlurDir = glGetUniformLocation(m_blur_prog, "u_BlurDir"); - m_uBlurTexelSize = glGetUniformLocation(m_blur_prog, "u_BlurTexelSize"); + _uBlurTex = glGetUniformLocation(_blur_prog, "u_BlurTex"); + _uBlurDir = glGetUniformLocation(_blur_prog, "u_BlurDir"); + _uBlurTexelSize = glGetUniformLocation(_blur_prog, "u_BlurTexelSize"); } void @@ -1002,7 +1002,7 @@ GlRenderer::create_BloomFBOs_(int scene_w, int scene_h) int h = scene_h / 4; if (w < 1) w = 1; if (h < 1) h = 1; - m_blur_w = w; m_blur_h = h; + _blur_w = w; _blur_h = h; auto make_fbo = [&](GLuint& fbo, GLuint& tex) { glGenFramebuffers(1, &fbo); @@ -1022,9 +1022,9 @@ GlRenderer::create_BloomFBOs_(int scene_w, int scene_h) SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Bloom FBO incomplete: 0x%x", s); }; - make_fbo(m_bright_fbo, m_bright_tex); - make_fbo(m_blur_fbo[0], m_blur_tex[0]); - make_fbo(m_blur_fbo[1], m_blur_tex[1]); + make_fbo(_bright_fbo, _bright_tex); + make_fbo(_blur_fbo[0], _blur_tex[0]); + make_fbo(_blur_fbo[1], _blur_tex[1]); glBindFramebuffer(GL_FRAMEBUFFER, 0); } @@ -1032,13 +1032,13 @@ GlRenderer::create_BloomFBOs_(int scene_w, int scene_h) void GlRenderer::destroy_BloomFBOs_() { - if (m_bright_tex) { glDeleteTextures(1, &m_bright_tex); m_bright_tex = 0; } - if (m_bright_fbo) { glDeleteFramebuffers(1, &m_bright_fbo); m_bright_fbo = 0; } + if (_bright_tex) { glDeleteTextures(1, &_bright_tex); _bright_tex = 0; } + if (_bright_fbo) { glDeleteFramebuffers(1, &_bright_fbo); _bright_fbo = 0; } for (int i = 0; i < 2; ++i) { - if (m_blur_tex[i]) { glDeleteTextures(1, &m_blur_tex[i]); m_blur_tex[i] = 0; } - if (m_blur_fbo[i]) { glDeleteFramebuffers(1, &m_blur_fbo[i]); m_blur_fbo[i] = 0; } + if (_blur_tex[i]) { glDeleteTextures(1, &_blur_tex[i]); _blur_tex[i] = 0; } + if (_blur_fbo[i]) { glDeleteFramebuffers(1, &_blur_fbo[i]); _blur_fbo[i] = 0; } } - m_blur_w = 0; m_blur_h = 0; + _blur_w = 0; _blur_h = 0; } void @@ -1046,7 +1046,7 @@ GlRenderer::resize_BloomFBOs_(int scene_w, int scene_h) { int want_w = scene_w / 4; if (want_w < 1) want_w = 1; int want_h = scene_h / 4; if (want_h < 1) want_h = 1; - if (want_w == m_blur_w && want_h == m_blur_h) return; + if (want_w == _blur_w && want_h == _blur_h) return; destroy_BloomFBOs_(); create_BloomFBOs_(scene_w, scene_h); } @@ -1054,55 +1054,55 @@ GlRenderer::resize_BloomFBOs_(int scene_w, int scene_h) void GlRenderer::run_BloomPipeline_() { - { FP_ZONE("bloom.resize"); resize_BloomFBOs_(m_fbo_w, m_fbo_h); } + { FP_ZONE("bloom.resize"); resize_BloomFBOs_(_fbo_w, _fbo_h); } glDisable(GL_DEPTH_TEST); - glBindVertexArray(m_fullscreen_vao); + glBindVertexArray(_fullscreen_vao); { FP_ZONE("bloom.extract"); - glBindFramebuffer(GL_FRAMEBUFFER, m_bright_fbo); - glViewport(0, 0, m_blur_w, m_blur_h); - glUseProgram(m_extract_prog); + glBindFramebuffer(GL_FRAMEBUFFER, _bright_fbo); + glViewport(0, 0, _blur_w, _blur_h); + glUseProgram(_extract_prog); glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, m_scene_color_tex); - glUniform1i(m_uExtractTex, 0); + glBindTexture(GL_TEXTURE_2D, _scene_color_tex); + glUniform1i(_uExtractTex, 0); glDrawArrays(GL_TRIANGLES, 0, 6); } // ── Blur ping-pong ────────────────────────────────────────────────── - // First iteration reads from m_bright_tex, then ping-pongs between - // m_blur_tex[0] and m_blur_tex[1]. 4 full iterations = 8 passes. + // First iteration reads from _bright_tex, then ping-pongs between + // _blur_tex[0] and _blur_tex[1]. 4 full iterations = 8 passes. { FP_ZONE("bloom.blur"); const int ITERATIONS = 2; - glUseProgram(m_blur_prog); - glUniform2f(m_uBlurTexelSize, 1.0f / static_cast<float>(m_blur_w), - 1.0f / static_cast<float>(m_blur_h)); + glUseProgram(_blur_prog); + glUniform2f(_uBlurTexelSize, 1.0f / static_cast<float>(_blur_w), + 1.0f / static_cast<float>(_blur_h)); - GLuint src_tex = m_bright_tex; + GLuint src_tex = _bright_tex; for (int i = 0; i < ITERATIONS; ++i) { // Horizontal pass: src → blur_tex[0] via blur_fbo[0] - glBindFramebuffer(GL_FRAMEBUFFER, m_blur_fbo[0]); + glBindFramebuffer(GL_FRAMEBUFFER, _blur_fbo[0]); glBindTexture(GL_TEXTURE_2D, src_tex); - glUniform1i(m_uBlurTex, 0); - glUniform2f(m_uBlurDir, 1.0f, 0.0f); + glUniform1i(_uBlurTex, 0); + glUniform2f(_uBlurDir, 1.0f, 0.0f); glDrawArrays(GL_TRIANGLES, 0, 6); // Vertical pass: blur_tex[0] → blur_tex[1] via blur_fbo[1] - glBindFramebuffer(GL_FRAMEBUFFER, m_blur_fbo[1]); - glBindTexture(GL_TEXTURE_2D, m_blur_tex[0]); - glUniform1i(m_uBlurTex, 0); - glUniform2f(m_uBlurDir, 0.0f, 1.0f); + glBindFramebuffer(GL_FRAMEBUFFER, _blur_fbo[1]); + glBindTexture(GL_TEXTURE_2D, _blur_tex[0]); + glUniform1i(_uBlurTex, 0); + glUniform2f(_uBlurDir, 0.0f, 1.0f); glDrawArrays(GL_TRIANGLES, 0, 6); // Next iteration's input is blur_tex[1]. We swap the names so the // final result always ends up in blur_tex[0] for compositing. - src_tex = m_blur_tex[1]; + src_tex = _blur_tex[1]; } } - // After loop: final bloom is in m_blur_tex[1]. We'll sample it directly. + // After loop: final bloom is in _blur_tex[1]. We'll sample it directly. glBindVertexArray(0); glEnable(GL_DEPTH_TEST); } @@ -1112,29 +1112,29 @@ GlRenderer::create_CompositeProgram_() { GLuint v = compileShader(GL_VERTEX_SHADER, kBlitVertSrc); GLuint f = compileShader(GL_FRAGMENT_SHADER, kCompositeFragSrc); - m_composite_prog = glCreateProgram(); - glAttachShader(m_composite_prog, v); - glAttachShader(m_composite_prog, f); - glLinkProgram(m_composite_prog); + _composite_prog = glCreateProgram(); + glAttachShader(_composite_prog, v); + glAttachShader(_composite_prog, f); + glLinkProgram(_composite_prog); glDeleteShader(v); glDeleteShader(f); - m_uComposeScene = glGetUniformLocation(m_composite_prog, "u_SceneTex"); - m_uComposeBloom = glGetUniformLocation(m_composite_prog, "u_BloomTex"); - m_uComposeStrength = glGetUniformLocation(m_composite_prog, "u_BloomStrength"); + _uComposeScene = glGetUniformLocation(_composite_prog, "u_SceneTex"); + _uComposeBloom = glGetUniformLocation(_composite_prog, "u_BloomTex"); + _uComposeStrength = glGetUniformLocation(_composite_prog, "u_BloomStrength"); } void GlRenderer::destroy_FBO_() { - if (m_scene_color_tex) { glDeleteTextures(1, &m_scene_color_tex); m_scene_color_tex = 0; } - if (m_scene_depth_rbo) { glDeleteRenderbuffers(1, &m_scene_depth_rbo); m_scene_depth_rbo = 0; } - if (m_scene_fbo) { glDeleteFramebuffers(1, &m_scene_fbo); m_scene_fbo = 0; } - m_fbo_w = 0; m_fbo_h = 0; + if (_scene_color_tex) { glDeleteTextures (1, &_scene_color_tex); _scene_color_tex = 0; } + if (_scene_depth_rbo) { glDeleteRenderbuffers(1, &_scene_depth_rbo); _scene_depth_rbo = 0; } + if (_scene_fbo) { glDeleteFramebuffers (1, &_scene_fbo); _scene_fbo = 0; } + _fbo_w = 0; _fbo_h = 0; } void GlRenderer::resize_FBO_(int w, int h) { - if (w == m_fbo_w && h == m_fbo_h) return; + if (w == _fbo_w && h == _fbo_h) return; destroy_FBO_(); create_FBO_(w, h); } diff --git a/src/rendering/gl_renderer.hpp b/src/rendering/gl_renderer.hpp index e43da87..3810468 100644 --- a/src/rendering/gl_renderer.hpp +++ b/src/rendering/gl_renderer.hpp @@ -34,95 +34,95 @@ Mat4 buildModelMat4(const Vec3& pos, float yaw, float pitch); class GlRenderer { - int m_view_w{1}, m_view_h{1}; - float m_aspect{1.0f}; - Mat4 m_proj; - SDL_GLContext m_ctx{}; - GLuint m_prog{}; - - GLint m_uMVP {-1}, - m_uNormalMat {-1}, - m_uColor {-1}; - - GLint m_uBodyColor {-1}, - m_uBackDim {-1}, - m_uUseFront {-1}; - - GLint m_uLightDir {-1}, - m_uAmbient {-1}, - m_uIntensity {-1}, - m_uSunColor {-1}; - - GLint m_uFlashPos {-1}, - m_uFlashDir {-1}, - m_uFlashColor {-1}, - m_uFlashRange {-1}, - m_uFlashInnerCos {-1}, - m_uFlashOuterCos {-1}, - m_uFlashIntensity {-1}; - - GLint m_uModel {-1}; - GLint m_uWireframe {-1}; - GLint m_uMandelbrot {-1}; - GLint m_uWallPaper {-1}; - GLint m_uTextLineSpacing{-1}; - - GLuint m_emissive_prog{}, - m_emissive_vao{}, - m_emissive_vbo{}, - m_emissive_ebo{}; - - GLint m_uEmissiveMVP {-1}; - - GLuint m_vao{}, m_vbo{}, m_ebo{}; - GLuint m_vao_c{}, m_vbo_c{}, m_ebo_c{}; // VAO/VBO/EBO for colored mesh - GLint m_uUseVertexColor{-1}; - - GLuint m_line_vao{}, m_line_vbo{}; - GLuint m_menu_vao{}, m_menu_vbo{}; + int _view_w{1}, _view_h{1}; + float _aspect{1.0f}; + Mat4 _proj; + SDL_GLContext _ctx{}; + GLuint _prog{}; + + GLint _uMVP {-1}, + _uNormalMat {-1}, + _uColor {-1}; + + GLint _uBodyColor {-1}, + _uBackDim {-1}, + _uUseFront {-1}; + + GLint _uLightDir {-1}, + _uAmbient {-1}, + _uIntensity {-1}, + _uSunColor {-1}; + + GLint _uFlashPos {-1}, + _uFlashDir {-1}, + _uFlashColor {-1}, + _uFlashRange {-1}, + _uFlashInnerCos {-1}, + _uFlashOuterCos {-1}, + _uFlashIntensity {-1}; + + GLint _uModel {-1}; + GLint _uWireframe {-1}; + GLint _uMandelbrot {-1}; + GLint _uWallPaper {-1}; + GLint _uTextLineSpacing{-1}; + + GLuint _emissive_prog{}, + _emissive_vao{}, + _emissive_vbo{}, + _emissive_ebo{}; + + GLint _uEmissiveMVP {-1}; + + GLuint _vao{}, _vbo{}, _ebo{}; + GLuint _vao_c{}, _vbo_c{}, _ebo_c{}; // VAO/VBO/EBO for colored mesh + GLint _uUseVertexColor{-1}; + + GLuint _line_vao{}, _line_vbo{}; + GLuint _menu_vao{}, _menu_vbo{}; // Scene FBO: where the main rendering pass writes. - GLuint m_scene_fbo {0}; - GLuint m_scene_color_tex {0}; - GLuint m_scene_depth_rbo {0}; - int m_fbo_w {0}; - int m_fbo_h {0}; + GLuint _scene_fbo {0}; + GLuint _scene_color_tex {0}; + GLuint _scene_depth_rbo {0}; + int _fbo_w {0}; + int _fbo_h {0}; // Fullscreen-quad geometry for compositing passes. - GLuint m_fullscreen_vao {0}; - GLuint m_fullscreen_vbo {0}; + GLuint _fullscreen_vao {0}; + GLuint _fullscreen_vbo {0}; // Blit program: samples scene texture, writes to screen unchanged. - GLuint m_blit_prog {0}; - GLint m_uBlitTex {-1}; + GLuint _blit_prog {0}; + GLint _uBlitTex {-1}; // Half-resolution FBOs for the blur ping-pong. - GLuint m_bright_fbo {0}; - GLuint m_bright_tex {0}; - GLuint m_blur_fbo[2] {0, 0}; - GLuint m_blur_tex[2] {0, 0}; - int m_blur_w {0}; - int m_blur_h {0}; + GLuint _bright_fbo {0}; + GLuint _bright_tex {0}; + GLuint _blur_fbo[2] {0, 0}; + GLuint _blur_tex[2] {0, 0}; + int _blur_w {0}; + int _blur_h {0}; // Programs - GLuint m_extract_prog {0}; - GLuint m_blur_prog {0}; - GLuint m_composite_prog {0}; + GLuint _extract_prog {0}; + GLuint _blur_prog {0}; + GLuint _composite_prog {0}; // Uniforms - GLint m_uExtractTex {-1}; - GLint m_uBlurTex {-1}; - GLint m_uBlurDir {-1}; // (1,0) or (0,1) - GLint m_uBlurTexelSize {-1}; // (1/w, 1/h) - GLint m_uComposeScene {-1}; - GLint m_uComposeBloom {-1}; - GLint m_uComposeStrength{-1}; // how much bloom to add (default 1.0) - float m_bloom_strength { 0.6f }; + GLint _uExtractTex {-1}; + GLint _uBlurTex {-1}; + GLint _uBlurDir {-1}; // (1,0) or (0,1) + GLint _uBlurTexelSize {-1}; // (1/w, 1/h) + GLint _uComposeScene {-1}; + GLint _uComposeBloom {-1}; + GLint _uComposeStrength{-1}; // how much bloom to add (default 1.0) + float _bloom_strength { 0.6f }; // Emissive uniforms on the main program - GLint m_uEmissiveColor {-1}; - GLint m_uEmissiveStrength {-1}; + GLint _uEmissiveColor {-1}; + GLint _uEmissiveStrength {-1}; void create_FBO_(int w, int h); void resize_FBO_(int w, int h); @@ -155,7 +155,7 @@ public: void set_ColorUseVertex (bool on); void set_TextLineSpacing(float m); void set_Emissive (float r, float g, float b, float strength); - void set_BloomStrength (float s) { m_bloom_strength = s; } + void set_BloomStrength (float s) { _bloom_strength = s; } void enable_MandelbrotMode(bool on); void enable_WallPaperMode (bool on); @@ -189,5 +189,5 @@ public: const int* indices, int index_count, float r, float g, float b, float strength); - GLuint program() const { return m_prog; } + GLuint program() const { return _prog; } }; diff --git a/src/states/game_state.cpp b/src/states/game_state.cpp index fae00be..82d9257 100644 --- a/src/states/game_state.cpp +++ b/src/states/game_state.cpp @@ -28,59 +28,59 @@ GameState::GameState(size_t starting_level) { - ctx.player = cpputils::make_unique<Player>(); - ctx.world = cpputils::make_unique<World>(); - ctx.camera = cpputils::make_unique<Camera>(); - ctx.light = cpputils::make_unique<Light>(); - - input_sys = cpputils::make_unique<InputSystem>(); - physics_sys = cpputils::make_unique<PhysicsSystem>(); - projectiles_sys = cpputils::make_unique<ProjectileSystem>(); - compiler_sys = cpputils::make_unique<CompilerSystem>(); - word_anim_sys = cpputils::make_unique<WordAnimSystem>(); - freelook_sys = cpputils::make_unique<FreelookSystem>(); - particle_sys = cpputils::make_unique<ParticleSystem>(); - mod_loader_sys = cpputils::make_unique<ModLoader>(); - celebration_sys = cpputils::make_unique<CelebrationSystem>(); - - floor_sys = cpputils::make_unique<FloorMandelbrot>(); - floor_sys->generate(ctx.world->scale(), -ctx.world->scale()); - - word_ai_sys = cpputils::make_unique<WordAiSystem>(); - word_ai_sys->set_WorldScale(ctx.world->scale()); - - pult_sys = cpputils::make_unique<PultSystem>(); - pult_sys->init(ctx.scenery, ctx.buttons, ctx.world->scale()); + _ctx.player = cpputils::make_unique<Player>(); + _ctx.world = cpputils::make_unique<World>(); + _ctx.camera = cpputils::make_unique<Camera>(); + _ctx.light = cpputils::make_unique<Light>(); + + _input_sys = cpputils::make_unique<InputSystem>(); + _physics_sys = cpputils::make_unique<PhysicsSystem>(); + _projectiles_sys = cpputils::make_unique<ProjectileSystem>(); + _compiler_sys = cpputils::make_unique<CompilerSystem>(); + _word_anim_sys = cpputils::make_unique<WordAnimSystem>(); + _freelook_sys = cpputils::make_unique<FreelookSystem>(); + _particle_sys = cpputils::make_unique<ParticleSystem>(); + _mod_loader_sys = cpputils::make_unique<ModLoader>(); + _celebration_sys = cpputils::make_unique<CelebrationSystem>(); + + _floor_sys = cpputils::make_unique<FloorMandelbrot>(); + _floor_sys->generate(_ctx.world->scale(), -_ctx.world->scale()); + + _word_ai_sys = cpputils::make_unique<WordAiSystem>(); + _word_ai_sys->set_WorldScale(_ctx.world->scale()); + + _pult_sys = cpputils::make_unique<PultSystem>(); + _pult_sys->init(_ctx.scenery, _ctx.buttons, _ctx.world->scale()); if (starting_level >= level_Count()) starting_level = 0; - level_runner_sys = cpputils::make_unique<LevelRunner>(get_Level(starting_level)); + _level_runner_sys = cpputils::make_unique<LevelRunner>(get_Level(starting_level)); - DynArray<std::string> tokens = level_runner_sys->grants_for_step(); + DynArray<std::string> tokens = _level_runner_sys->grants_for_step(); step_Spawn(tokens); - scene_Setup(level_runner_sys->current().scene); + scene_Setup(_level_runner_sys->current().scene); step_SettingsApply(); infowall_StepdetailsShow(); - hint_sys = cpputils::make_unique<HintSystem>(); - if (level_runner_sys && !level_runner_sys->complete()) - hint_sys->set_Hint(level_runner_sys->current().hint); + _hint_sys = cpputils::make_unique<HintSystem>(); + if (_level_runner_sys && !_level_runner_sys->complete()) + _hint_sys->set_Hint(_level_runner_sys->current().hint); - if (level_runner_sys && level_runner_sys->dynamic_lib()) + if (_level_runner_sys && _level_runner_sys->dynamic_lib()) sandbox_LoadFileToWall(); /* - ctx.scenery.push_back( + _ctx.scenery.push_back( cpputils::make_unique<SolidBox>( Vec3{0, -15, -5}, Vec3{1.0, 0.5, 1.0} )); - ctx.scenery.push_back( + _ctx.scenery.push_back( cpputils::make_unique<SolidBox>( Vec3{3, -15, -5}, Vec3{1.0, 0.5, 1.0} )); - ctx.scenery.back()->body.mode = PhysicsMode::Dynamic; + _ctx.scenery.back()->body.mode = PhysicsMode::Dynamic; */ debug_SpawnWords(0); } @@ -107,26 +107,26 @@ GameState::debug_SpawnWords([[maybe_unused]]size_t n) std::tuple<Vec3, Vec3, double> GameState::anchorframe_Current() const { - if (freelook_sys->state.active) - return { freelook_sys->state.frozen_anchor, - freelook_sys->state.frozen_right, - freelook_sys->state.frozen_glyph_yaw }; - - return { CarryMath::line_Anchor(*ctx.camera, CarryMath::CARRY_DIST), - ctx.camera->right, - SDL_atan2(-ctx.camera->fwd.x, -ctx.camera->fwd.z) }; + if (_freelook_sys->state.active) + return { _freelook_sys->state.frozen_anchor, + _freelook_sys->state.frozen_right, + _freelook_sys->state.frozen_glyph_yaw }; + + return { CarryMath::line_Anchor(*_ctx.camera, CarryMath::CARRY_DIST), + _ctx.camera->right, + SDL_atan2(-_ctx.camera->fwd.x, -_ctx.camera->fwd.z) }; } void GameState::carriedline_Update() { - if (carried.empty()) return; + if (_carried.empty()) return; auto [anchor, right, glyph_yaw] = anchorframe_Current(); - DynArray<Vec3> positions = CarryMath::slot_positions(carried, anchor, right, CarryMath::CARRY_GAP); - DynArray<CarriedWordNode*> nodes = carried.reverse_nodes(); + DynArray<Vec3> positions = CarryMath::slot_positions(_carried, anchor, right, CarryMath::CARRY_GAP); + DynArray<CarriedWordNode*> nodes = _carried.reverse_nodes(); for (size_t i = 0; i < nodes.size() && i < positions.size(); ++i) { if (nodes[i]->word) { @@ -140,22 +140,22 @@ GameState::carriedline_Update() void GameState::pult_DispatchAction(PultAction act) { - step_ledger.buttons_pressed.push_back(act); + _step_ledger.buttons_pressed.push_back(act); - const double floor_y = -static_cast<double>(ctx.world->scale()); + const double floor_y = -static_cast<double>(_ctx.world->scale()); switch (act) { case PultAction::ScrollEditorUp: - TextWallScroll::scroll_Up(ctx.wall_texts, Wall::Role::Editor); - editor_wall.scroll(TextWallScroll::SCROLL_STEP); + TextWallScroll::scroll_Up(_ctx.wall_texts, Wall::Role::Editor); + _editor_wall.scroll(TextWallScroll::SCROLL_STEP); break; case PultAction::ScrollEditorDown: - TextWallScroll::scroll_Down(ctx.wall_texts, Wall::Role::Editor); - editor_wall.scroll(-TextWallScroll::SCROLL_STEP); + TextWallScroll::scroll_Down(_ctx.wall_texts, Wall::Role::Editor); + _editor_wall.scroll(-TextWallScroll::SCROLL_STEP); break; case PultAction::ClearEditor: - TextWallScroll::clear_ToFloor(ctx.wall_texts, ctx.words, Wall::Role::Editor, floor_y); - editor_wall.clear(); + TextWallScroll::clear_ToFloor(_ctx.wall_texts, _ctx.words, Wall::Role::Editor, floor_y); + _editor_wall.clear(); break; case PultAction::Compile: on_Compile(); @@ -166,12 +166,12 @@ GameState::pult_DispatchAction(PultAction act) void GameState::on_Click() { - PickResult r = PickSystem::pick(*ctx.camera, ctx.words, ctx.scenery, ctx.wall_texts); + PickResult r = PickSystem::pick(*_ctx.camera, _ctx.words, _ctx.scenery, _ctx.wall_texts); if (!r.hit()) return; if (r.kind == PickKind::Scenery && r.scenery_obj) { if (std::optional<PultAction> act = - pult_sys->try_Activate(r.scenery_obj, ctx.buttons); act) + _pult_sys->try_Activate(r.scenery_obj, _ctx.buttons); act) pult_DispatchAction(*act); } } @@ -179,36 +179,36 @@ GameState::on_Click() bool GameState::on_Pick() { - PickResult r = PickSystem::pick(*ctx.camera, ctx.words, ctx.scenery, ctx.wall_texts); + PickResult r = PickSystem::pick(*_ctx.camera, _ctx.words, _ctx.scenery, _ctx.wall_texts); if (!r.hit()) return false; // ── Wall text: pluck off the wall, animate into carry ─────────── if (r.kind == PickKind::Wall) { - if (ctx.wall_texts[r.wall_index] && ctx.wall_texts[r.wall_index]->text3d) - editor_wall.on_WordRemoved(ctx.wall_texts[r.wall_index]->text3d.get()); + if (_ctx.wall_texts[r.wall_index] && _ctx.wall_texts[r.wall_index]->text3d) + _editor_wall.on_WordRemoved(_ctx.wall_texts[r.wall_index]->text3d.get()); - Text3dPtr base = std::move(ctx.wall_texts[r.wall_index]->text3d); - ctx.wall_texts.erase(ctx.wall_texts.begin() + static_cast<std::ptrdiff_t>(r.wall_index)); + Text3dPtr base = std::move(_ctx.wall_texts[r.wall_index]->text3d); + _ctx.wall_texts.erase(_ctx.wall_texts.begin() + static_cast<std::ptrdiff_t>(r.wall_index)); if (!base) return false; if (base->type == ObjectType::Text) { - step_ledger.picked_up.push_back(base->text); + _step_ledger.picked_up.push_back(base->text); base->set_Look(Text3d::color_keep, Text3d::depth_floor); - TextWall::show_TokenInfo(ctx.wall_texts, base->text, ctx.world->scale()); + TextWall::show_TokenInfo(_ctx.wall_texts, base->text, _ctx.world->scale()); } carry_BeginAnim(std::move(base), /*with_pitch=*/true); return true; } - // ── Word: same flow, takes Text3dPtr out of ctx.words ─────────── + // ── Word: same flow, takes Text3dPtr out of _ctx.words ─────────── if (r.kind == PickKind::Word) { - Text3dPtr word = std::move(ctx.words[r.word_index]); - ctx.words.erase(ctx.words.begin() + static_cast<std::ptrdiff_t>(r.word_index)); + Text3dPtr word = std::move(_ctx.words[r.word_index]); + _ctx.words.erase(_ctx.words.begin() + static_cast<std::ptrdiff_t>(r.word_index)); if (!word) return false; - step_ledger.picked_up.push_back(word->text); + _step_ledger.picked_up.push_back(word->text); word->set_Look(Text3d::color_keep, Text3d::depth_floor); - TextWall::show_TokenInfo(ctx.wall_texts, word->text, ctx.world->scale()); + TextWall::show_TokenInfo(_ctx.wall_texts, word->text, _ctx.world->scale()); carry_BeginAnim(std::move(word), /*with_pitch=*/false); return true; @@ -220,53 +220,53 @@ GameState::on_Pick() void GameState::on_DropLast() { - if (carried.empty()) return; + if (_carried.empty()) return; - Text3dPtr word = carried.pop_back(); + Text3dPtr word = _carried.pop_back(); if (!word) return; infowall_Clear(); word->body.mode = PhysicsMode::Dynamic; - word->body.vel = { ctx.camera->fwd.x * 1.5, 0.8, ctx.camera->fwd.z * 1.5 }; + word->body.vel = { _ctx.camera->fwd.x * 1.5, 0.8, _ctx.camera->fwd.z * 1.5 }; WordAnim_Drop drop; drop.word = std::move(word); - anims_drop.push_back(std::move(drop)); + _anims_drop.push_back(std::move(drop)); - if (!carried.empty()) - TextWall::show_TokenInfo(ctx.wall_texts, carried.last->word->text, ctx.world->scale()); + if (!_carried.empty()) + TextWall::show_TokenInfo(_ctx.wall_texts, _carried.last->word->text, _ctx.world->scale()); else infowall_StepdetailsShow(); - step_ledger.dropped = true; + _step_ledger.dropped = true; } bool GameState::on_ShootOne() { - if (carried.empty()) return false; + if (_carried.empty()) return false; - Text3dPtr word = carried.pop_back(); + Text3dPtr word = _carried.pop_back(); if (!word) return false; infowall_Clear(); - freelook_sys->state.active = false; - freelook_sys->state.lerping = false; + _freelook_sys->state.active = false; + _freelook_sys->state.lerping = false; DynArray<Text3dPtr> single; single.push_back(std::move(word)); - projectiles_sys->launch(projectiles, std::move(single), ctx.camera->fwd); + _projectiles_sys->launch(_projectiles, std::move(single), _ctx.camera->fwd); - if (!carried.empty() && carried.last && carried.last->word) - TextWall::show_TokenInfo(ctx.wall_texts, - carried.last->word->text, - ctx.world->scale()); + if (!_carried.empty() && _carried.last && _carried.last->word) + TextWall::show_TokenInfo(_ctx.wall_texts, + _carried.last->word->text, + _ctx.world->scale()); else infowall_StepdetailsShow(); - step_ledger.shot = true; + _step_ledger.shot = true; return true; } @@ -274,41 +274,41 @@ GameState::on_ShootOne() void GameState::on_ShootAll() { - if (carried.empty()) return; + if (_carried.empty()) return; infowall_Clear(); - freelook_sys->state.active = false; - freelook_sys->state.lerping = false; + _freelook_sys->state.active = false; + _freelook_sys->state.lerping = false; DynArray<Text3dPtr> all_words; - for (CarriedWordNode* node : carried.nodes()) + for (CarriedWordNode* node : _carried.nodes()) if (node->word) all_words.push_back(std::move(node->word)); - carried = CarriedLine(); + _carried = CarriedLine(); if (!all_words.empty()) - projectiles_sys->launch(projectiles, std::move(all_words), ctx.camera->fwd); + _projectiles_sys->launch(_projectiles, std::move(all_words), _ctx.camera->fwd); infowall_StepdetailsShow(); - step_ledger.shot = true; + _step_ledger.shot = true; } void GameState::on_Compile() { - std::string src = TextWall::extract_Text(ctx.wall_texts, Wall::Role::Editor); + std::string src = TextWall::extract_Text(_ctx.wall_texts, Wall::Role::Editor); - if (level_runner_sys && !level_runner_sys->complete() && level_runner_sys->dynamic_lib()) { + if (_level_runner_sys && !_level_runner_sys->complete() && _level_runner_sys->dynamic_lib()) { const std::string path = sandbox_CanonicalPath(); std::string stripped; for (char c : src) if (!std::isspace((unsigned char)c)) { stripped = src; break; } if (!path.empty() && !stripped.empty()) SourceTokens::write_File(path, src); - mod_loader_sys->build(ctx.wall_texts, src, ctx.world->scale(), true); + _mod_loader_sys->build(_ctx.wall_texts, src, _ctx.world->scale(), true); } else { - compiler_sys->compile(ctx.wall_texts, src); + _compiler_sys->compile(_ctx.wall_texts, src); } } @@ -316,8 +316,8 @@ void GameState::on_Compile() { void GameState::on_DebugPrint() { - std::print("TEXT::: {0}\n", TextWall::extract_Text(ctx.wall_texts, Wall::Role::Program)); - for (TextWallPtr& wt : ctx.wall_texts) { + std::print("TEXT::: {0}\n", TextWall::extract_Text(_ctx.wall_texts, Wall::Role::Program)); + for (TextWallPtr& wt : _ctx.wall_texts) { if (wt->text3d->type == ObjectType::Text) { SDL_Log("wall text '%s' y=%.3f", wt->text3d->text.c_str(), wt->text3d->pos.y); } @@ -328,9 +328,9 @@ GameState::on_DebugPrint() void GameState::on_Jump() { - if (ctx.player->on_ground) { - ctx.player->vel.y = Player::JUMP_VELOCITY; - ctx.player->on_ground = false; + if (_ctx.player->on_ground) { + _ctx.player->vel.y = Player::JUMP_VELOCITY; + _ctx.player->on_ground = false; } } @@ -338,26 +338,26 @@ GameState::on_Jump() void GameState::on_FreelookStart() { - Vec3 anchor = CarryMath::line_Anchor(*ctx.camera, CarryMath::CARRY_DIST); - double yaw = SDL_atan2(-ctx.camera->fwd.x, -ctx.camera->fwd.z); - freelook_sys->begin(anchor, ctx.camera->right, yaw); + Vec3 anchor = CarryMath::line_Anchor(*_ctx.camera, CarryMath::CARRY_DIST); + double yaw = SDL_atan2(-_ctx.camera->fwd.x, -_ctx.camera->fwd.z); + _freelook_sys->begin(anchor, _ctx.camera->right, yaw); } void GameState::on_FreelookEnd() { - if (freelook_sys->state.active) - freelook_sys->end(ctx.player->yaw, ctx.player->pitch, - ctx.camera->pos, - ctx.player->yaw, ctx.player->pitch); + if (_freelook_sys->state.active) + _freelook_sys->end(_ctx.player->yaw, _ctx.player->pitch, + _ctx.camera->pos, + _ctx.player->yaw, _ctx.player->pitch); } void GameState::on_NumberAdjust(int delta) { - if (carried.empty() || !carried.last || !carried.last->word) return; - Text3d* w = carried.last->word.get(); + if (_carried.empty() || !_carried.last || !_carried.last->word) return; + Text3d* w = _carried.last->word.get(); // Parse the text as an integer; bail if it isn't one. const std::string& s = w->text; @@ -380,14 +380,14 @@ GameState::on_TextStart(FrameInput& input) { input.text_mode = true; input.text_buffer.clear(); - typing_words.clear(); - typing_last.clear(); + _typing_words.clear(); + _typing_last.clear(); } void GameState::on_TextCommit(FrameInput& input) { - typing_words.clear(); - typing_last.clear(); + _typing_words.clear(); + _typing_last.clear(); input.text_mode = false; input.text_buffer.clear(); } @@ -395,7 +395,7 @@ void GameState::on_TextCancel(FrameInput& input) { typing_ClearPreview(); - typing_last.clear(); + _typing_last.clear(); input.text_mode = false; input.text_buffer.clear(); } @@ -408,7 +408,7 @@ GameState::step_Spawn(const DynArray<std::string>& tokens) static constexpr int per_row = 8; static constexpr float row_gap = 3.0f; - const double floor_y = -static_cast<double>(ctx.world->scale()); + const double floor_y = -static_cast<double>(_ctx.world->scale()); const double hover_y = floor_y + 1.5; for (size_t i = 0; i < tokens.size(); ++i) { @@ -424,7 +424,7 @@ GameState::step_Spawn(const DynArray<std::string>& tokens) Text3dPtr obj = make_Text3d(tokens[i], Text3d::depth_floor, 0.003f, pos); obj->body.hover_height = hover_y; - ctx.words.push_back(std::move(obj)); + _ctx.words.push_back(std::move(obj)); } } @@ -437,7 +437,7 @@ GameState::projectile_LandOnFloor(ProjectileResult& result) w->set_Look(Text3d::color_keep, Text3d::depth_floor); w->body.mode = PhysicsMode::Dynamic; w->body.vel = result.vel; - ctx.words.push_back(std::move(w)); + _ctx.words.push_back(std::move(w)); } } @@ -453,16 +453,16 @@ GameState::projectile_LandOnWall(ProjectileResult& result) w->body.mode = PhysicsMode::Static; w->body.vel = Vec3{0, 0, 0}; - TextWallPtr wt = TextWall::from_Drop(std::move(w), ctx.world->scale()); + TextWallPtr wt = TextWall::from_Drop(std::move(w), _ctx.world->scale()); // Editor-wall snap: rewrite position to align with row. if (wt && wt->text3d && wt->role == Wall::Role::Editor) { const Vec3 impact = wt->text3d->pos; - const Vec3 snapped = editor_wall.on_WordPlaced(wt->text3d.get(), impact); + const Vec3 snapped = _editor_wall.on_WordPlaced(wt->text3d.get(), impact); wt->text3d->pos = snapped; } - ctx.wall_texts.push_back(std::move(wt)); + _ctx.wall_texts.push_back(std::move(wt)); } } @@ -471,18 +471,18 @@ void GameState::walltext_HandleShootDown(ProjectileResult& result, DynArray<size_t>& to_erase) { - if (result.wall_text_index < ctx.wall_texts.size()) { - TextWallPtr& wt = ctx.wall_texts[result.wall_text_index]; + if (result.wall_text_index < _ctx.wall_texts.size()) { + TextWallPtr& wt = _ctx.wall_texts[result.wall_text_index]; if (wt && wt->text3d) { - editor_wall.on_WordRemoved(wt->text3d.get()); + _editor_wall.on_WordRemoved(wt->text3d.get()); Text3dPtr orphan = std::move(wt->text3d); orphan->body.mode = PhysicsMode::Dynamic; orphan->body.vel = { 0.0, 1.5, 0.0 }; - orphan->body.hover_height = -static_cast<double>(ctx.world->scale()) + 1.5; + orphan->body.hover_height = -static_cast<double>(_ctx.world->scale()) + 1.5; orphan->yaw = 0.0f; orphan->set_Look(Text3d::color_keep, Text3d::depth_floor); - ctx.words.push_back(std::move(orphan)); + _ctx.words.push_back(std::move(orphan)); to_erase.push_back(result.wall_text_index); } } @@ -494,7 +494,7 @@ GameState::walltext_HandleShootDown(ProjectileResult& result, } w->body.mode = PhysicsMode::Dynamic; w->body.vel = result.vel; - ctx.words.push_back(std::move(w)); + _ctx.words.push_back(std::move(w)); } } @@ -502,16 +502,16 @@ GameState::walltext_HandleShootDown(ProjectileResult& result, void GameState::handle_Event(Game& game, const SDL_Event& event) { - input_sys->handle_Event(game, event, frame_input); + _input_sys->handle_Event(game, event, _frame_input); } void GameState::update(double dt) { - FrameInput& input = frame_input; + FrameInput& input = _frame_input; - step_age += dt; + _step_age += dt; { FP_ZONE("update.input_dispatch"); for (InputCommand cmd : input.commands) { @@ -535,87 +535,87 @@ GameState::update(double dt) if (input.text_mode) { input.forward = input.backward = input.left = input.right = false; - if (input.text_buffer != typing_last) { + if (input.text_buffer != _typing_last) { typing_RebuildPreview(input.text_buffer); - typing_last = input.text_buffer; + _typing_last = input.text_buffer; } } - if (pick_cooldown > 0.0) pick_cooldown -= dt; - if (input.pick && pick_cooldown <= 0.0) - { if (on_Pick()) pick_cooldown = 0.15; } + if (_pick_cooldown > 0.0) _pick_cooldown -= dt; + if (input.pick && _pick_cooldown <= 0.0) + { if (on_Pick()) _pick_cooldown = 0.15; } - if (shoot_cooldown > 0.0) shoot_cooldown -= dt; - if (input.shoot && shoot_cooldown <= 0.0) - { if (on_ShootOne()) shoot_cooldown = 0.15; } + if (_shoot_cooldown > 0.0) _shoot_cooldown -= dt; + if (input.shoot && _shoot_cooldown <= 0.0) + { if (on_ShootOne()) _shoot_cooldown = 0.15; } } - const bool freelook_active = freelook_sys->state.active || - freelook_sys->state.lerping; + const bool freelook_active = _freelook_sys->state.active || + _freelook_sys->state.lerping; if (!freelook_active) - ctx.player->add_Look(input.look_x, input.look_y); + _ctx.player->add_Look(input.look_x, input.look_y); - freelook_sys->update(dt, ctx.player->yaw, ctx.player->pitch); + _freelook_sys->update(dt, _ctx.player->yaw, _ctx.player->pitch); - accumulator += dt; - ctx.player->compute_Movement(input); + _accumulator += dt; + _ctx.player->compute_Movement(input); // why do i still have that MAX_SUBSTEPS and not whatever frames we get int steps = 0; - while (accumulator >= dt && steps < MAX_SUBSTEPS) { + while (_accumulator >= dt && steps < MAX_SUBSTEPS) { FP_ZONE("update.fixed_substep"); substep(dt); - accumulator -= dt; + _accumulator -= dt; ++steps; } - accumulator = SDL_min(accumulator, dt * MAX_SUBSTEPS); - alpha = accumulator / dt; + _accumulator = SDL_min(_accumulator, dt * MAX_SUBSTEPS); + _alpha = _accumulator / dt; { FP_ZONE("update.post_step"); - ctx.camera->syncFromPlayer(*ctx.player, alpha); + _ctx.camera->syncFromPlayer(*_ctx.player, _alpha); - for (TextWallPtr& wt : ctx.wall_texts) { + for (TextWallPtr& wt : _ctx.wall_texts) { if (!wt || !wt->text3d) continue; - wt->text3d->pitch = Wall::tilt_TowardEye(wt->text3d->pos, ctx.camera->pos); + wt->text3d->pitch = Wall::tilt_TowardEye(wt->text3d->pos, _ctx.camera->pos); } carriedline_Update(); - const double floor_y = -static_cast<double>(ctx.world->scale()); - word_anim_sys->update(anims_add, anims_drop, carried, ctx.words, dt, floor_y); + const double floor_y = -static_cast<double>(_ctx.world->scale()); + _word_anim_sys->update(_anims_add, _anims_drop, _carried, _ctx.words, dt, floor_y); - pult_sys->update(dt, *ctx.camera); + _pult_sys->update(dt, *_ctx.camera); - plate_sys->update(dt, *ctx.player, step_plates); + _plate_sys->update(dt, *_ctx.player, _step_plates); } { FP_ZONE("update.particles"); DynArray<GameObject*> particle_colliders; - particle_colliders.reserve(ctx.scenery.size()); - for (const GameObjectPtr& s : ctx.scenery) + particle_colliders.reserve(_ctx.scenery.size()); + for (const GameObjectPtr& s : _ctx.scenery) if (s) particle_colliders.push_back(s.get()); - particle_sys->update(dt, particle_colliders, ctx.world->scale()); + _particle_sys->update(dt, particle_colliders, _ctx.world->scale()); } - { FP_ZONE("update.compiler_sys"); - compiler_sys->update(ctx.wall_texts, ctx.world->scale()); - if (compiler_sys->last_compile_ok) { - compiler_sys->last_compile_ok = false; - step_ledger.compile_ok = true; + { FP_ZONE("update._compiler_sys"); + _compiler_sys->update(_ctx.wall_texts, _ctx.world->scale()); + if (_compiler_sys->last_compile_ok) { + _compiler_sys->last_compile_ok = false; + _step_ledger.compile_ok = true; } - mod_loader_sys->update(ctx.wall_texts, ctx.world->scale()); - if (mod_loader_sys->last_build_ok) { - mod_loader_sys->last_build_ok = false; - mod_Apply(mod_loader_sys->load_Objects()); + _mod_loader_sys->update(_ctx.wall_texts, _ctx.world->scale()); + if (_mod_loader_sys->last_build_ok) { + _mod_loader_sys->last_build_ok = false; + mod_Apply(_mod_loader_sys->load_Objects()); SourceTokens::copy_File(sandbox_CanonicalPath(), sandbox_BackupPath()); } } { FP_ZONE("update.goals"); - celebration_sys->tick(dt, *particle_sys); + _celebration_sys->tick(dt, *_particle_sys); level_TryAdvance(); } @@ -632,70 +632,70 @@ GameState::render(SDL_Window& window, GlRenderer& renderer) SDL_GetWindowSizeInPixels(&window, &w, &h); { FP_ZONE("render.light_setup"); - const double yaw_r = BINRAD * static_cast<double>(ctx.camera->yaw); - const double pitch_r = BINRAD * static_cast<double>(ctx.camera->pitch); + const double yaw_r = BINRAD * static_cast<double>(_ctx.camera->yaw); + const double pitch_r = BINRAD * static_cast<double>(_ctx.camera->pitch); const double cy = SDL_cos(yaw_r), sy = SDL_sin(yaw_r); const double cp = SDL_cos(pitch_r), sp = SDL_sin(pitch_r); - ctx.light->flashlight_pos = ctx.camera->pos; - ctx.light->flashlight_dir = Vec3{ -sy*cp, sp, -cy*cp }; + _ctx.light->flashlight_pos = _ctx.camera->pos; + _ctx.light->flashlight_dir = Vec3{ -sy*cp, sp, -cy*cp }; } { FP_ZONE("render.begin_Frame"); renderer.begin_Frame(w, h); } - { FP_ZONE("render.set_Light"); renderer.set_Light(*ctx.light); } + { FP_ZONE("render.set_Light"); renderer.set_Light(*_ctx.light); } - { FP_ZONE("render.world"); ctx.world ->draw(renderer, *ctx.camera, *ctx.light); } - { FP_ZONE("render.editor_wall"); editor_wall.draw(renderer, *ctx.camera, *ctx.light); } + { FP_ZONE("render.world"); _ctx.world ->draw(renderer, *_ctx.camera, *_ctx.light); } + { FP_ZONE("render._editor_wall"); _editor_wall.draw(renderer, *_ctx.camera, *_ctx.light); } { FP_ZONE("render.scenery"); - for (const GameObjectPtr& s : ctx.scenery) - if (s) s->draw(renderer, *ctx.camera, *ctx.light); + for (const GameObjectPtr& s : _ctx.scenery) + if (s) s->draw(renderer, *_ctx.camera, *_ctx.light); } { FP_ZONE("render.words"); - for (const Text3dPtr& t : ctx.words) - if (t) t->draw(renderer, *ctx.camera, *ctx.light); + for (const Text3dPtr& t : _ctx.words) + if (t) t->draw(renderer, *_ctx.camera, *_ctx.light); } { FP_ZONE("render.wall_texts"); - for (const TextWallPtr& wt : ctx.wall_texts) - wt->draw(renderer, *ctx.camera, *ctx.light); + for (const TextWallPtr& wt : _ctx.wall_texts) + wt->draw(renderer, *_ctx.camera, *_ctx.light); } - { FP_ZONE("render.carried"); - DynArray<CarriedWordNode*> nodes = carried.nodes(); + { FP_ZONE("render._carried"); + DynArray<CarriedWordNode*> nodes = _carried.nodes(); for (const CarriedWordNode* node : nodes) if (node && node->word) - node->word->draw(renderer, *ctx.camera, *ctx.light); + node->word->draw(renderer, *_ctx.camera, *_ctx.light); } { FP_ZONE("render.anims"); - for (const WordAnim_Add& a : anims_add) - if (a.word) a.word->draw(renderer, *ctx.camera, *ctx.light); - for (const WordAnim_Drop& d : anims_drop) - if (d.word) d.word->draw(renderer, *ctx.camera, *ctx.light); + for (const WordAnim_Add& a : _anims_add) + if (a.word) a.word->draw(renderer, *_ctx.camera, *_ctx.light); + for (const WordAnim_Drop& d : _anims_drop) + if (d.word) d.word->draw(renderer, *_ctx.camera, *_ctx.light); } { FP_ZONE("render.ai_stolen"); - for (const Text3dPtr& t : ctx.words) { + for (const Text3dPtr& t : _ctx.words) { if (!t) continue; for (const Text3dPtr& s : t->ai_stolen) - if (s) s->draw(renderer, *ctx.camera, *ctx.light); + if (s) s->draw(renderer, *_ctx.camera, *_ctx.light); } } - { FP_ZONE("render.projectiles"); - for (const Projectile& proj : projectiles) + { FP_ZONE("render._projectiles"); + for (const Projectile& proj : _projectiles) for (const Text3dPtr& wd : proj.words) - if (wd) wd->draw(renderer, *ctx.camera, *ctx.light); + if (wd) wd->draw(renderer, *_ctx.camera, *_ctx.light); } - { FP_ZONE("render.hint"); hint_sys ->draw(renderer, *ctx.camera, *ctx.light); } - { FP_ZONE("render.pult_labels"); pult_sys ->draw_Labels(renderer, *ctx.camera, *ctx.light); } - { FP_ZONE("render.particles"); particle_sys->draw(renderer, *ctx.camera, *ctx.light); } - { FP_ZONE("render.floor_sys"); floor_sys ->draw(renderer, *ctx.camera, *ctx.light); } + { FP_ZONE("render.hint"); _hint_sys ->draw(renderer, *_ctx.camera, *_ctx.light); } + { FP_ZONE("render.pult_labels"); _pult_sys ->draw_Labels(renderer, *_ctx.camera, *_ctx.light); } + { FP_ZONE("render.particles"); _particle_sys->draw(renderer, *_ctx.camera, *_ctx.light); } + { FP_ZONE("render._floor_sys"); _floor_sys ->draw(renderer, *_ctx.camera, *_ctx.light); } { FP_ZONE("render.celebration"); - celebration_sys->draw(renderer, *ctx.camera, *ctx.light); + _celebration_sys->draw(renderer, *_ctx.camera, *_ctx.light); } { FP_ZONE("render.end_Frame"); renderer.end_Frame(&window); } @@ -705,25 +705,25 @@ GameState::render(SDL_Window& window, GlRenderer& renderer) void GameState::infowall_Clear() { - ctx.wall_texts.erase( - std::remove_if(ctx.wall_texts.begin(), ctx.wall_texts.end(), + _ctx.wall_texts.erase( + std::remove_if(_ctx.wall_texts.begin(), _ctx.wall_texts.end(), [](const TextWallPtr& wt) { return wt->role == Wall::Role::Info; }), - ctx.wall_texts.end()); + _ctx.wall_texts.end()); } void GameState::step_SettingsApply() { - if (!level_runner_sys || level_runner_sys->complete()) { - word_ai_sys->set_MaxActiveAi(0); + if (!_level_runner_sys || _level_runner_sys->complete()) { + _word_ai_sys->set_MaxActiveAi(0); return; } - const LevelStep& step = level_runner_sys->current(); - word_ai_sys->set_MaxActiveAi(step.max_ai_words); + const LevelStep& step = _level_runner_sys->current(); + _word_ai_sys->set_MaxActiveAi(step.max_ai_words); } void @@ -731,12 +731,12 @@ GameState::infowall_StepdetailsShow() { infowall_Clear(); - if (!level_runner_sys || level_runner_sys->complete()) return; + if (!_level_runner_sys || _level_runner_sys->complete()) return; - const std::string& details = level_runner_sys->current().details; + const std::string& details = _level_runner_sys->current().details; if (details.empty()) return; - const float world_scale = ctx.world->scale(); + const float world_scale = _ctx.world->scale(); Wall::Transform wall_transform = Wall::get_Transform(Wall::Role::Info, world_scale); constexpr size_t MAX_INFO_LINE_CHARS = 92; @@ -755,7 +755,7 @@ GameState::infowall_StepdetailsShow() pos, Text3d::color_white); t->yaw = wall_transform.yaw; - ctx.wall_texts.push_back(cpputils::make_unique<TextWall>( + _ctx.wall_texts.push_back(cpputils::make_unique<TextWall>( TextWall{ wall_transform.wall_position, Wall::Role::Info, std::move(t) })); } } @@ -768,23 +768,23 @@ GameState::scene_Setup(const Scene& scene) Text3dPtr t = make_Text3d(pw.text, Text3d::depth_floor, 0.003f, pw.pos, pw.color); t->body.hover_height = pw.pos.y; - ctx.words.push_back(std::move(t)); + _ctx.words.push_back(std::move(t)); } for (const PlacedPlate& pp : scene.plates) { auto plate = cpputils::make_unique<Plate>(pp.pos); Plate* raw = plate.get(); - step_plates .push_back({ raw, pp.tag }); - step_scenery.push_back(raw); - ctx.scenery .push_back(std::move(plate)); + _step_plates .push_back({ raw, pp.tag }); + _step_scenery.push_back(raw); + _ctx.scenery .push_back(std::move(plate)); } for (const PlacedPlatform& pl : scene.platforms) { auto box = cpputils::make_unique<SolidBox>(pl.pos, pl.half_extents, pl.fill_color, pl.wire_color); GameObject* raw = box.get(); - step_scenery.push_back(raw); - ctx.scenery .push_back(std::move(box)); + _step_scenery.push_back(raw); + _ctx.scenery .push_back(std::move(box)); } for (const PlacedAi& a : scene.ai_seeds) { @@ -811,7 +811,7 @@ GameState::scene_Setup(const Scene& scene) break; } - ctx.words.push_back(std::move(t)); + _ctx.words.push_back(std::move(t)); } } @@ -819,78 +819,78 @@ GameState::scene_Setup(const Scene& scene) void GameState::scene_Teardown() { - if (!step_scenery.empty()) { - std::unordered_set<GameObject*> scenery_set(step_scenery.begin(), step_scenery.end()); - ctx.scenery.erase( - std::remove_if(ctx.scenery.begin(), ctx.scenery.end(), + if (!_step_scenery.empty()) { + std::unordered_set<GameObject*> scenery_set(_step_scenery.begin(), _step_scenery.end()); + _ctx.scenery.erase( + std::remove_if(_ctx.scenery.begin(), _ctx.scenery.end(), [&scenery_set](const GameObjectPtr& sp) { return scenery_set.count(sp.get()) > 0; }), - ctx.scenery.end()); + _ctx.scenery.end()); } mod_Clear(); - step_scenery.clear(); - step_plates.clear(); + _step_scenery.clear(); + _step_plates.clear(); } void GameState::substep(double dt) { - ctx.player->prev_pos = ctx.player->pos; + _ctx.player->prev_pos = _ctx.player->pos; { FP_ZONE("subst.phys_player"); - physics_sys->update_Player(*ctx.player, - ctx.player->get_AccX(), - ctx.player->get_AccZ(), + _physics_sys->update_Player(*_ctx.player, + _ctx.player->get_AccX(), + _ctx.player->get_AccZ(), dt); } DynArray<GameObject*> colliders; { FP_ZONE("subst.build_colliders"); - colliders.reserve(ctx.scenery.size() + ctx.words.size()); - for (const GameObjectPtr& p : ctx.scenery) if (p) colliders.push_back(p.get()); - for (const Text3dPtr& p : ctx.words) if (p) colliders.push_back(p.get()); + colliders.reserve(_ctx.scenery.size() + _ctx.words.size()); + for (const GameObjectPtr& p : _ctx.scenery) if (p) colliders.push_back(p.get()); + for (const Text3dPtr& p : _ctx.words) if (p) colliders.push_back(p.get()); } { FP_ZONE("subst.phys_objects"); - physics_sys->update_Objects(colliders, dt, 25.0, ctx.world->scale()); + _physics_sys->update_Objects(colliders, dt, 25.0, _ctx.world->scale()); } { FP_ZONE("subst.word_ai"); DynArray<Text3dPtr> ai_dropped; - word_ai_sys->update(ctx.words, *ctx.player, carried, ai_dropped, dt); + _word_ai_sys->update(_ctx.words, *_ctx.player, _carried, ai_dropped, dt); for (Text3dPtr& d : ai_dropped) { - if (d) ctx.words.push_back(std::move(d)); + if (d) _ctx.words.push_back(std::move(d)); } } { FP_ZONE("subst.phys_projectiles"); - physics_sys->update_Projectiles(projectiles, dt); + _physics_sys->update_Projectiles(_projectiles, dt); } DynArray<ProjectileContactEvent> projectile_contacts; - DynArray<TextLabel*> all_labels = pult_sys->labels(); + DynArray<TextLabel*> all_labels = _pult_sys->labels(); { FP_ZONE("subst.hint_and_labels"); - hint_sys->update(dt, *ctx.camera); + _hint_sys->update(dt, *_ctx.camera); for (TextLabel* lbl : all_labels) - lbl->update(dt, *ctx.camera); + lbl->update(dt, *_ctx.camera); - all_labels.push_back(&hint_sys->get_Label()); + all_labels.push_back(&_hint_sys->get_Label()); } { FP_ZONE("subst.resolve_projectiles"); - physics_sys->resolve_Projectiles(projectiles, &colliders, &all_labels, &projectile_contacts); + _physics_sys->resolve_Projectiles(_projectiles, &colliders, &all_labels, &projectile_contacts); } DynArray<WallTextHitTest> wall_text_hits; { FP_ZONE("subst.build_wall_hits"); - wall_text_hits.reserve(ctx.wall_texts.size()); - for (size_t i = 0; i < ctx.wall_texts.size(); ++i) { - const TextWallPtr& wt = ctx.wall_texts[i]; + wall_text_hits.reserve(_ctx.wall_texts.size()); + for (size_t i = 0; i < _ctx.wall_texts.size(); ++i) { + const TextWallPtr& wt = _ctx.wall_texts[i]; if (!wt || !wt->text3d) continue; wall_text_hits.push_back({ wt->wall_position, @@ -903,8 +903,8 @@ GameState::substep(double dt) DynArray<ProjectileResult> proj_results; { FP_ZONE("subst.projectile_sys"); - projectiles_sys->update(projectiles, proj_results, - wall_text_hits, dt, ctx.world->scale()); + _projectiles_sys->update(_projectiles, proj_results, + wall_text_hits, dt, _ctx.world->scale()); } DynArray<size_t> wall_text_to_erase; @@ -922,20 +922,20 @@ GameState::substep(double dt) std::sort(wall_text_to_erase.begin(), wall_text_to_erase.end(), std::greater<size_t>{}); for (size_t idx : wall_text_to_erase) { - if (idx < ctx.wall_texts.size()) - ctx.wall_texts.erase(ctx.wall_texts.begin() + static_cast<std::ptrdiff_t>(idx)); + if (idx < _ctx.wall_texts.size()) + _ctx.wall_texts.erase(_ctx.wall_texts.begin() + static_cast<std::ptrdiff_t>(idx)); } for (const ProjectileContactEvent& ev : projectile_contacts) { if (std::optional<PultAction> act = - pult_sys->handle_ProjectileContact(ev, ctx.buttons); act) { + _pult_sys->handle_ProjectileContact(ev, _ctx.buttons); act) { pult_DispatchAction(*act); continue; } if (ev.other && ev.other->type == ObjectType::Text) { Text3d* word = static_cast<Text3d*>(ev.other); - step_ledger.ai_defeated.push_back(word->text); + _step_ledger.ai_defeated.push_back(word->text); word->ai_state = Text3d::Ai::Stunned; word->ai_state_timer = 0.0; @@ -946,10 +946,10 @@ GameState::substep(double dt) } { FP_ZONE("subst.player_collision"); - PlayerCollision col = ctx.world->resolvePlayer(*ctx.player); - ctx.player->apply_Collision(col); + PlayerCollision col = _ctx.world->resolvePlayer(*_ctx.player); + _ctx.player->apply_Collision(col); - physics_sys->resolve_PlayerVsObjects(*ctx.player, carried, colliders); + _physics_sys->resolve_PlayerVsObjects(*_ctx.player, _carried, colliders); } } @@ -959,19 +959,19 @@ GameState::goal_ContextBuild() const { GoalContext gctx; - for (const StepPlate& sp : step_plates) + for (const StepPlate& sp : _step_plates) if (sp.plate && sp.plate->active) gctx.active_plate_tags.push_back(sp.tag); - gctx.buttons_pressed_this_step = step_ledger.buttons_pressed; - gctx.dropped_this_step = step_ledger.dropped; - gctx.shot_this_step = step_ledger.shot; - gctx.compile_ok_this_step = step_ledger.compile_ok; - gctx.ai_words_defeated_this_step = step_ledger.ai_defeated; - gctx.picked_up_this_step = step_ledger.picked_up; + gctx.buttons_pressed_this_step = _step_ledger.buttons_pressed; + gctx.dropped_this_step = _step_ledger.dropped; + gctx.shot_this_step = _step_ledger.shot; + gctx.compile_ok_this_step = _step_ledger.compile_ok; + gctx.ai_words_defeated_this_step = _step_ledger.ai_defeated; + gctx.picked_up_this_step = _step_ledger.picked_up; if (gctx.compile_ok_this_step) { - std::string src = TextWall::extract_Text(ctx.wall_texts, + std::string src = TextWall::extract_Text(_ctx.wall_texts, Wall::Role::Editor); gctx.editor_normalized = LevelCheck::normalize(src); } @@ -983,9 +983,9 @@ GameState::goal_ContextBuild() const bool GameState::level_TryAdvance() { - if (celebration_sys->active()) { - if (celebration_sys->progress() >= 1.0) { - celebration_sys->finish(*particle_sys); + if (_celebration_sys->active()) { + if (_celebration_sys->progress() >= 1.0) { + _celebration_sys->finish(*_particle_sys); level_Advance(); return true; } @@ -993,15 +993,15 @@ GameState::level_TryAdvance() } GoalContext gctx = goal_ContextBuild(); - if (!goal_Satisfied(level_runner_sys->current().goal, gctx)) + if (!goal_Satisfied(_level_runner_sys->current().goal, gctx)) return false; - if (step_age < SETTLE_TIME_FOR_STEP) + if (_step_age < SETTLE_TIME_FOR_STEP) return false; - if (!level_runner_sys || level_runner_sys->complete()) + if (!_level_runner_sys || _level_runner_sys->complete()) return false; auto [anchor, right, glyph_yaw] = anchorframe_Current(); - celebration_sys->start(*ctx.camera, glyph_yaw); + _celebration_sys->start(*_ctx.camera, glyph_yaw); return false; } @@ -1010,46 +1010,46 @@ void GameState::level_Advance() { scene_Teardown(); - step_ledger.clear(); - - if (level_runner_sys->advance()) { - if (level_runner_sys->current().reset_carry) { - ctx.words .clear(); - projectiles.clear(); - anims_add .clear(); - anims_drop .clear(); - carried = CarriedLine(); + _step_ledger.clear(); + + if (_level_runner_sys->advance()) { + if (_level_runner_sys->current().reset_carry) { + _ctx.words .clear(); + _projectiles.clear(); + _anims_add .clear(); + _anims_drop .clear(); + _carried = CarriedLine(); } - DynArray<std::string> tokens = level_runner_sys->grants_for_step(); + DynArray<std::string> tokens = _level_runner_sys->grants_for_step(); step_Spawn(tokens); - scene_Setup(level_runner_sys->current().scene); + scene_Setup(_level_runner_sys->current().scene); step_SettingsApply(); infowall_StepdetailsShow(); - hint_sys->set_Hint(level_runner_sys->current().hint); + _hint_sys->set_Hint(_level_runner_sys->current().hint); } else { - hint_sys->clear(); + _hint_sys->clear(); infowall_StepdetailsShow(); } - step_age = 0.0; + _step_age = 0.0; } void GameState::mod_Clear() { - if (mod_scenery.empty()) { return; } + if (_mod_scenery.empty()) { return; } - std::unordered_set<GameObject*> set(mod_scenery.begin(), mod_scenery.end()); - ctx.scenery.erase( - std::remove_if(ctx.scenery.begin(), ctx.scenery.end(), + std::unordered_set<GameObject*> set(_mod_scenery.begin(), _mod_scenery.end()); + _ctx.scenery.erase( + std::remove_if(_ctx.scenery.begin(), _ctx.scenery.end(), [&set](const GameObjectPtr& sp) { return set.count(sp.get()) > 0; }), - ctx.scenery.end()); - ctx.words.erase( - std::remove_if(ctx.words.begin(), ctx.words.end(), + _ctx.scenery.end()); + _ctx.words.erase( + std::remove_if(_ctx.words.begin(), _ctx.words.end(), [&set](const Text3dPtr& wp) { return set.count(wp.get()) > 0; }), - ctx.words.end()); - mod_scenery.clear(); + _ctx.words.end()); + _mod_scenery.clear(); } @@ -1066,21 +1066,21 @@ GameState::mod_Apply(const DynArray<ModObject>& objs) Vec3{ o.hx, o.hy, o.hz }, SDL_FColor{ o.r, o.g, o.b, 1.0f }); box->body.mode = o.dynamic ? PhysicsMode::Dynamic : PhysicsMode::Static; - mod_scenery.push_back(box.get()); - ctx.scenery.push_back(std::move(box)); + _mod_scenery.push_back(box.get()); + _ctx.scenery.push_back(std::move(box)); } else { // MOD_TEXT Text3dPtr t = make_Text3d(o.text, Text3d::depth_floor, 0.003f, Vec3{ o.x, o.y, o.z }, SDL_FColor{ o.r, o.g, o.b, 1.0f }); t->body.mode = PhysicsMode::Static; // lib text just sits where placed - mod_scenery.push_back(t.get()); - ctx.words.push_back(std::move(t)); + _mod_scenery.push_back(t.get()); + _ctx.words.push_back(std::move(t)); } } } std::string GameState::sandbox_CanonicalPath() const { - return level_runner_sys ? level_runner_sys->source_file() : std::string{}; + return _level_runner_sys ? _level_runner_sys->source_file() : std::string{}; } std::string GameState::sandbox_BackupPath() const { std::string c = sandbox_CanonicalPath(); @@ -1101,13 +1101,13 @@ GameState::sandbox_LoadFileToWall() } // Clear any existing editor-wall words first. - editor_wall.clear(); - ctx.wall_texts.erase( - std::remove_if(ctx.wall_texts.begin(), ctx.wall_texts.end(), + _editor_wall.clear(); + _ctx.wall_texts.erase( + std::remove_if(_ctx.wall_texts.begin(), _ctx.wall_texts.end(), [](const TextWallPtr& wt){ return wt->role == Wall::Role::Editor; }), - ctx.wall_texts.end()); + _ctx.wall_texts.end()); - const float ws = ctx.world->scale(); + const float ws = _ctx.world->scale(); const double x_wall = -static_cast<double>(ws) + 0.05; // NegX wall surface Wall::Transform tf = Wall::get_Transform(Wall::Role::Editor, ws); @@ -1125,10 +1125,10 @@ GameState::sandbox_LoadFileToWall() t->yaw = tf.yaw; // Snap into the editor wall's line tracking, like a thrown word. - Vec3 snapped = editor_wall.on_WordPlaced(t.get(), Vec3{ x_wall, y, z }); + Vec3 snapped = _editor_wall.on_WordPlaced(t.get(), Vec3{ x_wall, y, z }); t->pos = snapped; - ctx.wall_texts.push_back(cpputils::make_unique<TextWall>(TextWall{ + _ctx.wall_texts.push_back(cpputils::make_unique<TextWall>(TextWall{ Wall::Position::NegX, Wall::Role::Editor, std::move(t) })); @@ -1142,7 +1142,7 @@ GameState::sandbox_LoadFileToWall() void GameState::sandbox_Restore() { - if (!level_runner_sys || !level_runner_sys->dynamic_lib()) return; + if (!_level_runner_sys || !_level_runner_sys->dynamic_lib()) return; if (SourceTokens::copy_File(sandbox_BackupPath(), sandbox_CanonicalPath())) sandbox_LoadFileToWall(); } @@ -1162,8 +1162,8 @@ GameState::typing_RebuildPreview(const std::string& s) anchor, Text3d::color_floor); t->yaw = static_cast<float>(glyph_yaw); t->body.mode = PhysicsMode::Carried; - typing_words.push_back(t.get()); // track raw ptr for later removal - carried.push(std::move(t)); + _typing_words.push_back(t.get()); // track raw ptr for later removal + _carried.push(std::move(t)); } } @@ -1173,11 +1173,11 @@ GameState::typing_ClearPreview() { // Preview words are the most recently pushed → at the tail. Pop exactly // as many as we added; let them be destroyed (don't re-add to scene). - for (size_t i = 0; i < typing_words.size(); ++i) { - if (carried.empty()) break; - carried.pop_back(); // returns Text3dPtr; dropping it frees the word + for (size_t i = 0; i < _typing_words.size(); ++i) { + if (_carried.empty()) break; + _carried.pop_back(); // returns Text3dPtr; dropping it frees the word } - typing_words.clear(); + _typing_words.clear(); } @@ -1199,6 +1199,6 @@ GameState::carry_BeginAnim(Text3dPtr word, bool with_pitch) anim.target_pos = anchor; anim.yaw_target = static_cast<float>(glyph_yaw); - anims_add.push_back(std::move(anim)); + _anims_add.push_back(std::move(anim)); } diff --git a/src/states/game_state.hpp b/src/states/game_state.hpp index 7fb2fe0..3c8ffe5 100644 --- a/src/states/game_state.hpp +++ b/src/states/game_state.hpp @@ -58,45 +58,44 @@ struct StepPlate { class GameState : public IState { - GameContext ctx; - FrameInput frame_input; - CarriedLine carried; - EditorWall editor_wall; - - StepLedger step_ledger; - - double pick_cooldown { 0.0 }; - double shoot_cooldown { 0.0 }; - double step_age { 0.0 }; - double accumulator { 0.0 }; - double alpha { 0.0 }; - - DynArray<Text3d*> typing_words; - std::string typing_last; - - DynArray<Projectile> projectiles; - DynArray<WordAnim_Add> anims_add; - DynArray<WordAnim_Drop> anims_drop; - - DynArray<GameObject*> mod_scenery; - DynArray<GameObject*> step_scenery; - DynArray<StepPlate> step_plates; - - cpputils::unique_ptr<InputSystem> input_sys; - cpputils::unique_ptr<PhysicsSystem> physics_sys; - cpputils::unique_ptr<ProjectileSystem> projectiles_sys; - cpputils::unique_ptr<WordAnimSystem> word_anim_sys; - cpputils::unique_ptr<CompilerSystem> compiler_sys; - cpputils::unique_ptr<FreelookSystem> freelook_sys; - cpputils::unique_ptr<PultSystem> pult_sys; - cpputils::unique_ptr<HintSystem> hint_sys; - cpputils::unique_ptr<WordAiSystem> word_ai_sys; - cpputils::unique_ptr<PlateSystem> plate_sys; - cpputils::unique_ptr<ParticleSystem> particle_sys; - cpputils::unique_ptr<FloorMandelbrot> floor_sys; - cpputils::unique_ptr<LevelRunner> level_runner_sys; - cpputils::unique_ptr<ModLoader> mod_loader_sys; - cpputils::unique_ptr<CelebrationSystem>celebration_sys; + GameContext _ctx; + FrameInput _frame_input; + CarriedLine _carried; + EditorWall _editor_wall; + StepLedger _step_ledger; + + double _pick_cooldown { 0.0 }; + double _shoot_cooldown { 0.0 }; + double _step_age { 0.0 }; + double _accumulator { 0.0 }; + double _alpha { 0.0 }; + + DynArray<Text3d*> _typing_words; + std::string _typing_last; + + DynArray<Projectile> _projectiles; + DynArray<WordAnim_Add> _anims_add; + DynArray<WordAnim_Drop> _anims_drop; + + DynArray<GameObject*> _mod_scenery; + DynArray<GameObject*> _step_scenery; + DynArray<StepPlate> _step_plates; + + cpputils::unique_ptr<InputSystem> _input_sys; + cpputils::unique_ptr<PhysicsSystem> _physics_sys; + cpputils::unique_ptr<ProjectileSystem> _projectiles_sys; + cpputils::unique_ptr<WordAnimSystem> _word_anim_sys; + cpputils::unique_ptr<CompilerSystem> _compiler_sys; + cpputils::unique_ptr<FreelookSystem> _freelook_sys; + cpputils::unique_ptr<PultSystem> _pult_sys; + cpputils::unique_ptr<HintSystem> _hint_sys; + cpputils::unique_ptr<WordAiSystem> _word_ai_sys; + cpputils::unique_ptr<PlateSystem> _plate_sys; + cpputils::unique_ptr<ParticleSystem> _particle_sys; + cpputils::unique_ptr<FloorMandelbrot> _floor_sys; + cpputils::unique_ptr<LevelRunner> _level_runner_sys; + cpputils::unique_ptr<ModLoader> _mod_loader_sys; + cpputils::unique_ptr<CelebrationSystem>_celebration_sys; bool on_Pick (); diff --git a/src/states/menu_state.cpp b/src/states/menu_state.cpp index 007edc1..127a956 100644 --- a/src/states/menu_state.cpp +++ b/src/states/menu_state.cpp @@ -12,9 +12,9 @@ // ───────────────────────────────────────────────────────────────────────── // Layout: three columns at -90° / 0° / +90°. Left holds "Open File", right // holds "Quit", middle holds the level list — Tutorial at eye level, every -// further level stacked downward. Camera stands at world origin. +// further level stacked downward. Camera stands at _world origin. // -// W/S scroll the level list (the list moves; the camera does not). At +// W/S scroll the level list (the list moves; the _camera does not). At // scroll = 0 the first level sits at eye level. At scroll = N the (N+1)th // level does. // ───────────────────────────────────────────────────────────────────────── @@ -70,19 +70,19 @@ slot_PosForColumn(double column_angle_rad, double y) MenuState::MenuState() { - world = cpputils::make_unique<World>(); - camera = cpputils::make_unique<Camera>(); - light = cpputils::make_unique<Light>(); + _world = cpputils::make_unique<World>(); + _camera = cpputils::make_unique<Camera>(); + _light = cpputils::make_unique<Light>(); - camera->pos = { 0.0, EYE_Y, 0.0 }; - camera->yaw = 0; - camera->pitch = 0; + _camera->pos = { 0.0, EYE_Y, 0.0 }; + _camera->yaw = 0; + _camera->pitch = 0; - title = make_Text3d("Runtime Compiler", + _title = make_Text3d("Runtime Compiler", TEXT_DEPTH, TITLE_SCALE, slot_PosForColumn(COLUMN_MID_RAD, TITLE_Y), COLOR_TITLE); - title->body.mode = PhysicsMode::Static; + _title->body.mode = PhysicsMode::Static; build_Items(); } @@ -91,14 +91,14 @@ MenuState::MenuState() bool MenuState::is_LevelItem(size_t idx) const { - return idx < items.size() && items[idx].kind == ItemKind::StartLevel; + return idx < _items.size() && _items[idx].kind == ItemKind::StartLevel; } void MenuState::build_Items() { - items.clear(); + _items.clear(); // ── Left column: Open File ─────────────────────────────────────────── { @@ -106,12 +106,12 @@ MenuState::build_Items() mi.label = "Open File"; mi.kind = ItemKind::OpenFile; mi.slot_pos = slot_PosForColumn(COLUMN_LEFT_RAD, EYE_Y); - items.push_back(std::move(mi)); + _items.push_back(std::move(mi)); } // ── Middle column: levels, stacked top-to-bottom ───────────────────── // We DON'T set slot_pos.y here; vertical position is recomputed each - // frame in update() based on scroll_current. The X/Z components (the + // frame in update() based on _scroll_current. The X/Z components (the // middle column) are fixed. for (size_t i = 0; i < level_Count(); ++i) { MenuItem mi; @@ -119,7 +119,7 @@ MenuState::build_Items() mi.kind = ItemKind::StartLevel; mi.level_index = i; mi.slot_pos = slot_PosForColumn(COLUMN_MID_RAD, EYE_Y); // y replaced each frame - items.push_back(std::move(mi)); + _items.push_back(std::move(mi)); } // ── Right column: Quit ─────────────────────────────────────────────── @@ -128,17 +128,17 @@ MenuState::build_Items() mi.label = "Quit"; mi.kind = ItemKind::Quit; mi.slot_pos = slot_PosForColumn(COLUMN_RIGHT_RAD, EYE_Y); - items.push_back(std::move(mi)); + _items.push_back(std::move(mi)); } // Build Text3d objects. - for (size_t i = 0; i < items.size(); ++i) { - const auto color = (i == selected) ? COLOR_SELECTED : COLOR_NORMAL; - items[i].text3d = make_Text3d(items[i].label, + for (size_t i = 0; i < _items.size(); ++i) { + const auto color = (i == _selected) ? COLOR_SELECTED : COLOR_NORMAL; + _items[i].text3d = make_Text3d(_items[i].label, TEXT_DEPTH, ITEM_SCALE, - items[i].slot_pos, + _items[i].slot_pos, color); - items[i].text3d->body.mode = PhysicsMode::Static; + _items[i].text3d->body.mode = PhysicsMode::Static; } } @@ -151,16 +151,16 @@ MenuState::handle_Event(Game& game, const SDL_Event& e) const double dx_rad = static_cast<double>(e.motion.xrel) * MOUSE_SENSITIVITY; const double dy_rad = static_cast<double>(e.motion.yrel) * MOUSE_SENSITIVITY; - const double cur_yaw = yaw_ToRadians(camera->yaw); - camera->yaw = yaw_FromRadians(cur_yaw - dx_rad); + const double cur_yaw = yaw_ToRadians(_camera->yaw); + _camera->yaw = yaw_FromRadians(cur_yaw - dx_rad); constexpr int32_t PITCH_MAX = 0x40000000; const int32_t dpitch = static_cast<int32_t>( dy_rad * (2147483648.0 / SDL_PI_D)); - int32_t p = camera->pitch - dpitch; + int32_t p = _camera->pitch - dpitch; if (p > PITCH_MAX) p = PITCH_MAX; if (p < -PITCH_MAX) p = -PITCH_MAX; - camera->pitch = p; + _camera->pitch = p; return; } @@ -170,7 +170,7 @@ MenuState::handle_Event(Game& game, const SDL_Event& e) { const size_t hit = pick_FromCrosshair(); if (hit != static_cast<size_t>(-1)) { - selected = hit; + _selected = hit; activate(game); } return; @@ -184,7 +184,7 @@ MenuState::handle_Event(Game& game, const SDL_Event& e) // Only scroll the level list when the player is looking at a // level. Other columns ignore W/S. if (is_LevelItem(pick_FromCrosshair())) { - if (scroll_target > 0.0) scroll_target -= 1.0; + if (_scroll_target > 0.0) _scroll_target -= 1.0; } break; @@ -193,7 +193,7 @@ MenuState::handle_Event(Game& game, const SDL_Event& e) if (is_LevelItem(pick_FromCrosshair())) { const double max_scroll = static_cast<double>(level_Count() > 0 ? level_Count() - 1 : 0); - if (scroll_target < max_scroll) scroll_target += 1.0; + if (_scroll_target < max_scroll) _scroll_target += 1.0; } break; @@ -201,7 +201,7 @@ MenuState::handle_Event(Game& game, const SDL_Event& e) case SDLK_SPACE: { const size_t hit = pick_FromCrosshair(); if (hit != static_cast<size_t>(-1)) { - selected = hit; + _selected = hit; activate(game); } break; @@ -220,13 +220,13 @@ MenuState::handle_Event(Game& game, const SDL_Event& e) void MenuState::activate(Game& game) { - if (selected >= items.size()) return; + if (_selected >= _items.size()) return; - const MenuItem& mi = items[selected]; + const MenuItem& mi = _items[_selected]; switch (mi.kind) { case ItemKind::StartLevel: - game.changeState(cpputils::make_unique<GameState>(mi.level_index)); + game.change_State(cpputils::make_unique<GameState>(mi.level_index)); break; case ItemKind::OpenFile: @@ -246,8 +246,8 @@ MenuState::activate(Game& game) size_t MenuState::pick_FromCrosshair() const { - const double yaw = yaw_ToRadians(camera->yaw); - const double pitch = static_cast<double>(camera->pitch) * BINRAD; + const double yaw = yaw_ToRadians(_camera->yaw); + const double pitch = static_cast<double>(_camera->pitch) * BINRAD; const double cy = SDL_cos(yaw), sy = SDL_sin(yaw); const double cp = SDL_cos(pitch), sp = SDL_sin(pitch); @@ -257,16 +257,16 @@ MenuState::pick_FromCrosshair() const size_t best = static_cast<size_t>(-1); double best_t = 1e9; - for (size_t i = 0; i < items.size(); ++i) { - if (!items[i].text3d || !items[i].text3d->loaded) continue; + for (size_t i = 0; i < _items.size(); ++i) { + if (!_items[i].text3d || !_items[i].text3d->loaded) continue; - const Vec3 mn = items[i].text3d->aabb_min(); - const Vec3 mx = items[i].text3d->aabb_max(); + const Vec3 mn = _items[i].text3d->aabb_min(); + const Vec3 mx = _items[i].text3d->aabb_max(); double tmin = 0.0, tmax = 1e9; - const double ox = camera->pos.x; - const double oy = camera->pos.y; - const double oz = camera->pos.z; + const double ox = _camera->pos.x; + const double oy = _camera->pos.y; + const double oz = _camera->pos.z; auto slab = [&](double o, double d, double lo, double hi) -> bool { if (SDL_fabs(d) < 1e-9) return o >= lo && o <= hi; @@ -296,32 +296,32 @@ MenuState::pick_FromCrosshair() const void MenuState::update(double dt) { - t += dt; + _t += dt; // ── Scroll lerp ────────────────────────────────────────────────────── { const double k = 1.0 - SDL_exp(-SCROLL_LERP_RATE * dt); - scroll_current += (scroll_target - scroll_current) * k; + _scroll_current += (_scroll_target - _scroll_current) * k; } - // ── Reposition level items based on scroll ─────────────────────────── - // For each level i: y = EYE_Y - (i - scroll_current) * SPACING. - // At scroll_current = 0, i=0 sits at EYE_Y, i=1 below it, etc. - // As scroll_current grows, the whole list slides upward, so further + // ── Reposition level _items based on scroll ─────────────────────────── + // For each level i: y = EYE_Y - (i - _scroll_current) * SPACING. + // At _scroll_current = 0, i=0 sits at EYE_Y, i=1 below it, etc. + // As _scroll_current grows, the whole list slides upward, so further // levels reach eye level. { size_t level_n = 0; - for (MenuItem& mi : items) { + for (MenuItem& mi : _items) { if (mi.kind != ItemKind::StartLevel) continue; - const double y = EYE_Y - (static_cast<double>(level_n) - scroll_current) + const double y = EYE_Y - (static_cast<double>(level_n) - _scroll_current) * LEVEL_SPACING; mi.text3d->pos = { mi.slot_pos.x, y, mi.slot_pos.z }; ++level_n; } } - // ── Non-level items stay at their fixed slot positions ─────────────── - for (MenuItem& mi : items) { + // ── Non-level _items stay at their fixed slot positions ─────────────── + for (MenuItem& mi : _items) { if (mi.kind == ItemKind::StartLevel) continue; mi.text3d->pos = mi.slot_pos; } @@ -329,30 +329,30 @@ MenuState::update(double dt) // ── Crosshair-driven selection (mouse hover) ───────────────────────── { const size_t hover = pick_FromCrosshair(); - if (hover != static_cast<size_t>(-1) && hover != selected) { - items[selected].text3d->set_Color(COLOR_NORMAL); - items[hover].text3d->set_Color(COLOR_SELECTED); - selected = hover; + if (hover != static_cast<size_t>(-1) && hover != _selected) { + _items[_selected].text3d->set_Color(COLOR_NORMAL); + _items[hover].text3d->set_Color(COLOR_SELECTED); + _selected = hover; } } - // ── Billboard: every item faces the camera ─────────────────────────── - for (MenuItem& mi : items) { + // ── Billboard: every item faces the _camera ─────────────────────────── + for (MenuItem& mi : _items) { if (!mi.text3d) continue; - const double dx = camera->pos.x - mi.text3d->pos.x; - const double dz = camera->pos.z - mi.text3d->pos.z; + const double dx = _camera->pos.x - mi.text3d->pos.x; + const double dz = _camera->pos.z - mi.text3d->pos.z; mi.text3d->yaw = static_cast<float>(SDL_atan2(dx, dz)); } - if (title) { - const double dx = camera->pos.x - title->pos.x; - const double dz = camera->pos.z - title->pos.z; - title->yaw = static_cast<float>(SDL_atan2(dx, dz)); + if (_title) { + const double dx = _camera->pos.x - _title->pos.x; + const double dz = _camera->pos.z - _title->pos.z; + _title->yaw = static_cast<float>(SDL_atan2(dx, dz)); } - // ── Bob the selected item ──────────────────────────────────────────── - if (selected < items.size() && items[selected].text3d) { - const double bob = SDL_sin(t * 3.0) * 0.10; - items[selected].text3d->pos.y += bob; + // ── Bob the _selected item ──────────────────────────────────────────── + if (_selected < _items.size() && _items[_selected].text3d) { + const double bob = SDL_sin(_t * 3.0) * 0.10; + _items[_selected].text3d->pos.y += bob; } } @@ -363,25 +363,25 @@ MenuState::render(SDL_Window& window, GlRenderer& renderer) int w, h; SDL_GetWindowSizeInPixels(&window, &w, &h); - // Update flashlight: pos = camera, dir = where the camera is looking. + // Update flashlight: pos = _camera, dir = where the _camera is looking. { - const double yaw_r = BINRAD * static_cast<double>(camera->yaw); - const double pitch_r = BINRAD * static_cast<double>(camera->pitch); + const double yaw_r = BINRAD * static_cast<double>(_camera->yaw); + const double pitch_r = BINRAD * static_cast<double>(_camera->pitch); const double cy = SDL_cos(yaw_r), sy = SDL_sin(yaw_r); const double cp = SDL_cos(pitch_r), sp = SDL_sin(pitch_r); - light->flashlight_pos = camera->pos; - light->flashlight_dir = Vec3{ -sy * cp, sp, -cy * cp }; + _light->flashlight_pos = _camera->pos; + _light->flashlight_dir = Vec3{ -sy * cp, sp, -cy * cp }; } renderer.begin_Frame(w, h); - renderer.set_Light(*light); + renderer.set_Light(*_light); - world->draw(renderer, *camera, *light); + _world->draw(renderer, *_camera, *_light); - if (title) title->draw(renderer, *camera, *light); - for (const MenuItem& mi : items) - if (mi.text3d) mi.text3d->draw(renderer, *camera, *light); + if (_title) _title->draw(renderer, *_camera, *_light); + for (const MenuItem& mi : _items) + if (mi.text3d) mi.text3d->draw(renderer, *_camera, *_light); renderer.end_Frame(&window); } diff --git a/src/states/menu_state.hpp b/src/states/menu_state.hpp index c536606..f789845 100644 --- a/src/states/menu_state.hpp +++ b/src/states/menu_state.hpp @@ -13,14 +13,6 @@ class MenuState : public IState { -public: - MenuState(); - - void handle_Event(Game&, const SDL_Event&) override; - void update(double dt) override; - void render(SDL_Window&, GlRenderer&) override; - -private: enum class ItemKind : uint8_t { OpenFile, StartLevel, @@ -35,28 +27,30 @@ private: Vec3 slot_pos {}; // base position in the column (no scroll/bob) }; - void build_Items(); - void activate(Game& game); - size_t pick_FromCrosshair() const; - bool is_LevelItem(size_t idx) const; + cpputils::unique_ptr<World> _world; + cpputils::unique_ptr<Camera> _camera; + cpputils::unique_ptr<Light> _light; - static uint32_t yaw_FromRadians(double rad); - static double yaw_ToRadians(uint32_t yaw); + Text3dPtr _title; + DynArray<MenuItem> _items; + size_t _selected{0}; - cpputils::unique_ptr<World> world; - cpputils::unique_ptr<Camera> camera; - cpputils::unique_ptr<Light> light; + double _scroll_current{0.0}; + double _scroll_target {0.0}; - Text3dPtr title; - DynArray<MenuItem> items; - size_t selected{0}; + double _t{0.0}; - // Vertical scroll of the level list. - // 0 = Tutorial (first level) at eye level. - // i = level i at eye level. - // Camera doesn't move; the items reposition themselves each frame. - double scroll_current{0.0}; - double scroll_target {0.0}; + void build_Items (); + void activate (Game& game); + size_t pick_FromCrosshair() const; + bool is_LevelItem (size_t idx) const; + + static uint32_t yaw_FromRadians(double rad); + static double yaw_ToRadians (uint32_t yaw); +public: + MenuState(); - double t{0.0}; + void handle_Event(Game&, const SDL_Event&) override; + void update(double dt) override; + void render(SDL_Window&, GlRenderer&) override; }; diff --git a/src/systems/celebration_system.cpp b/src/systems/celebration_system.cpp index 080f93e..2066b8b 100644 --- a/src/systems/celebration_system.cpp +++ b/src/systems/celebration_system.cpp @@ -5,9 +5,9 @@ void CelebrationSystem::start(const Camera& cam, double& glyph_yaw) { - active_ = true; - t_ = 0.0; - next_burst_ = 0.0; + _active = true; + _t = 0.0; + _next_burst = 0.0; Vec3 banner_pos { cam.pos.x + cam.fwd.x * 10.0, @@ -18,30 +18,30 @@ CelebrationSystem::start(const Camera& cam, double& glyph_yaw) if (banner_pos.y < static_cast<double>(-WORLD_BOX_SCALE+1.0f) ) banner_pos.y = -WORLD_BOX_SCALE+1.0f; - banner_ = make_Text3d("Success", + _banner = make_Text3d("Success", Text3d::depth_floor * 2.0f, 0.012f, banner_pos, Text3d::color_white); - banner_->yaw = static_cast<float>(glyph_yaw); - banner_->body.mode = PhysicsMode::Static; + _banner->yaw = static_cast<float>(glyph_yaw); + _banner->body.mode = PhysicsMode::Static; } void CelebrationSystem::tick(double dt, ParticleSystem& particle_sys) { - if (!active_) return; + if (!_active) return; - t_ += dt; + _t += dt; // Slow banner spin - if (banner_) - banner_->yaw += static_cast<float>(dt * 0.6); + if (_banner) + _banner->yaw += static_cast<float>(dt * 0.6); // Fireworks bursts on a schedule. We aim for ~7 bursts across the // duration, with slight jitter to avoid mechanical pacing. - if (t_ >= next_burst_ && - t_ < duration_ - 0.3) + if (_t >= _next_burst && + _t < _duration - 0.3) { // Random position across the play area, biased to upper half so // bursts read as airborne fireworks not floor_sys explosions. @@ -74,7 +74,7 @@ CelebrationSystem::tick(double dt, ParticleSystem& particle_sys) particle_sys.emit_FireworkBurst(center, SDL_FColor{r, g, b, 1.0f}, 80); // Next burst in 0.5..1.0s. - next_burst_ = t_ + 0.5 + rnd() * 0.5; + _next_burst = _t + 0.5 + rnd() * 0.5; } } @@ -82,8 +82,8 @@ CelebrationSystem::tick(double dt, ParticleSystem& particle_sys) void CelebrationSystem::finish(ParticleSystem& particle_sys) { - active_ = false; - banner_.reset(); + _active = false; + _banner.reset(); particle_sys.clear(); } @@ -91,20 +91,20 @@ CelebrationSystem::finish(ParticleSystem& particle_sys) bool CelebrationSystem::active() const { - return active_; + return _active; } double CelebrationSystem::progress() const { - return (duration_ > 0.0) ? (t_ / duration_) : 1.0; + return (_duration > 0.0) ? (_t / _duration) : 1.0; } void CelebrationSystem::draw(GlRenderer& gl, const Camera& cam, const Light& light) const { - if (!active_ || !banner_) return; - banner_->draw(gl, cam, light); + if (!_active || !_banner) return; + _banner->draw(gl, cam, light); } diff --git a/src/systems/celebration_system.hpp b/src/systems/celebration_system.hpp index 36dbe45..244de1c 100644 --- a/src/systems/celebration_system.hpp +++ b/src/systems/celebration_system.hpp @@ -9,11 +9,11 @@ class GlRenderer; class CelebrationSystem { - bool active_ = false; - double t_ = 0, - duration_ = 3.5, - next_burst_ = 0; - Text3dPtr banner_; + bool _active = false; + double _t = 0, + _duration = 3.5, + _next_burst = 0; + Text3dPtr _banner; public: void start(const Camera& cam, double& glyph_yaw); void tick(double dt, ParticleSystem& particle_sys); diff --git a/src/systems/compiler_system.cpp b/src/systems/compiler_system.cpp index a0375fe..68ee01b 100644 --- a/src/systems/compiler_system.cpp +++ b/src/systems/compiler_system.cpp @@ -14,41 +14,46 @@ CompilerSystem::compile(TextWallList& texts, const std::string& src) // Clear previous output from PosX wall texts.erase( std::remove_if(texts.begin(), texts.end(), - [](const TextWallPtr& wt) { return wt->wall_position == Wall::position_of(Wall::Role::Compiler); }), + [](const TextWallPtr& wt) { + return wt->wall_position == Wall::position_of(Wall::Role::Compiler); + }), texts.end()); - count = 0; + _count = 0; // Write source to temp file FILE* f = fopen("/tmp/game_prog.c", "w"); - if (!f) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "CompilerSystem: could not write temp file"); return; } + if (!f) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "CompilerSystem: could not write temp file"); + return; + } fputs(src.c_str(), f); fclose(f); - // Open gcc pipe — stderr redirected to stdout so we get errors too - if (pipe) { pclose(pipe); pipe = nullptr; } - 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"); + // Open gcc _pipe — stderr redirected to stdout so we get errors too + if (_pipe) { pclose(_pipe); _pipe = nullptr; } + _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"); } void CompilerSystem::update(TextWallList& texts, float world_scale) { - if (!pipe) return; + if (!_pipe) return; char buf[512]; // Non-blocking: try to read a line, but don't stall the frame // popen is blocking by default so we set fd non-blocking - int fd = fileno(pipe); + int fd = fileno(_pipe); fd_set set; FD_ZERO(&set); FD_SET(fd, &set); struct timeval tv{0, 0}; // zero timeout = poll while (select(fd+1, &set, nullptr, nullptr, &tv) > 0) { - if (!fgets(buf, sizeof(buf), pipe)) { + if (!fgets(buf, sizeof(buf), _pipe)) { // EOF — compile finished - pclose(pipe); - pipe = nullptr; - if (count == 0) + pclose(_pipe); + _pipe = nullptr; + if (_count == 0) push_Line(texts, "OK", world_scale); return; } @@ -89,5 +94,5 @@ CompilerSystem::push_Line(TextWallList& texts, const std::string& line, float wo }); texts.push_back(std::move(wt)); - count++; + _count++; } diff --git a/src/systems/compiler_system.hpp b/src/systems/compiler_system.hpp index 1ddd14f..aa7e405 100644 --- a/src/systems/compiler_system.hpp +++ b/src/systems/compiler_system.hpp @@ -7,22 +7,19 @@ struct CompilerSystem { - static inline float line_height = 0.4f; - static inline float start_y = -15.0f; // bottom of PosX wall - - bool last_compile_ok{false}; - - // Call once per frame — reads available lines from gcc, spawns TextWalls - void update(TextWallList&, float world_scale); - - // Trigger a compile — writes src to /tmp, opens popen pipe - void compile(TextWallList&, const std::string& src); - - bool is_Running() const { return pipe != nullptr; } private: - FILE* pipe {nullptr}; - int count {0}; // how many output lines so far + FILE* _pipe {nullptr}; + int _count {0}; void push_Line(TextWallList&, const std::string& line, float world_scale); +public: + static inline float line_height = 0.4f; + static inline float start_y = -WORLD_BOX_SCALE+1; + + bool last_compile_ok{false}; + + void update (TextWallList&, float world_scale); + void compile (TextWallList&, const std::string& src); + bool is_Running() const { return _pipe != nullptr; } }; diff --git a/src/systems/freelook_system.hpp b/src/systems/freelook_system.hpp index e9769f9..4cde0e8 100644 --- a/src/systems/freelook_system.hpp +++ b/src/systems/freelook_system.hpp @@ -29,8 +29,8 @@ public: // Call when shift released — starts lerp back to face anchor void end(uint32_t player_yaw, int32_t player_pitch, - const Vec3& camera_pos, - uint32_t& out_yaw, int32_t& out_pitch); + const Vec3& camera_pos, + uint32_t& out_yaw, int32_t& out_pitch); // Call every frame void diff --git a/src/systems/hint_system.cpp b/src/systems/hint_system.cpp index c043a89..6ab4e3b 100644 --- a/src/systems/hint_system.cpp +++ b/src/systems/hint_system.cpp @@ -3,32 +3,32 @@ HintSystem::HintSystem() { - label_.set_Centre(Vec3{ 0.0, static_cast<double>(-WORLD_BOX_SCALE) + 2.5, 0.0 }); - label_.set_Billboard(true); - label_.set_Style(Text3d::color_yellow, Text3d::depth_wall, 0.003f); - label_.set_Collidable(true); + _label.set_Centre(Vec3{ 0.0, static_cast<double>(-WORLD_BOX_SCALE) + 2.5, 0.0 }); + _label.set_Billboard(true); + _label.set_Style(Text3d::color_yellow, Text3d::depth_wall, 0.003f); + _label.set_Collidable(true); } void HintSystem::set_Hint(const std::string& hint_text) { - if (hint_text == current_hint_) return; - current_hint_ = hint_text; - label_.set_Text(hint_text); + if (hint_text == _current_hint) return; + _current_hint = hint_text; + _label.set_Text(hint_text); } void HintSystem::clear() { - current_hint_.clear(); - label_.clear(); + _current_hint.clear(); + _label.clear(); } void -HintSystem::update(double dt, const Camera& camera) { label_.update(dt, camera); } +HintSystem::update(double dt, const Camera& camera) { _label.update(dt, camera); } void HintSystem::draw(GlRenderer& gl, const Camera& camera, const Light& light) const -{ label_.draw(gl, camera, light); } +{ _label.draw(gl, camera, light); } diff --git a/src/systems/hint_system.hpp b/src/systems/hint_system.hpp index 63c25e5..740a7d2 100644 --- a/src/systems/hint_system.hpp +++ b/src/systems/hint_system.hpp @@ -8,18 +8,18 @@ class GlRenderer; class HintSystem { - TextLabel label_; - std::string current_hint_; + TextLabel _label; + std::string _current_hint; public: - HintSystem(); + HintSystem (); void set_Hint(const std::string& hint_text); - void clear(); - void update(double dt, const Camera& camera); - void draw(GlRenderer& gl, const Camera& camera, const Light& light) const; + void clear (); + void update (double dt, const Camera& camera); + void draw (GlRenderer& gl, const Camera& camera, const Light& light) const; TextLabel& - get_Label() { return label_; } + get_Label() { return _label; } const TextLabel& - get_Label() const { return label_; } + get_Label() const { return _label; } }; diff --git a/src/systems/input_system.cpp b/src/systems/input_system.cpp index 19cff5d..30213ab 100644 --- a/src/systems/input_system.cpp +++ b/src/systems/input_system.cpp @@ -47,7 +47,7 @@ InputSystem::handle_Event(Game& game, const SDL_Event& e, FrameInput& input) case SDLK_D: input.right = true; break; case SDLK_E: input.pick = true; break; - case SDLK_F1: game.changeState(cpputils::make_unique<GameState>()); break; + case SDLK_F1: game.change_State(cpputils::make_unique<GameState>()); break; case SDLK_F2: input.commands.push_back(InputCommand::SandboxRestore);break; case SDLK_SPACE: input.commands.push_back(InputCommand::Jump); break; case SDLK_R: input.commands.push_back(InputCommand::Drop); break; @@ -57,7 +57,7 @@ InputSystem::handle_Event(Game& game, const SDL_Event& e, FrameInput& input) case SDLK_T: input.commands.push_back(InputCommand::TextStart); break; case SDLK_LSHIFT: case SDLK_RSHIFT: input.commands.push_back(InputCommand::FreelookStart); break; - case SDLK_ESCAPE: game.changeState(cpputils::make_unique<MenuState>()); break; + case SDLK_ESCAPE: game.change_State(cpputils::make_unique<MenuState>()); break; case SDLK_PLUS: if (e.key.mod & SDL_KMOD_CTRL) input.commands.push_back(InputCommand::NumberInc); diff --git a/src/systems/level_runner_system.cpp b/src/systems/level_runner_system.cpp index 6345e38..400468e 100644 --- a/src/systems/level_runner_system.cpp +++ b/src/systems/level_runner_system.cpp @@ -1,10 +1,10 @@ #include "level_runner_system.hpp" -LevelRunner::LevelRunner(const Level& l) : level(&l) {} +LevelRunner::LevelRunner(const Level& l) : _level(&l) {} bool LevelRunner::advance() { - current_step++; + _current_step++; return !complete(); } diff --git a/src/systems/level_runner_system.hpp b/src/systems/level_runner_system.hpp index 277bbef..9936b83 100644 --- a/src/systems/level_runner_system.hpp +++ b/src/systems/level_runner_system.hpp @@ -2,24 +2,22 @@ #include "levels/level.hpp" class LevelRunner { + const Level* _level; + size_t _current_step{0}; public: - explicit LevelRunner(const Level& level); + explicit LevelRunner(const Level& _level); // Call after a successful compile - // Returns true if there are more steps, false if level complete + // Returns true if there are more steps, false if _level complete bool advance(); - bool complete() const { return current_step >= level->steps.size(); } - size_t step() const { return current_step; } - const LevelStep& current() const { return level->steps[current_step]; } - bool dynamic_lib() const { return level->dynamic_lib; } - const std::string& source_file() const { return level->source_file; } + bool complete() const { return _current_step >= _level->steps.size(); } + size_t step() const { return _current_step; } + const LevelStep& current() const { return _level->steps[_current_step]; } + bool dynamic_lib() const { return _level->dynamic_lib; } + const std::string& source_file() const { return _level->source_file; } // All tokens to spawn for the current step (resolved — no choices yet) // Choices are returned as multiple Text3d objects placed near each other DynArray<std::string> grants_for_step() const; - -private: - const Level* level; - size_t current_step{0}; }; diff --git a/src/systems/mod_loader_system.cpp b/src/systems/mod_loader_system.cpp index c8566dd..335dd8b 100644 --- a/src/systems/mod_loader_system.cpp +++ b/src/systems/mod_loader_system.cpp @@ -74,7 +74,7 @@ ModLoader::build(TextWallList& texts, const std::string& user_src, float world_s return wt->wall_position == Wall::position_of(Wall::Role::Compiler); }), texts.end()); - count_ = 0; + _count = 0; // Write wrapped source. FILE* f = fopen(MOD_SRC_PATH, "w"); @@ -90,7 +90,7 @@ ModLoader::build(TextWallList& texts, const std::string& user_src, float world_s // Unique output path each build — dlopen() caches handles by path, so a // fresh path guarantees the next checkpoint actually loads new code. - pending_so_ = "/tmp/game_mod_" + std::to_string(build_serial_++) + ".so"; + _pending_so = "/tmp/game_mod_" + std::to_string(_build_serial++) + ".so"; // Build a shared library. -fPIC + -shared; stderr→stdout for error capture. std::string cmd = "LC_ALL=C gcc -shared -fPIC -O0 -I"; @@ -98,12 +98,12 @@ ModLoader::build(TextWallList& texts, const std::string& user_src, float world_s cmd += " "; cmd += MOD_SRC_PATH; cmd += " -o "; - cmd += pending_so_; + cmd += _pending_so; cmd += " 2>&1"; - if (pipe_) { pclose(pipe_); pipe_ = nullptr; } - pipe_ = popen(cmd.c_str(), "r"); - if (!pipe_) + if (_pipe) { pclose(_pipe); _pipe = nullptr; } + _pipe = popen(cmd.c_str(), "r"); + if (!_pipe) SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ModLoader: popen failed"); } @@ -111,21 +111,21 @@ ModLoader::build(TextWallList& texts, const std::string& user_src, float world_s void ModLoader::update(TextWallList& texts, float world_scale) { - if (!pipe_) return; + if (!_pipe) return; char buf[512]; - int fd = fileno(pipe_); + int fd = fileno(_pipe); fd_set set; FD_ZERO(&set); FD_SET(fd, &set); struct timeval tv{0, 0}; // poll, never block the frame while (select(fd + 1, &set, nullptr, nullptr, &tv) > 0) { - if (!fgets(buf, sizeof(buf), pipe_)) { + if (!fgets(buf, sizeof(buf), _pipe)) { // EOF — build finished. No error lines means success. - pclose(pipe_); - pipe_ = nullptr; - if (count_ == 0) { + pclose(_pipe); + _pipe = nullptr; + if (_count == 0) { last_build_ok = true; - last_so_path_ = pending_so_; + _last_so_path = _pending_so; push_Line(texts, "BUILD OK", world_scale); } return; @@ -162,26 +162,26 @@ ModLoader::push_Line(TextWallList& texts, const std::string& line, float world_s Wall::Role::Compiler, std::move(t) })); - count_++; + _count++; } DynArray<ModObject> ModLoader::load_Objects() { DynArray<ModObject> result; - if (last_so_path_.empty()) return result; + if (_last_so_path.empty()) return result; // Close the previous handle before loading the new one. Safe because the // engine — not the .so — owns every object we spawn from these PODs, so // nothing live points into the unmapped library after dlclose. - if (handle_) { - dlclose(handle_); - handle_ = nullptr; + if (_handle) { + dlclose(_handle); + _handle = nullptr; } dlerror(); // clear stale error - handle_ = dlopen(last_so_path_.c_str(), RTLD_NOW | RTLD_LOCAL); - if (!handle_) { + _handle = dlopen(_last_so_path.c_str(), RTLD_NOW | RTLD_LOCAL); + if (!_handle) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ModLoader: dlopen failed: %s", dlerror()); return result; @@ -190,7 +190,7 @@ ModLoader::load_Objects() using BuildFn = int(*)(ModObject*, int); // The cast-through-void* dance silences -Wpedantic on function-pointer casts. BuildFn game_build = - reinterpret_cast<BuildFn>(dlsym(handle_, "game_build")); + reinterpret_cast<BuildFn>(dlsym(_handle, "game_build")); if (!game_build) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ModLoader: dlsym(game_build) failed: %s", dlerror()); @@ -209,6 +209,6 @@ ModLoader::load_Objects() ModLoader::~ModLoader() { - if (handle_) dlclose(handle_); - if (pipe_) pclose(pipe_); + if (_handle) dlclose(_handle); + if (_pipe) pclose(_pipe); } diff --git a/src/systems/mod_loader_system.hpp b/src/systems/mod_loader_system.hpp index b1f2925..5e19860 100644 --- a/src/systems/mod_loader_system.hpp +++ b/src/systems/mod_loader_system.hpp @@ -9,31 +9,34 @@ class ModLoader { + FILE* _pipe { nullptr }; + int _count { 0 }; + int _build_serial { 0 }; + std::string _pending_so; + std::string _last_so_path; + + void* _handle { nullptr }; // current dlopen handle + + static constexpr float line_height = 0.25f; + static constexpr float start_y = -15.0f; + + static std::string + wrap_Source(const std::string& user_body); + void push_Line (TextWallList& texts, const std::string& line, float world_scale); + public: - void build(TextWallList& texts, const std::string& user_src, float world_scale, bool full_source); - void update(TextWallList& texts, float world_scale); - bool is_Running() const { return pipe_ != nullptr; } bool last_build_ok { false }; - const std::string& last_so_path() const { return last_so_path_; } + + void build (TextWallList& texts, const std::string& user_src, float world_scale, bool full_source); + void update (TextWallList& texts, float world_scale); + bool is_Running () const { return _pipe != nullptr; } + const std::string& + last_so_path() const { return _last_so_path; } // Checkpoint 2: dlopen the last successful .so, call game_build, // return the spawned descriptions. Empty vector on any failure. - DynArray<ModObject> load_Objects(); + DynArray<ModObject> + load_Objects(); ~ModLoader(); // dlclose on teardown - -private: - static std::string wrap_Source(const std::string& user_body); - void push_Line(TextWallList& texts, const std::string& line, float world_scale); - - FILE* pipe_ { nullptr }; - int count_ { 0 }; - int build_serial_ { 0 }; - std::string pending_so_; - std::string last_so_path_; - - void* handle_ { nullptr }; // current dlopen handle - - static constexpr float line_height = 0.25f; - static constexpr float start_y = -15.0f; }; diff --git a/src/systems/particle_system.cpp b/src/systems/particle_system.cpp index c2fdd83..07abea3 100644 --- a/src/systems/particle_system.cpp +++ b/src/systems/particle_system.cpp @@ -35,7 +35,7 @@ ParticleSystem::emit_FireworkBurst(const Vec3& center, SDL_FColor color, int count) { - particles_.reserve(particles_.size() + static_cast<size_t>(count)); + _particles.reserve(_particles.size() + static_cast<size_t>(count)); for (int i = 0; i < count; ++i) { Particle p; @@ -56,7 +56,7 @@ ParticleSystem::emit_FireworkBurst(const Vec3& center, p.spin = static_cast<float>((frand() - 0.5) * 12.0); // ± 6 rad/s p.alive = true; - particles_.push_back(p); + _particles.push_back(p); } } @@ -68,7 +68,7 @@ ParticleSystem::update(double dt, { const double ws = static_cast<double>(world_scale); - for (Particle& p : particles_) { + for (Particle& p : _particles) { if (!p.alive) continue; p.age += dt; @@ -108,17 +108,17 @@ ParticleSystem::update(double dt, } // Compact: drop dead particles. - particles_.erase( - std::remove_if(particles_.begin(), particles_.end(), + _particles.erase( + std::remove_if(_particles.begin(), _particles.end(), [](const Particle& p) { return !p.alive; }), - particles_.end()); + _particles.end()); } void ParticleSystem::draw(GlRenderer& gl, const Camera& cam, const Light& light) const { - if (particles_.empty()) return; + if (_particles.empty()) return; // Glow look: high ambient, low diffuse contribution. Same trick Plate uses. Light glow = light; @@ -132,7 +132,7 @@ ParticleSystem::draw(GlRenderer& gl, const Camera& cam, const Light& light) cons gl.set_Wireframe(false); gl.set_Light(glow); - for (const Particle& p : particles_) { + for (const Particle& p : _particles) { // Fade out over the last 30% of lifetime. double tail = p.lifetime * 0.3; double t_left = p.lifetime - p.age; @@ -155,5 +155,5 @@ ParticleSystem::draw(GlRenderer& gl, const Camera& cam, const Light& light) cons void ParticleSystem::clear() { - particles_.clear(); + _particles.clear(); } diff --git a/src/systems/particle_system.hpp b/src/systems/particle_system.hpp index 13127ec..8aa7633 100644 --- a/src/systems/particle_system.hpp +++ b/src/systems/particle_system.hpp @@ -38,6 +38,7 @@ struct Particle { // They do NOT collide with words, AI, or each other — by design. class ParticleSystem { + DynArray<Particle> _particles; public: void update(double dt, const DynArray<GameObject*>& solid_colliders, @@ -52,8 +53,5 @@ public: // Clear all particles — called when celebration ends. void clear(); - bool empty() const { return particles_.empty(); } - -private: - DynArray<Particle> particles_; + bool empty() const { return _particles.empty(); } }; diff --git a/src/systems/physics_system.cpp b/src/systems/physics_system.cpp index 6862242..cf59310 100644 --- a/src/systems/physics_system.cpp +++ b/src/systems/physics_system.cpp @@ -232,7 +232,7 @@ PhysicsSystem::update_Objects(const DynArray<GameObject*>& objects, // which is the bulk of the old O(n²) work. { FP_ZONE("phys.pairs"); // Build grid over ALL objects (passive included — movers must find them). - grid_.build(objects, static_cast<double>(world_scale)); + _grid.build(objects, static_cast<double>(world_scale)); // Only active bodies initiate collision tests. DynArray<GameObject*> active; @@ -491,20 +491,20 @@ PhysicsSystem::collide_Grid(const DynArray<GameObject*>& active) for (GameObject* a : active) { if (!a) continue; - int cx = static_cast<int>((a->pos.x - grid_.min_x) * grid_.inv); - int cz = static_cast<int>((a->pos.z - grid_.min_z) * grid_.inv); - cx = cx < 0 ? 0 : (cx >= grid_.nx ? grid_.nx - 1 : cx); - cz = cz < 0 ? 0 : (cz >= grid_.nz ? grid_.nz - 1 : cz); + int cx = static_cast<int>((a->pos.x - _grid.min_x) * _grid.inv); + int cz = static_cast<int>((a->pos.z - _grid.min_z) * _grid.inv); + cx = cx < 0 ? 0 : (cx >= _grid.nx ? _grid.nx - 1 : cx); + cz = cz < 0 ? 0 : (cz >= _grid.nz ? _grid.nz - 1 : cz); for (int dz = -1; dz <= 1; ++dz) { const int ncz = cz + dz; - if (ncz < 0 || ncz >= grid_.nz) continue; + if (ncz < 0 || ncz >= _grid.nz) continue; for (int dx = -1; dx <= 1; ++dx) { const int ncx = cx + dx; - if (ncx < 0 || ncx >= grid_.nx) continue; + if (ncx < 0 || ncx >= _grid.nx) continue; - const auto& cell = grid_.cells[static_cast<size_t>(grid_.index(ncx, ncz))]; + const auto& cell = _grid.cells[static_cast<size_t>(_grid.index(ncx, ncz))]; for (GameObject* b : cell) { if (b == a) continue; diff --git a/src/systems/physics_system.hpp b/src/systems/physics_system.hpp index 0bc1a22..e919f3b 100644 --- a/src/systems/physics_system.hpp +++ b/src/systems/physics_system.hpp @@ -17,13 +17,6 @@ struct ProjectileContactEvent { }; class PhysicsSystem { - static void resolve_WorldBounds(GameObject& obj, float world_scale); - bool resolve_SingleBoxCollision(Projectile& proj, - const Vec3& box_min, const Vec3& box_max, - const Vec3& word_he, double restitution, - Vec3& cur, Vec3& prev, Vec3& dir, - Collision::SweptResult& out_sw); - void try_Pair(GameObject* a, GameObject* b); // Uniform spatial grid scratch, reused each frame to avoid reallocation. struct SpatialGrid { double cell = 2.0; @@ -35,7 +28,17 @@ class PhysicsSystem { void build(const DynArray<GameObject*>& objs, double world_scale); int index(int cx, int cz) const { return cz * nx + cx; } }; - SpatialGrid grid_; + + SpatialGrid _grid; + + static void + resolve_WorldBounds(GameObject& obj, float world_scale); + bool resolve_SingleBoxCollision(Projectile& proj, + const Vec3& box_min, const Vec3& box_max, + const Vec3& word_he, double restitution, + Vec3& cur, Vec3& prev, Vec3& dir, + Collision::SweptResult& out_sw); + void try_Pair(GameObject* a, GameObject* b); void collide_Grid(const DynArray<GameObject*>& active); public: diff --git a/src/systems/plate_system.hpp b/src/systems/plate_system.hpp index 26fd991..bfd408a 100644 --- a/src/systems/plate_system.hpp +++ b/src/systems/plate_system.hpp @@ -9,12 +9,7 @@ struct StepPlate; class PlateSystem { public: - // Updates each plate: bob/pulse animation, and detects whether the player - // is standing on each one. Sets plate->active based on player AABB overlap. - void update(double dt, - const Player& player, + void update(double dt, const Player& player, const DynArray<StepPlate>& plates); - - // True if the player is currently standing on any plate. bool any_Active(const DynArray<StepPlate>& plates) const; }; diff --git a/src/systems/pult_system.cpp b/src/systems/pult_system.cpp index 83ff7da..6863408 100644 --- a/src/systems/pult_system.cpp +++ b/src/systems/pult_system.cpp @@ -9,7 +9,7 @@ void PultSystem::init(DynArray<GameObjectPtr>& scenery, DynArray<PultButton*>& buttons_out, - float world_scale) + float world_scale) { const float floor_y = -world_scale; const float pult_y = floor_y + Pult::H; @@ -37,7 +37,7 @@ PultSystem::init(DynArray<GameObjectPtr>& scenery, { auto owned = cpputils::make_unique<Pult>(name, make_pult_pos(role, along)); Pult* raw = owned.get(); - pults_.push_back(raw); + _pults.push_back(raw); scenery.push_back(std::move(owned)); return raw; }; @@ -103,7 +103,7 @@ PultSystem::handle_ProjectileContact(const ProjectileContactEvent& ev, void PultSystem::update(double dt, const Camera& camera) { - for (Pult* p : pults_) { + for (Pult* p : _pults) { p->tick(dt); p->label.update(dt, camera); } @@ -113,7 +113,7 @@ PultSystem::update(double dt, const Camera& camera) void PultSystem::draw_Labels(GlRenderer& gl, const Camera& camera, const Light& light) const { - for (const Pult* p : pults_) + for (const Pult* p : _pults) p->label.draw(gl, camera, light); } @@ -122,7 +122,7 @@ DynArray<TextLabel*> PultSystem::labels() { DynArray<TextLabel*> out; - out.reserve(pults_.size()); - for (Pult* p : pults_) out.push_back(&p->label); + out.reserve(_pults.size()); + for (Pult* p : _pults) out.push_back(&p->label); return out; } diff --git a/src/systems/pult_system.hpp b/src/systems/pult_system.hpp index 2abdb47..a1e89d0 100644 --- a/src/systems/pult_system.hpp +++ b/src/systems/pult_system.hpp @@ -14,6 +14,7 @@ struct ProjectileContactEvent; class PultSystem { + DynArray<Pult*> _pults; public: void init(DynArray<GameObjectPtr>& scenery, DynArray<PultButton*>& buttons_out, @@ -28,7 +29,4 @@ public: void draw_Labels(GlRenderer& gl, const Camera& camera, const Light& light) const; DynArray<TextLabel*> labels(); - -private: - DynArray<Pult*> pults_; }; diff --git a/src/systems/word_ai_system.cpp b/src/systems/word_ai_system.cpp index 63c4680..c141d4b 100644 --- a/src/systems/word_ai_system.cpp +++ b/src/systems/word_ai_system.cpp @@ -91,7 +91,7 @@ WordAiSystem::update_Idle(Text3d& w, const Player& p, int active_ai_count, doubl if (w.body.mode != PhysicsMode::Hover) return; // Hard cap: don't start new AI behavior if we're already at the limit. - if (active_ai_count >= max_active_ai) return; + if (active_ai_count >= _max_active_ai) return; Vec3 to_player = p.pos - w.pos; double dist_sq = to_player.x*to_player.x + @@ -362,7 +362,7 @@ WordAiSystem::apply_Locomotion(Text3d& w, const Vec3& target_vel, double dt) w.pos.z += w.body.vel.z * dt; // Clamp to world bounds - const double ws = static_cast<double>(world_scale); + const double ws = static_cast<double>(_world_scale); auto clamp_axis = [](double& p, double& v, double he, double lo, double hi) { diff --git a/src/systems/word_ai_system.hpp b/src/systems/word_ai_system.hpp index d01349b..c4cea5e 100644 --- a/src/systems/word_ai_system.hpp +++ b/src/systems/word_ai_system.hpp @@ -7,6 +7,20 @@ struct Player; struct CarriedLine; class WordAiSystem { + static constexpr double TRIGGER_RANGE = 6.0; + static constexpr double IDLE_AGGRO_ROLL = 0.4; // per-second chance × aggressiveness + static constexpr double FLEE_BIAS = 0.35; // fraction of state changes that are Flee vs Attack + static constexpr double STUNNED_DURATION = 1.2; + static constexpr double FLEE_ESCAPE_DIST = 10.0; + static constexpr double FLEE_ESCAPE_TIME = 2.0; + static constexpr double STEAL_PROBABILITY = 0.5; // chance per contact + static constexpr double VELOCITY_LERP_RATE = 6.0; + static constexpr double WIGGLE_AMPLITUDE = 0.8; + + float _world_scale; + int _max_active_ai = 5; + + void update_Idle (Text3d& w, const Player& p, int active_ai_count, double dt); void update_Attack (Text3d& w, const Player& p, CarriedLine& carried, DynArray<Text3dPtr>& all_words, @@ -26,22 +40,9 @@ class WordAiSystem { void enter_Idle (Text3d& w); void apply_Locomotion(Text3d& w, const Vec3& target_vel, double dt); - - static constexpr double TRIGGER_RANGE = 6.0; - static constexpr double IDLE_AGGRO_ROLL = 0.4; // per-second chance × aggressiveness - static constexpr double FLEE_BIAS = 0.35; // fraction of state changes that are Flee vs Attack - static constexpr double STUNNED_DURATION = 1.2; - static constexpr double FLEE_ESCAPE_DIST = 10.0; - static constexpr double FLEE_ESCAPE_TIME = 2.0; - static constexpr double STEAL_PROBABILITY = 0.5; // chance per contact - static constexpr double VELOCITY_LERP_RATE = 6.0; - static constexpr double WIGGLE_AMPLITUDE = 0.8; - - float world_scale; - int max_active_ai = 5; public: - void set_MaxActiveAi(int n) { max_active_ai = n; } - void set_WorldScale(float ws) { world_scale = ws; } + void set_MaxActiveAi(int n) { _max_active_ai = n; } + void set_WorldScale (float ws) { _world_scale = ws; } void update(DynArray<Text3dPtr>& words, const Player& player, CarriedLine& carried, diff --git a/src/systems/word_anim.hpp b/src/systems/word_anim.hpp index a867546..ac53435 100644 --- a/src/systems/word_anim.hpp +++ b/src/systems/word_anim.hpp @@ -18,14 +18,14 @@ struct WordAnim_Add { struct WordAnim_Drop { Text3dPtr word; - bool complete{false}; + bool complete{false}; }; class WordAnimSystem { public: void update(DynArray<WordAnim_Add>& anims_add, - DynArray<WordAnim_Drop>& anims_drop, - CarriedLine& carried, - DynArray<Text3dPtr>& words, - double dt, double floor_y); + DynArray<WordAnim_Drop>& anims_drop, + CarriedLine& carried, + DynArray<Text3dPtr>& words, + double dt, double floor_y); }; diff --git a/src/text_3d/text_label.cpp b/src/text_3d/text_label.cpp index b363e0e..f1df0e7 100644 --- a/src/text_3d/text_label.cpp +++ b/src/text_3d/text_label.cpp @@ -19,9 +19,9 @@ split_words(const std::string& text) void TextLabel::set_Text(const std::string& text) { - if (text == current_text_) return; - current_text_ = text; - rebuild_(text); + if (text == _current_text) return; + _current_text = text; + rebuild(text); } @@ -30,7 +30,7 @@ TextLabel::set_Text(const std::string& text, SDL_FColor color, float depth, float scale) { set_Style(color, depth, scale); - current_text_.clear(); + _current_text.clear(); set_Text(text); } @@ -38,54 +38,54 @@ TextLabel::set_Text(const std::string& text, void TextLabel::clear() { - words_.clear(); - offsets_.clear(); - anchor_pos_.clear(); - jiggle_off_.clear(); - jiggle_vel_.clear(); - current_text_.clear(); + _words.clear(); + _offsets.clear(); + _anchor_pos.clear(); + _jiggle_off.clear(); + _jiggle_vel.clear(); + _current_text.clear(); } void TextLabel::set_Centre(const Vec3& p) { - mode_ = PositionMode::Absolute; - centre_ = p; - anchor_ptr_ = nullptr; + _mode = PositionMode::Absolute; + _centre = p; + _anchor_ptr = nullptr; } void TextLabel::attach_To(const Vec3* anchor, const Vec3& offset) { - mode_ = PositionMode::Anchor; - anchor_ptr_ = anchor; - attach_offset_ = offset; + _mode = PositionMode::Anchor; + _anchor_ptr = anchor; + _attach_offset = offset; } void TextLabel::detach() { - mode_ = PositionMode::Absolute; - anchor_ptr_ = nullptr; + _mode = PositionMode::Absolute; + _anchor_ptr = nullptr; } void TextLabel::set_Style(SDL_FColor color, float depth, float scale) { - style_color_ = color; - style_depth_ = depth; - style_scale_ = scale; + _style_color = color; + _style_depth = depth; + _style_scale = scale; } void TextLabel::set_Collidable(bool on) { - collidable_ = on; - for (Text3dPtr& w : words_) { + _collidable = on; + for (Text3dPtr& w : _words) { if (!w) continue; w->solid = on; w->carriable = false; @@ -96,13 +96,13 @@ TextLabel::set_Collidable(bool on) void -TextLabel::rebuild_(const std::string& text) +TextLabel::rebuild(const std::string& text) { - words_.clear(); - offsets_.clear(); - anchor_pos_.clear(); - jiggle_off_.clear(); - jiggle_vel_.clear(); + _words.clear(); + _offsets.clear(); + _anchor_pos.clear(); + _jiggle_off.clear(); + _jiggle_vel.clear(); DynArray<std::string> tokens = split_words(text); if (tokens.empty()) return; @@ -111,8 +111,8 @@ TextLabel::rebuild_(const std::string& text) DynArray<Tmp> tmp; tmp.reserve(tokens.size()); for (const std::string& tok : tokens) { - tmp.push_back({ make_Text3d(tok, style_depth_, style_scale_, - Vec3{0,0,0}, style_color_) }); + tmp.push_back({ make_Text3d(tok, _style_depth, _style_scale, + Vec3{0,0,0}, _style_color) }); } float total_w = 0.0f; @@ -122,19 +122,19 @@ TextLabel::rebuild_(const std::string& text) float x_cur = -total_w * 0.5f; for (auto& t : tmp) { float he = t.obj->half_extent; - offsets_.push_back(static_cast<double>(x_cur + he)); + _offsets.push_back(static_cast<double>(x_cur + he)); t.obj->carriable = false; t.obj->interactable = false; - t.obj->solid = collidable_; - t.obj->body.mode = collidable_ ? PhysicsMode::Static + t.obj->solid = _collidable; + t.obj->body.mode = _collidable ? PhysicsMode::Static : PhysicsMode::Hover; t.obj->body.restitution = 0.55; - words_.push_back(std::move(t.obj)); - anchor_pos_.push_back(Vec3{}); - jiggle_off_.push_back(Vec3{}); - jiggle_vel_.push_back(Vec3{}); + _words.push_back(std::move(t.obj)); + _anchor_pos.push_back(Vec3{}); + _jiggle_off.push_back(Vec3{}); + _jiggle_vel.push_back(Vec3{}); x_cur += he * 2.0f + WORD_GAP; } @@ -142,25 +142,25 @@ TextLabel::rebuild_(const std::string& text) Vec3 -TextLabel::current_Centre_() const +TextLabel::current_Centre() const { - if (mode_ == PositionMode::Anchor && anchor_ptr_) { + if (_mode == PositionMode::Anchor && _anchor_ptr) { return { - anchor_ptr_->x + attach_offset_.x, - anchor_ptr_->y + attach_offset_.y, - anchor_ptr_->z + attach_offset_.z + _anchor_ptr->x + _attach_offset.x, + _anchor_ptr->y + _attach_offset.y, + _anchor_ptr->z + _attach_offset.z }; } - return centre_; + return _centre; } void TextLabel::update(double dt, const Camera& camera) { - if (words_.empty()) return; + if (_words.empty()) return; - Vec3 centre = current_Centre_(); + Vec3 centre = current_Centre(); // ── Compute orientation ───────────────────────────────────────────── // @@ -176,7 +176,7 @@ TextLabel::update(double dt, const Camera& camera) float yaw_for_glyphs = 0.0f; float pitch_for_glyphs = 0.0f; - if (billboard_) { + if (_billboard) { Vec3 forward = camera.pos - centre; double flen = length(forward); if (flen < 0.0001) return; @@ -204,17 +204,17 @@ TextLabel::update(double dt, const Camera& camera) // what we want when the camera is above. pitch_for_glyphs = -SDL_asinf(static_cast<float>(forward.y)); } else { - yaw_for_glyphs = face_yaw_; + yaw_for_glyphs = _face_yaw; pitch_for_glyphs = 0.0f; - right = { SDL_cos(face_yaw_), 0.0, -SDL_sin(face_yaw_) }; + right = { SDL_cos(_face_yaw), 0.0, -SDL_sin(_face_yaw) }; } // ── Place each word at anchor + jiggle, apply shared orientation ──── - for (size_t i = 0; i < words_.size(); ++i) { - Text3d& t = *words_[i]; + for (size_t i = 0; i < _words.size(); ++i) { + Text3d& t = *_words[i]; if (!t.loaded) continue; - double off = offsets_[i]; + double off = _offsets[i]; // Line stays on the horizontal `right` axis through centre. Vec3 anchor{ @@ -222,11 +222,11 @@ TextLabel::update(double dt, const Camera& camera) centre.y + right.y * off, centre.z + right.z * off }; - anchor_pos_[i] = anchor; + _anchor_pos[i] = anchor; // Spring-damp the jiggle - Vec3& off3 = jiggle_off_[i]; - Vec3& vel3 = jiggle_vel_[i]; + Vec3& off3 = _jiggle_off[i]; + Vec3& vel3 = _jiggle_vel[i]; Vec3 acc{ -JIGGLE_STIFF * off3.x - JIGGLE_DAMP * vel3.x, @@ -259,7 +259,7 @@ TextLabel::update(double dt, const Camera& camera) void TextLabel::draw(GlRenderer& gl, const Camera& camera, const Light& light) const { - for (const Text3dPtr& w : words_) { + for (const Text3dPtr& w : _words) { if (!w || !w->loaded) continue; w->draw(gl, camera, light); } @@ -269,7 +269,7 @@ TextLabel::draw(GlRenderer& gl, const Camera& camera, const Light& light) const void TextLabel::kick(size_t word_index, const Vec3& projectile_vel, const Vec3& normal) { - if (word_index >= words_.size()) return; + if (word_index >= _words.size()) return; double v_into = -(projectile_vel.x * normal.x + projectile_vel.y * normal.y + @@ -278,7 +278,7 @@ TextLabel::kick(size_t word_index, const Vec3& projectile_vel, const Vec3& norma double mag = v_into * KICK_STRENGTH; - Vec3& vel3 = jiggle_vel_[word_index]; + Vec3& vel3 = _jiggle_vel[word_index]; vel3.x += -normal.x * mag; vel3.y += -normal.y * mag; vel3.z += -normal.z * mag; diff --git a/src/text_3d/text_label.hpp b/src/text_3d/text_label.hpp index 37baa79..0e768fb 100644 --- a/src/text_3d/text_label.hpp +++ b/src/text_3d/text_label.hpp @@ -10,12 +10,36 @@ class GlRenderer; class TextLabel { -public: enum class PositionMode : uint8_t { Absolute, Anchor, }; + DynArray<Text3dPtr> _words; + DynArray<double> _offsets; + DynArray<Vec3> _anchor_pos; + DynArray<Vec3> _jiggle_off; + DynArray<Vec3> _jiggle_vel; + + PositionMode _mode { PositionMode::Absolute }; + Vec3 _centre {}; + const Vec3* _anchor_ptr { nullptr }; + Vec3 _attach_offset {}; + + bool _billboard { true }; + float _face_yaw { 0.0f }; + + SDL_FColor _style_color { 1.0f, 1.0f, 0.0f, 1.0f }; + float _style_depth { 0.06f }; + float _style_scale { 0.003f }; + + bool _collidable { true }; + std::string _current_text; + + void rebuild(const std::string& text); + Vec3 current_Centre() const; + +public: static constexpr float WORD_GAP = 0.25f; static constexpr double JIGGLE_STIFF = 80.0; static constexpr double JIGGLE_DAMP = 9.0; @@ -31,40 +55,15 @@ public: void set_Centre(const Vec3& p); void attach_To(const Vec3* anchor, const Vec3& offset = {}); void detach(); - void set_Billboard(bool on) { billboard_ = on; } - void set_FaceYaw(float y) { face_yaw_ = y; } + void set_Billboard(bool on) { _billboard = on; } + void set_FaceYaw(float y) { _face_yaw = y; } void set_Style(SDL_FColor color, float depth, float scale); void set_Collidable(bool on); void update(double dt, const Camera& camera); void draw(GlRenderer& gl, const Camera& camera, const Light& light) const; const DynArray<Text3dPtr>& - words() const { return words_; } + words() const { return _words; } void kick(size_t word_index, const Vec3& projectile_vel, const Vec3& normal); - bool empty() const { return words_.empty(); } - -private: - DynArray<Text3dPtr> words_; - DynArray<double> offsets_; - DynArray<Vec3> anchor_pos_; - DynArray<Vec3> jiggle_off_; - DynArray<Vec3> jiggle_vel_; - - PositionMode mode_ { PositionMode::Absolute }; - Vec3 centre_ {}; - const Vec3* anchor_ptr_ { nullptr }; - Vec3 attach_offset_ {}; - - bool billboard_ { true }; - float face_yaw_ { 0.0f }; - - SDL_FColor style_color_ { 1.0f, 1.0f, 0.0f, 1.0f }; - float style_depth_ { 0.06f }; - float style_scale_ { 0.003f }; - - bool collidable_ { true }; - std::string current_text_; - - void rebuild_(const std::string& text); - Vec3 current_Centre_() const; + bool empty() const { return _words.empty(); } }; diff --git a/src/wall/editor_wall.cpp b/src/wall/editor_wall.cpp index 4f80b3c..a5bc98a 100644 --- a/src/wall/editor_wall.cpp +++ b/src/wall/editor_wall.cpp @@ -10,7 +10,7 @@ void EditorWall::clear() { - lines_.clear(); + _lines.clear(); } @@ -19,7 +19,7 @@ EditorWall::find_NearestLine(double y) { Line* best = nullptr; double best_dy = SNAP_THRESHOLD_Y; - for (Line& l : lines_) { + for (Line& l : _lines) { if (l.words.empty()) continue; const double center_y = l.words.front()->pos.y; // any word on the row; they share y const double dy = SDL_fabs(center_y - y); @@ -87,8 +87,8 @@ EditorWall::on_WordPlaced(Text3d* word, const Vec3& impact_pos) if (!target) { Line fresh; fresh.y = impact_pos.y; - lines_.push_back(std::move(fresh)); - target = &lines_.back(); + _lines.push_back(std::move(fresh)); + target = &_lines.back(); } const double new_half_z = word->half_extent; @@ -109,13 +109,13 @@ EditorWall::on_WordRemoved(Text3d* word) { if (!word) return; - for (auto it = lines_.begin(); it != lines_.end(); ) { + for (auto it = _lines.begin(); it != _lines.end(); ) { auto& ws = it->words; auto wit = std::find(ws.begin(), ws.end(), word); if (wit != ws.end()) { ws.erase(wit); if (ws.empty()) { - it = lines_.erase(it); + it = _lines.erase(it); return; } return; @@ -128,12 +128,12 @@ EditorWall::on_WordRemoved(Text3d* word) void EditorWall::draw(GlRenderer& gl, const Camera& cam, const Light& light) const { - if (lines_.empty()) return; + if (_lines.empty()) return; DynArray<float> verts; DynArray<int> indices; - verts.reserve(lines_.size() * 4 * 9); - indices.reserve(lines_.size() * 6); + verts .reserve(_lines.size() * 4 * 9); + indices.reserve(_lines.size() * 6); const float ws = WORLD_BOX_SCALE; const float x_front = -ws + 0.02f; @@ -142,7 +142,7 @@ EditorWall::draw(GlRenderer& gl, const Camera& cam, const Light& light) const constexpr float cr = 0.40f, cg = 0.50f, cb = 0.78f; int base = 0; - for (const Line& l : lines_) { + for (const Line& l : _lines) { if (l.words.empty()) continue; const float y_mid = static_cast<float>(l.y - UNDERLINE_DROP); diff --git a/src/wall/editor_wall.hpp b/src/wall/editor_wall.hpp index 0f21ffc..028d60c 100644 --- a/src/wall/editor_wall.hpp +++ b/src/wall/editor_wall.hpp @@ -41,7 +41,7 @@ class EditorWall size_t insert_index; }; - DynArray<Line> lines_; + DynArray<Line> _lines; Line* find_NearestLine(double y); // Decide where the new word lands on the line and shift neighbours if a @@ -77,7 +77,7 @@ public: void draw(GlRenderer& gl, const Camera& cam, const Light& light) const; // Diagnostics. - size_t line_Count() const { return lines_.size(); } + size_t line_Count() const { return _lines.size(); } - void scroll(double delta) { for (Line& l : lines_) l.y += delta; } + void scroll(double delta) { for (Line& l : _lines) l.y += delta; } }; diff --git a/src/wall/wall_surfaces.cpp b/src/wall/wall_surfaces.cpp index 976d33b..18b7bf4 100644 --- a/src/wall/wall_surfaces.cpp +++ b/src/wall/wall_surfaces.cpp @@ -107,8 +107,8 @@ build_Wall(WallSurfaces::WallQuad& out, void WallSurfaces::generate(float world_scale) { - walls_.clear(); - walls_.resize(4); + _walls.clear(); + _walls.resize(4); struct Spec { Wall::Role role; @@ -124,9 +124,9 @@ WallSurfaces::generate(float world_scale) }; for (size_t i = 0; i < 4; ++i) { - walls_[i].role = specs[i].role; - walls_[i].is_editor = specs[i].is_editor; - build_Wall(walls_[i], specs[i].pos, world_scale, specs[i].color); + _walls[i].role = specs[i].role; + _walls[i].is_editor = specs[i].is_editor; + build_Wall(_walls[i], specs[i].pos, world_scale, specs[i].color); } } @@ -134,7 +134,7 @@ WallSurfaces::generate(float world_scale) void WallSurfaces::draw(GlRenderer& gl, const Camera& cam, const Light& light) const { - if (walls_.empty()) return; + if (_walls.empty()) return; Mat4 view = buildViewMat4(cam); Mat4 proj = gl.projection(); @@ -147,7 +147,7 @@ WallSurfaces::draw(GlRenderer& gl, const Camera& cam, const Light& light) const gl.set_Light(light); gl.set_TextLineSpacing(Wall::TEXT_LINE_SPACING); - for (const WallQuad& w : walls_) { + for (const WallQuad& w : _walls) { gl.set_Color(w.color.r, w.color.g, w.color.b); gl.enable_WallPaperMode(w.is_editor); gl.set_ColorUseVertex(false); diff --git a/src/wall/wall_surfaces.hpp b/src/wall/wall_surfaces.hpp index 0057e3d..6150a17 100644 --- a/src/wall/wall_surfaces.hpp +++ b/src/wall/wall_surfaces.hpp @@ -27,14 +27,13 @@ public: Wall::Role role; DynArray<float> verts; DynArray<int> indices; - SDL_FColor color; - bool is_editor; + SDL_FColor color; + bool is_editor; }; void generate(float world_scale); void draw(GlRenderer& gl, const Camera& cam, const Light& light) const; - private: - DynArray<WallQuad> walls_; + DynArray<WallQuad> _walls; };