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.gzCleanup Rename Refractor
benchmark/bench_collision.cpp | 1 +
benchmark/bench_text_mesh.cpp | 8 +-
src/core/game.hpp | 11 +-
src/core/main.cpp | 2 +-
src/cpp_token/cpp_highlight.hpp | 14 +-
src/cpp_token/token.hpp | 6 +-
src/cpp_token/token_db.cpp | 4 +-
src/cpp_token/token_db.hpp | 15 +-
src/entities/camera.hpp | 9 +-
src/entities/game_object.hpp | 55 ++++---
src/entities/plate.cpp | 10 +-
src/entities/plate.hpp | 7 +-
src/entities/pult.cpp | 4 +-
src/entities/pult.hpp | 21 ++-
src/entities/solid_box.hpp | 19 ++-
src/entities/world.cpp | 3 +-
src/entities/world.hpp | 15 +-
src/levels/goal.cpp | 27 ++--
src/levels/goal.hpp | 18 ++-
src/levels/level.cpp | 44 ++++++
src/levels/level.hpp | 37 +++--
src/levels/level/char_copy.cpp | 12 +-
src/levels/level/sandbox.cpp | 2 +-
src/levels/level/tutorial.cpp | 48 +++---
src/levels/level_check.cpp | 39 -----
src/levels/level_check.hpp | 10 --
src/levels/scene.hpp | 68 ++++----
src/rendering/floor_mandelbrot.cpp | 22 +--
src/rendering/floor_mandelbrot.hpp | 7 +-
src/rendering/gl_renderer.cpp | 49 +++---
src/rendering/gl_renderer.hpp | 226 ++++++++++++--------------
src/states/game_context.cpp | 9 +-
src/states/game_context.hpp | 8 +-
src/states/game_state.cpp | 151 +++++++++---------
src/states/game_state.hpp | 63 ++++----
src/states/istate.hpp | 2 +
src/states/menu_state.cpp | 12 +-
src/states/menu_state.hpp | 18 +--
src/systems/aim.hpp | 27 ++--
src/systems/carry_system.cpp | 5 +
src/systems/carry_system.hpp | 8 +-
src/systems/celebration_system.cpp | 4 +-
src/systems/celebration_system.hpp | 14 +-
src/systems/collision.cpp | 29 ++--
src/systems/collision.hpp | 14 +-
src/systems/compiler_system.cpp | 18 +--
src/systems/compiler_system.hpp | 21 +--
src/systems/cpp_highlight_system.hpp | 36 +++--
src/systems/dyn_loader_system.cpp | 18 +--
src/systems/dyn_loader_system.hpp | 19 +--
src/systems/freelook_system.cpp | 4 +-
src/systems/freelook_system.hpp | 14 +-
src/systems/hint_system.hpp | 9 +-
src/systems/input_system.hpp | 13 +-
src/systems/level_director.cpp | 52 +++---
src/systems/level_director.hpp | 35 ++--
src/systems/level_runner_system.cpp | 9 +-
src/systems/level_runner_system.hpp | 22 +--
src/systems/particle_system.cpp | 7 +-
src/systems/particle_system.hpp | 26 +--
src/systems/physics_system.cpp | 30 ++--
src/systems/physics_system.hpp | 17 +-
src/systems/pick_system.cpp | 4 +-
src/systems/pick_system.hpp | 15 +-
src/systems/plate_system.cpp | 4 +-
src/systems/program_system.cpp | 26 +--
src/systems/program_system.hpp | 20 +--
src/systems/projectile_system.cpp | 24 +--
src/systems/projectile_system.hpp | 49 +++---
src/systems/pult_system.cpp | 2 +-
src/systems/pult_system.hpp | 23 +--
src/systems/wall_connection.cpp | 79 +++++-----
src/systems/wall_connection.hpp | 39 +++--
src/systems/word_ai_system.hpp | 40 ++---
src/systems/word_anim.hpp | 17 +-
src/text_3d/text_3d.cpp | 26 +--
src/text_3d/text_3d.hpp | 81 +++++-----
src/text_3d/text_file.hpp | 84 ----------
src/text_3d/text_label.cpp | 4 +-
src/text_3d/text_label.hpp | 26 +--
src/text_3d/text_mesh.cpp | 61 +++----
src/text_3d/text_mesh.hpp | 30 ++--
src/text_3d/vim_buffer.cpp | 228 +++++++++++++++++++++++++++
src/text_3d/vim_buffer.hpp | 205 +++++-------------------
src/utils/ascii.hpp | 53 -------
src/utils/carry_math.cpp | 13 +-
src/utils/carry_math.hpp | 15 +-
src/utils/config.hpp | 2 +-
src/utils/frame_profiler.hpp | 31 ++--
src/utils/globals.hpp | 14 +-
src/utils/light.hpp | 48 ++----
src/utils/math.hpp | 23 ++-
src/utils/text.cpp | 165 +++++++++++++++++++
src/utils/text.hpp | 49 ++++++
src/utils/text_wrap.hpp | 59 -------
src/wall/{editor_wall.cpp => editor.cpp} | 79 +++++-----
src/wall/{editor_wall.hpp => editor.hpp} | 21 ++-
src/wall/{wall_label.cpp => label.cpp} | 24 ++-
src/wall/{wall_surfaces.cpp => surfaces.cpp} | 64 +++++---
src/wall/{text_wall.cpp => text.cpp} | 116 +++++++++++---
src/wall/text_wall.hpp | 23 ---
src/wall/text_wall_scroll.hpp | 52 ------
src/wall/wall.cpp | 77 +++++++++
src/wall/wall.hpp | 142 ++++++++---------
src/wall/wall_label.hpp | 36 -----
src/wall/wall_surfaces.hpp | 31 ----
106 files changed, 1992 insertions(+), 1759 deletions(-)
diff --git a/benchmark/bench_collision.cpp b/benchmark/bench_collision.cpp
index 19ddff5..f9203d8 100644
--- a/benchmark/bench_collision.cpp
+++ b/benchmark/bench_collision.cpp
@@ -3,6 +3,7 @@
#include "systems/collision.hpp"
#include "entities/solid_box.hpp"
+#include "utils/globals.hpp"
#include "utils/math.hpp"
diff --git a/benchmark/bench_text_mesh.cpp b/benchmark/bench_text_mesh.cpp
index f233032..029ffcc 100644
--- a/benchmark/bench_text_mesh.cpp
+++ b/benchmark/bench_text_mesh.cpp
@@ -14,7 +14,7 @@ static void BM_BuildTextMesh_Short(benchmark::State& state)
out.tris.clear();
out.vertex_normals.clear();
benchmark::DoNotOptimize(
- buildTextMesh(out, FONT, "if", 64, 0.14f, 0.003f)
+ out.build(FONT, "if", 64, 0.14f, 0.003f)
);
}
}
@@ -29,7 +29,7 @@ static void BM_BuildTextMesh_Medium(benchmark::State& state)
out.tris.clear();
out.vertex_normals.clear();
benchmark::DoNotOptimize(
- buildTextMesh(out, FONT, "function", 64, 0.14f, 0.003f)
+ out.build(FONT, "function", 64, 0.14f, 0.003f)
);
}
}
@@ -45,7 +45,7 @@ static void BM_BuildTextMesh_Length(benchmark::State& state)
out.tris.clear();
out.vertex_normals.clear();
benchmark::DoNotOptimize(
- buildTextMesh(out, FONT, text, 64, 0.14f, 0.003f)
+ out.build(FONT, text, 64, 0.14f, 0.003f)
);
}
state.SetLabel("len=" + std::to_string(state.range(0)));
@@ -63,7 +63,7 @@ static void BM_BuildTextMesh_Depth(benchmark::State& state)
out.tris.clear();
out.vertex_normals.clear();
benchmark::DoNotOptimize(
- buildTextMesh(out, FONT, "hello", 64, depth, 0.003f)
+ out.build(FONT, "hello", 64, depth, 0.003f)
);
}
state.SetLabel("depth=" + std::to_string(depth));
diff --git a/src/core/game.hpp b/src/core/game.hpp
index 7f5bb17..7aa3f78 100644
--- a/src/core/game.hpp
+++ b/src/core/game.hpp
@@ -4,9 +4,9 @@
#include <cpputils/unique_ptr.hpp>
#include <memory>
+#include "rendering/gl_renderer.hpp"
#include "states/istate.hpp"
#include "utils/globals.hpp"
-#include "rendering/gl_renderer.hpp"
class Game
@@ -17,12 +17,11 @@ class Game
cpputils::unique_ptr<IState> m_state;
public:
~Game();
- void change_State (cpputils::unique_ptr<IState> next);
+ void change_State (cpputils::unique_ptr<IState> next);
void handle_Event (const SDL_Event& event);
- bool init ();
- void update (double dt_ns);
- void render ();
-
+ bool init ();
+ void update (double dt_ns);
+ void render ();
void shutdown ();
};
diff --git a/src/core/main.cpp b/src/core/main.cpp
index 2b77a70..172d3db 100644
--- a/src/core/main.cpp
+++ b/src/core/main.cpp
@@ -2,7 +2,7 @@
#include <SDL3/SDL_main.h>
#include "utils/config.hpp"
-#include "utils/math.hpp"
+#include "utils/globals.hpp"
#include "core/game.hpp"
#include "entities/world.hpp"
#include "entities/player.hpp"
diff --git a/src/cpp_token/cpp_highlight.hpp b/src/cpp_token/cpp_highlight.hpp
index 13e65e1..9bd26d7 100644
--- a/src/cpp_token/cpp_highlight.hpp
+++ b/src/cpp_token/cpp_highlight.hpp
@@ -3,9 +3,17 @@
#include "cpp_token/token.hpp"
#include "utils/globals.hpp"
-struct HiSpan { size_t byte_begin; size_t byte_end; TokenType type; };
-namespace CppHighlight {
- DynArray<HiSpan> classify(const std::string& source);
+struct HiSpan
+{
+ size_t byte_begin;
+ size_t byte_end;
+ TokenType type;
+};
+
+
+namespace CppHighlight
+{
+ DynArray<HiSpan> classify (const std::string& source);
TokenType classify_Word(const std::string& word);
}
diff --git a/src/cpp_token/token.hpp b/src/cpp_token/token.hpp
index 5a1aa3a..700ff85 100644
--- a/src/cpp_token/token.hpp
+++ b/src/cpp_token/token.hpp
@@ -3,7 +3,8 @@
#include <cstdint>
#include <string>
-enum class TokenType : uint8_t {
+enum class TokenType : uint8_t
+{
Delimiter,
Identifier,
Keyword,
@@ -19,7 +20,8 @@ enum class TokenType : uint8_t {
Namespace,
};
-struct Token {
+struct Token
+{
std::string text;
TokenType type;
std::string short_desc;
diff --git a/src/cpp_token/token_db.cpp b/src/cpp_token/token_db.cpp
index 457993b..e4894d0 100644
--- a/src/cpp_token/token_db.cpp
+++ b/src/cpp_token/token_db.cpp
@@ -119,7 +119,7 @@ generic_For(TokenType type)
TokenDB::Desc
-TokenDB::describe(const std::string& text, TokenType type)
+TokenDB::get_Description(const std::string& text, TokenType type)
{
const auto& t = table();
auto it = t.find(text);
@@ -130,7 +130,7 @@ TokenDB::describe(const std::string& text, TokenType type)
const char*
-TokenDB::type_Name(TokenType t)
+TokenDB::get_TypeName(TokenType t)
{
switch (t) {
case TokenType::Keyword: return "Keyword";
diff --git a/src/cpp_token/token_db.hpp b/src/cpp_token/token_db.hpp
index 8e2d59e..dd7ee79 100644
--- a/src/cpp_token/token_db.hpp
+++ b/src/cpp_token/token_db.hpp
@@ -7,11 +7,14 @@
namespace TokenDB
{
- struct Desc { std::string short_desc; std::string long_desc; };
+ struct Desc
+ {
+ std::string short_desc;
+ std::string long_desc;
+ };
- Desc describe(const std::string& text, TokenType type);
-
- const char* type_Name(TokenType type);
-
- DynArray<std::string> get_TestArrayAllKeywords();
+ const char* get_TypeName (TokenType type);
+ Desc get_Description(const std::string& text, TokenType type);
+ DynArray<std::string>
+ get_TestArrayAllKeywords();
}
diff --git a/src/entities/camera.hpp b/src/entities/camera.hpp
index aa8f82b..94be3be 100644
--- a/src/entities/camera.hpp
+++ b/src/entities/camera.hpp
@@ -2,11 +2,12 @@
#include <SDL3/SDL.h>
-#include "utils/config.hpp"
-#include "utils/math.hpp"
#include "entities/player.hpp"
+#include "utils/config.hpp"
+#include "utils/globals.hpp"
-struct Camera {
+struct Camera
+{
int32_t pitch {};
uint32_t yaw {};
double yaw_r {};
@@ -16,7 +17,7 @@ struct Camera {
Vec3 fwd {};
Vec3 right{};
- void syncFromPlayer(const Player& player)
+ void sync_FromPlayer(const Player& player)
{
pos = player.prev_pos;
yaw = player.yaw;
diff --git a/src/entities/game_object.hpp b/src/entities/game_object.hpp
index 33bc68c..e3a1888 100644
--- a/src/entities/game_object.hpp
+++ b/src/entities/game_object.hpp
@@ -1,21 +1,23 @@
#pragma once
-#include <memory>
+
#include <SDL3/SDL.h>
+#include "utils/globals.hpp"
#include "utils/light.hpp"
-#include "utils/math.hpp"
class Camera;
class GlRenderer;
-enum class ObjectType : uint8_t {
+enum class ObjectType : uint8_t
+{
Text,
Prop,
};
-enum class PhysicsMode : uint8_t {
+enum class PhysicsMode : uint8_t
+{
AiHover,
Carried,
Dynamic,
@@ -25,12 +27,14 @@ enum class PhysicsMode : uint8_t {
};
-struct CollisionShape {
+struct CollisionShape
+{
Vec3 half_extents{0.5, 0.5, 0.5};
};
-struct RigidBody {
+struct RigidBody
+{
bool hover_disturbed{false};
double friction {0.8};
double hover_height{0.0};
@@ -39,8 +43,7 @@ struct RigidBody {
double restitution {0.3};
Vec3 vel {};
Vec3 force{};
-
- PhysicsMode mode{PhysicsMode::Hover};
+ PhysicsMode mode {PhysicsMode::Hover};
RigidBody(PhysicsMode m = PhysicsMode::Hover,
@@ -50,15 +53,18 @@ struct RigidBody {
) : friction(friction_),
mass(mass_),
restitution(restitution_),
- mode(m) {}
+ mode(m)
+ {}
- void apply_Force(const Vec3& f) {
+ void apply_Force(const Vec3& f)
+ {
force.x += f.x;
force.y += f.y;
force.z += f.z;
}
- void apply_KickImpulse(const Vec3& impulse) {
+ void apply_KickImpulse(const Vec3& impulse)
+ {
if ( mode == PhysicsMode::Hover ||
mode == PhysicsMode::AiHover) {
mode = PhysicsMode::Dynamic;
@@ -69,7 +75,8 @@ struct RigidBody {
}
}
- void integrate(double dt) {
+ void integrate(double dt)
+ {
if (mode != PhysicsMode::Dynamic) return;
vel.x += (force.x / mass) * dt;
vel.y += (force.y / mass) * dt;
@@ -79,7 +86,8 @@ struct RigidBody {
};
-struct GameObject {
+struct GameObject
+{
bool carriable {true};
bool interactable {true};
bool solid {true};
@@ -93,25 +101,28 @@ struct GameObject {
GameObject() {}
- // c = carriable, a = active, i = interactable, s = solid
GameObject(Vec3 p, ObjectType t, CollisionShape sh, RigidBody b,
bool c = true, bool i = true, bool s = true)
: carriable(c), interactable(i), solid(s),
pos(p), type(t), shape(sh), body(b) {}
- virtual ~GameObject() = default;
- virtual void draw(GlRenderer&, const Camera&, const Light&) const = 0;
+ virtual
+ ~GameObject() = default;
+ virtual void
+ draw (GlRenderer&, const Camera&, const Light&) const = 0;
- Vec3 aabb_min() const {
- const double c = std::abs(SDL_cos(yaw));
- const double s = std::abs(SDL_sin(yaw));
+ Vec3 aabb_Min () const
+ {
+ const double c = SDL_fabs(SDL_cosf(yaw));
+ const double s = SDL_fabs(SDL_sinf(yaw));
const double ex = shape.half_extents.x * c + shape.half_extents.z * s;
const double ez = shape.half_extents.x * s + shape.half_extents.z * c;
return { pos.x - ex, pos.y - shape.half_extents.y, pos.z - ez };
}
- Vec3 aabb_max() const {
- const double c = std::abs(SDL_cos(yaw));
- const double s = std::abs(SDL_sin(yaw));
+ Vec3 aabb_Max () const
+ {
+ const double c = SDL_fabs(SDL_cosf(yaw));
+ const double s = SDL_fabs(SDL_sinf(yaw));
const double ex = shape.half_extents.x * c + shape.half_extents.z * s;
const double ez = shape.half_extents.x * s + shape.half_extents.z * c;
return { pos.x + ex, pos.y + shape.half_extents.y, pos.z + ez };
diff --git a/src/entities/plate.cpp b/src/entities/plate.cpp
index 091fc04..d41ff45 100644
--- a/src/entities/plate.cpp
+++ b/src/entities/plate.cpp
@@ -1,8 +1,9 @@
-#include "plate.hpp"
-
#include <SDL3/SDL.h>
-#include "rendering/gl_renderer.hpp"
+
#include "entities/camera.hpp"
+#include "plate.hpp"
+#include "rendering/gl_renderer.hpp"
+
void
Plate::tick(double dt)
@@ -18,6 +19,7 @@ Plate::tick(double dt)
was_active = active;
}
+
void
Plate::draw(GlRenderer& gl, const Camera& cam, const Light& light) const
{
@@ -26,7 +28,7 @@ Plate::draw(GlRenderer& gl, const Camera& cam, const Light& light) const
const float hz = static_cast<float>(shape.half_extents.z);
Mat4 view = buildViewMat4(cam);
- Mat4 proj = gl.projection();
+ Mat4 proj = gl.get_Projection();
Mat4 model = buildModelMat4(pos, yaw);
Mat4 mvp = Mat4::mul(proj, Mat4::mul(view, model));
diff --git a/src/entities/plate.hpp b/src/entities/plate.hpp
index 445e136..47834d2 100644
--- a/src/entities/plate.hpp
+++ b/src/entities/plate.hpp
@@ -4,7 +4,7 @@
#include "entities/solid_box.hpp"
#include "utils/light.hpp"
-#include "utils/math.hpp"
+#include "utils/globals.hpp"
class Camera;
class GlRenderer;
@@ -27,11 +27,10 @@ struct Plate final : public SolidBox
Vec3{ _HALF_W, _HALF_H, _HALF_D },
SDL_FColor{ 0.3f, 1.0f, 0.6f, 1.0f },
SDL_FColor{ 0.6f, 1.0f, 0.8f, 1.0f },
- false)
- , base_pos(world_pos)
+ false),
+ base_pos(world_pos)
{}
void tick(double dt);
-
void draw(GlRenderer& gl, const Camera& cam, const Light& light) const override;
};
diff --git a/src/entities/pult.cpp b/src/entities/pult.cpp
index 03444c6..e0521b5 100644
--- a/src/entities/pult.cpp
+++ b/src/entities/pult.cpp
@@ -31,7 +31,7 @@ void
PultButton::draw(GlRenderer& gl, const Camera& cam, const Light& light) const
{
Mat4 view = buildViewMat4(cam);
- Mat4 proj = gl.projection();
+ Mat4 proj = gl.get_Projection();
Mat4 model = buildModelMat4(pos, yaw);
Mat4 mvp = Mat4::mul(proj, Mat4::mul(view, model));
@@ -83,7 +83,7 @@ void
Pult::draw(GlRenderer& gl, const Camera& cam, const Light& light) const
{
Mat4 view = buildViewMat4(cam);
- Mat4 proj = gl.projection();
+ Mat4 proj = gl.get_Projection();
Mat4 model = buildModelMat4(pos, yaw);
Mat4 mvp = Mat4::mul(proj, Mat4::mul(view, model));
diff --git a/src/entities/pult.hpp b/src/entities/pult.hpp
index 5983119..82e4c68 100644
--- a/src/entities/pult.hpp
+++ b/src/entities/pult.hpp
@@ -6,7 +6,6 @@
#include "text_3d/text_label.hpp"
#include "utils/globals.hpp"
#include "utils/light.hpp"
-#include "utils/math.hpp"
class Camera;
class GlRenderer;
@@ -35,21 +34,21 @@ struct PultButton final : public SolidBox
PultButton(const std::string& lbl, PultAction act, Vec3 world_pos);
void press();
-
- void tick(double dt);
- void draw(GlRenderer& gl, const Camera& cam, const Light& light) const override;
+ void tick (double dt);
+ void draw (GlRenderer& gl, const Camera& cam, const Light& light) const override;
};
struct Pult : public SolidBox
{
- std::string name;
- DynArray<PultButton*> buttons;
- TextLabel label;
-
- static constexpr float W = 0.50f; // default half-width (X)
- static constexpr float H = 0.28f; // half-height (Y)
- static constexpr float D = 0.40f; // default half-depth (Z)
+ std::string name;
+ TextLabel label;
+ DynArray<PultButton*>
+ buttons;
+
+ static constexpr float W = 0.50f;
+ static constexpr float H = 0.28f;
+ static constexpr float D = 0.40f;
float half_w { W };
float half_d { D };
diff --git a/src/entities/solid_box.hpp b/src/entities/solid_box.hpp
index 0e5dac8..dc91f5b 100644
--- a/src/entities/solid_box.hpp
+++ b/src/entities/solid_box.hpp
@@ -1,10 +1,9 @@
#pragma once
+#include "entities/camera.hpp"
#include "entities/game_object.hpp"
#include "rendering/gl_renderer.hpp"
-#include "entities/camera.hpp"
#include "utils/light.hpp"
-#include "utils/math.hpp"
struct SolidBox : public GameObject
{
@@ -31,16 +30,16 @@ struct SolidBox : public GameObject
const float hy = static_cast<float>(shape.half_extents.y);
const float hz = static_cast<float>(shape.half_extents.z);
- Mat4 view = buildViewMat4(cam);
- Mat4 proj = gl.projection();
- Mat4 model = buildModelMat4(pos, yaw);
- Mat4 mvp = Mat4::mul(proj, Mat4::mul(view, model));
+ Mat4 view = buildViewMat4 (cam);
+ Mat4 model = buildModelMat4 (pos, yaw);
+ Mat4 proj = gl.get_Projection();
+ Mat4 mvp = Mat4::mul (proj, Mat4::mul(view, model));
gl.set_Wireframe(false);
- gl.set_MVP(model, mvp);
+ gl.set_MVP (model, mvp);
gl.set_NormalMat(model);
- gl.set_Light(light);
- gl.set_Color(fill_color.r, fill_color.g, fill_color.b);
- gl.draw_Box(hx, hy, hz);
+ gl.set_Light (light);
+ gl.set_Color (fill_color.r, fill_color.g, fill_color.b);
+ gl.draw_Box (hx, hy, hz);
}
};
diff --git a/src/entities/world.cpp b/src/entities/world.cpp
index e657f51..63818a5 100644
--- a/src/entities/world.cpp
+++ b/src/entities/world.cpp
@@ -1,5 +1,6 @@
#include "entities/world.hpp"
+
World::World()
{
// initEdges();
@@ -53,7 +54,7 @@ void
World::draw(GlRenderer& gl, const Camera& camera, const Light& light) const
{
Mat4 view = buildViewMat4(camera);
- Mat4 proj = gl.projection();
+ Mat4 proj = gl.get_Projection();
Mat4 model = Mat4::identity();
Mat4 mvp = Mat4::mul(proj, Mat4::mul(view, model));
diff --git a/src/entities/world.hpp b/src/entities/world.hpp
index f244aef..583a205 100644
--- a/src/entities/world.hpp
+++ b/src/entities/world.hpp
@@ -4,10 +4,11 @@
#include "entities/player.hpp"
#include "rendering/gl_renderer.hpp"
-#include "wall/wall_surfaces.hpp"
+#include "wall/wall.hpp"
-struct SweepResult {
+struct SweepResult
+{
Vec3 pos;
Vec3 vel;
bool hit_x{};
@@ -15,16 +16,18 @@ struct SweepResult {
bool hit_z{};
};
-class World {
- WallSurfaces _wall_surfaces;
+
+class World
+{
+ Wall::Surfaces _wall_surfaces;
public:
World();
+ void draw(GlRenderer& gl, const Camera& camera, const Light& light) const;
+
PlayerCollision
resolve_Player(const Player& player) const;
- void draw(GlRenderer& gl, const Camera& camera, const Light& light) const;
-
Vec3 get_SpawnPoint() const;
template <typename T = float>
diff --git a/src/levels/goal.cpp b/src/levels/goal.cpp
index 2c029eb..67a49a7 100644
--- a/src/levels/goal.cpp
+++ b/src/levels/goal.cpp
@@ -1,10 +1,10 @@
-#include "goal.hpp"
-#include "level_check.hpp"
-
#include <algorithm>
+#include "goal.hpp"
+#include "level.hpp"
+
-namespace {
+namespace Goal {
bool
contains(const DynArray<std::string>& v, const std::string& s)
@@ -18,11 +18,9 @@ contains(const DynArray<PultAction>& v, PultAction a)
return std::find(v.begin(), v.end(), a) != v.end();
}
-} // namespace
-
bool
-goal_Satisfied(const Goal& g, const GoalContext& ctx)
+is_Satisfied(const Type& g, const Context& ctx)
{
return std::visit([&ctx](const auto& concrete) -> bool {
using T = std::decay_t<decltype(concrete)>;
@@ -47,17 +45,17 @@ goal_Satisfied(const Goal& g, const GoalContext& ctx)
else if constexpr (std::is_same_v<T, CompilePattern>) {
if (!ctx.compile_ok_this_step) return false;
if (concrete.pattern.empty()) return true;
- return LevelCheck::contains_pattern(ctx.editor_normalized,
+ return Level::Check::contains_Pattern(ctx.editor_normalized,
concrete.pattern);
}
else if constexpr (std::is_same_v<T, AnyOf>) {
- for (const Goal& sub : concrete.options)
- if (goal_Satisfied(sub, ctx)) return true;
+ for (const Type& sub : concrete.options)
+ if (Goal::is_Satisfied(sub, ctx)) return true;
return false;
}
else if constexpr (std::is_same_v<T, AllOf>) {
- for (const Goal& sub : concrete.options)
- if (!goal_Satisfied(sub, ctx)) return false;
+ for (const Type& sub : concrete.options)
+ if (!Goal::is_Satisfied(sub, ctx)) return false;
return !concrete.options.empty();
}
else if constexpr (std::is_same_v<T, AiWordDefeated>) {
@@ -66,7 +64,10 @@ goal_Satisfied(const Goal& g, const GoalContext& ctx)
return contains(ctx.ai_words_defeated_this_step, concrete.text);
}
else {
- static_assert(sizeof(T) == 0, "Unhandled Goal alternative");
+ static_assert(sizeof(T) == 0, "Unhandled Type alternative");
}
}, g);
}
+
+
+} // namespace Type
diff --git a/src/levels/goal.hpp b/src/levels/goal.hpp
index 46e458e..de5137e 100644
--- a/src/levels/goal.hpp
+++ b/src/levels/goal.hpp
@@ -7,6 +7,9 @@
#include "utils/globals.hpp"
+namespace Goal
+{
+
struct ReachPlate { std::string tag; };
struct PressButton { PultAction action; };
struct CollectWord { std::string text; };
@@ -20,7 +23,7 @@ struct AnyOf;
struct AllOf;
-using Goal = std::variant<
+using Type = std::variant<
ReachPlate,
PressButton,
CollectWord,
@@ -33,15 +36,12 @@ using Goal = std::variant<
>;
-// Composition: any one option satisfies the goal.
-struct AnyOf { DynArray<Goal> options; };
+struct AnyOf { DynArray<Type> options; };
-// Composition: all options must hold simultaneously.
-// Empty AllOf{} is intentionally unsatisfiable.
-struct AllOf { DynArray<Goal> options; };
+struct AllOf { DynArray<Type> options; };
-struct GoalContext {
+struct Context {
DynArray<std::string> active_plate_tags;
DynArray<PultAction> buttons_pressed_this_step;
DynArray<std::string> picked_up_this_step;
@@ -55,4 +55,6 @@ struct GoalContext {
};
-bool goal_Satisfied(const Goal& g, const GoalContext& ctx);
+bool is_Satisfied(const Type& g, const Context& ctx);
+
+} // namespace Goal
diff --git a/src/levels/level.cpp b/src/levels/level.cpp
new file mode 100644
index 0000000..294adeb
--- /dev/null
+++ b/src/levels/level.cpp
@@ -0,0 +1,44 @@
+#include <cctype>
+
+#include "level.hpp"
+
+namespace Level
+{
+
+namespace Check
+{
+
+ std::string
+ normalize(const std::string& s)
+ {
+ std::string out;
+ out.reserve(s.size());
+
+ bool last_space = true;
+ for (char c : s) {
+ if (std::isspace(static_cast<unsigned char>(c))) {
+ if (!last_space) {
+ out += ' ';
+ last_space = true;
+ }
+ }
+ else {
+ out += c;
+ last_space = false;
+ }
+ }
+ if (!out.empty() && out.back() == ' ')
+ out.pop_back();
+ return out;
+ }
+
+ bool
+ contains_Pattern(const std::string& haystack, const std::string& needle)
+ {
+ if (needle.empty()) return true;
+ std::string norm_needle = normalize(needle);
+ return haystack.find(norm_needle) != std::string::npos;
+ }
+
+} // namespace Check
+} // namespace Level
diff --git a/src/levels/level.hpp b/src/levels/level.hpp
index eb9dcc7..0adf036 100644
--- a/src/levels/level.hpp
+++ b/src/levels/level.hpp
@@ -9,9 +9,18 @@
namespace Level
{
- struct TokenGrant {
- DynArray<std::string> choices;
+ namespace Check
+ {
+ std::string normalize(const std::string& s);
+ bool contains_Pattern(const std::string& haystack,
+ const std::string& needle);
+ }
+
+ struct TokenGrant
+ {
+ DynArray<std::string>
+ choices;
static TokenGrant give(const std::string& text)
{ return { { text } }; }
static TokenGrant choice(std::initializer_list<std::string> options)
@@ -19,12 +28,13 @@ namespace Level
};
- struct Step {
- bool reset_carry = false;
- int max_ai_words = 5;
+ struct Step
+ {
+ bool reset_carry = false;
+ int max_ai_words = 5;
- Scene scene;
- Goal goal = AllOf{};
+ Scene::Data scene;
+ Goal::Type goal = Goal::AllOf{};
std::string hint;
std::string details;
@@ -33,7 +43,8 @@ namespace Level
};
- struct Data {
+ struct Data
+ {
bool dynamic_lib = false;
std::string name;
@@ -47,16 +58,18 @@ namespace Level
extern Data build_Sandbox ();
extern Data build_Tutorial();
- inline const DynArray<Data> levels =
- {
+ inline const DynArray<Data>
+ levels = {
build_CharCopy(),
build_Sandbox (),
build_Tutorial(),
};
- inline const Data& get_Level(size_t i)
+ inline const Data&
+ get_Data(size_t i)
{ return levels[i]; }
- inline size_t level_Count()
+ inline size_t
+ get_Count()
{ return levels.size(); }
}
diff --git a/src/levels/level/char_copy.cpp b/src/levels/level/char_copy.cpp
index db2ff62..4e579de 100644
--- a/src/levels/level/char_copy.cpp
+++ b/src/levels/level/char_copy.cpp
@@ -15,7 +15,7 @@ Level::build_CharCopy()
.reset_carry = false,
.max_ai_words = 3,
.scene = {},
- .goal = CompilePattern{ "int main ( void ) { return 0 ; }" },
+ .goal = Goal::CompilePattern{ "int main ( void ) { return 0 ; }" },
.hint = "Build a working main()",
.details = R"(C programs start at main().
@@ -46,7 +46,7 @@ Grab tokens and arrange them on the editor wall.)",
.reset_carry = false,
.max_ai_words = 3,
.scene = {},
- .goal = CompilePattern{ "void copy_str ( char src [ ] , char dst [ ] ) { }" },
+ .goal = Goal::CompilePattern{ "void copy_str ( char src [ ] , char dst [ ] ) { }" },
.hint = "Declare the copy_str function",
.details = R"(Now add a function above main().
@@ -85,7 +85,7 @@ Place this BEFORE main.)",
.reset_carry = false,
.max_ai_words = 3,
.scene = {},
- .goal = CompilePattern{ "void copy_str ( char src [ ] , char dst [ ] ) { int i ; }" },
+ .goal = Goal::CompilePattern{ "void copy_str ( char src [ ] , char dst [ ] ) { int i ; }" },
.hint = "Add a loop counter inside copy_str",
.details = R"(Inside copy_str's body, declare an integer
to track our position in the array.
@@ -106,7 +106,7 @@ of copy_str.)",
.reset_carry = false,
.max_ai_words = 3,
.scene = {},
- .goal = CompilePattern{ "for ( i = 0 ; i < strlen ( src ) ; i ++ ) { }" },
+ .goal = Goal::CompilePattern{ "for ( i = 0 ; i < strlen ( src ) ; i ++ ) { }" },
.hint = "Loop through src",
.details = R"(Add a for loop after 'int i;'.
@@ -132,7 +132,7 @@ This is the loop scaffold only — the body comes next.)",
.reset_carry = false,
.max_ai_words = 3,
.scene = {},
- .goal = CompilePattern{ "dst [ i ] = src [ i ] ;" },
+ .goal = Goal::CompilePattern{ "dst [ i ] = src [ i ] ;" },
.hint = "Copy one character per iteration",
.details = R"(Inside the for loop body, copy src[i] into dst[i].
@@ -153,7 +153,7 @@ Goal (inside the for loop):
.reset_carry = false,
.max_ai_words = 3,
.scene = {},
- .goal = CompilePattern{ "char dst [ 100 ] ; copy_str ( \"hello\" , dst ) ; printf ( \"%s\" , dst ) ;" },
+ .goal = Goal::CompilePattern{ "char dst [ 100 ] ; copy_str ( \"hello\" , dst ) ; printf ( \"%s\" , dst ) ;" },
.hint = "Call copy_str and print the result",
.details = R"(In main(), do three things before 'return 0;':
diff --git a/src/levels/level/sandbox.cpp b/src/levels/level/sandbox.cpp
index 32558b4..fdcd169 100644
--- a/src/levels/level/sandbox.cpp
+++ b/src/levels/level/sandbox.cpp
@@ -15,7 +15,7 @@ Level::build_Sandbox()
.reset_carry = true,
.max_ai_words = 0,
.scene = {},
- .goal = AllOf{},
+ .goal = Goal::AllOf{},
.hint = "Spawn a box with box(x,y,z, hx,hy,hz);",
.details = R"(This level IS the code you write.
diff --git a/src/levels/level/tutorial.cpp b/src/levels/level/tutorial.cpp
index 4603f63..f60398f 100644
--- a/src/levels/level/tutorial.cpp
+++ b/src/levels/level/tutorial.cpp
@@ -14,7 +14,7 @@ Level::build_Tutorial()
{
.reset_carry = true,
.max_ai_words = 0,
- .scene = Scene{
+ .scene = Scene::Data{
.ai_seeds = {},
.plates = {
{ .pos = { 8.6, World::get_FloorY<double>() + 2.2, 0.0 }, .tag = "" },
@@ -26,7 +26,7 @@ Level::build_Tutorial()
},
.words = {},
},
- .goal = ReachPlate{ "" },
+ .goal = Goal::ReachPlate{ "" },
.hint = "Jump up the steps to the plate",
.details = R"(Press SPACE to jump.
@@ -42,7 +42,7 @@ Jump on the plate on top of the platform. )",
{
.reset_carry = true,
.max_ai_words = 0,
- .scene = Scene{
+ .scene = Scene::Data{
.ai_seeds = {},
.plates = {
{ .pos = { 0.0, World::get_FloorY<double>() + 1.2, 6.0 }, .tag = "" },
@@ -52,7 +52,7 @@ Jump on the plate on top of the platform. )",
},
.words = {},
},
- .goal = ReachPlate{ "" },
+ .goal = Goal::ReachPlate{ "" },
.hint = "Look at each wall, then jump onto the plate",
.details = R"(Move the mouse to look around.
@@ -68,7 +68,7 @@ Four walls surround you:
{
.reset_carry = true,
.max_ai_words = 0,
- .scene = Scene{
+ .scene = Scene::Data{
.ai_seeds = {},
.plates = {},
.platforms = {},
@@ -76,7 +76,7 @@ Four walls surround you:
{ .pos = { 5.0, World::get_FloorY<double>() + 1.5, 0.0 }, .text = "hello" },
},
},
- .goal = CollectWord{ "hello" },
+ .goal = Goal::CollectWord{ "hello" },
.hint = "Walk into the floating word and press 'e'",
.details = R"(Words float in the air.
@@ -91,7 +91,7 @@ Picked words trail in front of you as you move.
{
.reset_carry = false,
.max_ai_words = 0,
- .scene = Scene{
+ .scene = Scene::Data{
.ai_seeds = {},
.plates = {},
.platforms = {},
@@ -101,10 +101,10 @@ Picked words trail in front of you as you move.
{ .pos = { -5.0, World::get_FloorY<double>() + 1.5, -3.0 }, .text = "pressed", },
},
},
- .goal = AllOf{{
- CollectWord{ "keep" },
- CollectWord{ "e" },
- CollectWord{ "pressed" },
+ .goal = Goal::AllOf{{
+ Goal::CollectWord{ "keep" },
+ Goal::CollectWord{ "e" },
+ Goal::CollectWord{ "pressed" },
}},
.hint = "Keep 'e' pressed and pick up all words.",
.details = R"(You can carry several words at once.
@@ -118,7 +118,7 @@ They queue up in the order you grab them.)",
.reset_carry = false,
.max_ai_words = 0,
.scene = {},
- .goal = DroppedWord{},
+ .goal = Goal::DroppedWord{},
.hint = "Press 'q' to drop a word",
.details = R"('q' drops the most recently picked word.
@@ -138,7 +138,7 @@ putting back something you grabbed by mistake.)",
{ .pos = { 2.0, World::get_FloorY<double>() + 1.5, -3.0 }, .text = "pressed" },
},
},
- .goal = ShotWord{},
+ .goal = Goal::ShotWord{},
.hint = "LEFT CLICK to throw a word (you can keep it pressed)",
.details = R"(Left click throws the word at the front of your line.
@@ -157,7 +157,7 @@ Carrying several? Tap F to throw the WHOLE line at once.)",
{ .pos = { 0.0, World::get_FloorY<double>() + 1.5, -3.0 }, .text = "flush",},
},
},
- .goal = ShotWord{},
+ .goal = Goal::ShotWord{},
.hint = "Press 'f' to flush all carried words",
.details = R"(Bla blub
...)",
@@ -167,7 +167,7 @@ Carrying several? Tap F to throw the WHOLE line at once.)",
{
.reset_carry = true,
.max_ai_words = 0,
- .scene = Scene{
+ .scene = Scene::Data{
.ai_seeds = {
{
.aggressiveness = 1.0,
@@ -186,7 +186,7 @@ Carrying several? Tap F to throw the WHOLE line at once.)",
{ .pos = { 6.0, World::get_FloorY<double>() + 1.5, 1.0 }, .text = "ammo", },
},
},
- .goal = AllOf{{ CollectWord{ "ammo" }, AiWordDefeated{ "danger" } }},
+ .goal = Goal::AllOf{{ Goal::CollectWord{ "ammo" }, Goal::AiWordDefeated{ "danger" } }},
.hint = "Grab the ammo, then shoot the red word",
.details = R"(Some words turn red and chase you to steal what
you carry.
@@ -201,7 +201,7 @@ reaches you.)",
.reset_carry = true,
.max_ai_words = 0,
.scene = {},
- .goal = CompilePattern{ "int main ( void ) { return 0 ; }" },
+ .goal = Goal::CompilePattern{ "int main ( void ) { return 0 ; }" },
.hint = "Build int main(void) { return 0; } and press BUILD",
.details = R"(Now make code.
@@ -237,9 +237,9 @@ press it (or press 'c' to compile).)",
.reset_carry = false,
.max_ai_words = 0,
.scene = {},
- .goal = AllOf{{
- CompilePattern{ "int main ( void ) { printf ( \"hello\" ) ; return 0 ; }" },
- PressButton{ PultAction::RunProgram },
+ .goal = Goal::AllOf{{
+ Goal::CompilePattern{ "int main ( void ) { printf ( \"hello\" ) ; return 0 ; }" },
+ Goal::PressButton{ PultAction::RunProgram },
}},
.hint = "Add printf, BUILD, then press RUN",
.details = R"(A program that does nothing is dull. Make it print.
@@ -267,7 +267,7 @@ the Program wall — and that's what finishes this step.)",
{
.reset_carry = false,
.max_ai_words = 0,
- .scene = Scene{
+ .scene = Scene::Data{
.ai_seeds = {},
.plates = {
{ .pos = { 0.0, World::get_FloorY<double>() + 1.2, -6.0 }, .tag = "" },
@@ -277,7 +277,7 @@ the Program wall — and that's what finishes this step.)",
},
.words = {},
},
- .goal = ReachPlate{ "" },
+ .goal = Goal::ReachPlate{ "" },
.hint = "Try the editor pults, then jump onto the plate",
.details = R"(A few tools for managing the Editor wall:
@@ -308,7 +308,7 @@ Have a play, then jump onto the plate to continue.)",
{
.reset_carry = true,
.max_ai_words = 0,
- .scene = Scene{
+ .scene = Scene::Data{
.ai_seeds = {},
.plates = {
{ .pos = { 0.0, World::get_FloorY<double>() + 1.2, 0.0 }, .tag = "" },
@@ -318,7 +318,7 @@ Have a play, then jump onto the plate to continue.)",
},
.words = {},
},
- .goal = ReachPlate{ "" },
+ .goal = Goal::ReachPlate{ "" },
.hint = "Jump onto the plate to begin \"Char Copy\"",
.details = R"(You're ready.
diff --git a/src/levels/level_check.cpp b/src/levels/level_check.cpp
deleted file mode 100644
index 5ee94a5..0000000
--- a/src/levels/level_check.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-#include "level_check.hpp"
-#include <cctype>
-
-namespace LevelCheck {
-
-std::string
-normalize(const std::string& s)
-{
- std::string out;
- out.reserve(s.size());
-
- bool last_space = true; // treat start as if previous was space (trims leading)
- for (char c : s) {
- if (std::isspace(static_cast<unsigned char>(c))) {
- if (!last_space) {
- out += ' ';
- last_space = true;
- }
- }
- else {
- out += c;
- last_space = false;
- }
- }
- // Trim trailing space if any
- if (!out.empty() && out.back() == ' ')
- out.pop_back();
- return out;
-}
-
-bool
-contains_pattern(const std::string& haystack, const std::string& needle)
-{
- if (needle.empty()) return true;
- std::string norm_needle = normalize(needle);
- return haystack.find(norm_needle) != std::string::npos;
-}
-
-}
diff --git a/src/levels/level_check.hpp b/src/levels/level_check.hpp
deleted file mode 100644
index 21d13b6..0000000
--- a/src/levels/level_check.hpp
+++ /dev/null
@@ -1,10 +0,0 @@
-#pragma once
-#include <string>
-
-namespace LevelCheck
-{
- std::string
- normalize(const std::string& s);
-
- bool contains_pattern(const std::string& haystack, const std::string& needle);
-}
diff --git a/src/levels/scene.hpp b/src/levels/scene.hpp
index 8f74766..fc6f5be 100644
--- a/src/levels/scene.hpp
+++ b/src/levels/scene.hpp
@@ -5,47 +5,59 @@
#include "text_3d/text_3d.hpp"
#include "utils/globals.hpp"
-#include "utils/math.hpp"
-struct PlacedWord {
- bool required = false;
- Vec3 pos {};
+namespace Scene
+{
- SDL_FColor color = ConfigColor::floor;
- std::string text;
-};
+ namespace Placed
+ {
+ struct Word
+ {
+ bool required = false;
+ Vec3 pos {};
+ SDL_FColor color = ConfigColor::floor;
+ std::string text;
+ };
-struct PlacedPlate {
- Vec3 pos;
- std::string tag;
-};
+ struct Plate
+ {
+ Vec3 pos;
+ std::string tag;
+ };
-struct PlacedPlatform {
- Vec3 pos;
- Vec3 half_extents { 1.0, 0.2, 1.0 };
- SDL_FColor fill_color { 0.45f, 0.45f, 0.65f, 1.0f };
- SDL_FColor wire_color { 0.70f, 0.70f, 0.90f, 1.0f };
-};
+ struct Platform
+ {
+ Vec3 pos;
+ Vec3 half_extents { 1.0, 0.2, 1.0 };
+ SDL_FColor fill_color { 0.45f, 0.45f, 0.65f, 1.0f };
+ SDL_FColor wire_color { 0.70f, 0.70f, 0.90f, 1.0f };
+ };
-struct PlacedAi {
- double aggressiveness = 1.0;
- Vec3 pos;
- std::string text;
+ struct Ai
+ {
+ double aggressiveness = 1.0;
+ Vec3 pos;
- Text3dAI::State initial_state = Text3dAI::State::Attack;
-};
+ std::string text;
+
+ Text3dAI::State initial_state = Text3dAI::State::Attack;
+ };
+ } // namespace Placed::
-struct Scene {
- DynArray<PlacedAi> ai_seeds {};
- DynArray<PlacedPlate> plates {};
- DynArray<PlacedPlatform> platforms{};
- DynArray<PlacedWord> words {};
+struct Data
+{
+ DynArray<Placed::Ai> ai_seeds {};
+ DynArray<Placed::Plate> plates {};
+ DynArray<Placed::Platform> platforms{};
+ DynArray<Placed::Word> words {};
};
+
+} // namespace Scene
diff --git a/src/rendering/floor_mandelbrot.cpp b/src/rendering/floor_mandelbrot.cpp
index 5c05a2c..2001635 100644
--- a/src/rendering/floor_mandelbrot.cpp
+++ b/src/rendering/floor_mandelbrot.cpp
@@ -60,21 +60,21 @@ FloorMandelbrot::draw(GlRenderer& gl, const Camera& cam, const Light& light) con
{
if (_verts.empty()) return;
- Mat4 view = buildViewMat4(cam);
- Mat4 proj = gl.projection();
- Mat4 model = Mat4::identity();
- Mat4 mvp = Mat4::mul(proj, Mat4::mul(view, model));
+ Mat4 view = buildViewMat4 (cam);
+ Mat4 proj = gl.get_Projection();
+ Mat4 model = Mat4::identity ();
+ Mat4 mvp = Mat4::mul (proj, Mat4::mul(view, model));
gl.set_Wireframe(false);
- gl.set_MVP(model, mvp);
+ gl.set_MVP (model, mvp);
gl.set_NormalMat(model);
- gl.set_Light(light);
+ gl.set_Light (light);
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.set_ColorUseVertex (false);
+ 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 7c68419..6f5a269 100644
--- a/src/rendering/floor_mandelbrot.hpp
+++ b/src/rendering/floor_mandelbrot.hpp
@@ -5,14 +5,15 @@
#include "rendering/gl_renderer.hpp"
#include "utils/globals.hpp"
#include "utils/light.hpp"
-#include "utils/math.hpp"
+
class Camera;
-class FloorMandelbrot {
- DynArray<float> _verts;
+class FloorMandelbrot
+{
DynArray<int> _indices;
+ DynArray<float> _verts;
public:
void generate(float world_scale,
float floor_y,
diff --git a/src/rendering/gl_renderer.cpp b/src/rendering/gl_renderer.cpp
index fb9a861..88ce1be 100644
--- a/src/rendering/gl_renderer.cpp
+++ b/src/rendering/gl_renderer.cpp
@@ -432,10 +432,10 @@ bool GlRenderer::init(SDL_Window* window)
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to initialize GLAD"); return false;
}
- GLuint vert = compileShader(GL_VERTEX_SHADER, kVertSrc);
- GLuint frag = compileShader(GL_FRAGMENT_SHADER, kFragSrc);
+ GLuint vert = compile_Shader(GL_VERTEX_SHADER, kVertSrc);
+ GLuint frag = compile_Shader(GL_FRAGMENT_SHADER, kFragSrc);
if (!vert || !frag) return false;
- if (!linkProgram(vert, frag)) return false;
+ if (!link_Program(vert, frag)) return false;
glDeleteShader(vert);
glDeleteShader(frag);
@@ -513,8 +513,8 @@ bool GlRenderer::init(SDL_Window* window)
create_CompositeProgram_();
{ // crosshair: reuse the blit vertex shader (vec2 aPos @ loc 0)
- GLuint v = compileShader(GL_VERTEX_SHADER, kBlitVertSrc);
- GLuint f = compileShader(GL_FRAGMENT_SHADER, kCrosshairFragSrc);
+ GLuint v = compile_Shader(GL_VERTEX_SHADER, kBlitVertSrc);
+ GLuint f = compile_Shader(GL_FRAGMENT_SHADER, kCrosshairFragSrc);
_crosshair_prog = glCreateProgram();
glAttachShader(_crosshair_prog, v);
glAttachShader(_crosshair_prog, f);
@@ -669,9 +669,9 @@ void GlRenderer::set_Light(const Light& light)
{
// Sun
glUniform3f(_uLightDir,
- (float)light.direction.x,
- (float)light.direction.y,
- (float)light.direction.z);
+ (float)light.sun_direction.x,
+ (float)light.sun_direction.y,
+ (float)light.sun_direction.z);
glUniform3f(_uSunColor,
(float)light.sun_color.x,
(float)light.sun_color.y,
@@ -955,7 +955,7 @@ GlRenderer::draw_Emissive(const Camera& cam,
// ─────────────────────────────────────────────────────────────────────────────
// Shader helpers
// ─────────────────────────────────────────────────────────────────────────────
-GLuint GlRenderer::compileShader(GLenum type, const char* src)
+GLuint GlRenderer::compile_Shader(GLenum type, const char* src)
{
GLuint s = glCreateShader(type);
glShaderSource(s, 1, &src, nullptr);
@@ -969,7 +969,7 @@ GLuint GlRenderer::compileShader(GLenum type, const char* src)
return s;
}
-bool GlRenderer::linkProgram(GLuint vert, GLuint frag)
+bool GlRenderer::link_Program(GLuint vert, GLuint frag)
{
_prog = glCreateProgram();
glAttachShader(_prog, vert); glAttachShader(_prog, frag);
@@ -983,13 +983,18 @@ bool GlRenderer::linkProgram(GLuint vert, GLuint frag)
return true;
}
-float GlRenderer::aspect() const { return _aspect; }
-const Mat4& GlRenderer::projection() const { return _proj; }
+float
+GlRenderer::get_Aspect() const { return _aspect; }
-void GlRenderer::enable_MandelbrotMode(bool on)
+const Mat4&
+GlRenderer::get_Projection() const { return _proj; }
+
+void
+GlRenderer::enable_MandelbrotMode(bool on)
{ glUniform1i(_uMandelbrot, on ? 1 : 0); }
-void GlRenderer::enable_WallPaperMode(bool on)
+void
+GlRenderer::enable_WallPaperMode(bool on)
{ glUniform1i(_uWallPaper, on ? 1 : 0); }
@@ -1018,8 +1023,8 @@ GlRenderer::create_FullscreenQuad_()
void
GlRenderer::create_BlitProgram_()
{
- GLuint v = compileShader(GL_VERTEX_SHADER, kBlitVertSrc);
- GLuint f = compileShader(GL_FRAGMENT_SHADER, kBlitFragSrc);
+ GLuint v = compile_Shader(GL_VERTEX_SHADER, kBlitVertSrc);
+ GLuint f = compile_Shader(GL_FRAGMENT_SHADER, kBlitFragSrc);
_blit_prog = glCreateProgram();
glAttachShader(_blit_prog, v);
glAttachShader(_blit_prog, f);
@@ -1087,8 +1092,8 @@ GlRenderer::create_FBO_(int w, int h)
void
GlRenderer::create_ExtractProgram_()
{
- GLuint v = compileShader(GL_VERTEX_SHADER, kBlitVertSrc);
- GLuint f = compileShader(GL_FRAGMENT_SHADER, kExtractFragSrc);
+ GLuint v = compile_Shader(GL_VERTEX_SHADER, kBlitVertSrc);
+ GLuint f = compile_Shader(GL_FRAGMENT_SHADER, kExtractFragSrc);
_extract_prog = glCreateProgram();
glAttachShader(_extract_prog, v);
glAttachShader(_extract_prog, f);
@@ -1100,8 +1105,8 @@ GlRenderer::create_ExtractProgram_()
void
GlRenderer::create_BlurProgram_()
{
- GLuint v = compileShader(GL_VERTEX_SHADER, kBlitVertSrc);
- GLuint f = compileShader(GL_FRAGMENT_SHADER, kBlurFragSrc);
+ GLuint v = compile_Shader(GL_VERTEX_SHADER, kBlitVertSrc);
+ GLuint f = compile_Shader(GL_FRAGMENT_SHADER, kBlurFragSrc);
_blur_prog = glCreateProgram();
glAttachShader(_blur_prog, v);
glAttachShader(_blur_prog, f);
@@ -1227,8 +1232,8 @@ GlRenderer::run_BloomPipeline_()
void
GlRenderer::create_CompositeProgram_()
{
- GLuint v = compileShader(GL_VERTEX_SHADER, kBlitVertSrc);
- GLuint f = compileShader(GL_FRAGMENT_SHADER, kCompositeFragSrc);
+ GLuint v = compile_Shader(GL_VERTEX_SHADER, kBlitVertSrc);
+ GLuint f = compile_Shader(GL_FRAGMENT_SHADER, kCompositeFragSrc);
_composite_prog = glCreateProgram();
glAttachShader(_composite_prog, v);
glAttachShader(_composite_prog, f);
diff --git a/src/rendering/gl_renderer.hpp b/src/rendering/gl_renderer.hpp
index d45c782..b8e3e59 100644
--- a/src/rendering/gl_renderer.hpp
+++ b/src/rendering/gl_renderer.hpp
@@ -1,41 +1,40 @@
#pragma once
-// ─────────────────────────────────────────────────────────────────────────────
-// GlRenderer
-//
-// Shader uniforms:
-// u_MVP mat4 — model-view-projection
-// u_NormalMat mat3 — transpose(inverse(MV))
-// u_Color vec3 — base object colour
-// u_LightDir vec3 — world-space light direction (normalised, toward light)
-// u_Ambient vec3 — RGB ambient floor colour
-// u_Intensity float — diffuse scale
-// u_Wireframe bool — when true: skip lighting, output u_Color directly
-// ─────────────────────────────────────────────────────────────────────────────
-
#include <SDL3/SDL.h>
#include <glad/glad.h>
#include "entities/camera.hpp"
#include "utils/globals.hpp"
#include "utils/light.hpp"
-#include "utils/math.hpp"
-struct Mat4 {
+
+struct Mat4
+{
float m[16]{};
static Mat4 identity();
static Mat4 perspective(float fovY_rad, float aspect, float near, float far);
static Mat4 mul(const Mat4& a, const Mat4& b);
};
-Mat4 buildViewMat4(const Camera& cam);
+Mat4 buildViewMat4 (const Camera& cam);
Mat4 buildModelMat4(const Vec3& pos, float yaw);
Mat4 buildModelMat4(const Vec3& pos, float yaw, float pitch);
-class GlRenderer {
- int _view_w{1}, _view_h{1};
- float _aspect{1.0f};
+class GlRenderer
+{
+ bool _crosshair_enabled {true};
+ int _view_w {1};
+ int _view_h {1};
+ int _fbo_w {0};
+ int _fbo_h {0};
+ int _msaa_samples {4};
+ int _blur_w {0};
+ int _blur_h {0};
+ float _bloom_strength { 0.6f };
+ float _aspect {1.0f};
+
+
Mat4 _proj;
SDL_GLContext _ctx{};
GLuint _prog{};
@@ -66,144 +65,121 @@ class GlRenderer {
GLint _uMandelbrot {-1};
GLint _uWallPaper {-1};
GLint _uTextLineSpacing{-1};
+ GLint _uUseVertexColor {-1};
- GLuint _emissive_prog{},
- _emissive_vao{},
- _emissive_vbo{},
- _emissive_ebo{};
+ GLuint _emissive_prog {},
+ _emissive_vao {},
+ _emissive_vbo {},
+ _emissive_ebo {};
- GLint _uEmissiveMVP {-1};
+ GLint _uEmissiveMVP {-1};
- GLuint _vao{}, _vbo{}, _ebo{};
- GLuint _vao_c{}, _vbo_c{}, _ebo_c{}; // VAO/VBO/EBO for colored mesh
- GLint _uUseVertexColor{-1};
+ GLuint _vao{}, _vbo{}, _ebo{};
+ GLuint _vao_c{}, _vbo_c{}, _ebo_c{}; // VAO/VBO/EBO for colored mesh
GLuint _line_vao{}, _line_vbo{};
GLuint _menu_vao{}, _menu_vbo{};
- // Scene FBO: where the main rendering pass writes.
- GLuint _scene_fbo {0};
- GLuint _scene_color_tex {0};
- GLuint _scene_depth_rbo {0};
- GLuint _scene_fbo_ms {0};
- GLuint _scene_color_rbo_ms {0};
- GLuint _scene_depth_rbo_ms {0};
- int _msaa_samples {4};
- int _fbo_w {0};
- int _fbo_h {0};
+ GLuint _scene_fbo {0},
+ _scene_color_tex {0},
+ _scene_depth_rbo {0},
+ _scene_fbo_ms {0},
+ _scene_color_rbo_ms {0},
+ _scene_depth_rbo_ms {0};
- // Fullscreen-quad geometry for compositing passes.
- GLuint _fullscreen_vao {0};
- GLuint _fullscreen_vbo {0};
+ GLuint _fullscreen_vao {0},
+ _fullscreen_vbo {0};
- // Blit program: samples scene texture, writes to screen unchanged.
GLuint _blit_prog {0};
GLint _uBlitTex {-1};
- // Half-resolution FBOs for the blur ping-pong.
- 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};
-
- // Crosshair: tiny screen-space overlay, inverts the pixels behind it.
- GLuint _crosshair_prog {0};
- GLuint _crosshair_vao {0};
- GLuint _crosshair_vbo {0};
- bool _crosshair_enabled {true};
-
- // Programs
- GLuint _extract_prog {0};
- GLuint _blur_prog {0};
- GLuint _composite_prog {0};
-
- // Uniforms
+ GLuint _bright_fbo {0},
+ _bright_tex {0};
+ GLuint _blur_fbo[2] {0, 0},
+ _blur_tex[2] {0, 0};
+
+ GLuint _crosshair_prog {0},
+ _crosshair_vao {0},
+ _crosshair_vbo {0};
+
+ GLuint _extract_prog {0},
+ _blur_prog {0},
+ _composite_prog {0};
+
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 _uBlurDir {-1};
+ GLint _uBlurTexelSize {-1};
+ GLint _uComposeScene {-1},
+ _uComposeBloom {-1},
+ _uComposeStrength{-1};
+
GLint _uEmissiveColor {-1};
GLint _uEmissiveStrength {-1};
- void create_FBO_(int w, int h);
- void resize_FBO_(int w, int h);
- void destroy_FBO_();
- void create_FullscreenQuad_();
- void create_BlitProgram_();
- void create_BloomFBOs_(int scene_w, int scene_h);
- void resize_BloomFBOs_(int scene_w, int scene_h);
- void destroy_BloomFBOs_();
- void create_ExtractProgram_();
- void create_BlurProgram_();
+ void create_FBO_ (int w, int h);
+ void resize_FBO_ (int w, int h);
+ void destroy_FBO_ ();
+ void create_FullscreenQuad_ ();
+ void create_BlitProgram_ ();
+ void create_BloomFBOs_ (int scene_w, int scene_h);
+ void resize_BloomFBOs_ (int scene_w, int scene_h);
+ void destroy_BloomFBOs_ ();
+ void create_ExtractProgram_ ();
+ void create_BlurProgram_ ();
void create_CompositeProgram_();
- void run_BloomPipeline_();
+ void run_BloomPipeline_ ();
void draw_Crosshair_();
- GLuint compileShader(GLenum type, const char* src);
- bool linkProgram(GLuint vert, GLuint frag);
+ GLuint compile_Shader(GLenum type, const char* src);
+ bool link_Program (GLuint vert, GLuint frag);
public:
- bool init(SDL_Window* window);
- void begin_Frame(int viewport_w, int viewport_h);
- void end_Frame(SDL_Window* window);
- void clear_Depth();
-
- void set_MVP (const Mat4& model, const Mat4& mvp);
- void set_NormalMat (const Mat4& model);
- void set_Color (float r, float g, float b);
- void set_FaceShade (float r, float g, float b,
+ static void free_MeshBuffers(unsigned int vbo, unsigned int ebo);
+
+ bool init (SDL_Window* window);
+ void begin_Frame (int viewport_w, int viewport_h);
+ void end_Frame (SDL_Window* window);
+ void clear_Depth ();
+
+ void set_MVP (const Mat4& model, const Mat4& mvp);
+ void set_NormalMat (const Mat4& model);
+ void set_Color (float r, float g, float b);
+ void set_FaceShade (float r, float g, float b,
float back_dim, bool use_front);
- void set_Light (const Light& light);
- void set_Wireframe (bool on);
+ void set_Light (const Light& light);
+ void set_Wireframe (bool on);
+ void set_Emissive (float r, float g, float b, float strength);
+ void set_Crosshair (bool on) { _crosshair_enabled = on; }
+ void set_DepthTest (bool on);
+ void set_CullBack (bool on);
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) { _bloom_strength = s; }
- void set_Crosshair(bool on) { _crosshair_enabled = on; }
- void set_DepthTest(bool on);
- void set_CullBack (bool on);
void enable_MandelbrotMode(bool on);
void enable_WallPaperMode (bool on);
- float fov_y() const { return SDL_PI_F / 3.0f; }
- float aspect() const;
- const Mat4& projection() const;
+ float get_Fov_y () const { return SDL_PI_F / 3.0f; }
+ float get_Aspect () const;
+ const Mat4& get_Projection() const;
+ GLuint get_Program () const { return _prog; }
- // ── Draw calls ───────────────────────────────────────────────────────────
- // Indexed triangle mesh: verts = interleaved [pos(3f) | normal(3f)]
- void draw_Mesh(const float* verts, int vert_count,
- const int* indices, int index_count);
+ void draw_Mesh (const float* verts, int vert_count,
+ const int* indices, int index_count);
void draw_MeshColored(const float* verts, int vert_count,
const int* indices, int index_count);
- void draw_MeshCached(unsigned int& vbo, unsigned int& ebo, int& index_count,
- bool dirty,
- const float* verts, int vert_count,
- const int* indices, int idx_count);
- static void free_MeshBuffers(unsigned int vbo, unsigned int ebo);
-
- // Line pairs: flat [x,y,z, x,y,z, ...]
- void draw_Lines(const float* points, int point_count);
-
- // Solid lit box centred at origin (in model space) with given half-extents.
- // Call set_MVP / set_NormalMat / set_Color / set_Light before this.
- void draw_Box(float hx, float hy, float hz);
-
- void draw_Menu();
-
- void 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);
-
- GLuint program() const { return _prog; }
+ void draw_MeshCached (unsigned int& vbo, unsigned int& ebo, int& index_count,
+ bool dirty,
+ const float* verts, int vert_count,
+ const int* indices, int idx_count);
+
+ void draw_Lines (const float* points, int point_count);
+ void draw_Box (float hx, float hy, float hz);
+ void draw_Menu ();
+ void 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);
};
diff --git a/src/states/game_context.cpp b/src/states/game_context.cpp
index 0d064ec..5b408a2 100644
--- a/src/states/game_context.cpp
+++ b/src/states/game_context.cpp
@@ -1,8 +1,7 @@
-#include "states/game_context.hpp"
-
#include <algorithm>
#include "text_3d/text_3d.hpp"
+#include "states/game_context.hpp"
void
@@ -21,7 +20,7 @@ GameContext::clear_WallRole(Wall::Role role)
{
wall_texts.erase(
std::remove_if(wall_texts.begin(), wall_texts.end(),
- [role](const TextWallPtr& wt){ return wt->role == role; }),
+ [role](const Wall::Ptr& wt){ return wt->role == role; }),
wall_texts.end());
}
@@ -29,8 +28,8 @@ GameContext::clear_WallRole(Wall::Role role)
void
GameContext::add_WallText(Wall::Position pos, Wall::Role role, Text3dPtr t)
{
- wall_texts.push_back(cpputils::make_unique<TextWall>(
- TextWall{ pos, role, std::move(t) }));
+ wall_texts.push_back(cpputils::make_unique<Wall::Text>(
+ Wall::Text{ pos, role, std::move(t) }));
}
diff --git a/src/states/game_context.hpp b/src/states/game_context.hpp
index d42b88b..4962355 100644
--- a/src/states/game_context.hpp
+++ b/src/states/game_context.hpp
@@ -1,20 +1,20 @@
#pragma once
-#include <memory>
#include <string>
#include "entities/game_object.hpp"
#include "text_3d/text_3d.hpp"
#include "utils/globals.hpp"
-#include "wall/text_wall.hpp"
#include "wall/wall.hpp"
-class Player;
+
class Camera;
+class Player;
class World;
struct Light;
struct PultButton;
+
struct GameContext
{
cpputils::unique_ptr<Player> player;
@@ -25,7 +25,7 @@ struct GameContext
DynArray<Text3dPtr> words;
DynArray<GameObjectPtr> scenery;
DynArray<PultButton*> buttons;
- TextWallList wall_texts;
+ Wall::PtrList wall_texts;
void drop_WordToFloor(Text3dPtr word, const Vec3& vel);
void clear_WallRole (Wall::Role role);
diff --git a/src/states/game_state.cpp b/src/states/game_state.cpp
index 8612639..b8b00a4 100644
--- a/src/states/game_state.cpp
+++ b/src/states/game_state.cpp
@@ -7,7 +7,6 @@
#include "entities/solid_box.hpp"
#include "entities/world.hpp"
#include "game_state.hpp"
-#include "levels/level_check.hpp"
#include "rendering/gl_renderer.hpp"
#include "systems/aim.hpp"
#include "systems/celebration_system.hpp"
@@ -19,9 +18,8 @@
#include "text_3d/text_label.hpp"
#include "utils/config.hpp"
#include "utils/frame_profiler.hpp"
-#include "utils/text_wrap.hpp"
-#include "wall/text_wall.hpp"
-#include "wall/text_wall_scroll.hpp"
+#include "utils/text.hpp"
+#include "wall/wall.hpp"
@@ -49,38 +47,39 @@ GameState::GameState(size_t starting_level)
_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> ();
- _program_sys = cpputils::make_unique<ProgramSystem> ();
- _word_anim_sys = cpputils::make_unique<WordAnimSystem> ();
- _freelook_sys = cpputils::make_unique<FreelookSystem> ();
- _particle_sys = cpputils::make_unique<ParticleSystem> ();
- _dyn_loader_sys = cpputils::make_unique<DynLoaderSystem> ();
- _celebration_sys = cpputils::make_unique<CelebrationSystem>();
+ _input_sys = cpputils::make_unique<InputSystem> ();
+ _physics_sys = cpputils::make_unique<PhysicsSystem> ();
+ _projectiles_sys = cpputils::make_unique<ProjectileSystem> ();
+ _compiler_sys = cpputils::make_unique<CompilerSystem> ();
+ _program_sys = cpputils::make_unique<ProgramSystem> ();
+ _word_anim_sys = cpputils::make_unique<WordAnimSystem> ();
+ _freelook_sys = cpputils::make_unique<FreelookSystem> ();
+ _particle_sys = cpputils::make_unique<ParticleSystem> ();
+ _dyn_loader_sys = cpputils::make_unique<DynLoaderSystem> ();
+ _celebration_sys = cpputils::make_unique<CelebrationSystem> ();
+ _highlight_sys = cpputils::make_unique<CppHighlightSystem>();
_floor_sys = cpputils::make_unique<FloorMandelbrot> ();
_floor_sys->generate(World::get_BoxScale(), World::get_FloorY());
- _wall_labels = WallLabel::generate_All(World::get_BoxScale());
+ _wall_labels = Wall::Label::generate_All(World::get_BoxScale());
_word_ai_sys = cpputils::make_unique<WordAiSystem>();
_pult_sys = cpputils::make_unique<PultSystem> ();
_pult_sys->init(_ctx.scenery, _ctx.buttons, World::get_BoxScale());
- if (starting_level >= Level::level_Count()) starting_level = 0;
- _level_director = cpputils::make_unique<LevelDirector>(Level::get_Level(starting_level));
+ if (starting_level >= Level::get_Count()) starting_level = 0;
+ _level_director = cpputils::make_unique<LevelDirector>(Level::get_Data(starting_level));
_level_director->enter_Step(_ctx);
_word_ai_sys->set_MaxActiveAi(_level_director->get_MaxAiForStep());
_hint_sys = cpputils::make_unique<HintSystem>();
- if (!_level_director->complete())
- _hint_sys->set_Hint(_level_director->current_hint());
+ if (!_level_director->is_LevelComplete())
+ _hint_sys->set_Hint(_level_director->get_CurrentHint());
- if (_level_director->runner().dynamic_lib())
+ if (_level_director->get_Runner().is_DynamicLib())
sandbox_LoadFileToWall();
/*
@@ -133,11 +132,11 @@ GameState::carriedline_Update()
if (fs.active) return;
- const Vec3 anchor = CarryMath::line_Anchor(*_ctx.camera, CarryMath::CARRY_DIST);
+ const Vec3 anchor = CarryMath::get_LineAnchor(*_ctx.camera, CarryMath::CARRY_DIST);
const Vec3 right = _ctx.camera->right;
const double glyph_yaw = SDL_atan2(-_ctx.camera->fwd.x, -_ctx.camera->fwd.z);
- DynArray<Vec3> slots = CarryMath::slot_Positions(_carried, anchor, right, CarryMath::CARRY_GAP);
+ DynArray<Vec3> slots = CarryMath::get_SlotPosition(_carried, anchor, right, CarryMath::CARRY_GAP);
DynArray<CarriedWordNode*> nodes = _carried.reverse_nodes();
// Easing back from the frozen spots: lerp each word from its release
@@ -174,13 +173,13 @@ GameState::pult_DispatchAction(PultAction act)
switch (act) {
case PultAction::Compile: on_Compile(); break;
case PultAction::RunProgram: on_Run(); break;
- case PultAction::ScrollEditorUp: TextWallScroll::scroll_Up(_ctx.wall_texts, Wall::Role::Editor);
+ case PultAction::ScrollEditorUp: Wall::Text::scroll_Up(_ctx.wall_texts, Wall::Role::Editor);
_editor_wall.scroll(ConfigWall::scroll_step);
break;
- case PultAction::ScrollEditorDown: TextWallScroll::scroll_Down(_ctx.wall_texts, Wall::Role::Editor);
+ case PultAction::ScrollEditorDown: Wall::Text::scroll_Down(_ctx.wall_texts, Wall::Role::Editor);
_editor_wall.scroll(-ConfigWall::scroll_step);
break;
- case PultAction::ClearEditor: TextWallScroll::clear_ToFloor(_ctx.wall_texts, _ctx.words, Wall::Role::Editor);
+ case PultAction::ClearEditor: Wall::Text::clear_ToFloor(_ctx.wall_texts, _ctx.words, Wall::Role::Editor);
_editor_wall.clear();
break;
case PultAction::ConnectEditor: wallconnect_BeginEditor(); break;
@@ -218,7 +217,7 @@ GameState::on_Pick()
if (base->type == ObjectType::Text) {
_level_director->record_PickedUp(base->text);
base->set_Look(ConfigColor::keep, Text3d::depth_floor);
- TextWall::show_TokenInfo(_ctx.wall_texts, base->text);
+ Wall::Text::show_TokenInfo(_ctx.wall_texts, base->text);
}
carry_BeginAnim(std::move(base), true);
return true;
@@ -231,7 +230,7 @@ GameState::on_Pick()
_level_director->record_PickedUp(word->text);
word->set_Look(ConfigColor::keep, Text3d::depth_floor);
- TextWall::show_TokenInfo(_ctx.wall_texts, word->text);
+ Wall::Text::show_TokenInfo(_ctx.wall_texts, word->text);
carry_BeginAnim(std::move(word), false);
return true;
@@ -258,7 +257,7 @@ GameState::on_DropLast()
_anims_drop.push_back(std::move(drop));
if (!_carried.empty())
- TextWall::show_TokenInfo(_ctx.wall_texts, _carried.last->word->text);
+ Wall::Text::show_TokenInfo(_ctx.wall_texts, _carried.last->word->text);
else
_level_director->show_Details(_ctx);
@@ -288,7 +287,7 @@ GameState::on_ShootOne()
_ctx.camera->fwd, _ctx.camera->pos, aim);
if (!_carried.empty() && _carried.last && _carried.last->word)
- TextWall::show_TokenInfo(_ctx.wall_texts, _carried.last->word->text);
+ Wall::Text::show_TokenInfo(_ctx.wall_texts, _carried.last->word->text);
else _level_director->show_Details(_ctx);
_level_director->record_Shot();
@@ -325,10 +324,10 @@ GameState::on_ShootAll()
void GameState::on_Compile() {
- std::string src = TextWall::extract_Text(_ctx.wall_texts, Wall::Role::Editor);
+ std::string src = Wall::Text::extract_Text(_ctx.wall_texts, Wall::Role::Editor);
- if ( !_level_director->complete() &&
- _level_director->runner().dynamic_lib()) {
+ if ( !_level_director->is_LevelComplete() &&
+ _level_director->get_Runner().is_DynamicLib()) {
const std::string path = sandbox_CanonicalPath();
std::string stripped;
for (char c : src) if (!std::isspace((unsigned char)c))
@@ -354,8 +353,8 @@ GameState::on_Run()
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", Wall::Text::extract_Text(_ctx.wall_texts, Wall::Role::Program));
+ for (Wall::Ptr& 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);
}
@@ -469,7 +468,7 @@ GameState::projectile_LandOnFloor(ProjectileResult& result)
void
GameState::projectile_LandOnWall(ProjectileResult& result)
{
- DynArray<TextWallPtr> placed;
+ DynArray<Wall::Ptr> placed;
DynArray<Text3d*> editor_group;
placed.reserve(result.words.size());
@@ -481,7 +480,7 @@ 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));
+ Wall::Ptr wt = Wall::Text::from_Drop(std::move(w));
if (wt && wt->text3d && wt->role == Wall::Role::Editor)
editor_group.push_back(wt->text3d.get());
placed.push_back(std::move(wt));
@@ -496,7 +495,7 @@ GameState::projectile_LandOnWall(ProjectileResult& result)
_editor_wall.on_LinePlaced(editor_group, impact);
}
- for (TextWallPtr& wt : placed)
+ for (Wall::Ptr& wt : placed)
_ctx.wall_texts.push_back(std::move(wt));
if (!editor_group.empty())
@@ -508,11 +507,11 @@ void
GameState::projectile_LandOnWallText(ProjectileResult& result,
DynArray<size_t>& wall_text_to_erase)
{
- if (EditorWall::is_LineNumberHit(result.wall_text_index)) {
- const size_t lid = EditorWall::line_Of(result.wall_text_index);
+ if (Wall::Editor::is_LineNumberHit(result.wall_text_index)) {
+ const size_t lid = Wall::Editor::line_Of(result.wall_text_index);
const double delta = _editor_wall.scroll_DeltaToEye(lid, _ctx.camera->pos.y);
- for (TextWallPtr& wt : _ctx.wall_texts)
+ for (Wall::Ptr& wt : _ctx.wall_texts)
if (wt && wt->text3d && wt->role == Wall::Role::Editor)
wt->text3d->pos.y += delta;
_editor_wall.scroll(delta);
@@ -533,7 +532,7 @@ GameState::walltext_HandleShootDown(ProjectileResult& result,
{
bool removed_editor = false;
if (result.wall_text_index < _ctx.wall_texts.size()) {
- TextWallPtr& wt = _ctx.wall_texts[result.wall_text_index];
+ Wall::Ptr& wt = _ctx.wall_texts[result.wall_text_index];
if (wt && wt->text3d) {
removed_editor = (wt->role == Wall::Role::Editor);
_editor_wall.on_WordRemoved(wt->text3d.get());
@@ -586,26 +585,26 @@ GameState::handle_Input(FrameInput& input, double dt) {
}
}
- if (_wall_connection.target() == WallConnection::Target::Editor) {
+ if (_wall_connection.get_Target() == WallConnection::Target::Editor) {
WallConnection::Request req = _wall_connection.feed_Vim(input.vim_keys, _ctx.camera->pos.y);
input.vim_keys.clear();
switch (req) {
case WallConnection::Request::Write:
- editor_CommitToWall(_wall_connection.lines(), false);
+ editor_CommitToWall(_wall_connection.get_Lines(), false);
_wall_connection.mark_Saved();
break;
case WallConnection::Request::WriteQuit:
- editor_CommitToWall(_wall_connection.lines(), true);
+ editor_CommitToWall(_wall_connection.get_Lines(), true);
_wall_connection.end();
_frame_input.capture_vim = false;
break;
case WallConnection::Request::Exit:
- editor_CommitToWall(_wall_connection.lines(), true);
+ editor_CommitToWall(_wall_connection.get_Lines(), true);
_wall_connection.end();
_frame_input.capture_vim = false;
break;
case WallConnection::Request::QuitDiscard:
- editor_CommitToWall(_wall_connection.lines(), true);
+ editor_CommitToWall(_wall_connection.get_Lines(), true);
_wall_connection.end();
_frame_input.capture_vim = false;
break;
@@ -613,7 +612,7 @@ GameState::handle_Input(FrameInput& input, double dt) {
break;
}
}
- else if (_wall_connection.target() == WallConnection::Target::Program) {
+ else if (_wall_connection.get_Target() == WallConnection::Target::Program) {
_wall_connection.set_ProgramBuffer(input.typing_buffer);
}
else if (input.typing_mode) {
@@ -638,7 +637,7 @@ GameState::update_PlayerCamera(FrameInput& input, double dt)
_freelook_sys->update(dt);
_ctx.player->compute_Movement(input);
- _ctx.camera->syncFromPlayer(*_ctx.player);
+ _ctx.camera->sync_FromPlayer(*_ctx.player);
}
void
@@ -660,12 +659,12 @@ GameState::update(double dt, const GlRenderer* gl)
{ FP_ZONE("update.post_step");
- for (TextWallPtr& wt : _ctx.wall_texts) {
+ for (Wall::Ptr& 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::Text::tilt_TowardEye(wt->text3d->pos, _ctx.camera->pos);
}
- for (WallLabel& lbl : _wall_labels)
+ for (Wall::Label& lbl : _wall_labels)
lbl.update(dt, *_ctx.camera);
carriedline_Update();
@@ -673,10 +672,10 @@ GameState::update(double dt, const GlRenderer* gl)
_word_anim_sys->update(_anims_add, _anims_drop, _carried, _ctx.words, dt);
_pult_sys-> update(dt, *_ctx.camera);
- _plate_sys-> update(dt, *_ctx.player, _level_director->step_Plates());
+ _plate_sys-> update(dt, *_ctx.player, _level_director->get_StepPlates());
_editor_wall.update(dt, _ctx.camera->pos);
- _wall_connection.update(dt, *_ctx.camera, gl->aspect(), gl->fov_y());
+ _wall_connection.update(dt, *_ctx.camera, gl->get_Aspect(), gl->get_Fov_y());
}
@@ -715,7 +714,7 @@ GameState::update(double dt, const GlRenderer* gl)
{ FP_ZONE("update.highlight");
DynArray<HiSpan> spans;
uint64_t gen;
- if (_highlight_sys.poll(spans, gen) && gen == _editor_gen)
+ if (_highlight_sys->poll(spans, gen) && gen == _editor_gen)
_editor_file.apply_Spans(spans);
}
@@ -761,14 +760,14 @@ GameState::render(SDL_Window& window, GlRenderer& renderer)
}
{ FP_ZONE("render.wall_texts");
- for (const TextWallPtr& wt : _ctx.wall_texts) {
+ for (const Wall::Ptr& wt : _ctx.wall_texts) {
if (_editor_hidden && wt && wt->role == Wall::Role::Editor) continue;
wt->draw(renderer, *_ctx.camera, *_ctx.light);
}
}
{ FP_ZONE("render.wall_labels");
- for (const WallLabel& lbl : _wall_labels)
+ for (const Wall::Label& lbl : _wall_labels)
lbl.draw(renderer, *_ctx.camera, *_ctx.light);
}
@@ -866,7 +865,7 @@ GameState::update_WorldSimulation(double dt)
lbl->update(dt, *_ctx.camera);
all_labels.push_back(&_hint_sys->get_Label());
- for (WallLabel& wl : _wall_labels)
+ for (Wall::Label& wl : _wall_labels)
all_labels.push_back(&wl.label);
}
@@ -878,30 +877,30 @@ GameState::update_WorldSimulation(double dt)
{ FP_ZONE("updateworldsim.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];
+ const Wall::Ptr& wt = _ctx.wall_texts[i];
if (!wt || !wt->text3d) continue;
wall_text_hits.push_back({
wt->wall_position,
i,
- wt->text3d->aabb_min(),
- wt->text3d->aabb_max(),
+ wt->text3d->aabb_Min(),
+ wt->text3d->aabb_Max(),
});
}
- for (const EditorWall::NumberHit& nh : _editor_wall.number_Hitboxes())
+ for (const Wall::Editor::NumberHit& nh : _editor_wall.number_Hitboxes())
wall_text_hits.push_back({ Wall::Position::NegX, nh.index,
- nh.aabb_min, nh.aabb_max });
+ nh.aabb_Min, nh.aabb_Max });
for (size_t li = 0; li < _wall_labels.size(); ++li) {
- const DynArray<Text3dPtr>& words = _wall_labels[li].label.words();
+ const DynArray<Text3dPtr>& words = _wall_labels[li].label.get_Words();
for (size_t wi = 0; wi < words.size(); ++wi) {
if (!words[wi]) continue;
constexpr size_t LABEL_HIT_BASE = size_t(1) << 48;
wall_text_hits.push_back({
- Wall::position_of(_wall_labels[li].role),
+ Wall::position_Of(_wall_labels[li].role),
LABEL_HIT_BASE | (li << 16) | wi,
- words[wi]->aabb_min(),
- words[wi]->aabb_max(),
+ words[wi]->aabb_Min(),
+ words[wi]->aabb_Max(),
});
}
}
@@ -986,7 +985,7 @@ GameState::level_TryAdvance(double dt)
if (res.advanced) {
_level_director->enter_Step(_ctx);
_word_ai_sys->set_MaxActiveAi(_level_director->get_MaxAiForStep());
- _hint_sys->set_Hint(_level_director->current_hint());
+ _hint_sys->set_Hint(_level_director->get_CurrentHint());
} else {
_hint_sys->clear();
_level_director->show_Details(_ctx);
@@ -1045,7 +1044,7 @@ GameState::dyn_Apply(const DynArray<DynObject>& objs)
std::string
GameState::sandbox_CanonicalPath() const {
- return _level_director ? _level_director->runner().source_file() : std::string{};
+ return _level_director ? _level_director->get_Runner().get_SourceFile() : std::string{};
}
std::string
@@ -1081,7 +1080,7 @@ GameState::sandbox_LoadFileToWall()
void
GameState::sandbox_Restore() {
- if (!_level_director || !_level_director->runner().dynamic_lib()) return;
+ if (!_level_director || !_level_director->get_Runner().is_DynamicLib()) return;
if (SourceTokens::copy_File(sandbox_BackupPath(), sandbox_CanonicalPath()))
sandbox_LoadFileToWall();
}
@@ -1092,7 +1091,7 @@ GameState::typing_RebuildPreview(const std::string& s)
{
typing_ClearPreview();
- const Vec3 anchor = CarryMath::line_Anchor(*_ctx.camera, CarryMath::CARRY_DIST);
+ const Vec3 anchor = CarryMath::get_LineAnchor(*_ctx.camera, CarryMath::CARRY_DIST);
const double glyph_yaw = SDL_atan2(-_ctx.camera->fwd.x, -_ctx.camera->fwd.z);
std::istringstream in(s);
@@ -1135,7 +1134,7 @@ GameState::carry_BeginAnim(Text3dPtr word, bool with_pitch)
anim.t = 0.0;
anim.complete = false;
- const Vec3 anchor = CarryMath::line_Anchor(*_ctx.camera, CarryMath::CARRY_DIST);
+ const Vec3 anchor = CarryMath::get_LineAnchor(*_ctx.camera, CarryMath::CARRY_DIST);
const double glyph_yaw = SDL_atan2(-_ctx.camera->fwd.x, -_ctx.camera->fwd.z);
anim.target_pos = anchor;
anim.yaw_target = static_cast<float>(glyph_yaw);
@@ -1211,7 +1210,7 @@ GameState::editor_Clear()
DynArray<std::string>
GameState::editor_AbsorbLines()
{
- std::string src = TextWall::extract_Text(_ctx.wall_texts, Wall::Role::Editor);
+ std::string src = Wall::Text::extract_Text(_ctx.wall_texts, Wall::Role::Editor);
DynArray<std::string> lines;
std::string cur;
@@ -1229,7 +1228,7 @@ GameState::editor_AbsorbLines()
DynArray<std::string>
GameState::editor_ReadLines() const
{
- std::string src = TextWall::extract_Text(_ctx.wall_texts, Wall::Role::Editor);
+ std::string src = Wall::Text::extract_Text(_ctx.wall_texts, Wall::Role::Editor);
DynArray<std::string> lines;
std::string cur;
for (char ch : src) {
@@ -1336,12 +1335,12 @@ GameState::editor_SyncFile()
{
_editor_file.clear();
for (const DynArray<Text3d*>& line : _editor_wall.lines_InOrder()) {
- TextFile::Line fl;
+ Text::Line fl;
for (Text3d* w : line)
- if (w) fl.tokens.push_back(TextFile::Token{ w->text, 0, 0, w });
+ if (w) fl.tokens.push_back(Text::Token{ w->text, 0, 0, w });
_editor_file.lines.push_back(std::move(fl));
}
++_editor_gen;
- _highlight_sys.request(_editor_file.render_Source(), _editor_gen);
+ _highlight_sys->request(_editor_file.render_Source(), _editor_gen);
}
diff --git a/src/states/game_state.hpp b/src/states/game_state.hpp
index 8d6a19e..096c5e0 100644
--- a/src/states/game_state.hpp
+++ b/src/states/game_state.hpp
@@ -1,7 +1,5 @@
#pragma once
-#include <memory>
-
#include "cpputils/unique_ptr.hpp"
#include "entities/plate.hpp"
#include "istate.hpp"
@@ -27,49 +25,48 @@
#include "systems/wall_connection.hpp"
#include "systems/word_ai_system.hpp"
#include "systems/word_anim.hpp"
-#include "text_3d/text_file.hpp"
#include "text_3d/vim_buffer.hpp"
#include "utils/carry_math.hpp"
#include "utils/globals.hpp"
-#include "wall/editor_wall.hpp"
-#include "wall/text_wall.hpp"
-#include "wall/wall_label.hpp"
+#include "utils/text.hpp"
+#include "wall/editor.hpp"
+#include "wall/wall.hpp"
class GameState : public IState
{
- cpputils::unique_ptr<CelebrationSystem>_celebration_sys;
- cpputils::unique_ptr<CompilerSystem> _compiler_sys;
- cpputils::unique_ptr<DynLoaderSystem> _dyn_loader_sys;
- cpputils::unique_ptr<FloorMandelbrot> _floor_sys;
- cpputils::unique_ptr<FreelookSystem> _freelook_sys;
- cpputils::unique_ptr<HintSystem> _hint_sys;
- cpputils::unique_ptr<InputSystem> _input_sys;
- cpputils::unique_ptr<LevelDirector> _level_director;
- cpputils::unique_ptr<ParticleSystem> _particle_sys;
- cpputils::unique_ptr<PhysicsSystem> _physics_sys;
- cpputils::unique_ptr<PlateSystem> _plate_sys;
- cpputils::unique_ptr<ProgramSystem> _program_sys;
- cpputils::unique_ptr<ProjectileSystem> _projectiles_sys;
- cpputils::unique_ptr<PultSystem> _pult_sys;
- cpputils::unique_ptr<WordAiSystem> _word_ai_sys;
- cpputils::unique_ptr<WordAnimSystem> _word_anim_sys;
+ cpputils::unique_ptr<CelebrationSystem> _celebration_sys;
+ cpputils::unique_ptr<CompilerSystem> _compiler_sys;
+ cpputils::unique_ptr<CppHighlightSystem> _highlight_sys;
+ cpputils::unique_ptr<DynLoaderSystem> _dyn_loader_sys;
+ cpputils::unique_ptr<FloorMandelbrot> _floor_sys;
+ cpputils::unique_ptr<FreelookSystem> _freelook_sys;
+ cpputils::unique_ptr<HintSystem> _hint_sys;
+ cpputils::unique_ptr<InputSystem> _input_sys;
+ cpputils::unique_ptr<LevelDirector> _level_director;
+ cpputils::unique_ptr<ParticleSystem> _particle_sys;
+ cpputils::unique_ptr<PhysicsSystem> _physics_sys;
+ cpputils::unique_ptr<PlateSystem> _plate_sys;
+ cpputils::unique_ptr<ProgramSystem> _program_sys;
+ cpputils::unique_ptr<ProjectileSystem> _projectiles_sys;
+ cpputils::unique_ptr<PultSystem> _pult_sys;
+ cpputils::unique_ptr<WordAiSystem> _word_ai_sys;
+ cpputils::unique_ptr<WordAnimSystem> _word_anim_sys;
bool _editor_hidden { false };
uint64_t _editor_gen { 0 };
double _pick_cooldown { 0.0 };
double _shoot_cooldown { 0.0 };
- std::string _typing_last;
+ std::string _typing_last;
- CarriedLine _carried;
- EditorWall _editor_wall;
- FrameInput _frame_input;
- GameContext _ctx;
- WallConnection _wall_connection;
- TextFile _editor_file;
- CppHighlightSystem _highlight_sys;
+ CarriedLine _carried;
+ Wall::Editor _editor_wall;
+ FrameInput _frame_input;
+ GameContext _ctx;
+ WallConnection _wall_connection;
+ Text::View _editor_file;
DynArray<GameObject*> _dyn_scenery;
@@ -77,7 +74,7 @@ class GameState : public IState
DynArray<Vec3> _freelook_return_from;
DynArray<std::string> _editor_absorbed;
DynArray<Projectile> _projectiles;
- DynArray<WallLabel> _wall_labels;
+ DynArray<Wall::Label> _wall_labels;
DynArray<WordAnim_Add> _anims_add;
DynArray<WordAnim_Drop> _anims_drop;
@@ -128,9 +125,9 @@ class GameState : public IState
void projectile_LandOnWall (ProjectileResult&);
void projectile_LandOnWallText (ProjectileResult&, DynArray<size_t>& wall_text_to_erase);
- void pult_DispatchAction (PultAction act);
+ void pult_DispatchAction(PultAction act);
- void debug_SpawnWords (size_t n);
+ void debug_SpawnWords (size_t n);
void handle_Input (FrameInput&, double dt);
void update_PlayerCamera(FrameInput& input, double dt);
diff --git a/src/states/istate.hpp b/src/states/istate.hpp
index bf8b062..2e483ce 100644
--- a/src/states/istate.hpp
+++ b/src/states/istate.hpp
@@ -2,9 +2,11 @@
#include <SDL3/SDL.h>
+
class Game;
class GlRenderer;
+
class IState
{
public:
diff --git a/src/states/menu_state.cpp b/src/states/menu_state.cpp
index ed5e474..7e0e3c1 100644
--- a/src/states/menu_state.cpp
+++ b/src/states/menu_state.cpp
@@ -95,9 +95,9 @@ MenuState::build_Items()
_items.push_back(std::move(mi));
}
- for (size_t i = 0; i < Level::level_Count(); ++i) {
+ for (size_t i = 0; i < Level::get_Count(); ++i) {
MenuItem mi;
- mi.label = Level::get_Level(i).name;
+ mi.label = Level::get_Data(i).name;
mi.kind = ItemKind::StartLevel;
mi.level_index = i;
mi.slot_pos = slot_PosForColumn(COLUMN_MID_RAD, EYE_Y);
@@ -168,8 +168,8 @@ MenuState::handle_Event(Game& game, const SDL_Event& e)
case SDLK_DOWN:
if (is_LevelItem(pick_FromCrosshair())) {
const double max_scroll =
- static_cast<double>(Level::level_Count() > 0
- ? Level::level_Count() - 1 : 0);
+ static_cast<double>(Level::get_Count() > 0
+ ? Level::get_Count() - 1 : 0);
if (_scroll_target < max_scroll) _scroll_target += 1.0;
}
break;
@@ -238,8 +238,8 @@ MenuState::pick_FromCrosshair() const
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;
diff --git a/src/states/menu_state.hpp b/src/states/menu_state.hpp
index cf26887..1050634 100644
--- a/src/states/menu_state.hpp
+++ b/src/states/menu_state.hpp
@@ -13,32 +13,32 @@
class MenuState : public IState
{
- enum class ItemKind : uint8_t {
+ enum class ItemKind : uint8_t
+ {
OpenFile,
StartLevel,
Quit,
};
- struct MenuItem {
- std::string label;
+ struct MenuItem
+ {
ItemKind kind;
size_t level_index = 0;
Text3dPtr text3d;
Vec3 slot_pos {};
+ std::string label;
};
cpputils::unique_ptr<World> _world;
cpputils::unique_ptr<Camera> _camera;
cpputils::unique_ptr<Light> _light;
-
- Text3dPtr _title;
- DynArray<MenuItem> _items;
- size_t _selected{0};
-
+ Text3dPtr _title;
+ size_t _selected {0};
double _scroll_current{0.0};
double _scroll_target {0.0};
+ double _t {0.0};
- double _t{0.0};
+ DynArray<MenuItem> _items;
void build_Items ();
void activate (Game& game);
diff --git a/src/systems/aim.hpp b/src/systems/aim.hpp
index bf54bd1..cbb1641 100644
--- a/src/systems/aim.hpp
+++ b/src/systems/aim.hpp
@@ -7,37 +7,39 @@
#include "systems/collision.hpp"
#include "text_3d/text_3d.hpp"
#include "utils/globals.hpp"
-#include "utils/math.hpp"
-#include "wall/text_wall.hpp"
+#include "wall/wall.hpp"
namespace Aim
{
-struct Result {
+
+struct Result
+{
Text3d* track { nullptr };
Vec3 point {};
Vec3 local {};
};
+
inline Result
crosshair_Target(const Camera& camera,
const DynArray<Text3dPtr>& words,
const DynArray<GameObjectPtr>& scenery,
- const DynArray<TextWallPtr>& wall_texts,
+ const DynArray<Wall::Ptr>& wall_texts,
float world_scale)
{
const Vec3 eye = camera.pos;
const Vec3 dir = camera.fwd;
const double ws = static_cast<double>(world_scale);
- // 1. Distance along the ray to the box surface (nearest bounding plane).
double wall_t = 1e18;
auto plane = [&](double o, double d) {
if (SDL_fabs(d) < 1e-9) return;
const double t = SDL_max((ws - o) / d, (-ws - o) / d);
if (t > 0.0 && t < wall_t) wall_t = t;
};
+
plane(eye.x, dir.x);
plane(eye.y, dir.y);
plane(eye.z, dir.z);
@@ -46,9 +48,10 @@ crosshair_Target(const Camera& camera,
const Vec3 seg { dir.x * wall_t, dir.y * wall_t, dir.z * wall_t };
Result out;
- out.point = Vec3{ eye.x + seg.x, eye.y + seg.y, eye.z + seg.z }; // wall point
- double best_t = 1.0; // seg-fraction
- Text3d* win = nullptr; // winning word, if any
+ out.point = Vec3{ eye.x + seg.x, eye.y + seg.y, eye.z + seg.z };
+
+ double best_t = 1.0;
+ Text3d* win = nullptr;
auto test = [&](const Vec3& mn, const Vec3& mx, Text3d* obj) {
Collision::SweptResult sw = Collision::swept_RayAabb(eye, seg, mn, mx);
@@ -62,11 +65,11 @@ crosshair_Target(const Camera& camera,
};
for (const Text3dPtr& w : words)
- if (w) test(w->aabb_min(), w->aabb_max(), w.get());
+ if (w) test(w->aabb_Min(), w->aabb_Max(), w.get());
for (const GameObjectPtr& s : scenery)
- if (s) test(s->aabb_min(), s->aabb_max(), nullptr);
- for (const TextWallPtr& wt : wall_texts)
- if (wt && wt->text3d) test(wt->text3d->aabb_min(), wt->text3d->aabb_max(), nullptr);
+ if (s) test(s->aabb_Min(), s->aabb_Max(), nullptr);
+ for (const Wall::Ptr& wt : wall_texts)
+ if (wt && wt->text3d) test(wt->text3d->aabb_Min(), wt->text3d->aabb_Max(), nullptr);
if (win) {
out.track = win;
diff --git a/src/systems/carry_system.cpp b/src/systems/carry_system.cpp
index a564c37..ea84023 100644
--- a/src/systems/carry_system.cpp
+++ b/src/systems/carry_system.cpp
@@ -7,6 +7,7 @@ CarriedLine::empty() const
return size == 0;
}
+
void
CarriedLine::push(Text3dPtr w)
{
@@ -24,6 +25,7 @@ CarriedLine::push(Text3dPtr w)
size++;
}
+
Text3dPtr
CarriedLine::pop_back()
{
@@ -54,6 +56,7 @@ CarriedLine::pop_back()
return word;
}
+
Text3dPtr
CarriedLine::pop_front()
{
@@ -74,6 +77,7 @@ CarriedLine::pop_front()
return word;
}
+
DynArray<CarriedWordNode*>
CarriedLine::nodes() const
{
@@ -103,6 +107,7 @@ CarriedLine::clear()
size = 0;
}
+
void
CarriedLine::compact()
{
diff --git a/src/systems/carry_system.hpp b/src/systems/carry_system.hpp
index 7e81a21..06e53eb 100644
--- a/src/systems/carry_system.hpp
+++ b/src/systems/carry_system.hpp
@@ -1,19 +1,21 @@
#pragma once
-#include <memory>
#include "text_3d/text_3d.hpp"
#include "utils/globals.hpp"
-struct CarriedWordNode {
+struct CarriedWordNode
+{
Text3dPtr word;
CarriedWordNode* prev{nullptr};
cpputils::unique_ptr<CarriedWordNode> next;
CarriedWordNode(Text3dPtr w) : word(std::move(w)) {}
};
-struct CarriedLine {
+
+struct CarriedLine
+{
cpputils::unique_ptr<CarriedWordNode> first;
CarriedWordNode* last{nullptr};
size_t size{0};
diff --git a/src/systems/celebration_system.cpp b/src/systems/celebration_system.cpp
index 50295b9..2538ae9 100644
--- a/src/systems/celebration_system.cpp
+++ b/src/systems/celebration_system.cpp
@@ -92,14 +92,14 @@ CelebrationSystem::finish(ParticleSystem& particle_sys)
bool
-CelebrationSystem::active() const
+CelebrationSystem::is_Active() const
{
return _active;
}
double
-CelebrationSystem::progress() const
+CelebrationSystem::get_Progress() const
{
return (_duration > 0.0) ? (_t / _duration) : 1.0;
}
diff --git a/src/systems/celebration_system.hpp b/src/systems/celebration_system.hpp
index dca732a..9a24e9a 100644
--- a/src/systems/celebration_system.hpp
+++ b/src/systems/celebration_system.hpp
@@ -2,13 +2,14 @@
#include "utils/globals.hpp"
-struct Light;
-struct Camera;
-class ParticleSystem;
class GlRenderer;
+class ParticleSystem;
+struct Camera;
+struct Light;
-class CelebrationSystem {
+class CelebrationSystem
+{
bool _active = false;
double _t = 0,
_duration = 3.5,
@@ -18,7 +19,8 @@ public:
void start (const Camera& cam, double& glyph_yaw);
void tick (double dt, ParticleSystem& particle_sys);
void finish (ParticleSystem& particle_sys);
- bool active () const;
- double progress() const;
void draw (GlRenderer&, const Camera&, const Light&) const;
+
+ bool is_Active () const;
+ double get_Progress() const;
};
diff --git a/src/systems/collision.cpp b/src/systems/collision.cpp
index d2b554a..1aa158b 100644
--- a/src/systems/collision.cpp
+++ b/src/systems/collision.cpp
@@ -1,9 +1,8 @@
-#include "systems/collision.hpp"
-
#include <SDL3/SDL.h>
#include <algorithm>
#include "entities/game_object.hpp"
+#include "systems/collision.hpp"
namespace Collision
@@ -14,12 +13,12 @@ static constexpr double FRICTION_IMPULSE_CUTOFF = 2.0;
bool
aabb_Overlap(const GameObject& a, const GameObject& b)
{
- return a.aabb_min().x <= b.aabb_max().x &&
- a.aabb_max().x >= b.aabb_min().x &&
- a.aabb_min().y <= b.aabb_max().y &&
- a.aabb_max().y >= b.aabb_min().y &&
- a.aabb_min().z <= b.aabb_max().z &&
- a.aabb_max().z >= b.aabb_min().z;
+ return a.aabb_Min().x <= b.aabb_Max().x &&
+ a.aabb_Max().x >= b.aabb_Min().x &&
+ a.aabb_Min().y <= b.aabb_Max().y &&
+ a.aabb_Max().y >= b.aabb_Min().y &&
+ a.aabb_Min().z <= b.aabb_Max().z &&
+ a.aabb_Max().z >= b.aabb_Min().z;
}
@@ -28,12 +27,12 @@ aabb_Manifold(const GameObject& a, const GameObject& b)
{
Manifold m;
- double ox = std::min(a.aabb_max().x, b.aabb_max().x) -
- std::max(a.aabb_min().x, b.aabb_min().x);
- double oy = std::min(a.aabb_max().y, b.aabb_max().y) -
- std::max(a.aabb_min().y, b.aabb_min().y);
- double oz = std::min(a.aabb_max().z, b.aabb_max().z) -
- std::max(a.aabb_min().z, b.aabb_min().z);
+ double ox = SDL_min(a.aabb_Max().x, b.aabb_Max().x) -
+ SDL_max(a.aabb_Min().x, b.aabb_Min().x);
+ double oy = SDL_min(a.aabb_Max().y, b.aabb_Max().y) -
+ SDL_max(a.aabb_Min().y, b.aabb_Min().y);
+ double oz = SDL_min(a.aabb_Max().z, b.aabb_Max().z) -
+ SDL_max(a.aabb_Min().z, b.aabb_Min().z);
if (ox <= 0.0 || oy <= 0.0 || oz <= 0.0)
return m;
@@ -85,7 +84,7 @@ resolve_Objects(GameObject& a, GameObject& b)
if (rel_vel >= 0.0) return; // already separating
- double e = std::min(a.body.restitution, b.body.restitution);
+ double e = SDL_min(a.body.restitution, b.body.restitution);
double inv_mass_a = a_static ? 0.0 : 1.0 / a.body.mass;
double inv_mass_b = b_static ? 0.0 : 1.0 / b.body.mass;
double j = -(1.0 + e) * rel_vel / (inv_mass_a + inv_mass_b);
diff --git a/src/systems/collision.hpp b/src/systems/collision.hpp
index ae8e8a0..1bb04d6 100644
--- a/src/systems/collision.hpp
+++ b/src/systems/collision.hpp
@@ -1,26 +1,28 @@
#pragma once
-#include "utils/math.hpp"
+#include "utils/globals.hpp"
class GameObject;
namespace Collision
{
- struct Manifold {
+ struct Manifold
+ {
bool hit = false;
double overlap {};
Vec3 normal {};
};
- struct SweptResult {
+ struct SweptResult
+ {
bool hit = false;
- double t = 0.0; // entry time clamped to [0, 1]
- Vec3 normal {}; // outward-facing normal of the entry face
+ double t = 0.0;
+ Vec3 normal {};
};
+ void resolve_Objects(GameObject& a, GameObject& b);
bool aabb_Overlap (const GameObject& a, const GameObject& b);
Manifold aabb_Manifold(const GameObject& a, const GameObject& b);
- void resolve_Objects(GameObject& a, GameObject& b);
Vec3 reflect (const Vec3& vel, const Vec3& normal, double restitution);
SweptResult swept_RayAabb(const Vec3& origin, const Vec3& dir,
const Vec3& box_min, const Vec3& box_max);
diff --git a/src/systems/compiler_system.cpp b/src/systems/compiler_system.cpp
index 554008c..35d5602 100644
--- a/src/systems/compiler_system.cpp
+++ b/src/systems/compiler_system.cpp
@@ -3,7 +3,7 @@
#include "systems/compiler_system.hpp"
#include "text_3d/text_3d.hpp"
-#include "utils/ascii.hpp"
+#include "utils/text.hpp"
CompilerSystem::~CompilerSystem()
@@ -13,7 +13,7 @@ CompilerSystem::~CompilerSystem()
void
-CompilerSystem::compile(TextWallList& texts, const std::string& src)
+CompilerSystem::compile(Wall::PtrList& texts, const std::string& src)
{
// One compile at a time. Reap a finished worker; ignore re-triggers while
// one is still running.
@@ -25,8 +25,8 @@ CompilerSystem::compile(TextWallList& texts, const std::string& src)
// Clear previous output from the compiler wall (main thread — GL-owned).
texts.erase(
std::remove_if(texts.begin(), texts.end(),
- [](const TextWallPtr& wt) {
- return wt->wall_position == Wall::position_of(Wall::Role::Compiler);
+ [](const Wall::Ptr& wt) {
+ return wt->wall_position == Wall::position_Of(Wall::Role::Compiler);
}),
texts.end());
_count = 0;
@@ -86,7 +86,7 @@ CompilerSystem::run_Compile(CompilerSystem* self, std::string src)
void
-CompilerSystem::update(TextWallList& texts)
+CompilerSystem::update(Wall::PtrList& texts)
{
// Drain whatever the worker produced and render it (main thread, GL-safe).
DynArray<std::string> lines;
@@ -102,13 +102,13 @@ CompilerSystem::update(TextWallList& texts)
void
-CompilerSystem::push_Line(TextWallList& texts, const std::string& line)
+CompilerSystem::push_Line(Wall::PtrList& texts, const std::string& line)
{
if (line == "OK") last_compile_ok = true;
- std::string clean = ascii_Sanitize(line);
+ std::string clean = Text::ascii_Sanitize(line);
- for (TextWallPtr& wt : texts)
+ for (Wall::Ptr& wt : texts)
if (wt->role == Wall::Role::Compiler)
wt->text3d->pos.y += static_cast<double>(line_height);
@@ -120,7 +120,7 @@ CompilerSystem::push_Line(TextWallList& texts, const std::string& line)
Text3dPtr t = make_Text3d(clean, Text3d::depth_compiler, 0.003f, pos, ConfigColor::white);
t->yaw = tf.yaw;
- texts.push_back(cpputils::make_unique<TextWall>(TextWall{
+ texts.push_back(cpputils::make_unique<Wall::Text>(Wall::Text{
tf.wall_position, Wall::Role::Compiler, std::move(t) }));
_count++;
}
diff --git a/src/systems/compiler_system.hpp b/src/systems/compiler_system.hpp
index af125c6..e835fd0 100644
--- a/src/systems/compiler_system.hpp
+++ b/src/systems/compiler_system.hpp
@@ -1,24 +1,25 @@
#pragma once
-#include <string>
+
+#include <atomic>
#include <cstdio>
-#include <thread>
#include <mutex>
-#include <atomic>
+#include <string>
+#include <thread>
#include "entities/world.hpp"
#include "utils/globals.hpp"
-#include "wall/text_wall.hpp"
+
struct CompilerSystem
{
private:
- int _count {0};
+ int _count {0};
std::atomic<bool> _running{false};
std::mutex _mtx;
std::thread _worker;
DynArray<std::string> _pending;
- void push_Line (TextWallList&, const std::string& line);
+ void push_Line (Wall::PtrList&, const std::string& line);
static void run_Compile(CompilerSystem* self, std::string src);
public:
static inline float line_height = 0.4f;
@@ -26,8 +27,10 @@ public:
bool last_compile_ok{false};
- ~CompilerSystem();
- void update (TextWallList&);
- void compile (TextWallList&, const std::string& src);
+ void update (Wall::PtrList&);
+ void compile (Wall::PtrList&, const std::string& src);
+
bool is_Running() const { return _running.load(); }
+
+ ~CompilerSystem();
};
diff --git a/src/systems/cpp_highlight_system.hpp b/src/systems/cpp_highlight_system.hpp
index baf3268..f7a8f89 100644
--- a/src/systems/cpp_highlight_system.hpp
+++ b/src/systems/cpp_highlight_system.hpp
@@ -8,36 +8,37 @@
#include "cpp_token/cpp_highlight.hpp"
#include "utils/globals.hpp"
-class CppHighlightSystem {
+
+class CppHighlightSystem
+{
public:
~CppHighlightSystem() { if (_worker.joinable()) _worker.join(); }
- // Request a lex of `source` tagged with `gen`. No-op if source unchanged
- // since last request. Single-flight: coalesces while a lex is in flight.
void request(const std::string& source, uint64_t gen)
{
- if (source == _last_requested) return; // content unchanged → skip
+ // TODO: dont send a request twice?!
+ if (source == _last_requested) return;
_last_requested = source;
- if (_running.load()) { _redo = true; return; } // coalesce
+ if (_running.load()) { _redo = true; return; }
spawn(source, gen);
}
- // Drain finished results. Returns true + fills out if a lex completed this
- // call; caller checks gen against current content before applying.
bool poll(DynArray<HiSpan>& out, uint64_t& out_gen)
{
if (!_done.load()) return false;
+
{
std::lock_guard<std::mutex> lk(_mtx);
out = _pending;
out_gen = _result_gen;
}
+
_done.store(false);
if (_worker.joinable()) _worker.join();
_running.store(false);
- if (_redo) { // content changed mid-lex → relex
+ if (_redo) {
_redo = false;
spawn(_last_requested, _last_gen_pending);
}
@@ -45,6 +46,16 @@ public:
}
private:
+ bool _redo { false };
+ std::atomic<bool> _running { false };
+ std::atomic<bool> _done { false };
+ uint64_t _result_gen { 0 };
+ uint64_t _last_gen_pending { 0 };
+ std::thread _worker;
+ std::mutex _mtx;
+ std::string _last_requested;
+ DynArray<HiSpan> _pending;
+
void spawn(const std::string& source, uint64_t gen)
{
if (_worker.joinable()) _worker.join();
@@ -62,13 +73,4 @@ private:
});
}
- std::thread _worker;
- std::mutex _mtx;
- std::atomic<bool> _running { false };
- std::atomic<bool> _done { false };
- DynArray<HiSpan> _pending;
- uint64_t _result_gen { 0 };
- uint64_t _last_gen_pending { 0 };
- std::string _last_requested;
- bool _redo { false };
};
diff --git a/src/systems/dyn_loader_system.cpp b/src/systems/dyn_loader_system.cpp
index 307175a..8109e3a 100644
--- a/src/systems/dyn_loader_system.cpp
+++ b/src/systems/dyn_loader_system.cpp
@@ -7,7 +7,7 @@
#include "entities/world.hpp"
#include "systems/dyn_loader_system.hpp"
#include "text_3d/text_3d.hpp"
-#include "utils/ascii.hpp"
+#include "utils/text.hpp"
// Where game_mod_abi.h is installed at runtime, and the build scratch dir.
@@ -64,15 +64,15 @@ DynLoaderSystem::wrap_Source(const std::string& user_body)
void
-DynLoaderSystem::build(TextWallList& texts, const std::string& user_src, bool full_source)
+DynLoaderSystem::build(Wall::PtrList& texts, const std::string& user_src, bool full_source)
{
last_build_ok = false;
// Clear previous output from the Compiler wall.
texts.erase(
std::remove_if(texts.begin(), texts.end(),
- [](const TextWallPtr& wt) {
- return wt->wall_position == Wall::position_of(Wall::Role::Compiler);
+ [](const Wall::Ptr& wt) {
+ return wt->wall_position == Wall::position_Of(Wall::Role::Compiler);
}),
texts.end());
_count = 0;
@@ -110,7 +110,7 @@ DynLoaderSystem::build(TextWallList& texts, const std::string& user_src, bool fu
void
-DynLoaderSystem::update(TextWallList& texts)
+DynLoaderSystem::update(Wall::PtrList& texts)
{
if (!_pipe) return;
@@ -142,10 +142,10 @@ DynLoaderSystem::update(TextWallList& texts)
void
-DynLoaderSystem::push_Line(TextWallList& texts, const std::string& line)
+DynLoaderSystem::push_Line(Wall::PtrList& texts, const std::string& line)
{
// Shift existing compiler lines up, drop the new one at the bottom.
- for (TextWallPtr& wt : texts)
+ for (Wall::Ptr& wt : texts)
if (wt->role == Wall::Role::Compiler)
wt->text3d->pos.y += static_cast<double>(line_height);
@@ -153,12 +153,12 @@ DynLoaderSystem::push_Line(TextWallList& texts, const std::string& line)
Vec3 pos = tf.position;
pos.y = start_y;
- std::string clean = ascii_Sanitize(line);
+ std::string clean = Text::ascii_Sanitize(line);
Text3dPtr t = make_Text3d(clean, Text3d::depth_compiler, 0.003f,
pos, ConfigColor::compiler);
t->yaw = tf.yaw;
- texts.push_back(cpputils::make_unique<TextWall>(TextWall{
+ texts.push_back(cpputils::make_unique<Wall::Text>(Wall::Text{
tf.wall_position,
Wall::Role::Compiler,
std::move(t)
diff --git a/src/systems/dyn_loader_system.hpp b/src/systems/dyn_loader_system.hpp
index 66ab185..183e4fa 100644
--- a/src/systems/dyn_loader_system.hpp
+++ b/src/systems/dyn_loader_system.hpp
@@ -1,11 +1,11 @@
#pragma once
-#include <cstdio>
#include <string>
#include "systems/game_mod_abi.h"
#include "utils/globals.hpp"
-#include "wall/text_wall.hpp"
+#include "wall/wall.hpp"
+
class DynLoaderSystem
{
@@ -15,28 +15,29 @@ class DynLoaderSystem
FILE* _pipe { nullptr };
void* _handle { nullptr };
- int _count { 0 };
+ int _count { 0 };
int _build_serial { 0 };
std::string _pending_so;
std::string _last_so_path;
+ void push_Line (Wall::PtrList& texts, const std::string& line);
static std::string
wrap_Source(const std::string& user_body);
- void push_Line (TextWallList& texts, const std::string& line);
public:
bool last_build_ok { false };
- void build (TextWallList& texts, const std::string& user_src, bool full_source);
- void update (TextWallList& texts);
- bool is_Running () const { return _pipe != nullptr; }
- const std::string&
- last_so_path() const { return _last_so_path; }
+ void build (Wall::PtrList& texts, const std::string& user_src, bool full_source);
+ void update (Wall::PtrList& texts);
DynArray<DynObject>
load_Objects();
+ bool is_Running () const { return _pipe != nullptr; }
+ const std::string&
+ get_LastSoPath() const { return _last_so_path; }
+
~DynLoaderSystem();
};
diff --git a/src/systems/freelook_system.cpp b/src/systems/freelook_system.cpp
index 42e0de5..f505d10 100644
--- a/src/systems/freelook_system.cpp
+++ b/src/systems/freelook_system.cpp
@@ -1,7 +1,9 @@
-#include "freelook_system.hpp"
#include <SDL3/SDL.h>
#include <algorithm>
+#include "freelook_system.hpp"
+
+
static constexpr double
FREELOOK_LERP_DUR = 0.20;
diff --git a/src/systems/freelook_system.hpp b/src/systems/freelook_system.hpp
index facedb5..de6a668 100644
--- a/src/systems/freelook_system.hpp
+++ b/src/systems/freelook_system.hpp
@@ -1,16 +1,18 @@
#pragma once
-#include <cstdint>
-#include "utils/math.hpp"
+
+#include "utils/globals.hpp"
#include "systems/carry_system.hpp"
-struct FreelookState {
- bool active{};
+struct FreelookState
+{
+ bool active {};
bool lerping{};
- double lerp_t{};
+ double lerp_t {};
};
-class FreelookSystem {
+class FreelookSystem
+{
public:
FreelookState state;
diff --git a/src/systems/hint_system.hpp b/src/systems/hint_system.hpp
index 142345a..8876730 100644
--- a/src/systems/hint_system.hpp
+++ b/src/systems/hint_system.hpp
@@ -5,19 +5,24 @@
#include "entities/camera.hpp"
#include "utils/light.hpp"
+
class GlRenderer;
-class HintSystem {
+
+class HintSystem
+{
std::string _current_hint;
TextLabel _label;
public:
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 set_Hint(const std::string& hint_text);
+
TextLabel&
get_Label() { return _label; }
const TextLabel&
diff --git a/src/systems/input_system.hpp b/src/systems/input_system.hpp
index 150e561..11fcea2 100644
--- a/src/systems/input_system.hpp
+++ b/src/systems/input_system.hpp
@@ -5,9 +5,12 @@
#include "utils/globals.hpp"
+
class Game;
-enum class InputCommand : uint8_t {
+
+enum class InputCommand : uint8_t
+{
Jump,
Click,
Drop,
@@ -24,7 +27,8 @@ enum class InputCommand : uint8_t {
};
-struct FrameInput {
+struct FrameInput
+{
bool forward = false;
bool backward = false;
bool left = false;
@@ -46,7 +50,8 @@ struct FrameInput {
DynArray<InputCommand> commands;
};
-class InputSystem {
-public:
+
+struct InputSystem
+{
void handle_Event(Game& game, const SDL_Event& e, FrameInput& input);
};
diff --git a/src/systems/level_director.cpp b/src/systems/level_director.cpp
index d2d1766..ef75de5 100644
--- a/src/systems/level_director.cpp
+++ b/src/systems/level_director.cpp
@@ -1,4 +1,3 @@
-#include "systems/level_director.hpp"
#include <algorithm>
#include <unordered_set>
@@ -7,13 +6,14 @@
#include "entities/plate.hpp"
#include "entities/solid_box.hpp"
#include "entities/world.hpp"
-#include "levels/level_check.hpp"
+#include "levels/level.hpp"
#include "states/game_context.hpp"
#include "systems/celebration_system.hpp"
+#include "systems/level_director.hpp"
#include "systems/particle_system.hpp"
#include "utils/config.hpp"
-#include "utils/text_wrap.hpp"
-#include "wall/text_wall.hpp"
+#include "utils/text.hpp"
+#include "wall/wall.hpp"
LevelDirector::LevelDirector(const Level::Data& level)
@@ -24,8 +24,8 @@ LevelDirector::LevelDirector(const Level::Data& level)
int
LevelDirector::get_MaxAiForStep() const
{
- if (_runner->complete()) return 0;
- return _runner->current().max_ai_words;
+ if (_runner->is_Complete()) return 0;
+ return _runner->get_Current().max_ai_words;
}
@@ -33,7 +33,7 @@ void
LevelDirector::enter_Step(GameContext& ctx)
{
spawn_Grants(ctx);
- setup_Scene(ctx, _runner->current().scene);
+ setup_Scene(ctx, _runner->get_Current().scene);
show_Details(ctx);
_step_age = 0.0;
}
@@ -42,7 +42,7 @@ LevelDirector::enter_Step(GameContext& ctx)
void
LevelDirector::spawn_Grants(GameContext& ctx)
{
- DynArray<std::string> tokens = _runner->garants_ForStep();
+ DynArray<std::string> tokens = _runner->get_GarantsForStep();
static constexpr float spacing = 3.0f;
static constexpr int per_row = 8;
@@ -69,15 +69,15 @@ LevelDirector::spawn_Grants(GameContext& ctx)
void
-LevelDirector::setup_Scene(GameContext& ctx, const Scene& scene)
+LevelDirector::setup_Scene(GameContext& ctx, const Scene::Data& scene)
{
- for (const PlacedWord& pw : scene.words) {
+ for (const Scene::Placed::Word& pw : scene.words) {
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));
}
- for (const PlacedPlate& pp : scene.plates) {
+ for (const Scene::Placed::Plate& pp : scene.plates) {
auto plate = cpputils::make_unique<Plate>(pp.pos);
Plate* raw = plate.get();
_step_plates .push_back({ raw, pp.tag });
@@ -85,7 +85,7 @@ LevelDirector::setup_Scene(GameContext& ctx, const Scene& scene)
ctx.scenery .push_back(std::move(plate));
}
- for (const PlacedPlatform& pl : scene.platforms) {
+ for (const Scene::Placed::Platform& pl : scene.platforms) {
auto box = cpputils::make_unique<SolidBox>(pl.pos, pl.half_extents,
pl.fill_color, pl.wire_color);
GameObject* raw = box.get();
@@ -93,7 +93,7 @@ LevelDirector::setup_Scene(GameContext& ctx, const Scene& scene)
ctx.scenery .push_back(std::move(box));
}
- for (const PlacedAi& a : scene.ai_seeds) {
+ for (const Scene::Placed::Ai& a : scene.ai_seeds) {
Text3dPtr t = make_Text3d(a.text, Text3d::depth_floor, 0.003f, a.pos, ConfigColor::floor);
t->body.hover_height = a.pos.y;
t->ai.aggressiveness = a.aggressiveness;
@@ -143,15 +143,15 @@ LevelDirector::show_Details(GameContext& ctx) const
{
ctx.clear_WallRole(Wall::Role::Info);
- if (_runner->complete()) return;
+ if (_runner->is_Complete()) return;
- const std::string& details = _runner->current().details;
+ const std::string& details = _runner->get_Current().details;
if (details.empty()) return;
Wall::Transform wt = Wall::get_Transform(Wall::Role::Info, World::get_BoxScale());
constexpr size_t MAX_INFO_LINE_CHARS = 92;
- DynArray<std::string> lines = wrap_Text(details, MAX_INFO_LINE_CHARS);
+ DynArray<std::string> lines = Text::wrap_String(details, MAX_INFO_LINE_CHARS);
const float bottom_y = World::get_FloorY() + 1.0f;
float y = bottom_y + static_cast<float>(lines.size() - 1) * ConfigWall::text_line_spacing;
@@ -169,10 +169,10 @@ LevelDirector::show_Details(GameContext& ctx) const
}
-GoalContext
+Goal::Context
LevelDirector::build_GoalCtx(const GameContext& ctx) const
{
- GoalContext gctx;
+ Goal::Context gctx;
for (const StepPlate& sp : _step_plates)
if (sp.plate && sp.plate->active)
@@ -186,8 +186,8 @@ LevelDirector::build_GoalCtx(const GameContext& ctx) const
gctx.picked_up_this_step = _ledger.picked_up;
if (gctx.compile_ok_this_step) {
- std::string src = TextWall::extract_Text(ctx.wall_texts, Wall::Role::Editor);
- gctx.editor_normalized = LevelCheck::normalize(src);
+ std::string src = Wall::Text::extract_Text(ctx.wall_texts, Wall::Role::Editor);
+ gctx.editor_normalized = Level::Check::normalize(src);
}
return gctx;
}
@@ -200,8 +200,8 @@ LevelDirector::try_Advance(GameContext& ctx, double dt,
_step_age += dt;
AdvanceResult res;
- if (celebration.active()) {
- if (celebration.progress() >= 1.0) {
+ if (celebration.is_Active()) {
+ if (celebration.get_Progress() >= 1.0) {
celebration.finish(particles);
teardown_Scene(ctx);
@@ -209,16 +209,16 @@ LevelDirector::try_Advance(GameContext& ctx, double dt,
res.stepped = true;
res.advanced = _runner->advance();
- res.reset_carry = res.advanced && _runner->current().reset_carry;
+ res.reset_carry = res.advanced && _runner->get_Current().reset_carry;
_step_age = 0.0;
}
return res;
}
- if (_runner->complete()) return res;
+ if (_runner->is_Complete()) return res;
- GoalContext gctx = build_GoalCtx(ctx);
- if (!goal_Satisfied(_runner->current().goal, gctx)) return res;
+ Goal::Context gctx = build_GoalCtx(ctx);
+ if (!Goal::is_Satisfied(_runner->get_Current().goal, gctx)) return res;
if (_step_age < ConfigLevel::settle_time_for_step) return res;
double glyph_yaw = SDL_atan2(-ctx.camera->fwd.x, -ctx.camera->fwd.z);
diff --git a/src/systems/level_director.hpp b/src/systems/level_director.hpp
index 76f6ecd..543ce34 100644
--- a/src/systems/level_director.hpp
+++ b/src/systems/level_director.hpp
@@ -10,16 +10,17 @@
#include "systems/level_runner_system.hpp"
#include "utils/globals.hpp"
-struct GameContext;
-class Plate;
-class WordAiSystem;
-class HintSystem;
+
class CelebrationSystem;
+class HintSystem;
class ParticleSystem;
+class Plate;
+class WordAiSystem;
+struct GameContext;
-
-struct StepLedger {
+struct StepLedger
+{
DynArray<PultAction> buttons_pressed;
DynArray<std::string> ai_defeated;
DynArray<std::string> picked_up;
@@ -29,8 +30,8 @@ struct StepLedger {
void clear() {
buttons_pressed.clear();
- ai_defeated.clear();
- picked_up.clear();
+ ai_defeated .clear();
+ picked_up .clear();
compile_ok = false;
dropped = false;
shot = false;
@@ -38,7 +39,8 @@ struct StepLedger {
};
-struct StepPlate {
+struct StepPlate
+{
Plate* plate;
std::string tag;
};
@@ -55,10 +57,10 @@ class LevelDirector
DynArray<GameObject*> _step_scenery;
void spawn_Grants (GameContext& ctx);
- void setup_Scene (GameContext& ctx, const Scene& scene);
+ void setup_Scene (GameContext& ctx, const Scene::Data& scene);
void teardown_Scene(GameContext& ctx);
- GoalContext build_GoalCtx (const GameContext& ctx) const;
+ Goal::Context build_GoalCtx (const GameContext& ctx) const;
public:
struct AdvanceResult {
@@ -84,10 +86,11 @@ public:
void record_AiDefeated(const std::string& t) { _ledger.ai_defeated.push_back(t); }
void record_CompileOk () { _ledger.compile_ok = true; }
- LevelRunner& runner() { return *_runner; }
- const LevelRunner& runner() const { return *_runner; }
- bool complete() const { return _runner->complete(); }
+ bool is_LevelComplete() const { return _runner->is_Complete(); }
+
+ LevelRunner& get_Runner() { return *_runner; }
+ const LevelRunner& get_Runner() const { return *_runner; }
+ const std::string& get_CurrentHint() const { return _runner->get_Current().hint; }
int get_MaxAiForStep() const;
- const std::string& current_hint() const { return _runner->current().hint; }
- DynArray<StepPlate>& step_Plates() { return _step_plates; }
+ DynArray<StepPlate>& get_StepPlates() { return _step_plates; }
};
diff --git a/src/systems/level_runner_system.cpp b/src/systems/level_runner_system.cpp
index f66dffe..388d186 100644
--- a/src/systems/level_runner_system.cpp
+++ b/src/systems/level_runner_system.cpp
@@ -2,16 +2,19 @@
LevelRunner::LevelRunner(const Level::Data& l) : _level(&l) {}
+
bool LevelRunner::advance()
{
_current_step++;
- return !complete();
+ return !is_Complete();
}
-DynArray<std::string> LevelRunner::garants_ForStep() const
+
+DynArray<std::string>
+LevelRunner::get_GarantsForStep() const
{
DynArray<std::string> result;
- for (const Level::TokenGrant& grant : current().grants)
+ for (const Level::TokenGrant& grant : get_Current().grants)
for (const std::string& c : grant.choices)
result.push_back(c);
return result;
diff --git a/src/systems/level_runner_system.hpp b/src/systems/level_runner_system.hpp
index c1d6131..5f249a5 100644
--- a/src/systems/level_runner_system.hpp
+++ b/src/systems/level_runner_system.hpp
@@ -1,7 +1,10 @@
#pragma once
+
#include "levels/level.hpp"
-class LevelRunner {
+
+class LevelRunner
+{
const Level::Data*
_level;
@@ -9,17 +12,16 @@ class LevelRunner {
public:
explicit LevelRunner(const Level::Data& _level);
- bool advance();
- bool complete() const { return _current_step >= _level->steps.size(); }
+ bool advance ();
- size_t step() const { return _current_step; }
- const Level::Step&
- current() const { return _level->steps[_current_step]; }
+ bool is_Complete () const { return _current_step >= _level->steps.size(); }
+ bool is_DynamicLib () const { return _level->dynamic_lib; }
- bool dynamic_lib() const { return _level->dynamic_lib; }
+ size_t get_Step () const { return _current_step; }
+ const Level::Step&
+ get_Current () const { return _level->steps[_current_step]; }
const std::string&
- source_file() const { return _level->source_file; }
-
+ get_SourceFile() const { return _level->source_file; }
DynArray<std::string>
- garants_ForStep() const;
+ get_GarantsForStep() const;
};
diff --git a/src/systems/particle_system.cpp b/src/systems/particle_system.cpp
index 4c25ed4..dd96552 100644
--- a/src/systems/particle_system.cpp
+++ b/src/systems/particle_system.cpp
@@ -2,7 +2,6 @@
#include <SDL3/SDL.h>
#include <algorithm>
-#include <cstdlib>
#include "entities/camera.hpp"
#include "entities/game_object.hpp"
@@ -90,8 +89,8 @@ ParticleSystem::update(double dt,
// Cheap point-in-AABB check; particles are tiny so this is fine.
for (const GameObject* obj : solid_colliders) {
if (!obj || !obj->solid) continue;
- const Vec3 mn = obj->aabb_min();
- const Vec3 mx = obj->aabb_max();
+ const Vec3 mn = obj->aabb_Min();
+ const Vec3 mx = obj->aabb_Max();
if (p.pos.x >= mn.x && p.pos.x <= mx.x &&
p.pos.y >= mn.y && p.pos.y <= mx.y &&
p.pos.z >= mn.z && p.pos.z <= mx.z)
@@ -122,7 +121,7 @@ ParticleSystem::draw(GlRenderer& gl, const Camera& cam, const Light& light) cons
glow.flashlight_intensity = 0.0f;
Mat4 view = buildViewMat4(cam);
- Mat4 proj = gl.projection();
+ Mat4 proj = gl.get_Projection();
gl.set_Wireframe(false);
gl.set_Light(glow);
diff --git a/src/systems/particle_system.hpp b/src/systems/particle_system.hpp
index a7b479f..066e125 100644
--- a/src/systems/particle_system.hpp
+++ b/src/systems/particle_system.hpp
@@ -5,38 +5,27 @@
#include "rendering/gl_renderer.hpp"
#include "utils/globals.hpp"
#include "utils/light.hpp"
-#include "utils/math.hpp"
+
class Camera;
class GameObject;
-// One particle. Lives ~1-2 seconds, falls under gravity, vanishes on
-// collision or when its lifetime expires.
-struct Particle {
+struct Particle
+{
bool alive { true };
float yaw { 0.0f };
- float spin { 0.0f }; // radians/sec
+ float spin { 0.0f };
double age { 0.0 };
double lifetime { 1.5 };
Vec3 pos{};
Vec3 vel{};
+
SDL_FColor color { 1.0f, 1.0f, 1.0f, 1.0f };
};
-// ParticleSystem owns a flat vector of particles.
-// Designed for the success celebration but generic — anyone can emit_Burst.
-//
-// Lifecycle:
-// update(dt, colliders, world_scale) — tick physics, kill on hit / lifetime
-// draw (gl, cam, light) — render every alive particle
-// emit_FireworkBurst(center, color) — spawn ~80 particles in a sphere
-//
-// Particles ignore everything except: the world bounds (floor/walls/ceiling)
-// and a caller-supplied list of solid GameObjects (so they pop on pults).
-// They do NOT collide with words, AI, or each other — by design.
class ParticleSystem
{
DynArray<Particle> _particles;
@@ -47,7 +36,6 @@ public:
void clear ();
bool empty () const { return _particles.empty(); }
void draw (GlRenderer& gl, const Camera& cam, const Light& light) const;
- void emit_FireworkBurst(const Vec3& center,
- SDL_FColor color,
- int count = 80);
+
+ void emit_FireworkBurst(const Vec3& center, SDL_FColor color, int count = 80);
};
diff --git a/src/systems/physics_system.cpp b/src/systems/physics_system.cpp
index 394e6e3..5d57e11 100644
--- a/src/systems/physics_system.cpp
+++ b/src/systems/physics_system.cpp
@@ -58,15 +58,15 @@ PhysicsSystem::resolve_PlayerVsObjects(Player& player, CarriedLine& carried,
for (GameObject* obj : colliders) {
if (!obj || !obj->solid) continue;
- const Vec3 omin = obj->aabb_min();
- const Vec3 omax = obj->aabb_max();
+ const Vec3 omin = obj->aabb_Min();
+ const Vec3 omax = obj->aabb_Max();
if (px_max >= omin.x && px_min <= omax.x &&
py_max >= omin.y && py_min <= omax.y &&
pz_max >= omin.z && pz_min <= omax.z) {
- double ox = std::min(px_max, omax.x) - std::max(px_min, omin.x);
- double oy = std::min(py_max, omax.y) - std::max(py_min, omin.y);
- double oz = std::min(pz_max, omax.z) - std::max(pz_min, omin.z);
+ double ox = SDL_min(px_max, omax.x) - SDL_max(px_min, omin.x);
+ double oy = SDL_min(py_max, omax.y) - SDL_max(py_min, omin.y);
+ double oz = SDL_min(pz_max, omax.z) - SDL_max(pz_min, omin.z);
Vec3 normal{};
double overlap{};
@@ -249,17 +249,17 @@ PhysicsSystem::resolve_WorldBounds(GameObject& obj)
// Floor
if (obj.pos.y - he.y < -ws) {
obj.pos.y = -ws + he.y;
- obj.body.vel.y = std::abs(obj.body.vel.y) * obj.body.restitution;
+ obj.body.vel.y = SDL_fabs(obj.body.vel.y) * obj.body.restitution;
obj.body.vel.x *= obj.body.friction;
obj.body.vel.z *= obj.body.friction;
- if (std::abs(obj.body.vel.y) < 0.05) obj.body.vel.y = 0.0;
- if (std::abs(obj.body.vel.x) < 0.01) obj.body.vel.x = 0.0;
- if (std::abs(obj.body.vel.z) < 0.01) obj.body.vel.z = 0.0;
+ if (SDL_fabs(obj.body.vel.y) < 0.05) obj.body.vel.y = 0.0;
+ if (SDL_fabs(obj.body.vel.x) < 0.01) obj.body.vel.x = 0.0;
+ if (SDL_fabs(obj.body.vel.z) < 0.01) obj.body.vel.z = 0.0;
}
// Ceiling
if (obj.pos.y + he.y > ws) {
obj.pos.y = ws - he.y;
- obj.body.vel.y = -std::abs(obj.body.vel.y) * obj.body.restitution;
+ obj.body.vel.y = -SDL_fabs(obj.body.vel.y) * obj.body.restitution;
}
// Side walls
if (obj.pos.x + he.x > ws) { obj.pos.x = ws - he.x; obj.body.vel.x *= -obj.body.restitution; }
@@ -408,7 +408,7 @@ PhysicsSystem::resolve_Projectiles(DynArray<Projectile>& projectiles,
constexpr double RESTITUTION_TEXT = 0.55;
Vec3 vel_before = proj.vel;
Collision::SweptResult sw;
- if (resolve_SingleBoxCollision(proj, obj->aabb_min(), obj->aabb_max(),
+ if (resolve_SingleBoxCollision(proj, obj->aabb_Min(), obj->aabb_Max(),
word_he, RESTITUTION_TEXT,
cur, prev, dir, sw)) {
proj.collided = true;
@@ -429,7 +429,7 @@ PhysicsSystem::resolve_Projectiles(DynArray<Projectile>& projectiles,
}
Collision::SweptResult sw;
- if (resolve_SingleBoxCollision(proj, obj->aabb_min(), obj->aabb_max(),
+ if (resolve_SingleBoxCollision(proj, obj->aabb_Min(), obj->aabb_Max(),
word_he, RESTITUTION_STATIC,
cur, prev, dir, sw)) {
proj.collided = true;
@@ -446,9 +446,9 @@ PhysicsSystem::resolve_Projectiles(DynArray<Projectile>& projectiles,
constexpr double RESTITUTION_LABEL = 0.55;
for (TextLabel* label : *labels) {
- if (!label || label->empty()) continue;
+ if (!label || label->is_Empty()) continue;
- const auto& lw = label->words();
+ const auto& lw = label->get_Words();
for (size_t i = 0; i < lw.size(); ++i) {
const Text3dPtr& hw = lw[i];
if (!hw || !hw->loaded) continue;
@@ -456,7 +456,7 @@ PhysicsSystem::resolve_Projectiles(DynArray<Projectile>& projectiles,
Vec3 vel_before = proj.vel;
Collision::SweptResult sw;
- if (resolve_SingleBoxCollision(proj, hw->aabb_min(), hw->aabb_max(),
+ if (resolve_SingleBoxCollision(proj, hw->aabb_Min(), hw->aabb_Max(),
word_he, RESTITUTION_LABEL,
cur, prev, dir, sw)) {
proj.collided = true;
diff --git a/src/systems/physics_system.hpp b/src/systems/physics_system.hpp
index f5fa74b..9c44789 100644
--- a/src/systems/physics_system.hpp
+++ b/src/systems/physics_system.hpp
@@ -6,18 +6,22 @@
#include "systems/collision.hpp"
#include "utils/globals.hpp"
+
struct Projectile;
class TextLabel;
-struct ProjectileContactEvent {
+
+struct ProjectileContactEvent
+{
Projectile* projectile = nullptr;
GameObject* other = nullptr;
Vec3 point{};
Vec3 normal{};
};
-class PhysicsSystem {
- // Uniform spatial grid scratch, reused each frame to avoid reallocation.
+
+class PhysicsSystem
+{
struct SpatialGrid {
int nx = 0, nz = 0;
double cell = 2.0;
@@ -43,12 +47,11 @@ class PhysicsSystem {
void collide_Grid(const DynArray<GameObject*>& active);
public:
- void update_Player(Player& player, double acc_x, double acc_z, double dt);
+ void update_Player (Player& player, double acc_x, double acc_z, double dt);
void update_Objects(const DynArray<GameObject*>& objects,
double dt, double gravity);
-
- void update_Projectiles(DynArray<Projectile>& projectiles, double dt,
- const DynArray<Text3dPtr>& words);
+ void update_Projectiles (DynArray<Projectile>& projectiles, double dt,
+ const DynArray<Text3dPtr>& words);
void resolve_Projectiles(DynArray<Projectile>& projectiles,
const DynArray<GameObject*>* statics,
const DynArray<TextLabel*>* labels,
diff --git a/src/systems/pick_system.cpp b/src/systems/pick_system.cpp
index 7267415..8663694 100644
--- a/src/systems/pick_system.cpp
+++ b/src/systems/pick_system.cpp
@@ -60,7 +60,7 @@ PickResult
pick(const Camera& camera,
const DynArray<Text3dPtr>& words,
const DynArray<GameObjectPtr>& scenery,
- const DynArray<TextWallPtr>& wall_texts)
+ const DynArray<Wall::Ptr>& wall_texts)
{
const Vec3& eye = camera.pos;
@@ -96,7 +96,7 @@ pick(const Camera& camera,
}
for (size_t i = 0; i < wall_texts.size(); ++i) {
- const TextWallPtr& wt = wall_texts[i];
+ const Wall::Ptr& wt = wall_texts[i];
if (!wt || !wt->text3d) continue;
if (wt->text3d->pos.y < floor_y) continue;
double a = ang_score(*wt->text3d, eye, camera.fwd);
diff --git a/src/systems/pick_system.hpp b/src/systems/pick_system.hpp
index 81a4ed0..fc31e4a 100644
--- a/src/systems/pick_system.hpp
+++ b/src/systems/pick_system.hpp
@@ -1,21 +1,23 @@
#pragma once
-#include <cstddef>
-
#include "entities/camera.hpp"
#include "entities/game_object.hpp"
#include "text_3d/text_3d.hpp"
#include "utils/globals.hpp"
-#include "wall/text_wall.hpp"
+#include "wall/wall.hpp"
+
-enum class PickKind : uint8_t {
+enum class PickKind : uint8_t
+{
None,
Scenery,
Wall,
Word,
};
-struct PickResult {
+
+struct PickResult
+{
size_t word_index { 0 };
size_t wall_index { 0 };
@@ -25,10 +27,11 @@ struct PickResult {
bool hit() const { return kind != PickKind::None; }
};
+
namespace PickSystem
{
PickResult pick(const Camera& camera,
const DynArray<Text3dPtr>& words,
const DynArray<GameObjectPtr>& scenery,
- const DynArray<TextWallPtr>& wall_texts);
+ const DynArray<Wall::Ptr>& wall_texts);
}
diff --git a/src/systems/plate_system.cpp b/src/systems/plate_system.cpp
index c60f7de..62ee1e1 100644
--- a/src/systems/plate_system.cpp
+++ b/src/systems/plate_system.cpp
@@ -20,8 +20,8 @@ PlateSystem::update(double dt,
plate->tick(dt);
- const Vec3 mn = plate->aabb_min();
- const Vec3 mx = plate->aabb_max();
+ const Vec3 mn = plate->aabb_Min();
+ const Vec3 mx = plate->aabb_Max();
const bool xz_overlap = px_max >= mn.x && px_min <= mx.x &&
pz_max >= mn.z && pz_min <= mx.z;
diff --git a/src/systems/program_system.cpp b/src/systems/program_system.cpp
index 22095be..09ad3dc 100644
--- a/src/systems/program_system.cpp
+++ b/src/systems/program_system.cpp
@@ -10,7 +10,7 @@
#include "entities/world.hpp"
#include "systems/program_system.hpp"
#include "text_3d/text_3d.hpp"
-#include "utils/ascii.hpp"
+#include "utils/text.hpp"
#include "utils/config.hpp"
@@ -38,12 +38,12 @@ ProgramSystem::close_Child()
void
-ProgramSystem::run(TextWallList& texts, float world_scale)
+ProgramSystem::run(Wall::PtrList& texts, float world_scale)
{
// Clear previous output from the Program wall.
texts.erase(
std::remove_if(texts.begin(), texts.end(),
- [](const TextWallPtr& wt) {
+ [](const Wall::Ptr& wt) {
return wt->role == Wall::Role::Program;
}),
texts.end());
@@ -105,7 +105,7 @@ ProgramSystem::run(TextWallList& texts, float world_scale)
void
-ProgramSystem::update(TextWallList& texts, float world_scale)
+ProgramSystem::update(Wall::PtrList& texts, float world_scale)
{
if (_out_fd < 0) return;
@@ -167,19 +167,19 @@ ProgramSystem::feed_Input(const std::string& text)
void
-ProgramSystem::echo_Input(TextWallList& texts, const std::string& line)
+ProgramSystem::echo_Input(Wall::PtrList& texts, const std::string& line)
{
push_Line(texts, line, World::get_BoxScale()); // scrolls up, lands at the prompt row
}
void
-ProgramSystem::echo_Words(TextWallList& texts, DynArray<Text3dPtr>& words, float world_scale)
+ProgramSystem::echo_Words(Wall::PtrList& texts, DynArray<Text3dPtr>& words, float world_scale)
{
if (words.empty()) return;
// Make room: scroll existing program output up by one line.
- for (TextWallPtr& wt : texts)
+ for (Wall::Ptr& wt : texts)
if (wt->role == Wall::Role::Program)
wt->text3d->pos.y += static_cast<double>(line_height);
@@ -194,8 +194,8 @@ ProgramSystem::echo_Words(TextWallList& texts, DynArray<Text3dPtr>& words, float
w->pos.y = start_y; // align the echoed row to the line
w->set_Look(ConfigColor::keep, Text3d::depth_wall);
- texts.push_back(cpputils::make_unique<TextWall>(TextWall{
- Wall::position_of(Wall::Role::Program),
+ texts.push_back(cpputils::make_unique<Wall::Text>(Wall::Text{
+ Wall::position_Of(Wall::Role::Program),
Wall::Role::Program,
std::move(w)
}));
@@ -205,12 +205,12 @@ ProgramSystem::echo_Words(TextWallList& texts, DynArray<Text3dPtr>& words, float
void
-ProgramSystem::push_Line(TextWallList& texts, const std::string& line, float world_scale)
+ProgramSystem::push_Line(Wall::PtrList& texts, const std::string& line, float world_scale)
{
- std::string clean = ascii_Sanitize(line);
+ std::string clean = Text::ascii_Sanitize(line);
// Shift existing program-wall lines up so new output appears at the bottom.
- for (TextWallPtr& wt : texts)
+ for (Wall::Ptr& wt : texts)
if (wt->role == Wall::Role::Program)
wt->text3d->pos.y += static_cast<double>(line_height);
@@ -223,7 +223,7 @@ ProgramSystem::push_Line(TextWallList& texts, const std::string& line, float wor
pos, ConfigColor::dark_gray);
t->yaw = tf.yaw;
- texts.push_back(cpputils::make_unique<TextWall>(TextWall{
+ texts.push_back(cpputils::make_unique<Wall::Text>(Wall::Text{
tf.wall_position,
Wall::Role::Program,
std::move(t)
diff --git a/src/systems/program_system.hpp b/src/systems/program_system.hpp
index 19e419a..8c436d9 100644
--- a/src/systems/program_system.hpp
+++ b/src/systems/program_system.hpp
@@ -1,10 +1,12 @@
#pragma once
+
#include <string>
#include <sys/types.h>
#include "entities/world.hpp"
#include "utils/globals.hpp"
-#include "wall/text_wall.hpp"
+#include "wall/wall.hpp"
+
struct ProgramSystem
{
@@ -15,21 +17,21 @@ private:
pid_t _child {-1};
- std::string _pending; // partial-line buffer for stdout
+ std::string _pending;
- void push_Line(TextWallList&, const std::string& line, float world_scale);
+ void push_Line (Wall::PtrList&, const std::string& line, float world_scale);
void close_Child();
public:
static inline float line_height = 0.4f;
static inline float start_y = World::get_FloorY() + 1;
- void run (TextWallList&, float world_scale);
- void update (TextWallList&, float world_scale);
+ void run (Wall::PtrList&, float world_scale);
+ void update (Wall::PtrList&, float world_scale);
+
void feed_Input (const std::string& text);
- void echo_Input (TextWallList&, const std::string& line);
- // Park already-thrown (animated) words on the Program wall as one echoed
- // input line, scrolling existing output up — terminal style.
- void echo_Words (TextWallList&, DynArray<Text3dPtr>& words, float world_scale);
+ void echo_Input (Wall::PtrList&, const std::string& line);
+ void echo_Words (Wall::PtrList&, DynArray<Text3dPtr>& words, float world_scale);
+
bool is_Running () const { return _child > 0; }
~ProgramSystem();
diff --git a/src/systems/projectile_system.cpp b/src/systems/projectile_system.cpp
index 89e2509..f4daef9 100644
--- a/src/systems/projectile_system.cpp
+++ b/src/systems/projectile_system.cpp
@@ -180,14 +180,14 @@ check_WallTextIntercept(const Projectile& p, const Vec3& centroid, double dt,
if (editor_wall) {
// Vertical row gate (as before): only the aimed row's words.
- const double center_y = (wt.aabb_min.y + wt.aabb_max.y) * 0.5;
+ const double center_y = (wt.aabb_Min.y + wt.aabb_Max.y) * 0.5;
if (SDL_fabs(aim_y - center_y) > ConfigWall::line_height * 0.5)
continue;
// Horizontal: only shoot the word down if the aim lands in its
// central 2/3. Outer 1/3 each side is "between words" → merge.
- const double center_z = (wt.aabb_min.z + wt.aabb_max.z) * 0.5;
- const double half_z = (wt.aabb_max.z - wt.aabb_min.z) * 0.5;
+ const double center_z = (wt.aabb_Min.z + wt.aabb_Max.z) * 0.5;
+ const double half_z = (wt.aabb_Max.z - wt.aabb_Min.z) * 0.5;
if (SDL_fabs(aim_z - center_z) > half_z * (2.0 / 3.0))
continue;
@@ -197,12 +197,12 @@ check_WallTextIntercept(const Projectile& p, const Vec3& centroid, double dt,
return true;
}
- Vec3 box_min { wt.aabb_min.x - word_he.x,
- wt.aabb_min.y - word_he.y,
- wt.aabb_min.z - word_he.z };
- Vec3 box_max { wt.aabb_max.x + word_he.x,
- wt.aabb_max.y + word_he.y,
- wt.aabb_max.z + word_he.z };
+ Vec3 box_min { wt.aabb_Min.x - word_he.x,
+ wt.aabb_Min.y - word_he.y,
+ wt.aabb_Min.z - word_he.z };
+ Vec3 box_max { wt.aabb_Max.x + word_he.x,
+ wt.aabb_Max.y + word_he.y,
+ wt.aabb_Max.z + word_he.z };
Collision::SweptResult sw =
Collision::swept_RayAabb(p.prev_centroid, ray_dir, box_min, box_max);
@@ -353,12 +353,12 @@ handle_WallHit(Projectile& p, const Vec3& centroid, Wall::Position hit_pos,
DynArray<ProjectileResult>& results,
bool program_running)
{
- if (Wall::role_of(hit_pos) == Wall::Role::Program) {
+ if (Wall::role_Of(hit_pos) == Wall::Role::Program) {
if (program_running) { begin_ProgramStick(p, ws); return false; }
return bounce_OffWall(p, hit_pos, ws, results);
}
- const bool editor = (Wall::role_of(hit_pos) == Wall::Role::Editor);
+ const bool editor = (Wall::role_Of(hit_pos) == Wall::Role::Editor);
const double plane = wall_plane_coord(hit_pos, ws);
const double aim_y = editor ? editor_AimY(p, plane) : 0.0;
const double aim_z = editor ? editor_AimZ(p, plane) : 0.0;
@@ -377,7 +377,7 @@ handle_WallHit(Projectile& p, const Vec3& centroid, Wall::Position hit_pos,
return true;
}
- if (Wall::role_of(hit_pos) == Wall::Role::Editor) {
+ if (Wall::role_Of(hit_pos) == Wall::Role::Editor) {
begin_EditorStick(p, hit_pos);
return false;
}
diff --git a/src/systems/projectile_system.hpp b/src/systems/projectile_system.hpp
index cee9fc1..f1655c1 100644
--- a/src/systems/projectile_system.hpp
+++ b/src/systems/projectile_system.hpp
@@ -1,29 +1,40 @@
#pragma once
-#include <cstdint>
-
#include "systems/aim.hpp"
#include "text_3d/text_3d.hpp"
#include "utils/globals.hpp"
-#include "utils/math.hpp"
#include "wall/wall.hpp"
+
static constexpr uint8_t BOUNCED_X = 1 << 0;
static constexpr uint8_t BOUNCED_Z = 1 << 1;
-struct Projectile {
+
+enum class ProjectileLanding : uint8_t
+{
+ None,
+ Floor,
+ ProgramInput,
+ Wall,
+ WallText,
+};
+
+
+struct Projectile
+{
Wall::Position
stick_wall { Wall::Position::PosX };
bool sticking = false;
bool collided = false;
bool program_stick = false;
- uint8_t bounce_state = 0;
+ uint8_t bounce_state = 0;
float ribbon_start_yaw {};
float ribbon_target_yaw {};
double yaw;
double stick_t = 0.0;
double step_dt = 0.0;
- Text3d* track_obj = nullptr;
+
+ Text3d* track_obj = nullptr;
Vec3 vel{};
Vec3 dir{};
@@ -42,36 +53,32 @@ struct Projectile {
DynArray<Text3dPtr> words;
};
-struct WallTextHitTest {
+
+struct WallTextHitTest
+{
Wall::Position
wall_position;
size_t index;
- Vec3 aabb_min;
- Vec3 aabb_max;
+ Vec3 aabb_Min;
+ Vec3 aabb_Max;
};
-enum class ProjectileLanding : uint8_t {
- Floor,
- None,
- ProgramInput,
- Wall,
- WallText,
-};
-struct ProjectileResult {
+struct ProjectileResult
+{
Wall::Position
- wall_pos = Wall::Position::NegZ;
+ wall_pos = Wall::Position::NegZ;
size_t wall_text_index = 0;
- Vec3 vel{};
+ Vec3 vel {};
ProjectileLanding landing = ProjectileLanding::None;
DynArray<Text3dPtr> words;
};
-class ProjectileSystem {
-public:
+struct ProjectileSystem
+{
void launch(DynArray<Projectile>& out,
DynArray<Text3dPtr> words,
const Vec3& fwd,
diff --git a/src/systems/pult_system.cpp b/src/systems/pult_system.cpp
index f7041c9..0683ac8 100644
--- a/src/systems/pult_system.cpp
+++ b/src/systems/pult_system.cpp
@@ -173,7 +173,7 @@ PultSystem::draw_Labels(GlRenderer& gl, const Camera& camera, const Light& light
DynArray<TextLabel*>
-PultSystem::get_Labels()
+PultSystem::get_Labels() const
{
DynArray<TextLabel*> out;
out.reserve(_pults.size());
diff --git a/src/systems/pult_system.hpp b/src/systems/pult_system.hpp
index c899c71..1d23239 100644
--- a/src/systems/pult_system.hpp
+++ b/src/systems/pult_system.hpp
@@ -13,15 +13,21 @@ struct Light;
struct Player;
struct ProjectileContactEvent;
+
class PultSystem
{
+ Pult* _connect_program { nullptr };
+ Pult* _connect_editor { nullptr };
+
DynArray<Pult*> _pults;
- Pult* _connect_program { nullptr };
- Pult* _connect_editor { nullptr };
public:
- void init (DynArray<GameObjectPtr>& scenery,
- DynArray<PultButton*>& buttons_out,
- float world_scale);
+ void init (DynArray<GameObjectPtr>& scenery,
+ DynArray<PultButton*>& buttons_out,
+ float world_scale);
+ void update (double dt, const Camera& camera);
+ void draw_Labels (GlRenderer& gl, const Camera& camera, const Light& light) const;
+
+
std::optional<PultAction>
try_Activate (GameObject* obj,
const DynArray<PultButton*>& buttons);
@@ -31,14 +37,11 @@ public:
std::optional<PultAction>
handle_PlayerContact (const Player& player,
const DynArray<PultButton*>& buttons);
+
Vec3 get_ConnectProgramPos () const;
Vec3 get_ConnectEditorPos () const;
-
DynArray<TextLabel*>
- get_Labels ();
-
- void update (double dt, const Camera& camera);
- void draw_Labels(GlRenderer& gl, const Camera& camera, const Light& light) const;
+ get_Labels () const;
};
diff --git a/src/systems/wall_connection.cpp b/src/systems/wall_connection.cpp
index c44a937..0484c5a 100644
--- a/src/systems/wall_connection.cpp
+++ b/src/systems/wall_connection.cpp
@@ -1,5 +1,4 @@
#include <SDL3/SDL.h>
-#include <cstdlib>
#include <sstream>
#include "cpp_token/cpp_highlight.hpp"
@@ -62,7 +61,7 @@ WallConnection::load_Editor(const DynArray<std::string>& lines, double eye_y)
std::vector<std::string> v(lines.begin(), lines.end());
_vim.load(v);
if (_vim.is_Empty()) _vim.start_Insert();
- _vim_seen_version = _vim.version();
+ _vim_seen_version = _vim.get_Version();
_eye_y = eye_y;
_status.clear();
rebuild_Editor();
@@ -133,18 +132,18 @@ WallConnection::feed_Vim(DynArray<int>& keys, double eye_y)
default: break;
}
- if (_vim.version() != _vim_seen_version) {
- _vim_seen_version = _vim.version();
+ if (_vim.get_Version() != _vim_seen_version) {
+ _vim_seen_version = _vim.get_Version();
rebuild_Editor();
}
return req;
}
DynArray<std::string>
-WallConnection::lines() const
+WallConnection::get_Lines() const
{
DynArray<std::string> out;
- for (const std::string& l : _vim.lines()) out.push_back(l);
+ for (const std::string& l : _vim.get_Lines()) out.push_back(l);
return out;
}
@@ -155,15 +154,15 @@ WallConnection::rebuild_Editor()
const float ws = World::get_BoxScale();
Wall::Transform tf = Wall::get_Transform(Wall::Role::Editor, ws);
const double lh = ConfigWall::line_height;
- const int R = _vim.row();
- const int N = (int)_vim.lines().size();
+ const int R = _vim.get_Row();
+ const int N = (int)_vim.get_Lines().size();
const double bottom_y = -static_cast<double>(ws) + 1.2;
const double anchor_cursor = _eye_y + static_cast<double>(R) * lh;
const double anchor_bottom = bottom_y + static_cast<double>(N - 1) * lh;
_row0_y = SDL_min(anchor_cursor, anchor_bottom);
- const auto& lines = _vim.lines();
+ const auto& lines = _vim.get_Lines();
const double char_w = mono_CharWidth();
const double he_y = mono_HalfExtentY();
@@ -322,10 +321,10 @@ WallConnection::rebuild_Cmdline()
_cmdline.reset();
std::string text;
- if (_vim.mode() == VimBuffer::Mode::Command) text = _vim.cmdline();
- else if (!_status.empty()) text = _status[0];
- else if (!_vim.status().empty()) text = _vim.status();
- else text = (_vim.mode() == VimBuffer::Mode::Insert) ? "-- INSERT --" : "-- NORMAL --";
+ if (_vim.get_Mode() == VimBuffer::Mode::Command) text = _vim.get_Cmdline();
+ else if (!_status.empty()) text = _status[0];
+ else if (!_vim.get_Status().empty()) text = _vim.get_Status();
+ else text = (_vim.get_Mode() == VimBuffer::Mode::Insert) ? "-- INSERT --" : "-- NORMAL --";
if (text.empty()) return;
// Built at origin; render() places it at the eased _cmd_pos each frame.
@@ -336,7 +335,7 @@ WallConnection::rebuild_Cmdline()
void
WallConnection::update(double dt, const Camera& cam, float aspect, float fov_y)
{
- if (!active()) return;
+ if (!is_Active()) return;
_blink += dt;
const Vec3 up = Math::cross(cam.right, cam.fwd);
@@ -413,18 +412,18 @@ WallConnection::draw_ProgramCursor(GlRenderer& gl, const Camera& cam, const Ligh
Vec3 c = _prog_input->pos;
c.z = _prog_input->pos.z - (static_cast<double>(_prog_input->half_extent) + 0.15);
- Mat4 view = buildViewMat4(cam);
- Mat4 model = buildModelMat4(c, _prog_input->yaw);
- Mat4 mvp = Mat4::mul(gl.projection(), Mat4::mul(view, model));
+ Mat4 view = buildViewMat4 (cam);
+ Mat4 get_Model = buildModelMat4(c, _prog_input->yaw);
+ Mat4 mvp = Mat4::mul (gl.get_Projection(), Mat4::mul(view, get_Model));
gl.set_Wireframe(false);
- gl.set_MVP(model, mvp);
- gl.set_NormalMat(model);
- gl.set_Light(light);
- gl.set_Color(0.6f, 1.0f, 1.0f);
- gl.set_Emissive(0.6f, 1.0f, 1.0f, 0.9f);
- gl.draw_Box(0.04f, 0.22f, 0.02f);
- gl.set_Emissive(0.0f, 0.0f, 0.0f, 0.0f);
+ gl.set_MVP (get_Model, mvp);
+ gl.set_NormalMat(get_Model);
+ gl.set_Light (light);
+ gl.set_Color (0.6f, 1.0f, 1.0f);
+ gl.set_Emissive (0.6f, 1.0f, 1.0f, 0.9f);
+ gl.draw_Box (0.04f, 0.22f, 0.02f);
+ gl.set_Emissive (0.0f, 0.0f, 0.0f, 0.0f);
}
void
@@ -432,7 +431,7 @@ WallConnection::draw_EditorCursor(GlRenderer& gl, const Camera& cam, const Light
{
if (SDL_fmod(_blink, 0.8) > 0.4) return;
- const int row = _vim.row();
+ const int row = _vim.get_Row();
if (row < 0 || row >= (int)_rows.size()) return;
Wall::Transform tf = Wall::get_Transform(Wall::Role::Editor, World::get_BoxScale());
@@ -441,23 +440,23 @@ WallConnection::draw_EditorCursor(GlRenderer& gl, const Camera& cam, const Light
const EditorRow& er = _rows[(size_t)row];
const double cw = er.char_w;
- const int col = _vim.col();
+ const int col = _vim.get_Col();
const double cz = er.left_z - (static_cast<double>(col) + 0.5) * cw;
Vec3 c { er.line_x, row_y - (er.he_y + 0.06), cz };
- Mat4 view = buildViewMat4(cam);
- Mat4 model = buildModelMat4(c, tf.yaw);
- Mat4 mvp = Mat4::mul(gl.projection(), Mat4::mul(view, model));
+ Mat4 view = buildViewMat4 (cam);
+ Mat4 get_Model = buildModelMat4(c, tf.yaw);
+ Mat4 mvp = Mat4::mul (gl.get_Projection(), Mat4::mul(view, get_Model));
gl.set_Wireframe(false);
- gl.set_MVP(model, mvp);
- gl.set_NormalMat(model);
- gl.set_Light(light);
- gl.set_Color(0.6f, 1.0f, 1.0f);
- gl.set_Emissive(0.6f, 1.0f, 1.0f, 0.9f);
- gl.draw_Box(static_cast<float>(cw * 0.45), 0.015f, 0.03f);
- gl.set_Emissive(0.0f, 0.0f, 0.0f, 0.0f);
+ gl.set_MVP (get_Model, mvp);
+ gl.set_NormalMat(get_Model);
+ gl.set_Light (light);
+ gl.set_Color (0.6f, 1.0f, 1.0f);
+ gl.set_Emissive (0.6f, 1.0f, 1.0f, 0.9f);
+ gl.draw_Box (static_cast<float>(cw * 0.45), 0.015f, 0.03f);
+ gl.set_Emissive (0.0f, 0.0f, 0.0f, 0.0f);
}
void
@@ -485,11 +484,11 @@ WallConnection::draw_Electric(GlRenderer& gl, const Camera& cam) const
}
Mat4 ident = Mat4::identity();
- Mat4 mvp = Mat4::mul(gl.projection(), buildViewMat4(cam));
- gl.set_MVP(ident, mvp);
+ Mat4 mvp = Mat4::mul(gl.get_Projection(), buildViewMat4(cam));
+ gl.set_MVP (ident, mvp);
gl.set_NormalMat(ident);
gl.set_Wireframe(true);
- gl.set_Color(0.5f, 0.9f, 1.0f);
- gl.draw_Lines(pts.data(), static_cast<int>(pts.size()) / 3);
+ gl.set_Color (0.5f, 0.9f, 1.0f);
+ gl.draw_Lines (pts.data(), static_cast<int>(pts.size()) / 3);
gl.set_Wireframe(false);
}
diff --git a/src/systems/wall_connection.hpp b/src/systems/wall_connection.hpp
index 1c4487c..e1e760b 100644
--- a/src/systems/wall_connection.hpp
+++ b/src/systems/wall_connection.hpp
@@ -6,14 +6,17 @@
#include "text_3d/text_3d.hpp"
#include "text_3d/vim_buffer.hpp"
#include "utils/globals.hpp"
-#include "utils/math.hpp"
+
class Camera;
class GlRenderer;
struct Light;
-struct EditorRow {
- DynArray<Text3dPtr> toks; // per-token meshes, left→right (decreasing z)
+
+struct EditorRow
+{
+ DynArray<Text3dPtr>
+ toks; // per-token meshes, left→right (decreasing z)
double left_z { 0.0 }; // z of the row's left edge (start of char 0)
double char_w { 0.18 }; // mean character width in z (for cursor placement)
double he_y { 0.2 }; // glyph half-height (for cursor vertical offset)
@@ -21,30 +24,34 @@ struct EditorRow {
bool has_text { false };
};
+
class WallConnection
{
public:
enum class Target : uint8_t { None, Program, Editor };
enum class Request : uint8_t { None, Exit, Write, WriteQuit, QuitDiscard };
- bool active() const { return _target != Target::None; }
- Target target() const { return _target; }
+ void update(double dt, const Camera& cam, float aspect, float fov_y);
+ void render(GlRenderer& gl, const Camera& cam, const Light& light) const;
+ void end ();
- void begin_Program(const Vec3& pult_pos);
- void begin_Editor (const Vec3& pult_pos, const DynArray<std::string>& lines, double eye_y);
- void load_Editor (const DynArray<std::string>& lines, double eye_y);
- void end();
+ bool is_Active () const { return _target != Target::None; }
- void set_ProgramBuffer (const std::string& buffer);
- void clear_ProgramPreview();
+ Target get_Target() const { return _target; }
+ DynArray<std::string>
+ get_Lines () const;
+ void set_ProgramBuffer (const std::string& buffer);
+
+ void begin_Program(const Vec3& pult_pos);
+ void begin_Editor (const Vec3& pult_pos, const DynArray<std::string>& lines, double eye_y);
+ void load_Editor (const DynArray<std::string>& lines, double eye_y);
+
+ void mark_Saved() { _vim.mark_Saved(); }
+ void clear_ProgramPreview();
Request feed_Vim(DynArray<int>& keys, double eye_y);
- DynArray<std::string>
- lines () const;
- void update(double dt, const Camera& cam, float aspect, float fov_y);
- void render(GlRenderer& gl, const Camera& cam, const Light& light) const;
- void mark_Saved() { _vim.mark_Saved(); }
+
private:
bool _cmd_pos_init { false };
diff --git a/src/systems/word_ai_system.hpp b/src/systems/word_ai_system.hpp
index a6de80f..b0d2033 100644
--- a/src/systems/word_ai_system.hpp
+++ b/src/systems/word_ai_system.hpp
@@ -3,23 +3,24 @@
#include "text_3d/text_3d.hpp"
#include "utils/globals.hpp"
-struct Player;
-struct CarriedLine;
-class WordAiSystem {
+struct CarriedLine;
+struct Player;
- int _max_active_ai = 5;
+class WordAiSystem
+{
+ 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,
- DynArray<Text3dPtr>& dropped,
- DynArray<Text3dPtr>& released,
- double dt);
- void update_Flee (Text3d& w, const Player& p,
- DynArray<Text3dPtr>& released, double dt);
- void update_Stunned(Text3d& w, DynArray<Text3dPtr>& released, double dt);
+ 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,
+ DynArray<Text3dPtr>& dropped,
+ DynArray<Text3dPtr>& released,
+ double dt);
+ void update_Flee (Text3d& w, const Player& p,
+ DynArray<Text3dPtr>& released, double dt);
+ void update_Stunned (Text3d& w, DynArray<Text3dPtr>& released, double dt);
void update_StolenTrail(Text3d& w, double dt);
void release_StolenWords(Text3d& w, DynArray<Text3dPtr>& out);
@@ -31,10 +32,11 @@ class WordAiSystem {
void apply_Locomotion(Text3d& w, const Vec3& target_vel, double dt);
public:
- void set_MaxActiveAi (int n) { _max_active_ai = n; }
- void update(DynArray<Text3dPtr>& words,
- const Player& player,
- CarriedLine& carried,
- DynArray<Text3dPtr>& dropped,
- double dt);
+ void set_MaxActiveAi (int n) { _max_active_ai = n; }
+
+ void update (DynArray<Text3dPtr>& words,
+ const Player& player,
+ CarriedLine& carried,
+ DynArray<Text3dPtr>& dropped,
+ double dt);
};
diff --git a/src/systems/word_anim.hpp b/src/systems/word_anim.hpp
index fa10fde..500ae93 100644
--- a/src/systems/word_anim.hpp
+++ b/src/systems/word_anim.hpp
@@ -4,13 +4,15 @@
#include "text_3d/text_3d.hpp"
#include "utils/globals.hpp"
-struct WordAnim_Add {
- bool complete{false};
+
+struct WordAnim_Add
+{
+ bool complete {false};
double yaw_start;
double yaw_target;
double pitch_start {0.0};
double pitch_target {0.0};
- double t{0.0};
+ double t {0.0};
Text3dPtr word;
@@ -18,14 +20,17 @@ struct WordAnim_Add {
Vec3 target_pos;
};
-struct WordAnim_Drop {
+
+struct WordAnim_Drop
+{
bool complete{false};
Text3dPtr word;
};
-class WordAnimSystem {
-public:
+
+struct WordAnimSystem
+{
void update(DynArray<WordAnim_Add>& anims_add,
DynArray<WordAnim_Drop>& anims_drop,
CarriedLine& carried,
diff --git a/src/text_3d/text_3d.cpp b/src/text_3d/text_3d.cpp
index b89b565..084e16d 100644
--- a/src/text_3d/text_3d.cpp
+++ b/src/text_3d/text_3d.cpp
@@ -81,7 +81,7 @@ Text3d::Text3d(const std::string& txt,
: GameObject(position, ObjectType::Text,
CollisionShape{}, RigidBody{PhysicsMode::Hover},
true, true, true),
- text(txt), color(colr), depth(dpth), scale(scle)
+ depth(dpth), scale(scle), color(colr), text(txt)
{
set_Color(TokenColor::get(CppHighlight::classify_Word(text)));
@@ -124,7 +124,7 @@ Text3d::words_centroid(const DynArray<Text3dPtr>& words)
Vec3
-Text3d::get_Distance(Vec3 position) {
+Text3d::get_Distance(Vec3 position) const {
return pos - position;
}
@@ -162,7 +162,7 @@ Text3d::set_Look(SDL_FColor c, float new_depth)
void
Text3d::rebuild_Mesh()
{
- loaded = buildTextMesh(mesh, font_path, text, 64, depth, scale);
+ loaded = mesh.build(font_path, text, 64, depth, scale);
if (!loaded) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Text3d: mesh build failed for \"%s\"", text.c_str());
return;
@@ -227,14 +227,14 @@ Text3d::draw(GlRenderer& gl, const Camera& camera, const Light& light) const
{
if (!loaded || packed_indices.empty()) return;
- Mat4 proj = gl.projection();
- Mat4 view = buildViewMat4(camera);
- Mat4 model = buildModelMat4(pos, yaw, pitch);
- Mat4 mvp = Mat4::mul(proj, Mat4::mul(view, model));
+ Mat4 proj = gl.get_Projection();
+ Mat4 view = buildViewMat4 (camera);
+ Mat4 model = buildModelMat4 (pos, yaw, pitch);
+ Mat4 mvp = Mat4::mul (proj, Mat4::mul(view, model));
gl.set_Wireframe(false);
- gl.set_Light(light);
- gl.set_MVP(model, mvp);
+ gl.set_Light (light);
+ gl.set_MVP (model, mvp);
gl.set_NormalMat(model);
gl.set_FaceShade(color.r, color.g, color.b, back_dim, front_tint);
@@ -249,7 +249,7 @@ Text3d::draw(GlRenderer& gl, const Camera& camera, const Light& light) const
packed_indices.data(), (int)packed_indices.size());
gpu_dirty = false;
- gl.set_Emissive(0.0f, 0.0f, 0.0f, 0.0f);
+ gl.set_Emissive (0.0f, 0.0f, 0.0f, 0.0f);
gl.set_FaceShade(0.0f, 0.0f, 0.0f, 1.0f, false);
// ── AI sparkle tail ──────────────────────────────────────────────────
@@ -331,15 +331,15 @@ Text3d::draw(GlRenderer& gl, const Camera& camera, const Light& light) const
}
Mat4 ident = buildModelMat4(Vec3{0,0,0}, 0.0f, 0.0f);
- gl.set_MVP(ident, Mat4::mul(proj, view));
+ gl.set_MVP (ident, Mat4::mul(proj, view));
gl.set_NormalMat(ident);
const SDL_FColor glint = aiGlintColor(ai.state);
for (int c = 0; c < PALN; ++c) {
if (si[c].empty()) continue;
SDL_FColor g = mix_col(PAL[c], glint, 0.15f); // keep only a hint of state
- gl.set_FaceShade(0.0f, 0.0f, 0.0f, 1.0f, false); // no lit term → no white-out
- gl.set_Emissive (g.r, g.g, g.b, 0.85f); // pure colour, below clip
+ gl.set_FaceShade (0.0f, 0.0f, 0.0f, 1.0f, false); // no lit term → no white-out
+ gl.set_Emissive (g.r, g.g, g.b, 0.85f); // pure colour, below clip
gl.draw_MeshCached(gpu_vbo_sparkle, gpu_ebo_sparkle,
gpu_sparkle_index_count, /*dirty=*/true,
sv[c].data(), (int)sv[c].size() / 9,
diff --git a/src/text_3d/text_3d.hpp b/src/text_3d/text_3d.hpp
index 9d85683..0ddb0ae 100644
--- a/src/text_3d/text_3d.hpp
+++ b/src/text_3d/text_3d.hpp
@@ -15,9 +15,11 @@
class Camera;
class GlRenderer;
+
struct Text3dAI
{
- enum class State : uint8_t {
+ enum class State : uint8_t
+ {
Idle,
Attack,
Flee,
@@ -42,70 +44,73 @@ struct Text3dAI
Vec3 trail_dir {1.0, 0.0, 0.0};
};
-struct Text3d final : public GameObject {
+
+struct Text3d final : public GameObject
+{
static inline const std::string font_path =
"/usr/share/fonts/dejavu/DejaVuSansMono.ttf";
- Text3dAI ai;
-
- float glow_strength { 0.2f };
- bool glow_enabled { false };
- float half_extent_y { 0.2f };
-
static inline constexpr float depth_wall = 0.06f;
static inline constexpr float depth_floor = 0.14f;
static inline constexpr float depth_compiler = 0.02f;
static Vec3 words_centroid(const DynArray<Text3dPtr>& words);
- std::string text;
- TextMesh mesh;
-
- // Cached GPU-ready data, rebuilt only in rebuild_Mesh().
- DynArray<float> packed_verts; // interleaved pos(3)|normal(3)|isfront(3)
- DynArray<int> packed_indices;
- mutable unsigned int gpu_vbo { 0 }; // owned GL buffer; 0 = not yet uploaded
- mutable unsigned int gpu_ebo { 0 };
- mutable int gpu_index_count { 0 };
mutable bool gpu_dirty { true };
+ mutable int gpu_index_count { 0 };
+ mutable unsigned int gpu_vbo { 0 };
+ mutable unsigned int gpu_ebo { 0 };
- // Sparkle overlay for AI words: a small star mesh rebuilt every frame.
mutable unsigned int gpu_vbo_sparkle { 0 };
mutable unsigned int gpu_ebo_sparkle { 0 };
mutable int gpu_sparkle_index_count { 0 };
- // Tail: recent world positions, sampled over time (index 0 = newest).
static constexpr int SPARKLE_TRAIL = 14;
- mutable Vec3 sparkle_trail[SPARKLE_TRAIL];
mutable int sparkle_trail_count { 0 };
- mutable Uint64 sparkle_last_ms { 0 };
+ mutable Uint64 sparkle_last_ms { 0 };
+ mutable Vec3 sparkle_trail[SPARKLE_TRAIL];
+
+ bool glow_enabled { false };
+ bool loaded { false };
+ bool front_tint { true };
- bool loaded{false};
- SDL_FColor color;
- float back_dim { 0.45f };
- bool front_tint { true };
- float depth;
- float scale;
- float half_extent{0.0f};
- float pitch{0.0f};
- Vec3 ribbon_local{};
+ float glow_strength{ 0.2f };
+ float half_extent_y{ 0.2f };
+ float back_dim { 0.45f };
+ float depth;
+ float scale;
+ float half_extent { 0.0f };
+ float pitch { 0.0f };
+
+ Vec3 ribbon_local {};
+
+ SDL_FColor color;
+ std::string text;
+ TextMesh mesh;
+ Text3dAI ai;
+
+ DynArray<int> packed_indices;
+ DynArray<float> packed_verts;
Text3d(const std::string& txt,
float depth, float scale,
- Vec3 position,
+ Vec3 position,
SDL_FColor colr = ConfigColor::blue);
~Text3d() override;
- Vec3 get_Distance(Vec3 position);
- void set_Color(SDL_FColor c);
- void set_Depth(float depth);
- void set_Look(SDL_FColor c, float depth);
+ Vec3 get_Distance(Vec3 position) const;
+ void set_Color (SDL_FColor c);
+ void set_Depth (float depth);
+ void set_Look (SDL_FColor c, float depth);
void rebuild_Mesh();
- void update(const Vec3& camera_pos, const double view_mat[9], float carry_dist = 1.5f);
- void draw(GlRenderer& gl, const Camera& camera, const Light& light) const override;
+ void update (const Vec3& camera_pos, const double view_mat[9], float carry_dist = 1.5f);
+ void draw (GlRenderer& gl, const Camera& camera, const Light& light) const override;
};
+
template<typename... Args>
-cpputils::unique_ptr<Text3d> make_Text3d(Args&&... args) {
+cpputils::unique_ptr<Text3d>
+make_Text3d(Args&&... args)
+{
return cpputils::make_unique<Text3d>(std::forward<Args>(args)...);
}
diff --git a/src/text_3d/text_file.hpp b/src/text_3d/text_file.hpp
deleted file mode 100644
index 21d2b93..0000000
--- a/src/text_3d/text_file.hpp
+++ /dev/null
@@ -1,84 +0,0 @@
-#pragma once
-
-#include <string>
-#include "cpp_token/cpp_highlight.hpp" // HiSpan
-#include "cpp_token/token_color.hpp" // TokenColor::get
-#include "text_3d/text_3d.hpp"
-#include "utils/globals.hpp"
-
-struct TextFile {
- struct Token {
- std::string text;
- size_t byte_begin { 0 };
- size_t byte_end { 0 };
- Text3d* view { nullptr };
- };
- struct Line {
- DynArray<Token> tokens;
- };
-
- DynArray<Line> lines;
-
- void clear() { lines.clear(); }
-
- std::string render_Source()
- {
- std::string out;
- for (Line& line : lines) {
- for (size_t ti = 0; ti < line.tokens.size(); ++ti) {
- if (ti) out += ' ';
- Token& tk = line.tokens[ti];
- tk.byte_begin = out.size();
- out += tk.text;
- tk.byte_end = out.size();
- }
- out += '\n';
- }
- return out;
- }
-
- Token* token_At(size_t off)
- {
- for (Line& line : lines)
- for (Token& tk : line.tokens)
- if (off >= tk.byte_begin && off < tk.byte_end)
- return &tk;
- return nullptr;
- }
-
- void apply_Spans(const DynArray<HiSpan>& spans)
- {
- for (Line& line : lines) {
- for (Token& tk : line.tokens) {
- if (!tk.view) continue;
-
- size_t best_overlap = 0;
- TokenType best_type = TokenType::Identifier;
- bool found = false;
- for (const HiSpan& s : spans) {
- size_t lo = (tk.byte_begin > s.byte_begin) ? tk.byte_begin : s.byte_begin;
- size_t hi = (tk.byte_end < s.byte_end) ? tk.byte_end : s.byte_end;
- if (lo < hi) {
- size_t ov = hi - lo;
- if (ov > best_overlap) { best_overlap = ov; best_type = s.type; found = true; }
- }
- }
- if (found) tk.view->set_Color(TokenColor::get(best_type));
- }
- }
- }
-
- DynArray<std::string> as_Lines() const
- {
- DynArray<std::string> out;
- for (const Line& line : lines) {
- std::string s;
- for (size_t ti = 0; ti < line.tokens.size(); ++ti) {
- if (ti) s += ' ';
- s += line.tokens[ti].text;
- }
- out.push_back(s);
- }
- return out;
- }
-};
diff --git a/src/text_3d/text_label.cpp b/src/text_3d/text_label.cpp
index 69f23ef..4e2b2eb 100644
--- a/src/text_3d/text_label.cpp
+++ b/src/text_3d/text_label.cpp
@@ -142,7 +142,7 @@ TextLabel::rebuild(const std::string& text)
Vec3
-TextLabel::current_Centre() const
+TextLabel::get_CurrentCentre() const
{
if (_mode == PositionMode::Anchor && _anchor_ptr) {
return {
@@ -160,7 +160,7 @@ TextLabel::update(double dt, const Camera& camera)
{
if (_words.empty()) return;
- Vec3 centre = current_Centre();
+ Vec3 centre = get_CurrentCentre();
Vec3 right {1, 0, 0};
float yaw_for_glyphs = 0.0f;
float pitch_for_glyphs = 0.0f;
diff --git a/src/text_3d/text_label.hpp b/src/text_3d/text_label.hpp
index 1f14ef1..1a83f94 100644
--- a/src/text_3d/text_label.hpp
+++ b/src/text_3d/text_label.hpp
@@ -7,10 +7,14 @@
#include "utils/globals.hpp"
#include "utils/light.hpp"
+
class GlRenderer;
-class TextLabel {
- enum class PositionMode : uint8_t {
+
+class TextLabel
+{
+ enum class PositionMode : uint8_t
+ {
Absolute,
Anchor,
};
@@ -39,27 +43,29 @@ class TextLabel {
void rebuild(const std::string& text);
- Vec3 current_Centre() const;
+ Vec3 get_CurrentCentre() const;
public:
TextLabel() = default;
+ void clear ();
+ void update (double dt, const Camera& camera);
+ void draw (GlRenderer& gl, const Camera& camera, const Light& light) const;
+ void kick (size_t word_index, const Vec3& projectile_vel, const Vec3& normal);
+
void attach_To (const Vec3* anchor, const Vec3& offset = {});
void detach ();
void set_Centre (const Vec3& p);
void set_Billboard (bool on) { _billboard = on; }
- void set_FaceYaw (float y) { _face_yaw = y; }
+ void set_FaceYaw (float y) { _face_yaw = y; }
void set_Style (SDL_FColor color, float depth, float scale);
void set_Collidable(bool on);
void set_Text (const std::string& text);
void set_Text (const std::string& text,
SDL_FColor color, float depth, float scale);
- void clear ();
- void update (double dt, const Camera& camera);
- void draw (GlRenderer& gl, const Camera& camera, const Light& light) const;
- void kick (size_t word_index, const Vec3& projectile_vel, const Vec3& normal);
- bool empty () const { return _words.empty(); }
+
+ bool is_Empty () const { return _words.empty(); }
const DynArray<Text3dPtr>&
- words () const { return _words; }
+ get_Words () const { return _words; }
};
diff --git a/src/text_3d/text_mesh.cpp b/src/text_3d/text_mesh.cpp
index a3d8373..364ff32 100644
--- a/src/text_3d/text_mesh.cpp
+++ b/src/text_3d/text_mesh.cpp
@@ -203,13 +203,14 @@ void computeVertexNormals(TextMesh& mesh)
}
}
-bool buildTextMesh(TextMesh& out, const std::string& font_path,
- const std::string& text, int size, float depth, float scale)
+bool
+TextMesh::build(const std::string& font_path,
+ const std::string& text, int size, float depth, float scale)
{
- out.verts .clear();
- out.tris .clear();
- out.is_front.clear();
- //out.edges.clear();
+ verts .clear();
+ tris .clear();
+ is_front.clear();
+ //edges.clear();
FT_Library ft;
if (FT_Init_FreeType(&ft)) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "FT_Init_FreeType failed"); return false; }
@@ -251,34 +252,34 @@ bool buildTextMesh(TextMesh& out, const std::string& font_path,
for (auto& p : ring)
flat.push_back(p);
- int base = static_cast<int>(out.verts.size());
+ int base = static_cast<int>(verts.size());
float half_d = depth * 0.5f;
// Front verts (z = -half_d, facing -Z = toward viewer)
for (auto& p : flat) {
- out.verts.push_back({ static_cast<double>(p[0]),
+ verts.push_back({ static_cast<double>(p[0]),
static_cast<double>(p[1]),
static_cast<double>(-half_d) });
- out.is_front.push_back(1.0f);
+ is_front.push_back(1.0f);
}
- int back_base = static_cast<int>(out.verts.size());
+ int back_base = static_cast<int>(verts.size());
// Back verts (z = +half_d)
for (auto& p : flat) {
- out.verts.push_back({ static_cast<double>(p[0]),
+ verts.push_back({ static_cast<double>(p[0]),
static_cast<double>(p[1]),
static_cast<double>( half_d) });
- out.is_front.push_back(0.0f);
+ is_front.push_back(0.0f);
}
// Front face triangles
for (size_t i = 0; i+2 < indices.size(); i += 3) {
- out.tris.push_back({ base + static_cast<int>(indices[i] ),
+ tris.push_back({ base + static_cast<int>(indices[i] ),
base + static_cast<int>(indices[i+2]),
base + static_cast<int>(indices[i+1]) });
}
// Back face triangles — natural winding so normal faces -Z.
for (size_t i = 0; i+2 < indices.size(); i += 3)
- out.tris.push_back({ back_base + static_cast<int>(indices[i] ),
+ tris.push_back({ back_base + static_cast<int>(indices[i] ),
back_base + static_cast<int>(indices[i+1]),
back_base + static_cast<int>(indices[i+2]) });
@@ -291,30 +292,30 @@ bool buildTextMesh(TextMesh& out, const std::string& font_path,
int i1 = (i + 1) % rn;
// 4 unique verts per quad — no sharing with face verts
- int wb = static_cast<int>(out.verts.size());
+ int wb = static_cast<int>(verts.size());
const Pt2& p0 = ring[static_cast<size_t>(i)];
const Pt2& p1 = ring[static_cast<size_t>(i1)];
- out.verts.push_back({ static_cast<double>(p0[0]),
+ verts.push_back({ static_cast<double>(p0[0]),
static_cast<double>(p0[1]),
static_cast<double>(-half_d) }); // front-left
- out.is_front.push_back(0.0f);
- out.verts.push_back({ static_cast<double>(p1[0]),
+ is_front.push_back(0.0f);
+ verts.push_back({ static_cast<double>(p1[0]),
static_cast<double>(p1[1]),
static_cast<double>(-half_d) }); // front-right
- out.is_front.push_back(0.0f);
- out.verts.push_back({ static_cast<double>(p1[0]),
+ is_front.push_back(0.0f);
+ verts.push_back({ static_cast<double>(p1[0]),
static_cast<double>(p1[1]),
static_cast<double>( half_d) }); // back-right
- out.is_front.push_back(0.0f);
- out.verts.push_back({ static_cast<double>(p0[0]),
+ is_front.push_back(0.0f);
+ verts.push_back({ static_cast<double>(p0[0]),
static_cast<double>(p0[1]),
static_cast<double>( half_d) }); // back-left
- out.is_front.push_back(0.0f);
+ is_front.push_back(0.0f);
- out.tris.push_back({ wb+0, wb+1, wb+2 });
- out.tris.push_back({ wb+0, wb+2, wb+3 });
+ tris.push_back({ wb+0, wb+1, wb+2 });
+ tris.push_back({ wb+0, wb+2, wb+3 });
}
ring_offset_flat += rn;
}
@@ -327,10 +328,10 @@ bool buildTextMesh(TextMesh& out, const std::string& font_path,
FT_Done_FreeType(ft);
// Centre mesh on bounding box
- if (!out.verts.empty()) {
+ if (!verts.empty()) {
float minX=1e9f, maxX=-1e9f;
- for (const Vec3& v : out.verts) {
+ for (const Vec3& v : verts) {
float vx = static_cast<float>(v.x);
if (vx < minX) minX = vx;
if (vx > maxX) maxX = vx;
@@ -338,12 +339,12 @@ bool buildTextMesh(TextMesh& out, const std::string& font_path,
double cx = static_cast<double>((minX + maxX) * 0.5f);
- for (Vec3& v : out.verts) {
+ for (Vec3& v : verts) {
v.x -= cx;
}
}
- computeVertexNormals(out);
+ computeVertexNormals(*this);
- return !out.verts.empty();
+ return !verts.empty();
}
diff --git a/src/text_3d/text_mesh.hpp b/src/text_3d/text_mesh.hpp
index 5107bf9..e8d3663 100644
--- a/src/text_3d/text_mesh.hpp
+++ b/src/text_3d/text_mesh.hpp
@@ -3,28 +3,34 @@
#include <string>
#include "utils/globals.hpp"
-#include "utils/math.hpp"
-struct Vertex {
+
+struct Vertex
+{
Vec3 pos;
Vec3 normal;
};
-struct MeshTri { int a, b, c; };
-struct TextMesh {
+struct MeshTri
+{ int a, b, c; };
+
+
+struct TextMesh
+{
DynArray<Vec3> verts;
DynArray<MeshTri> tris;
DynArray<Vec3> vertex_normals;
DynArray<float> is_front;
+
+ bool build(
+ const std::string& font_path,
+ const std::string& text,
+ int size = 64,
+ float depth = 0.4f,
+ float scale = 0.003f
+ );
};
-bool buildTextMesh(
- TextMesh& out,
- const std::string& font_path,
- const std::string& text,
- int size = 64,
- float depth = 0.4f,
- float scale = 0.003f
-);
+
diff --git a/src/text_3d/vim_buffer.cpp b/src/text_3d/vim_buffer.cpp
new file mode 100644
index 0000000..3c0fa79
--- /dev/null
+++ b/src/text_3d/vim_buffer.cpp
@@ -0,0 +1,228 @@
+#include "vim_buffer.hpp"
+
+
+void
+VimBuffer::load(const std::vector<std::string>& src)
+{
+ _lines = src;
+ if (_lines.empty()) _lines.push_back("");
+ _row = _col = 0; _mode = Mode::Normal;
+ _count = 0;
+ _sig = Signal::None; ++_version;
+ _saved = _lines;
+ _dirty = false;
+
+ _pending.clear();
+ _cmd .clear();
+ _status .clear();
+}
+
+
+void
+VimBuffer::key_char(char c)
+{
+ if (_mode == Mode::Insert) { insert_Char(c); }
+ else if (_mode == Mode::Command) { _cmd.push_back(c); touch(); }
+ else { normal_Key(c); }
+}
+
+void
+VimBuffer::key_enter()
+{
+ if (_mode == Mode::Insert) { split_Line(); }
+ else if (_mode == Mode::Command) { run_Command(); }
+ else { _row = get_ClampRow(_row + 1); clamp_Col(); touch(); }
+}
+
+void VimBuffer::key_backspace()
+{
+ if (_mode == Mode::Insert) { backspace_Insert(); }
+ else if (_mode == Mode::Command) { if (_cmd.size() > 1) _cmd.pop_back(); else cancel_Command(); touch(); }
+ else { _col = (_col > 0 ? _col - 1 : 0); touch(); }
+}
+
+void VimBuffer::key_escape()
+{
+ if (_mode == Mode::Command) { cancel_Command(); return; }
+ _mode = Mode::Normal;
+ if (_col > 0) --_col;
+ clamp_Col(); touch();
+}
+
+
+VimBuffer::Signal
+VimBuffer::take_Signal()
+{ Signal s = _sig; _sig = Signal::None; return s; }
+
+
+void
+VimBuffer::mark_Saved()
+{ _saved = _lines; _dirty = false; touch(); }
+
+
+void
+VimBuffer::touch()
+{ ++_version; }
+
+int
+VimBuffer::get_LineLen() const
+{ return (int)_lines[(size_t)_row].size(); }
+
+int
+VimBuffer::get_ClampRow(int r) const
+{ int n=(int)_lines.size(); return r<0?0:(r>=n?n-1:r); }
+
+void
+VimBuffer::clamp_Col()
+{
+ int maxc = (_mode==Mode::Insert) ? get_LineLen() : (get_LineLen()>0 ? get_LineLen()-1 : 0);
+ if (_col < 0) _col = 0;
+ if (_col > maxc) _col = maxc;
+}
+
+int
+VimBuffer::get_Eff() const
+{ return _count > 0 ? _count : 1; }
+
+void
+VimBuffer::normal_Key(char c)
+{
+ if (c == ':') { _mode = Mode::Command; _cmd = ":";
+ _status.clear(); touch(); return; }
+
+ if (std::isdigit((unsigned char)c)) {
+ if (c == '0' && _count == 0 && _pending.empty())
+ { _col = 0; touch(); return; }
+ _count = _count * 10 + (c - '0'); return;
+ }
+
+ if (_pending == "d") { _pending.clear();
+ if (c == 'd') { delete_Lines(get_Eff()); _count = 0;
+ touch(); return; }
+ _count = 0; return;
+ }
+ if (_pending == "g") { _pending.clear();
+ if (c == 'g') { _row = get_ClampRow(_count > 0 ? _count - 1 : 0);
+ _count = 0; clamp_Col(); touch(); return; }
+ _count = 0; return;
+ }
+
+ switch (c) {
+ case 'h': _col -= get_Eff(); break;
+ case 'l': _col += get_Eff(); break;
+ case 'j': _row = get_ClampRow(_row + get_Eff()); break;
+ case 'k': _row = get_ClampRow(_row - get_Eff()); break;
+ case '0': _col = 0; break;
+ case '$': _col = get_LineLen() > 0 ? get_LineLen() - 1 : 0; break;
+ case 'x': delete_Chars(get_Eff()); break;
+ case 'i': _mode = Mode::Insert; break;
+ case 'a': _col = (get_LineLen() > 0 ? _col + 1 : 0); _mode = Mode::Insert; break;
+ case 'A': _col = get_LineLen(); _mode = Mode::Insert; break;
+ case 'o': open_Below(); _mode = Mode::Insert; break;
+ case 'O': open_Above(); _mode = Mode::Insert; break;
+ case 'G': _row = get_ClampRow(_count > 0 ? _count - 1 : (int)_lines.size() - 1);break;
+ case 'd': _pending = "d"; return;
+ case 'g': _pending = "g"; return;
+ default: break;
+ }
+ _count = 0; clamp_Col(); touch();
+}
+
+void
+VimBuffer::insert_Char(char c)
+{
+ std::string& L = _lines[(size_t)_row];
+ if (_col > (int)L.size()) _col = (int)L.size();
+ L.insert((size_t)_col, 1, c); ++_col; _dirty = true; touch();
+}
+
+void
+VimBuffer::split_Line()
+{
+ std::string& L = _lines[(size_t)_row];
+ std::string tail = L.substr((size_t)_col);
+ L.erase((size_t)_col);
+ _lines.insert(_lines.begin() + _row + 1, tail);
+ ++_row; _col = 0; _dirty = true; touch();
+}
+
+void
+VimBuffer::backspace_Insert()
+{
+ if (_col > 0) { _lines[(size_t)_row].erase((size_t)(_col-1), 1); --_col; _dirty = true; }
+ else if (_row > 0) {
+ int prevlen = (int)_lines[(size_t)(_row-1)].size();
+ _lines[(size_t)(_row-1)] += _lines[(size_t)_row];
+ _lines.erase(_lines.begin() + _row);
+ --_row; _col = prevlen; _dirty = true;
+ }
+ touch();
+}
+
+void
+VimBuffer::delete_Chars(int n)
+{
+ std::string& L = _lines[(size_t)_row];
+ for (int i = 0; i < n && _col < (int)L.size(); ++i) { L.erase((size_t)_col, 1); _dirty = true; }
+ clamp_Col();
+}
+
+void
+VimBuffer::delete_Lines(int n)
+{
+ for (int i = 0; i < n && (int)_lines.size() > 0; ++i) {
+ if (_lines.size() == 1) { _lines[0].clear(); _dirty = true; break; }
+ _lines.erase(_lines.begin() + _row);
+ if (_row >= (int)_lines.size()) _row = (int)_lines.size() - 1;
+ _dirty = true;
+ }
+ clamp_Col();
+}
+void
+VimBuffer::open_Below()
+{ _lines.insert(_lines.begin() + _row + 1, ""); ++_row; _col = 0; _dirty = true; }
+
+void
+VimBuffer::open_Above()
+{ _lines.insert(_lines.begin() + _row, ""); _col = 0; _dirty = true; }
+
+void
+VimBuffer::run_Command()
+{
+ std::string c = _cmd.size() ? _cmd.substr(1) : "";
+ _cmd.clear(); _mode = Mode::Normal;
+
+ if (c == "w" || c == "write") {
+ _sig = Signal::Write;
+ }
+ else if (c == "wq" || c == "x") {
+ _sig = Signal::WriteQuit;
+ }
+ else if (c == "q" || c == "quit") {
+ if (_dirty) {
+ _status = "No write since last change (add ! to override)";
+ } else {
+ _sig = Signal::Exit;
+ }
+ }
+ else if (c == "q!" || c == "quit!") {
+ _lines = _saved;
+ _row = get_ClampRow(_row); clamp_Col();
+ _dirty = false;
+ _sig = Signal::QuitDiscard;
+ }
+ else if (!c.empty() && std::all_of(c.begin(), c.end(),
+ [](char ch){ return std::isdigit((unsigned char)ch); })) {
+ _row = get_ClampRow(std::stoi(c) - 1); clamp_Col();
+ }
+ else _status = "not a command: " + c;
+ touch();
+}
+
+void
+VimBuffer::cancel_Command()
+{ _cmd.clear(); _mode = Mode::Normal; touch(); }
+
+bool
+VimBuffer::is_Dirty() const
+{ return _dirty; }
diff --git a/src/text_3d/vim_buffer.hpp b/src/text_3d/vim_buffer.hpp
index a9dd8d2..c70fdb3 100644
--- a/src/text_3d/vim_buffer.hpp
+++ b/src/text_3d/vim_buffer.hpp
@@ -8,7 +8,7 @@
class VimBuffer {
public:
enum class Mode : uint8_t { Normal, Insert, Command };
- enum class Signal : uint8_t {
+ enum class Signal : uint8_t {
None,
Exit,
Help,
@@ -17,51 +17,29 @@ public:
QuitDiscard
};
- void load(const std::vector<std::string>& src) {
- _lines = src;
- if (_lines.empty()) _lines.push_back("");
- _row = _col = 0; _mode = Mode::Normal;
- _count = 0; _pending.clear(); _cmd.clear(); _status.clear();
- _sig = Signal::None; ++_version;
- _saved = _lines;
- _dirty = false;
- }
+ void key_char (char c);
+ void key_enter ();
+ void key_backspace();
+ void key_escape ();
+ void load (const std::vector<std::string>& src);
+ Signal take_Signal();
+ void mark_Saved ();
- void key_char(char c) {
- if (_mode == Mode::Insert) { insert_Char(c); }
- else if (_mode == Mode::Command) { _cmd.push_back(c); touch(); }
- else { normal_Key(c); }
- }
- void key_enter() {
- if (_mode == Mode::Insert) { split_Line(); }
- else if (_mode == Mode::Command) { run_Command(); }
- else { _row = clampRow(_row + 1); clampCol(); touch(); }
- }
- void key_backspace() {
- if (_mode == Mode::Insert) { backspace_Insert(); }
- else if (_mode == Mode::Command) { if (_cmd.size() > 1) _cmd.pop_back(); else cancel_Command(); touch(); }
- else { _col = (_col > 0 ? _col - 1 : 0); touch(); }
- }
- void key_escape() {
- if (_mode == Mode::Command) { cancel_Command(); return; }
- _mode = Mode::Normal;
- if (_col > 0) --_col;
- clampCol(); touch();
- }
+ bool is_Empty() const { return _lines.size() == 1 && _lines[0].empty(); }
const std::vector<std::string>&
- lines() const { return _lines; }
- int row() const { return _row; }
- int col() const { return _col; }
- Mode mode() const { return _mode; }
- unsigned version() const { return _version; }
- bool is_Empty() const { return _lines.size() == 1 && _lines[0].empty(); }
- void start_Insert() { _mode = Mode::Insert; _col = 0; touch(); }
- const std::string& cmdline() const { return _cmd; }
- const std::string& status() const { return _status; }
- Signal take_Signal() { Signal s = _sig; _sig = Signal::None; return s; }
- void mark_Saved() { _saved = _lines; _dirty = false; touch(); }
+ get_Lines () const { return _lines; }
+ int get_Row () const { return _row; }
+ int get_Col () const { return _col; }
+ Mode get_Mode () const { return _mode; }
+ unsigned
+ get_Version () const { return _version; }
+ const std::string&
+ get_Cmdline () const { return _cmd; }
+ const std::string&
+ get_Status () const { return _status; }
+ void start_Insert() { _mode = Mode::Insert; _col = 0; touch(); }
private:
bool _dirty = false;
@@ -76,128 +54,23 @@ private:
Mode _mode = Mode::Normal;
Signal _sig = Signal::None;
std::vector<std::string> _saved;
- std::vector<std::string> _lines { "" };
-
- void touch() { ++_version; }
- int lineLen() const { return (int)_lines[(size_t)_row].size(); }
- int clampRow(int r) const { int n=(int)_lines.size(); return r<0?0:(r>=n?n-1:r); }
- void clampCol() {
- int maxc = (_mode==Mode::Insert) ? lineLen() : (lineLen()>0 ? lineLen()-1 : 0);
- if (_col < 0) _col = 0;
- if (_col > maxc) _col = maxc;
- }
- int eff() const { return _count > 0 ? _count : 1; }
-
- void normal_Key(char c) {
- if (c == ':') { _mode = Mode::Command; _cmd = ":"; _status.clear(); touch(); return; }
-
- if (std::isdigit((unsigned char)c)) {
- if (c == '0' && _count == 0 && _pending.empty())
- { _col = 0; touch(); return; }
- _count = _count * 10 + (c - '0'); return;
- }
-
- if (_pending == "d") { _pending.clear();
- if (c == 'd') { delete_Lines(eff()); _count = 0; touch(); return; }
- _count = 0; return;
- }
- if (_pending == "g") { _pending.clear();
- if (c == 'g') { _row = clampRow(_count > 0 ? _count - 1 : 0); _count = 0; clampCol(); touch(); return; }
- _count = 0; return;
- }
-
- switch (c) {
- case 'h': _col -= eff(); break;
- case 'l': _col += eff(); break;
- case 'j': _row = clampRow(_row + eff()); break;
- case 'k': _row = clampRow(_row - eff()); break;
- case '0': _col = 0; break;
- case '$': _col = lineLen() > 0 ? lineLen() - 1 : 0; break;
- case 'x': delete_Chars(eff()); break;
- case 'i': _mode = Mode::Insert; break;
- case 'a': _col = (lineLen() > 0 ? _col + 1 : 0); _mode = Mode::Insert; break;
- case 'A': _col = lineLen(); _mode = Mode::Insert; break;
- case 'o': open_Below(); _mode = Mode::Insert; break;
- case 'O': open_Above(); _mode = Mode::Insert; break;
- case 'G': _row = clampRow(_count > 0 ? _count - 1 : (int)_lines.size() - 1);break;
- case 'd': _pending = "d"; return;
- case 'g': _pending = "g"; return;
- default: break;
- }
- _count = 0; clampCol(); touch();
- }
-
- void insert_Char(char c) {
- std::string& L = _lines[(size_t)_row];
- if (_col > (int)L.size()) _col = (int)L.size();
- L.insert((size_t)_col, 1, c); ++_col; _dirty = true; touch();
- }
- void split_Line() {
- std::string& L = _lines[(size_t)_row];
- std::string tail = L.substr((size_t)_col);
- L.erase((size_t)_col);
- _lines.insert(_lines.begin() + _row + 1, tail);
- ++_row; _col = 0; _dirty = true; touch();
- }
- void backspace_Insert() {
- if (_col > 0) { _lines[(size_t)_row].erase((size_t)(_col-1), 1); --_col; _dirty = true; }
- else if (_row > 0) {
- int prevlen = (int)_lines[(size_t)(_row-1)].size();
- _lines[(size_t)(_row-1)] += _lines[(size_t)_row];
- _lines.erase(_lines.begin() + _row);
- --_row; _col = prevlen; _dirty = true;
- }
- touch();
- }
- void delete_Chars(int n) {
- std::string& L = _lines[(size_t)_row];
- for (int i = 0; i < n && _col < (int)L.size(); ++i) { L.erase((size_t)_col, 1); _dirty = true; }
- clampCol();
- }
- void delete_Lines(int n) {
- for (int i = 0; i < n && (int)_lines.size() > 0; ++i) {
- if (_lines.size() == 1) { _lines[0].clear(); _dirty = true; break; }
- _lines.erase(_lines.begin() + _row);
- if (_row >= (int)_lines.size()) _row = (int)_lines.size() - 1;
- _dirty = true;
- }
- clampCol();
- }
- void open_Below() { _lines.insert(_lines.begin() + _row + 1, ""); ++_row; _col = 0; _dirty = true; }
- void open_Above() { _lines.insert(_lines.begin() + _row, ""); _col = 0; _dirty = true; }
-
- void run_Command() {
- std::string c = _cmd.size() ? _cmd.substr(1) : "";
- _cmd.clear(); _mode = Mode::Normal;
-
- if (c == "w" || c == "write") {
- _sig = Signal::Write;
- }
- else if (c == "wq" || c == "x") {
- _sig = Signal::WriteQuit;
- }
- else if (c == "q" || c == "quit") {
- if (_dirty) {
- _status = "No write since last change (add ! to override)";
- } else {
- _sig = Signal::Exit;
- }
- }
- else if (c == "q!" || c == "quit!") {
- _lines = _saved;
- _row = clampRow(_row); clampCol();
- _dirty = false;
- _sig = Signal::QuitDiscard;
- }
- else if (!c.empty() && std::all_of(c.begin(), c.end(),
- [](char ch){ return std::isdigit((unsigned char)ch); })) {
- _row = clampRow(std::stoi(c) - 1); clampCol();
- }
- else _status = "not a command: " + c;
- touch();
- }
- void cancel_Command() { _cmd.clear(); _mode = Mode::Normal; touch(); }
-
- bool dirty() const { return _dirty; }
-
+ std::vector<std::string> _lines{ "" };
+
+ void touch ();
+ void clamp_Col ();
+ void normal_Key (char c);
+ void insert_Char (char c);
+ void split_Line ();
+ void backspace_Insert();
+ void delete_Chars (int n);
+ void delete_Lines (int n);
+ void open_Below ();
+ void open_Above ();
+ void run_Command ();
+ void cancel_Command ();
+
+ bool is_Dirty () const;
+ int get_LineLen () const;
+ int get_Eff () const;
+ int get_ClampRow (int r) const;
};
diff --git a/src/utils/ascii.hpp b/src/utils/ascii.hpp
deleted file mode 100644
index 86c4bdc..0000000
--- a/src/utils/ascii.hpp
+++ /dev/null
@@ -1,53 +0,0 @@
-#pragma once
-#include <string>
-
-// ─────────────────────────────────────────────────────────────────────────
-// ascii_Sanitize — collapse non-ASCII bytes to safe ASCII for wall display.
-//
-// gcc diagnostics use Unicode directional quotes (U+2018/2019 ‘ ’, U+201C/201D
-// “ ”) which the text renderer can't draw. This maps the common ones to plain
-// ' and ", and replaces any other multibyte sequence with '?'. Used by both
-// CompilerSystem and DynLoaderSystem so their wall output stays renderable.
-//
-// Note: also set LC_ALL=C on the gcc invocation to make gcc emit ASCII quotes
-// at the source; this function is the belt-and-suspenders fallback.
-// ─────────────────────────────────────────────────────────────────────────
-inline std::string
-ascii_Sanitize(const std::string& in)
-{
- std::string out;
- out.reserve(in.size());
-
- size_t i = 0;
- while (i < in.size()) {
- const unsigned char c = static_cast<unsigned char>(in[i]);
-
- if (c < 0x80) {
- out += static_cast<char>(c);
- ++i;
- continue;
- }
-
- // U+2000–U+20FF punctuation block: E2 80 xx
- if (c == 0xE2 && i + 2 < in.size() &&
- static_cast<unsigned char>(in[i + 1]) == 0x80) {
- const unsigned char c3 = static_cast<unsigned char>(in[i + 2]);
- switch (c3) {
- case 0x98: case 0x99: out += '\''; break; // ‘ ’
- case 0x9C: case 0x9D: out += '"'; break; // “ ”
- case 0x93: case 0x94: out += '-'; break; // – —
- default: out += '\''; break;
- }
- i += 3;
- continue;
- }
-
- // Any other multibyte sequence: one '?', skip continuation bytes.
- out += '?';
- ++i;
- while (i < in.size() &&
- (static_cast<unsigned char>(in[i]) & 0xC0) == 0x80)
- ++i;
- }
- return out;
-}
diff --git a/src/utils/carry_math.cpp b/src/utils/carry_math.cpp
index ddbe43f..a247648 100644
--- a/src/utils/carry_math.cpp
+++ b/src/utils/carry_math.cpp
@@ -1,10 +1,11 @@
+#include <SDL3/SDL.h>
+
#include "carry_math.hpp"
#include "entities/camera.hpp"
-#include <SDL3/SDL.h>
Vec3
-CarryMath::line_Anchor(const Camera& camera, double carry_dist)
+CarryMath::get_LineAnchor(const Camera& camera, double carry_dist)
{
const Vec3& right = camera.right;
const Vec3 up = Math::cross(camera.right, camera.fwd);
@@ -21,10 +22,10 @@ CarryMath::line_Anchor(const Camera& camera, double carry_dist)
DynArray<Vec3>
-CarryMath::slot_Positions(const CarriedLine& carried,
- const Vec3& anchor,
- const Vec3& right,
- double carry_gap)
+CarryMath::get_SlotPosition(const CarriedLine& carried,
+ const Vec3& anchor,
+ const Vec3& right,
+ double carry_gap)
{
DynArray<Vec3> positions;
DynArray<CarriedWordNode*> nodes = carried.reverse_nodes();
diff --git a/src/utils/carry_math.hpp b/src/utils/carry_math.hpp
index 2fb88c9..c11f35e 100644
--- a/src/utils/carry_math.hpp
+++ b/src/utils/carry_math.hpp
@@ -1,13 +1,12 @@
#pragma once
-#include <cstdint>
-
#include "systems/carry_system.hpp"
#include "utils/globals.hpp"
-#include "utils/math.hpp"
+
class Camera;
+
namespace CarryMath
{
static constexpr double CARRY_DIST = 1.2;
@@ -17,10 +16,10 @@ namespace CarryMath
static constexpr double CARRY_HAND_DOWN = 0.35;
- Vec3 line_Anchor(const Camera& camera, double carry_dist);
+ Vec3 get_LineAnchor (const Camera& camera, double carry_dist);
DynArray<Vec3>
- slot_Positions(const CarriedLine& carried,
- const Vec3& anchor,
- const Vec3& right,
- double carry_gap);
+ get_SlotPosition(const CarriedLine& carried,
+ const Vec3& anchor,
+ const Vec3& right,
+ double carry_gap);
}
diff --git a/src/utils/config.hpp b/src/utils/config.hpp
index 07604b0..448f276 100644
--- a/src/utils/config.hpp
+++ b/src/utils/config.hpp
@@ -23,7 +23,7 @@ static constexpr double player_move_accel = 60.0;
static constexpr double proj_gravity = 9.0;
static constexpr double proj_throw_speed = 18.0;
-static constexpr double proj_t_min = 0.18; // clamp: nearest throws
+static constexpr double proj_t_min = 0.18; // clamp: nearest throws
static constexpr double proj_t_max = 1.2; // clamp: farthest throws
}
diff --git a/src/utils/frame_profiler.hpp b/src/utils/frame_profiler.hpp
index 8ef699e..9a8274a 100644
--- a/src/utils/frame_profiler.hpp
+++ b/src/utils/frame_profiler.hpp
@@ -36,15 +36,20 @@
#else
-namespace fp {
+namespace fp
+{
-inline double perf_to_ms(Uint64 ticks) {
+inline double
+perf_to_ms(Uint64 ticks)
+{
static const double inv_freq_ms =
1000.0 / static_cast<double>(SDL_GetPerformanceFrequency());
return static_cast<double>(ticks) * inv_freq_ms;
}
-struct Zone {
+
+struct Zone
+{
const char* name {nullptr};
uint32_t calls {0}; // calls across the report window
Uint64 total {0}; // accumulated ticks across the report window
@@ -52,7 +57,9 @@ struct Zone {
Uint64 peak {0}; // peak per-frame ticks in window
};
-struct Frame {
+
+struct Frame
+{
static constexpr size_t MAX_ZONES = 32;
bool started {false};
size_t num_zones {0};
@@ -63,7 +70,7 @@ struct Frame {
std::array<Zone, MAX_ZONES> zones{};
- Zone* find_or_add(const char* name) {
+ Zone* find_OrAdd(const char* name) {
// Pointer-equality lookup — string literals dedupe naturally.
for (size_t i = 0; i < num_zones; ++i)
if (zones[i].name == name) return &zones[i];
@@ -72,7 +79,7 @@ struct Frame {
return &zones[num_zones++];
}
- void begin_frame() {
+ void begin_Frame() {
if (!started) {
window_start = SDL_GetPerformanceCounter();
started = true;
@@ -80,7 +87,7 @@ struct Frame {
for (size_t i = 0; i < num_zones; ++i) zones[i].frame_sum = 0;
}
- void end_frame() {
+ void end_Frame() {
++frames_in_win;
for (size_t i = 0; i < num_zones; ++i) {
Zone& z = zones[i];
@@ -92,7 +99,7 @@ struct Frame {
Uint64 elapsed_ticks = now - window_start;
double elapsed_ms = perf_to_ms(elapsed_ticks);
if (elapsed_ms >= 1000.0) {
- print_report(elapsed_ms);
+ print_Report(elapsed_ms);
// reset window
for (size_t i = 0; i < num_zones; ++i) {
zones[i].total = 0;
@@ -104,7 +111,7 @@ struct Frame {
}
}
- void print_report(double elapsed_ms) const {
+ void print_Report(double elapsed_ms) const {
// Sort indices by total descending — don't reorder the zone array
// itself, names are stable pointers and we rely on order persistence.
std::array<size_t, MAX_ZONES> order{};
@@ -146,7 +153,7 @@ struct ScopedZone {
Zone* zone;
Uint64 t0;
ScopedZone(const char* name)
- : zone(frame().find_or_add(name))
+ : zone(frame().find_OrAdd(name))
, t0(zone ? SDL_GetPerformanceCounter() : 0) {}
~ScopedZone() {
if (!zone) return;
@@ -163,7 +170,7 @@ struct ScopedZone {
#define FP_CONCAT(a,b) FP_CONCAT_(a,b)
#define FP_ZONE(name) ::fp::ScopedZone FP_CONCAT(_fp_zone_, __LINE__){name}
-#define FRAME_BEGIN() ::fp::frame().begin_frame()
-#define FRAME_END() ::fp::frame().end_frame()
+#define FRAME_BEGIN() ::fp::frame().begin_Frame()
+#define FRAME_END() ::fp::frame().end_Frame()
#endif // !FRAME_PROFILER_DISABLED
diff --git a/src/utils/globals.hpp b/src/utils/globals.hpp
index b32df99..ed1d089 100644
--- a/src/utils/globals.hpp
+++ b/src/utils/globals.hpp
@@ -1,25 +1,25 @@
#pragma once
-#include "math.hpp"
#include <SDL3/SDL.h>
#include <memory>
#include <print>
#include <vector>
-#include <cpputils/unique_ptr.hpp>
+
+#include "cpputils/unique_ptr.hpp"
+#include "math.hpp"
class GlRenderer;
-struct Text3d;
-struct TextWall;
-struct GameObject;
struct CarriedWordNode;
+struct GameObject;
+struct Text3d;
+
+using Math::Vec3;
template<typename T>
using DynArray = std::vector<T>;
using GlRendererPtr = cpputils::unique_ptr<GlRenderer>;
using Text3dPtr = cpputils::unique_ptr<Text3d>;
-using TextWallPtr = cpputils::unique_ptr<TextWall>;
-using TextWallList = DynArray<TextWallPtr>;
using CarriedWordNodePtr = cpputils::unique_ptr<CarriedWordNode>;
using GameObjectPtr = cpputils::unique_ptr<GameObject>;
diff --git a/src/utils/light.hpp b/src/utils/light.hpp
index d436bd8..570513b 100644
--- a/src/utils/light.hpp
+++ b/src/utils/light.hpp
@@ -2,41 +2,17 @@
#include "math.hpp"
-// ─────────────────────────────────────────────────────────────────────────
-// Light
-//
-// Three components:
-//
-// 1. Sun — directional, fixed in world. `direction` is the direction
-// LIGHT TRAVELS (sun overhead → direction points downward).
-// Illumination at surface = max(dot(N, -direction), 0).
-// sun_intensity is 0 by default: the scene is lit entirely by the
-// flashlight and ambient. Raise it if you add an outdoor area.
-//
-// 2. Ambient — uniform fill, adds to every fragment.
-//
-// 3. Flashlight — positional + cone. Player carries it.
-// `flashlight_pos` is the beam origin (camera/head). `flashlight_dir`
-// is the unit vector the beam shines along (where the camera looks).
-// Cone has a smooth falloff between inner_cos and outer_cos.
-// Both must be updated per frame from the camera before set_Light().
-// ─────────────────────────────────────────────────────────────────────────
struct Light {
- // ── Sun ─────────────────────────────────────────────────────────────
- Vec3 direction { 0.3, -0.9, 0.2 };
+ Vec3 sun_direction { 0.3, -0.9, 0.2 };
Vec3 sun_color { 1.00, 0.95, 0.85 };
- float sun_intensity { 0.0f }; // 0 = sun disabled; scene uses flashlight only
+ float sun_intensity { 0.0f }; // off for now
- // ── Ambient ─────────────────────────────────────────────────────────
Vec3 ambient { 0.25, 0.27, 0.30 };
- // ── Flashlight (player's beam) ──────────────────────────────────────
- Vec3 flashlight_pos { 0.0, 0.0, 0.0 }; // set per-frame from camera
- Vec3 flashlight_dir { 0.0, 0.0, -1.0 }; // unit vec; set per-frame from camera
- Vec3 flashlight_color { 1.00, 0.95, 0.80 }; // warm white
+ Vec3 flashlight_pos { 0.0, 0.0, 0.0 };
+ Vec3 flashlight_dir { 0.0, 0.0, -1.0 };
+ Vec3 flashlight_color { 1.00, 0.95, 0.80 };
float flashlight_range { 40.0f };
- // Cone falloff: full brightness inside inner_cos, smooth fade to zero at outer_cos.
- // Both are cosines of the half-angle from the beam axis (1=on-axis, 0=perpendicular).
float flashlight_inner_cos { 0.85f }; // ≈ 32° full cone
float flashlight_outer_cos { 0.50f }; // ≈ 60° cutoff
float flashlight_intensity { 1.5f };
@@ -44,14 +20,14 @@ struct Light {
Light() { normalize(); }
void normalize() {
- double len = std::sqrt(direction.x*direction.x +
- direction.y*direction.y +
- direction.z*direction.z);
- if (len > 1e-6) direction = direction / len;
+ double len = SDL_sqrt(sun_direction.x*sun_direction.x +
+ sun_direction.y*sun_direction.y +
+ sun_direction.z*sun_direction.z);
+ if (len > 1e-6) sun_direction = sun_direction / len;
- len = std::sqrt(flashlight_dir.x*flashlight_dir.x +
- flashlight_dir.y*flashlight_dir.y +
- flashlight_dir.z*flashlight_dir.z);
+ len = SDL_sqrt(flashlight_dir.x*flashlight_dir.x +
+ flashlight_dir.y*flashlight_dir.y +
+ flashlight_dir.z*flashlight_dir.z);
if (len > 1e-6) flashlight_dir = flashlight_dir / len;
}
};
diff --git a/src/utils/math.hpp b/src/utils/math.hpp
index 4171cb9..4adbae8 100644
--- a/src/utils/math.hpp
+++ b/src/utils/math.hpp
@@ -1,15 +1,21 @@
#pragma once
+#include <SDL3/SDL_stdinc.h>
#include <random>
-namespace Random {
-inline int int_MinMax(int min, int max) {
+namespace Random
+{
+
+inline int
+int_MinMax(int min, int max)
+{
std::mt19937 rng(std::random_device{}());
std::uniform_int_distribution<int> dist(min, max);
return dist(rng);
}
+
inline double
unit()
{
@@ -17,10 +23,16 @@ unit()
static std::uniform_real_distribution<double> dist(0.0, 1.0);
return dist(rng);
}
+
} // Rendom
-struct Vec3 {
+namespace Math
+{
+
+
+struct Vec3
+{
double x{}, y{}, z{};
Vec3() = default;
@@ -41,9 +53,6 @@ inline Vec3 operator-(Vec3 a, const Vec3& b) { return a -= b; }
inline Vec3 operator*(Vec3 v, double s) { return v *= s; }
inline Vec3 operator/(Vec3 v, double s) { return v /= s; }
-namespace Math
-{
-
inline double
dot(const Vec3& a, const Vec3& b)
{ return a.x*b.x + a.y*b.y + a.z*b.z; }
@@ -64,7 +73,7 @@ length_sq(const Vec3& v)
inline double
length(const Vec3& v)
-{ return std::sqrt(length_sq(v)); }
+{ return SDL_sqrt(length_sq(v)); }
inline Vec3
normalize(const Vec3& v)
diff --git a/src/utils/text.cpp b/src/utils/text.cpp
new file mode 100644
index 0000000..aba7de4
--- /dev/null
+++ b/src/utils/text.cpp
@@ -0,0 +1,165 @@
+#include "text.hpp"
+
+
+namespace Text
+{
+
+DynArray<std::string>
+wrap_String(const std::string& text, size_t max_chars)
+{
+ std::string word;
+ std::string current_line;
+
+ DynArray<std::string> lines;
+
+ auto flush_line = [&]() {
+ while (!current_line.empty() && current_line.back() == ' ')
+ current_line.pop_back();
+ lines.push_back(current_line);
+ current_line.clear();
+ };
+
+ auto flush_word = [&]() {
+ if (word.empty()) return;
+ if (current_line.size() + word.size() + (current_line.empty() ? 0 : 1)
+ > max_chars) {
+ flush_line();
+ }
+ if (!current_line.empty()) current_line += ' ';
+ current_line += word;
+ word.clear();
+ };
+
+ for (char c : text) {
+ if (c == '\n') {
+ flush_word();
+ flush_line();
+ }
+ else if (c == ' ' || c == '\t') {
+ flush_word();
+ }
+ else {
+ word += c;
+ }
+ }
+ flush_word();
+ flush_line();
+
+ return lines;
+}
+
+std::string
+ascii_Sanitize(const std::string& in)
+{
+ std::string out;
+ out.reserve(in.size());
+
+ size_t i = 0;
+ while (i < in.size()) {
+ const unsigned char c = static_cast<unsigned char>(in[i]);
+
+ if (c < 0x80) {
+ out += static_cast<char>(c);
+ ++i;
+ continue;
+ }
+
+ // U+2000–U+20FF punctuation block: E2 80 xx
+ if (c == 0xE2 && i + 2 < in.size() &&
+ static_cast<unsigned char>(in[i + 1]) == 0x80) {
+ const unsigned char c3 = static_cast<unsigned char>(in[i + 2]);
+ switch (c3) {
+ case 0x98: case 0x99: out += '\''; break; // ‘ ’
+ case 0x9C: case 0x9D: out += '"'; break; // “ ”
+ case 0x93: case 0x94: out += '-'; break; // – —
+ default: out += '\''; break;
+ }
+ i += 3;
+ continue;
+ }
+
+ // Any other multibyte sequence: one '?', skip continuation bytes.
+ out += '?';
+ ++i;
+ while (i < in.size() &&
+ (static_cast<unsigned char>(in[i]) & 0xC0) == 0x80)
+ ++i;
+ }
+ return out;
+}
+
+
+
+void
+View::clear()
+{ lines.clear(); }
+
+
+std::string
+View::render_Source()
+{
+ std::string out;
+ for (Line& line : lines) {
+ for (size_t ti = 0; ti < line.tokens.size(); ++ti) {
+ if (ti) out += ' ';
+ Token& tk = line.tokens[ti];
+ tk.byte_begin = out.size();
+ out += tk.text;
+ tk.byte_end = out.size();
+ }
+ out += '\n';
+ }
+ return out;
+}
+
+
+Token*
+View::token_At(size_t off)
+{
+ for (Line& line : lines)
+ for (Token& tk : line.tokens)
+ if (off >= tk.byte_begin && off < tk.byte_end)
+ return &tk;
+ return nullptr;
+}
+
+
+void
+View::apply_Spans(const DynArray<HiSpan>& spans)
+{
+ for (Line& line : lines) {
+ for (Token& tk : line.tokens) {
+ if (!tk.view) continue;
+
+ size_t best_overlap = 0;
+ TokenType best_type = TokenType::Identifier;
+ bool found = false;
+ for (const HiSpan& s : spans) {
+ size_t lo = (tk.byte_begin > s.byte_begin) ? tk.byte_begin : s.byte_begin;
+ size_t hi = (tk.byte_end < s.byte_end) ? tk.byte_end : s.byte_end;
+ if (lo < hi) {
+ size_t ov = hi - lo;
+ if (ov > best_overlap) { best_overlap = ov; best_type = s.type; found = true; }
+ }
+ }
+ if (found) tk.view->set_Color(TokenColor::get(best_type));
+ }
+ }
+}
+
+DynArray<std::string>
+View::as_Lines() const
+{
+ DynArray<std::string> out;
+ for (const Line& line : lines) {
+ std::string s;
+ for (size_t ti = 0; ti < line.tokens.size(); ++ti) {
+ if (ti) s += ' ';
+ s += line.tokens[ti].text;
+ }
+ out.push_back(s);
+ }
+ return out;
+}
+
+} // namespace Text
diff --git a/src/utils/text.hpp b/src/utils/text.hpp
new file mode 100644
index 0000000..57e0522
--- /dev/null
+++ b/src/utils/text.hpp
@@ -0,0 +1,49 @@
+#pragma once
+
+#include <string>
+
+#include "cpp_token/cpp_highlight.hpp"
+#include "cpp_token/token_color.hpp"
+#include "text_3d/text_3d.hpp"
+#include "utils/globals.hpp"
+
+
+namespace Text
+{
+
+DynArray<std::string>
+ wrap_String(const std::string& text, size_t max_chars);
+
+std::string
+ ascii_Sanitize(const std::string& in);
+
+
+
+struct Token
+{
+ std::string text;
+ size_t byte_begin { 0 };
+ size_t byte_end { 0 };
+ Text3d* view { nullptr };
+};
+
+
+struct Line
+{
+ DynArray<Token> tokens;
+};
+
+struct View
+{
+
+ DynArray<Line> lines;
+
+ void clear ();
+ std::string render_Source();
+ Token* token_At (size_t off);
+ void apply_Spans (const DynArray<HiSpan>& spans);
+ DynArray<std::string>
+ as_Lines () const;
+};
+
+} // namespace Text
diff --git a/src/utils/text_wrap.hpp b/src/utils/text_wrap.hpp
deleted file mode 100644
index e75c9d8..0000000
--- a/src/utils/text_wrap.hpp
+++ /dev/null
@@ -1,59 +0,0 @@
-#pragma once
-
-#include <string>
-
-#include "utils/globals.hpp"
-
-// ─────────────────────────────────────────────────────────────────────────
-// wrap_Text — break `text` into lines no longer than `max_chars`.
-//
-// Rules (matching the infowall behavior it was extracted from):
-// - explicit '\n' forces a line break (and can produce an empty line)
-// - spaces/tabs separate words; a word that would overflow the current
-// line starts a new line instead of being split
-// - trailing spaces are trimmed from each line
-// - a single word longer than max_chars is NOT split — it occupies its
-// own (over-length) line, same as the original
-// ─────────────────────────────────────────────────────────────────────────
-inline DynArray<std::string>
-wrap_Text(const std::string& text, size_t max_chars)
-{
- DynArray<std::string> lines;
- std::string current_line;
- std::string word;
-
- auto flush_line = [&]() {
- while (!current_line.empty() && current_line.back() == ' ')
- current_line.pop_back();
- lines.push_back(current_line); // may be empty (blank line)
- current_line.clear();
- };
-
- auto flush_word = [&]() {
- if (word.empty()) return;
- if (current_line.size() + word.size() + (current_line.empty() ? 0 : 1)
- > max_chars) {
- flush_line();
- }
- if (!current_line.empty()) current_line += ' ';
- current_line += word;
- word.clear();
- };
-
- for (char c : text) {
- if (c == '\n') {
- flush_word();
- flush_line();
- }
- else if (c == ' ' || c == '\t') {
- flush_word();
- }
- else {
- word += c;
- }
- }
- flush_word();
- flush_line();
-
- return lines;
-}
diff --git a/src/wall/editor_wall.cpp b/src/wall/editor.cpp
similarity index 91%
rename from src/wall/editor_wall.cpp
rename to src/wall/editor.cpp
index 9017def..4d4db46 100644
--- a/src/wall/editor_wall.cpp
+++ b/src/wall/editor.cpp
@@ -2,21 +2,24 @@
#include <algorithm>
#include <string>
-#include "editor_wall.hpp"
+#include "editor.hpp"
#include "entities/camera.hpp"
#include "entities/world.hpp"
#include "rendering/gl_renderer.hpp"
+namespace Wall
+{
+
void
-EditorWall::clear()
+Editor::clear()
{
_lines.clear();
}
-EditorWall::Line*
-EditorWall::find_NearestLine(double y)
+Editor::Line*
+Editor::find_NearestLine(double y)
{
Line* best = nullptr;
double best_dy = ConfigWall::snap_threshold_y;
@@ -30,8 +33,8 @@ EditorWall::find_NearestLine(double y)
}
-EditorWall::Target
-EditorWall::resolve_Target(double y) const
+Editor::Target
+Editor::resolve_Target(double y) const
{
DynArray<size_t> order;
for (size_t i = 0; i < _lines.size(); ++i)
@@ -114,8 +117,8 @@ EditorWall::resolve_Target(double y) const
}
-EditorWall::Line&
-EditorWall::apply_Target(const Target& t)
+Editor::Line&
+Editor::apply_Target(const Target& t)
{
if (t.kind == Target::Merge)
return _lines[t.line_index];
@@ -137,8 +140,8 @@ EditorWall::apply_Target(const Target& t)
}
-EditorWall::Placement
-EditorWall::place_OnLine(Line& line, double new_half_z, double impact_z)
+Editor::Placement
+Editor::place_OnLine(Line& line, double new_half_z, double impact_z)
{
if (line.words.empty())
return { 0, impact_z };
@@ -187,7 +190,7 @@ EditorWall::place_OnLine(Line& line, double new_half_z, double impact_z)
void
-EditorWall::on_LinePlaced(const DynArray<Text3d*>& words_in, const Vec3& impact)
+Editor::on_LinePlaced(const DynArray<Text3d*>& words_in, const Vec3& impact)
{
if (words_in.empty()) return;
@@ -263,7 +266,7 @@ EditorWall::on_LinePlaced(const DynArray<Text3d*>& words_in, const Vec3& impact)
void
-EditorWall::on_WordRemoved(Text3d* word)
+Editor::on_WordRemoved(Text3d* word)
{
if (!word) return;
@@ -284,7 +287,7 @@ EditorWall::on_WordRemoved(Text3d* word)
Vec3
-EditorWall::on_WordPlaced(Text3d* word, const Vec3& impact_pos)
+Editor::on_WordPlaced(Text3d* word, const Vec3& impact_pos)
{
if (!word) return impact_pos;
@@ -305,7 +308,7 @@ EditorWall::on_WordPlaced(Text3d* word, const Vec3& impact_pos)
void
-EditorWall::add_PlacedLine(const DynArray<Text3d*>& words, double row_y)
+Editor::add_PlacedLine(const DynArray<Text3d*>& words, double row_y)
{
if (words.empty()) return;
Line line;
@@ -348,7 +351,7 @@ set_NumberText(Text3d* t, const std::string& s)
void
-EditorWall::update(double dt, const Vec3& eye_pos)
+Editor::update(double dt, const Vec3& eye_pos)
{
if (_lines.empty()) return;
@@ -361,7 +364,7 @@ EditorWall::update(double dt, const Vec3& eye_pos)
std::sort(order.begin(), order.end(),
[&](size_t a, size_t b){ return _lines[a].y > _lines[b].y; });
- const Wall::Transform tf = Wall::get_Transform(Wall::Role::Editor, World::get_BoxScale());
+ const Transform tf = get_Transform(Role::Editor, World::get_BoxScale());
if (order.empty()) return;
@@ -372,8 +375,8 @@ EditorWall::update(double dt, const Vec3& eye_pos)
for (size_t oi : order)
for (Text3d* w : _lines[oi].words) {
if (!w) continue;
- code_left = std::max(code_left, w->pos.z + (double)w->half_extent);
- code_right = std::min(code_right, w->pos.z - (double)w->half_extent);
+ code_left = SDL_max(code_left, w->pos.z + (double)w->half_extent);
+ code_right = SDL_min(code_right, w->pos.z - (double)w->half_extent);
}
// Pass 1: ensure labels exist, refresh digits, advance the bounce, and find
@@ -398,8 +401,8 @@ EditorWall::update(double dt, const Vec3& eye_pos)
l.bounce_vel += (-STIFFNESS * l.bounce_off - DAMPING * l.bounce_vel) * dt;
l.bounce_off += l.bounce_vel * dt;
- max_lh = std::max(max_lh, (double)l.num_left->half_extent);
- max_rh = std::max(max_rh, (double)l.num_right->half_extent);
+ max_lh = SDL_max(max_lh, static_cast<double>(l.num_left ->half_extent));
+ max_rh = SDL_max(max_rh, static_cast<double>(l.num_right->half_extent));
++rank;
}
@@ -411,8 +414,8 @@ EditorWall::update(double dt, const Vec3& eye_pos)
const double EDGE = 0.3;
double left_col_z = code_left + ConfigWall::line_number_gap;
double right_col_z = code_right - ConfigWall::line_number_gap;
- left_col_z = std::min(left_col_z, ws - EDGE - 2.0 * max_lh);
- right_col_z = std::max(right_col_z, -ws + EDGE + 2.0 * max_rh);
+ left_col_z = SDL_min(left_col_z, ws - EDGE - 2.0 * max_lh);
+ right_col_z = SDL_max(right_col_z, -ws + EDGE + 2.0 * max_rh);
// Pass 2: place each number against its column at its (bounced) row height.
for (size_t oi : order) {
@@ -424,19 +427,19 @@ EditorWall::update(double dt, const Vec3& eye_pos)
for (Text3d* w : l.words) { if (w) { x = w->pos.x; break; } }
const double ny = l.y + l.bounce_off;
- const double lh = (double)l.num_left->half_extent;
- const double rh = (double)l.num_right->half_extent;
+ const double lh = static_cast<double>(l.num_left-> half_extent);
+ const double rh = static_cast<double>(l.num_right->half_extent);
l.num_left->pos = Vec3{ x, ny, left_col_z + lh }; // code-facing edge on the column
l.num_right->pos = Vec3{ x, ny, right_col_z - rh };
- l.num_left->pitch = Wall::tilt_TowardEye(l.num_left->pos, eye_pos);
- l.num_right->pitch = Wall::tilt_TowardEye(l.num_right->pos, eye_pos);
+ l.num_left->pitch = Text::tilt_TowardEye(l.num_left->pos, eye_pos);
+ l.num_right->pitch = Text::tilt_TowardEye(l.num_right->pos, eye_pos);
}
}
DynArray<DynArray<Text3d*>>
-EditorWall::lines_InOrder() const
+Editor::lines_InOrder() const
{
// Order rows top→bottom (largest y first), matching update()'s numbering.
DynArray<size_t> order;
@@ -463,8 +466,8 @@ EditorWall::lines_InOrder() const
}
-DynArray<EditorWall::NumberHit>
-EditorWall::number_Hitboxes() const
+DynArray<Editor::NumberHit>
+Editor::number_Hitboxes() const
{
// Build the box live from the label's current pos + half-extents rather
// than the base aabb_*() (which can lag a constantly-repositioned object).
@@ -476,8 +479,8 @@ EditorWall::number_Hitboxes() const
out.reserve(_lines.size() * 2);
auto push_box = [&](const Text3d* t, size_t i) {
- const double hz = (double)t->half_extent + PAD; // along wall (z)
- const double hy = (double)t->half_extent_y + PAD; // vertical
+ const double hz = static_cast<double>(t->half_extent ) + PAD; // along wall (z)
+ const double hy = static_cast<double>(t->half_extent_y) + PAD; // vertical
const Vec3 c = t->pos;
out.push_back({ HIT_BASE + i,
Vec3{ c.x - DEPTH_X, c.y - hy, c.z - hz },
@@ -494,7 +497,7 @@ EditorWall::number_Hitboxes() const
double
-EditorWall::scroll_DeltaToEye(size_t line_id, double eye_y) const
+Editor::scroll_DeltaToEye(size_t line_id, double eye_y) const
{
if (line_id >= _lines.size()) return 0.0;
return eye_y - _lines[line_id].y;
@@ -502,7 +505,7 @@ EditorWall::scroll_DeltaToEye(size_t line_id, double eye_y) const
void
-EditorWall::bounce(size_t line_id)
+Editor::bounce(size_t line_id)
{
if (line_id < _lines.size())
_lines[line_id].bounce_vel += ConfigWall::bounce_impulse;
@@ -510,7 +513,7 @@ EditorWall::bounce(size_t line_id)
void
-EditorWall::draw(GlRenderer& gl, const Camera& cam, const Light& light) const
+Editor::draw(GlRenderer& gl, const Camera& cam, const Light& light) const
{
if (_lines.empty()) return;
@@ -588,7 +591,7 @@ EditorWall::draw(GlRenderer& gl, const Camera& cam, const Light& light) const
double
-EditorWall::get_GridOrigin() const
+Editor::get_GridOrigin() const
{
double origin = 0.0;
bool found = false;
@@ -600,7 +603,7 @@ EditorWall::get_GridOrigin() const
}
double
-EditorWall::snap_RowY(double y) const
+Editor::snap_RowY(double y) const
{
const double LH = ConfigWall::line_height;
const double origin = get_GridOrigin();
@@ -609,7 +612,7 @@ EditorWall::snap_RowY(double y) const
}
bool
-EditorWall::row_IsEmpty(double y) const
+Editor::row_IsEmpty(double y) const
{
const double LH = ConfigWall::line_height;
const double slot_y = snap_RowY(y);
@@ -619,3 +622,5 @@ EditorWall::row_IsEmpty(double y) const
}
return true;
}
+
+} // namepsace Wall
diff --git a/src/wall/editor_wall.hpp b/src/wall/editor.hpp
similarity index 90%
rename from src/wall/editor_wall.hpp
rename to src/wall/editor.hpp
index feb666c..c1cde5f 100644
--- a/src/wall/editor_wall.hpp
+++ b/src/wall/editor.hpp
@@ -3,16 +3,17 @@
#include "text_3d/text_3d.hpp"
#include "utils/globals.hpp"
#include "utils/light.hpp"
-#include "utils/math.hpp"
#include "wall.hpp"
class Camera;
class GlRenderer;
+namespace Wall {
-class EditorWall
+class Editor
{
- struct Line {
+ struct Line
+ {
int shown_number {-1};
double y {0.0};
double bounce_off {0.0};
@@ -21,15 +22,17 @@ class EditorWall
Text3dPtr num_left;
Text3dPtr num_right;
- DynArray<Text3d*> words; // left-to-right
+ DynArray<Text3d*> words;
};
- struct Placement {
+ struct Placement
+ {
size_t insert_index;
double z;
};
- struct Target {
+ struct Target
+ {
enum Kind { Merge, Insert } kind;
size_t line_index;
double new_y;
@@ -52,8 +55,8 @@ public:
struct NumberHit {
size_t index;
- Vec3 aabb_min;
- Vec3 aabb_max;
+ Vec3 aabb_Min;
+ Vec3 aabb_Max;
};
void clear ();
@@ -77,3 +80,5 @@ public:
DynArray<NumberHit>
number_Hitboxes() const;
};
+
+} // namespace Wall
diff --git a/src/wall/wall_label.cpp b/src/wall/label.cpp
similarity index 87%
rename from src/wall/wall_label.cpp
rename to src/wall/label.cpp
index fb7ecbc..dde80d5 100644
--- a/src/wall/wall_label.cpp
+++ b/src/wall/label.cpp
@@ -1,5 +1,3 @@
-#include "wall_label.hpp"
-
#include "entities/camera.hpp"
#include "rendering/gl_renderer.hpp"
#include "utils/config.hpp"
@@ -37,10 +35,10 @@ static SDL_FColor label_Color(Wall::Role r)
// ── generate_All ─────────────────────────────────────────────────────────────
-DynArray<WallLabel>
-WallLabel::generate_All(float world_scale)
+DynArray<Wall::Label>
+Wall::Label::generate_All(float world_scale)
{
- DynArray<WallLabel> labels;
+ DynArray<Wall::Label> labels;
labels.reserve(4);
const float label_y = -world_scale * 0.48f;
@@ -55,7 +53,7 @@ WallLabel::generate_All(float world_scale)
for (uint8_t ri = 0; ri < 4; ++ri) {
Wall::Role role = static_cast<Wall::Role> (ri);
- Wall::Position pos = Wall::position_of (role);
+ Wall::Position pos = Wall::position_Of (role);
Wall::Transform tf = Wall::get_Transform (role, world_scale);
Vec3 anch = tf.position;
@@ -68,7 +66,7 @@ WallLabel::generate_All(float world_scale)
case Wall::Position::NegZ: anch.z += extra_offset; break;
}
- WallLabel wl;
+ Wall::Label wl;
wl.role = role;
wl.anchor = anch;
wl.face_yaw = tf.yaw;
@@ -90,9 +88,9 @@ WallLabel::generate_All(float world_scale)
// ── on_Hit ───────────────────────────────────────────────────────────────────
void
-WallLabel::on_Hit(size_t word_index, const Vec3& projectile_vel)
+Wall::Label::on_Hit(size_t word_index, const Vec3& projectile_vel)
{
- const Vec3 normal = wall_InwardNormal(Wall::position_of(role));
+ const Vec3 normal = Wall::inward_Normal(Wall::position_Of(role));
label.kick(word_index, projectile_vel, normal);
}
@@ -100,7 +98,7 @@ WallLabel::on_Hit(size_t word_index, const Vec3& projectile_vel)
// ── update ───────────────────────────────────────────────────────────────────
void
-WallLabel::update(double dt, const Camera& camera)
+Wall::Label::update(double dt, const Camera& camera)
{
// Positions + jiggle spring first. In non-billboard mode TextLabel::update
// forces every word's pitch to 0, so we must apply our eye-tilt AFTER it,
@@ -111,8 +109,8 @@ WallLabel::update(double dt, const Camera& camera)
// Tilt up/down toward the player's eye, clamped — identical to the
// editor wall text tilt in wall.hpp::tilt_TowardEye. Shared anchor pitch
// keeps the whole word reading as one rigid plane.
- const float pitch = Wall::tilt_TowardEye(anchor, camera.pos);
- for (const Text3dPtr& w : label.words())
+ const float pitch = Wall::Text::tilt_TowardEye(anchor, camera.pos);
+ for (const Text3dPtr& w : label.get_Words())
if (w) w->pitch = pitch;
}
@@ -120,7 +118,7 @@ WallLabel::update(double dt, const Camera& camera)
// ── draw ─────────────────────────────────────────────────────────────────────
void
-WallLabel::draw(GlRenderer& gl, const Camera& camera, const Light& light) const
+Wall::Label::draw(GlRenderer& gl, const Camera& camera, const Light& light) const
{
label.draw(gl, camera, light);
}
diff --git a/src/wall/wall_surfaces.cpp b/src/wall/surfaces.cpp
similarity index 73%
rename from src/wall/wall_surfaces.cpp
rename to src/wall/surfaces.cpp
index 20c705d..6d2fa57 100644
--- a/src/wall/wall_surfaces.cpp
+++ b/src/wall/surfaces.cpp
@@ -1,8 +1,13 @@
-#include "wall_surfaces.hpp"
-
#include <SDL3/SDL.h>
#include "entities/camera.hpp"
+#include "wall.hpp"
+
+#include "rendering/gl_renderer.hpp"
+#include "utils/globals.hpp"
+#include "utils/light.hpp"
+#include "utils/math.hpp"
+
namespace {
@@ -12,7 +17,7 @@ namespace {
//
// Vertices wound CCW when viewed from inside the room.
static void
-build_Wall(WallSurfaces::WallQuad& out,
+build_Wall(Wall::Surfaces::Quad& out,
Wall::Position pos,
float world_scale,
SDL_FColor col)
@@ -97,23 +102,27 @@ build_Wall(WallSurfaces::WallQuad& out,
} // namespace
+
+namespace Wall
+{
+
void
-WallSurfaces::generate(float world_scale)
+Surfaces::generate(float world_scale)
{
_walls.clear();
_walls.resize(4);
struct Spec {
- Wall::Role role;
- Wall::Position pos;
+ Role role;
+ Position pos;
SDL_FColor color;
bool is_editor;
};
const Spec specs[4] = {
- { Wall::Role::Editor, Wall::Position::NegX, ConfigColor::editor, false },
- { Wall::Role::Program, Wall::Position::PosX, ConfigColor::program, false },
- { Wall::Role::Info, Wall::Position::PosZ, ConfigColor::info, false },
- { Wall::Role::Compiler, Wall::Position::NegZ, ConfigColor::compiler, false },
+ { Role::Editor, Position::NegX, ConfigColor::editor, false },
+ { Role::Program, Position::PosX, ConfigColor::program, false },
+ { Role::Info, Position::PosZ, ConfigColor::info, false },
+ { Role::Compiler, Position::NegZ, ConfigColor::compiler, false },
};
for (size_t i = 0; i < 4; ++i) {
@@ -125,29 +134,32 @@ WallSurfaces::generate(float world_scale)
void
-WallSurfaces::draw(GlRenderer& gl, const Camera& cam, const Light& light) const
+Surfaces::draw(GlRenderer& gl, const Camera& cam, const Light& light) const
{
if (_walls.empty()) return;
- Mat4 view = buildViewMat4(cam);
- Mat4 proj = gl.projection();
- Mat4 model = Mat4::identity();
- Mat4 mvp = Mat4::mul(proj, Mat4::mul(view, model));
+ Mat4 view = buildViewMat4 (cam);
+ Mat4 proj = gl.get_Projection();
+ Mat4 model = Mat4::identity ();
+ Mat4 mvp = Mat4::mul (proj, Mat4::mul(view, model));
- gl.set_Wireframe(false);
- gl.set_MVP(model, mvp);
- gl.set_NormalMat(model);
- gl.set_Light(light);
+ gl.set_Wireframe (false);
+ gl.set_MVP (model, mvp);
+ gl.set_NormalMat (model);
+ gl.set_Light (light);
gl.set_TextLineSpacing(ConfigWall::text_line_spacing);
- for (const WallQuad& w : _walls) {
- gl.set_Color(w.color.r, w.color.g, w.color.b);
+ for (const Quad& w : _walls) {
+ gl.set_Color (w.color.r, w.color.g, w.color.b);
gl.enable_WallPaperMode(w.is_editor);
- gl.set_ColorUseVertex(false);
- gl.draw_MeshColored(w.verts.data(),
- static_cast<int>(w.verts.size() / 9),
- w.indices.data(),
- static_cast<int>(w.indices.size()));
+ gl.set_ColorUseVertex (false);
+ gl.draw_MeshColored (w.verts.data(),
+ static_cast<int>(w.verts.size() / 9),
+ w.indices.data(),
+ static_cast<int>(w.indices.size()));
}
gl.enable_WallPaperMode(false);
}
+
+
+} // Wall
diff --git a/src/wall/text_wall.cpp b/src/wall/text.cpp
similarity index 55%
rename from src/wall/text_wall.cpp
rename to src/wall/text.cpp
index 7abb641..676edcd 100644
--- a/src/wall/text_wall.cpp
+++ b/src/wall/text.cpp
@@ -1,11 +1,13 @@
#include "entities/world.hpp"
#include "systems/cpp_highlight_system.hpp"
-#include "text_wall.hpp"
#include "utils/config.hpp"
+#include "wall/wall.hpp"
-TextWallPtr
-TextWall::from_Drop(Text3dPtr src)
+namespace Wall {
+
+Ptr
+Text::from_Drop(Text3dPtr src)
{
double ws = World::get_BoxScale<double>();
double x = src->pos.x;
@@ -36,9 +38,9 @@ TextWall::from_Drop(Text3dPtr src)
src->yaw = yaw;
- Wall::Role role = Wall::role_of(wall_pos);
+ Wall::Role role = Wall::role_Of(wall_pos);
- return cpputils::make_unique<TextWall>(TextWall{
+ return cpputils::make_unique<Wall::Text>(Wall::Text{
wall_pos,
role,
std::move(src)
@@ -47,12 +49,12 @@ TextWall::from_Drop(Text3dPtr src)
std::string
-TextWall::extract_Text(const TextWallList& texts, Wall::Role role, double line_threshold)
+Text::extract_Text(const PtrList& texts, Wall::Role role, double line_threshold)
{
- DynArray<TextWall*> items;
+ DynArray<Wall::Text*> items;
items.reserve(texts.size());
- for (const TextWallPtr& wt : texts) {
+ for (const Ptr& wt : texts) {
if (wt->role == role)
items.push_back(wt.get());
}
@@ -60,29 +62,29 @@ TextWall::extract_Text(const TextWallList& texts, Wall::Role role, double line_t
if (items.empty())
return "";
- const Wall::Position wall_pos = Wall::position_of(role);
+ const Wall::Position wall_pos = Wall::position_Of(role);
std::sort(items.begin(), items.end(),
- [](const TextWall* a, const TextWall* b) {
+ [](const Wall::Text* a, const Wall::Text* b) {
return a->text3d->pos.y > b->text3d->pos.y;
});
struct Line {
- DynArray<TextWall*> items;
+ DynArray<Wall::Text*> items;
double sum_y = 0.0;
};
DynArray<Line> lines;
lines.reserve(items.size());
- for (TextWall* wt : items) {
+ for (Wall::Text* wt : items) {
const double y = wt->text3d->pos.y;
if (!lines.empty()) {
Line& line = lines.back();
const double avg_y = line.sum_y / static_cast<double>(line.items.size());
- if (std::abs(y - avg_y) < line_threshold) {
+ if (SDL_fabs(y - avg_y) < line_threshold) {
line.items.push_back(wt);
line.sum_y += y;
continue;
@@ -94,7 +96,7 @@ TextWall::extract_Text(const TextWallList& texts, Wall::Role role, double line_t
for (Line& line : lines) {
std::sort(line.items.begin(), line.items.end(),
- [&](const TextWall* a, const TextWall* b) {
+ [&](const Wall::Text* a, const Wall::Text* b) {
if (wall_pos == Wall::Position::PosX ||
wall_pos == Wall::Position::NegX)
return a->text3d->pos.z > b->text3d->pos.z;
@@ -108,7 +110,7 @@ TextWall::extract_Text(const TextWallList& texts, Wall::Role role, double line_t
for (size_t i = 0; i < line.items.size(); ++i) {
if (i) result += ' ';
- const TextWall* wt = line.items[i];
+ const Wall::Text* wt = line.items[i];
if (wt->text3d->type == ObjectType::Text)
result += wt->text3d->text;
}
@@ -120,28 +122,26 @@ TextWall::extract_Text(const TextWallList& texts, Wall::Role role, double line_t
void
-TextWall::draw(GlRenderer& g, const Camera& c, const Light& l) const
+Text::draw(GlRenderer& g, const Camera& c, const Light& l) const
{
text3d->draw(g, c, l);
}
-
-
void
-TextWall::show_TokenInfo(TextWallList& texts, const std::string& token_text)
+Text::show_TokenInfo(PtrList& texts, const std::string& token_text)
{
texts.erase(
std::remove_if(texts.begin(), texts.end(),
- [](const TextWallPtr& wt){ return wt->role == Wall::Role::Info; }),
+ [](const Ptr& wt){ return wt->role == Wall::Role::Info; }),
texts.end());
Wall::Transform tf = Wall::get_Transform(Wall::Role::Info, World::get_BoxScale());
TokenType tt = CppHighlight::classify_Word(token_text);
- TokenDB::Desc d = TokenDB::describe(token_text, tt);
+ TokenDB::Desc d = TokenDB::get_Description(token_text, tt);
- std::string line1 = token_text + " [" + TokenDB::type_Name(tt) + "]";
+ std::string line1 = token_text + " [" + TokenDB::get_TypeName(tt) + "]";
std::string line2 = d.short_desc;
std::string line3 = d.long_desc;
@@ -151,8 +151,78 @@ TextWall::show_TokenInfo(TextWallList& texts, const std::string& token_text)
Vec3 pos = tf.position; pos.y = y;
Text3dPtr t = make_Text3d(line, Text3d::depth_wall, 0.003f, pos, ConfigColor::white);
t->yaw = tf.yaw;
- texts.push_back(cpputils::make_unique<TextWall>(TextWall{
+ texts.push_back(cpputils::make_unique<Wall::Text>(Wall::Text{
tf.wall_position, Wall::Role::Info, std::move(t) }));
y -= ConfigWall::text_line_spacing;
}
}
+
+
+float
+Text::tilt_TowardEye(const Vec3& text_pos, const Vec3& eye_pos)
+{
+ double dx = eye_pos.x - text_pos.x;
+ double dy = eye_pos.y - text_pos.y;
+ double dz = eye_pos.z - text_pos.z;
+
+ double horiz = SDL_sqrt(dx*dx + dz*dz);
+ if (horiz < 0.01) return 0.0f; // player directly above/below — no tilt
+
+ // Sign flipped: we want positive pitch when player is BELOW the text.
+ double pitch = -SDL_atan2(dy, horiz);
+
+ if (pitch > static_cast<double>(ConfigWall::max_tilt)) pitch = ConfigWall::max_tilt;
+ if (pitch < -static_cast<double>(ConfigWall::max_tilt)) pitch = -ConfigWall::max_tilt;
+ return static_cast<float>(pitch);
+}
+
+
+void
+Text::clear_ToFloor(Wall::PtrList& texts,
+ DynArray<Text3dPtr>& words,
+ Wall::Role role)
+{
+ for (Wall::Ptr& wt : texts) {
+ if (wt->role != role || !wt->text3d) continue;
+
+ Text3dPtr word = std::move(wt->text3d);
+ word->body.mode = PhysicsMode::Dynamic;
+ word->body.vel = { 0.0, 1.5, 0.0 };
+ word->body.hover_height = World::get_FloorY<double>() + 1.5;
+
+ word->set_Look(ConfigColor::floor, Text3d::depth_floor);
+
+ words.push_back(std::move(word));
+ }
+
+ texts.erase(
+ std::remove_if(texts.begin(), texts.end(),
+ [role](const Wall::Ptr& wt){
+ return wt->role == role && !wt->text3d;
+ }),
+ texts.end());
+}
+
+
+void
+Text::scroll(Wall::PtrList& texts, Wall::Role role, float delta)
+{
+ for (Wall::Ptr& wt : texts) {
+ if (wt->role == role && wt->text3d) {
+ wt->text3d->pos.y += static_cast<double>(delta);
+ }
+ }
+}
+
+
+void
+Text::scroll_Up (Wall::PtrList& texts, Wall::Role role)
+{ scroll(texts, role, ConfigWall::scroll_step); }
+
+
+void
+Text::scroll_Down(Wall::PtrList& texts, Wall::Role role)
+{ scroll(texts, role, -ConfigWall::scroll_step); }
+
+
+} // namespace Wall
diff --git a/src/wall/text_wall.hpp b/src/wall/text_wall.hpp
deleted file mode 100644
index 636c425..0000000
--- a/src/wall/text_wall.hpp
+++ /dev/null
@@ -1,23 +0,0 @@
-#pragma once
-
-#include "wall/wall.hpp"
-#include "text_3d/text_3d.hpp"
-#include "utils/globals.hpp"
-#include "cpp_token/token_db.hpp"
-
-class GlRenderer;
-
-struct TextWall
-{
- Wall::Position wall_position;
- Wall::Role role;
- Text3dPtr text3d;
-
- void draw (GlRenderer& gl, const Camera& camera, const Light& light) const;
- static TextWallPtr
- from_Drop (Text3dPtr src);
- static std::string
- extract_Text (const TextWallList&, Wall::Role, double line_threshold = 0.3);
- static void
- show_TokenInfo(TextWallList& texts, const std::string& token_text);
-};
diff --git a/src/wall/text_wall_scroll.hpp b/src/wall/text_wall_scroll.hpp
deleted file mode 100644
index 5fa89c9..0000000
--- a/src/wall/text_wall_scroll.hpp
+++ /dev/null
@@ -1,52 +0,0 @@
-#pragma once
-
-#include "entities/world.hpp"
-#include "text_wall.hpp"
-#include "utils/config.hpp"
-#include "wall/wall.hpp"
-
-namespace TextWallScroll
-{
- inline void
- scroll(TextWallList& texts, Wall::Role role, float delta)
- {
- for (TextWallPtr& wt : texts) {
- if (wt->role == role && wt->text3d) {
- wt->text3d->pos.y += static_cast<double>(delta);
- }
- }
- }
-
- inline void
- scroll_Up (TextWallList& texts, Wall::Role role)
- { scroll(texts, role, ConfigWall::scroll_step); }
-
- inline void
- scroll_Down(TextWallList& texts, Wall::Role role)
- { scroll(texts, role, -ConfigWall::scroll_step); }
-
- inline void
- clear_ToFloor(TextWallList& texts,
- DynArray<Text3dPtr>& words,
- Wall::Role role)
- {
- for (TextWallPtr& wt : texts) {
- if (wt->role != role || !wt->text3d) continue;
-
- Text3dPtr word = std::move(wt->text3d);
- word->body.mode = PhysicsMode::Dynamic;
- word->body.vel = { 0.0, 1.5, 0.0 };
- word->body.hover_height = World::get_FloorY<double>() + 1.5;
- word->set_Look(ConfigColor::floor, Text3d::depth_floor);
-
- words.push_back(std::move(word));
- }
-
- texts.erase(
- std::remove_if(texts.begin(), texts.end(),
- [role](const TextWallPtr& wt){
- return wt->role == role && !wt->text3d;
- }),
- texts.end());
- }
-}
diff --git a/src/wall/wall.cpp b/src/wall/wall.cpp
new file mode 100644
index 0000000..2e645f5
--- /dev/null
+++ b/src/wall/wall.cpp
@@ -0,0 +1,77 @@
+#include "entities/world.hpp"
+#include "wall.hpp"
+
+namespace Wall
+{
+
+ Role
+ role_Of(Position p)
+ {
+ switch (p) {
+ case Position::PosX: return Role::Program;
+ case Position::NegX: return Role::Editor;
+ case Position::PosZ: return Role::Info;
+ case Position::NegZ: return Role::Compiler;
+ }
+ return Role::Program;
+ }
+
+ Position
+ position_Of(Role r)
+ {
+ switch (r) {
+ case Role::Program: return Position::PosX;
+ case Role::Editor: return Position::NegX;
+ case Role::Info: return Position::PosZ;
+ case Role::Compiler: return Position::NegZ;
+ }
+ return Position::PosX;
+ }
+
+ static_assert(static_cast<uint8_t>(Position::PosX) == static_cast<uint8_t>(Role::Program), "");
+ static_assert(static_cast<uint8_t>(Position::NegX) == static_cast<uint8_t>(Role::Editor), "");
+ static_assert(static_cast<uint8_t>(Position::PosZ) == static_cast<uint8_t>(Role::Info), "");
+ static_assert(static_cast<uint8_t>(Position::NegZ) == static_cast<uint8_t>(Role::Compiler),"");
+
+ Vec3 inward_Normal(Wall::Position pos)
+ {
+ switch (pos) {
+ case Wall::Position::PosX: return { -1.0, 0.0, 0.0 };
+ case Wall::Position::NegX: return { 1.0, 0.0, 0.0 };
+ case Wall::Position::PosZ: return { 0.0, 0.0, -1.0 };
+ case Wall::Position::NegZ: return { 0.0, 0.0, 1.0 };
+ }
+ return { 0.0, 0.0, 1.0 };
+ }
+
+ Transform
+ get_Transform(Role role, float world_scale)
+ {
+
+ switch (position_Of(role)) {
+ case Position::PosX:
+ return { Position::PosX,
+ { world_scale - ConfigWall::text_offset, 0.0, 0.0 },
+ -SDL_PI_F * 0.5f };
+ case Position::NegX:
+ return { Position::NegX,
+ { -world_scale + ConfigWall::text_offset, 0.0, 0.0 },
+ SDL_PI_F * 0.5f };
+ case Position::PosZ:
+ return { Position::PosZ,
+ { 0.0, 0.0, world_scale - ConfigWall::text_offset },
+ SDL_PI_F };
+ case Position::NegZ:
+ default:
+ return { Position::NegZ,
+ { 0.0, 0.0, -world_scale + ConfigWall::text_offset },
+ 0.0f };
+ }
+ }
+
+ Vec3
+ get_Position(Role role, float world_scale)
+ {
+ return get_Transform(role, world_scale).position;
+ }
+} // namespace Wall
diff --git a/src/wall/wall.hpp b/src/wall/wall.hpp
index ff7b6bc..08c349a 100644
--- a/src/wall/wall.hpp
+++ b/src/wall/wall.hpp
@@ -1,97 +1,87 @@
#pragma once
-#include "utils/globals.hpp"
+#include "text_3d/text_3d.hpp"
+#include "text_3d/text_label.hpp"
#include "utils/config.hpp"
+#include "utils/globals.hpp"
+
-namespace Wall {
+namespace Wall
+{
+ struct Text;
+ using Ptr = cpputils::unique_ptr<Text>;
+ using PtrList = DynArray<Ptr>;
enum class Position : uint8_t { PosX, NegX, PosZ, NegZ };
enum class Role : uint8_t { Program, Editor, Info, Compiler };
- constexpr Role
- role_of(Position p)
- {
- switch (p) {
- case Position::PosX: return Role::Program;
- case Position::NegX: return Role::Editor;
- case Position::PosZ: return Role::Info;
- case Position::NegZ: return Role::Compiler;
- }
- return Role::Program;
- }
-
- constexpr Position
- position_of(Role r)
- {
- switch (r) {
- case Role::Program: return Position::PosX;
- case Role::Editor: return Position::NegX;
- case Role::Info: return Position::PosZ;
- case Role::Compiler: return Position::NegZ;
- }
- return Position::PosX;
- }
-
- static_assert(static_cast<uint8_t>(Position::PosX) == static_cast<uint8_t>(Role::Program), "");
- static_assert(static_cast<uint8_t>(Position::NegX) == static_cast<uint8_t>(Role::Editor), "");
- static_assert(static_cast<uint8_t>(Position::PosZ) == static_cast<uint8_t>(Role::Info), "");
- static_assert(static_cast<uint8_t>(Position::NegZ) == static_cast<uint8_t>(Role::Compiler),"");
-
- struct
- Transform
+ Role role_Of (Position p);
+ Position position_Of (Role r);
+ Vec3 inward_Normal(Wall::Position pos);
+
+ struct Transform
{
Position wall_position;
- Vec3 position;
- float yaw;
+ Vec3 position;
+ float yaw;
};
- static inline Transform
- get_Transform(Role role, float world_scale)
- {
+ Transform get_Transform (Role role, float world_scale);
+ Vec3 get_Position (Role role, float world_scale);
- switch (position_of(role)) {
- case Position::PosX:
- return { Position::PosX,
- { world_scale - ConfigWall::text_offset, 0.0, 0.0 },
- -SDL_PI_F * 0.5f };
- case Position::NegX:
- return { Position::NegX,
- { -world_scale + ConfigWall::text_offset, 0.0, 0.0 },
- SDL_PI_F * 0.5f };
- case Position::PosZ:
- return { Position::PosZ,
- { 0.0, 0.0, world_scale - ConfigWall::text_offset },
- SDL_PI_F };
- case Position::NegZ:
- default:
- return { Position::NegZ,
- { 0.0, 0.0, -world_scale + ConfigWall::text_offset },
- 0.0f };
- }
- }
-
- static inline Vec3
- get_Position(Role role, float world_scale)
+
+ class Surfaces
{
- return get_Transform(role, world_scale).position;
- }
+ public:
+ struct Quad {
+ bool is_editor;
+ Wall::Role role;
+ SDL_FColor color;
+ DynArray<float> verts;
+ DynArray<int> indices;
+ };
- static inline float
- tilt_TowardEye(const Vec3& text_pos, const Vec3& eye_pos)
+ void generate(float world_scale);
+ void draw(GlRenderer& gl, const Camera& cam, const Light& light) const;
+ private:
+ DynArray<Quad> _walls;
+ };
+
+ struct Text
{
- double dx = eye_pos.x - text_pos.x;
- double dy = eye_pos.y - text_pos.y;
- double dz = eye_pos.z - text_pos.z;
+ Wall::Position wall_position;
+ Wall::Role role;
+ Text3dPtr text3d;
+
+ void draw (GlRenderer& gl, const Camera& camera, const Light& light) const;
+
+ static void show_TokenInfo(PtrList& texts, const std::string& token_text);
+ static Ptr from_Drop (Text3dPtr src);
+ static std::string extract_Text (const PtrList&, Wall::Role, double line_threshold = 0.3);
+ static float tilt_TowardEye(const Vec3& text_pos, const Vec3& eye_pos);
+ static void clear_ToFloor (Wall::PtrList& texts,
+ DynArray<Text3dPtr>& words,
+ Wall::Role role);
+ static void scroll (Wall::PtrList& texts, Wall::Role role, float delta);
+ static void scroll_Up (Wall::PtrList& texts, Wall::Role role);
+ static void scroll_Down (Wall::PtrList& texts, Wall::Role role);
+ };
- double horiz = SDL_sqrt(dx*dx + dz*dz);
- if (horiz < 0.01) return 0.0f; // player directly above/below — no tilt
- // Sign flipped: we want positive pitch when player is BELOW the text.
- double pitch = -SDL_atan2(dy, horiz);
- if (pitch > static_cast<double>(ConfigWall::max_tilt)) pitch = ConfigWall::max_tilt;
- if (pitch < -static_cast<double>(ConfigWall::max_tilt)) pitch = -ConfigWall::max_tilt;
- return static_cast<float>(pitch);
- }
+ struct Label
+ {
+ Wall::Role role;
+ float face_yaw;
+ Vec3 anchor;
+ TextLabel label;
+
+ static DynArray<Label>
+ generate_All(float world_scale);
+
+ void on_Hit (size_t word_index, const Vec3& projectile_vel);
+ void update (double dt, const Camera& camera);
+ void draw (GlRenderer& gl, const Camera& camera, const Light& light) const;
+ };
}
diff --git a/src/wall/wall_label.hpp b/src/wall/wall_label.hpp
deleted file mode 100644
index 96af1bc..0000000
--- a/src/wall/wall_label.hpp
+++ /dev/null
@@ -1,36 +0,0 @@
-#pragma once
-
-#include "text_3d/text_label.hpp"
-#include "utils/globals.hpp"
-#include "utils/light.hpp"
-#include "wall/wall.hpp"
-
-class GlRenderer;
-class Camera;
-
-struct WallLabel
-{
- Wall::Role role;
- float face_yaw;
- Vec3 anchor;
- TextLabel label;
-
- static DynArray<WallLabel>
- generate_All(float world_scale);
-
- void on_Hit (size_t word_index, const Vec3& projectile_vel);
- void update (double dt, const Camera& camera);
- void draw (GlRenderer& gl, const Camera& camera, const Light& light) const;
-};
-
-
-inline Vec3 wall_InwardNormal(Wall::Position pos)
-{
- switch (pos) {
- case Wall::Position::PosX: return { -1.0, 0.0, 0.0 };
- case Wall::Position::NegX: return { 1.0, 0.0, 0.0 };
- case Wall::Position::PosZ: return { 0.0, 0.0, -1.0 };
- case Wall::Position::NegZ: return { 0.0, 0.0, 1.0 };
- }
- return { 0.0, 0.0, 1.0 };
-}
diff --git a/src/wall/wall_surfaces.hpp b/src/wall/wall_surfaces.hpp
deleted file mode 100644
index 100a25d..0000000
--- a/src/wall/wall_surfaces.hpp
+++ /dev/null
@@ -1,31 +0,0 @@
-#pragma once
-
-#include <SDL3/SDL.h>
-
-#include "rendering/gl_renderer.hpp"
-#include "utils/globals.hpp"
-#include "utils/light.hpp"
-#include "utils/math.hpp"
-#include "wall/wall.hpp"
-
-class Camera;
-
-
-class WallSurfaces
-{
-public:
- struct WallQuad {
- bool is_editor;
- Wall::Role role;
- SDL_FColor color;
-
- DynArray<float> verts;
- DynArray<int> indices;
- };
-
- void generate(float world_scale);
- void draw(GlRenderer& gl, const Camera& cam, const Light& light) const;
-private:
- DynArray<WallQuad> _walls;
-};
-