first commit
This commit is contained in:
commit
5c7d1905a9
25 changed files with 4034 additions and 0 deletions
11
include/components.hpp
Normal file
11
include/components.hpp
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
* @file components.hpp
|
||||
* @brief Master include for all ECS components
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "components/transform.hpp"
|
||||
#include "components/render.hpp"
|
||||
#include "components/input.hpp"
|
||||
#include "components/common.hpp"
|
||||
24
include/components/common.hpp
Normal file
24
include/components/common.hpp
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* @file common.hpp
|
||||
* @brief Common/utility components
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
struct Name {
|
||||
std::string value;
|
||||
};
|
||||
|
||||
// Tag component - empty struct marks entities for destruction
|
||||
struct ToDestroy {};
|
||||
|
||||
struct Lifetime {
|
||||
float remaining = 0.0f;
|
||||
};
|
||||
|
||||
struct Health {
|
||||
float current = 100.0f;
|
||||
float max = 100.0f;
|
||||
};
|
||||
21
include/components/input.hpp
Normal file
21
include/components/input.hpp
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* @file input.hpp
|
||||
* @brief Input-related components
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
struct PlayerControlled {
|
||||
int player_id = 0;
|
||||
};
|
||||
|
||||
struct InputState {
|
||||
bool move_up = false;
|
||||
bool move_down = false;
|
||||
bool move_left = false;
|
||||
bool move_right = false;
|
||||
bool action_primary = false;
|
||||
bool action_secondary = false;
|
||||
float mouse_x = 0.0f;
|
||||
float mouse_y = 0.0f;
|
||||
};
|
||||
32
include/components/render.hpp
Normal file
32
include/components/render.hpp
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* @file render.hpp
|
||||
* @brief Rendering-related components
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <cstdint>
|
||||
|
||||
struct Color {
|
||||
uint8_t r = 255;
|
||||
uint8_t g = 255;
|
||||
uint8_t b = 255;
|
||||
uint8_t a = 255;
|
||||
};
|
||||
|
||||
struct Sprite {
|
||||
SDL_Texture* texture = nullptr;
|
||||
SDL_FRect src_rect{};
|
||||
int z_order = 0;
|
||||
bool visible = true;
|
||||
};
|
||||
|
||||
struct RectShape {
|
||||
float width = 0.0f;
|
||||
float height = 0.0f;
|
||||
};
|
||||
|
||||
struct CircleShape {
|
||||
float radius = 0.0f;
|
||||
};
|
||||
25
include/components/transform.hpp
Normal file
25
include/components/transform.hpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* @file transform.hpp
|
||||
* @brief Transform components for position, velocity, and rotation
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
struct Position {
|
||||
float x = 0.0f;
|
||||
float y = 0.0f;
|
||||
};
|
||||
|
||||
struct Velocity {
|
||||
float x = 0.0f;
|
||||
float y = 0.0f;
|
||||
};
|
||||
|
||||
struct Rotation {
|
||||
float angle = 0.0f;
|
||||
};
|
||||
|
||||
struct Scale {
|
||||
float x = 1.0f;
|
||||
float y = 1.0f;
|
||||
};
|
||||
52
include/game.hpp
Normal file
52
include/game.hpp
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
* @file game.hpp
|
||||
* @brief Main game state and context
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <flecs.h>
|
||||
|
||||
struct WindowConfig {
|
||||
const char *title = "RIDGE RACER 37";
|
||||
int width = 1280;
|
||||
int height = 720;
|
||||
SDL_WindowFlags flags = 0;
|
||||
};
|
||||
|
||||
struct PipelineState;
|
||||
|
||||
/**
|
||||
* @brief Game context containing all core resources
|
||||
*/
|
||||
struct GameContext {
|
||||
// SDL Resources
|
||||
SDL_Window *window = nullptr;
|
||||
SDL_Renderer *renderer = nullptr;
|
||||
|
||||
// FLECS World (C++ wrapper)
|
||||
flecs::world ecs;
|
||||
|
||||
// Timing
|
||||
uint64_t last_time = 0;
|
||||
float delta_time = 0.0f;
|
||||
|
||||
// State
|
||||
bool running = true;
|
||||
bool paused = false;
|
||||
|
||||
// Window info
|
||||
int window_width = 0;
|
||||
int window_height = 0;
|
||||
|
||||
// Pipeline visualization
|
||||
PipelineState *pipeline = nullptr;
|
||||
};
|
||||
|
||||
bool game_init(GameContext &ctx, const WindowConfig &config);
|
||||
void game_shutdown(GameContext &ctx);
|
||||
void game_process_events(GameContext &ctx);
|
||||
void game_update(GameContext &ctx);
|
||||
void game_render(GameContext &ctx);
|
||||
bool game_loop(GameContext &ctx);
|
||||
129
include/math3d.hpp
Normal file
129
include/math3d.hpp
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/**
|
||||
* @file math3d.hpp
|
||||
* @brief Minimal 3D math library for render pipeline visualization
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
|
||||
constexpr float PI = 3.14159265358979323846f;
|
||||
|
||||
struct Vec3 {
|
||||
float x = 0, y = 0, z = 0;
|
||||
Vec3 operator+(Vec3 o) const { return {x+o.x, y+o.y, z+o.z}; }
|
||||
Vec3 operator-(Vec3 o) const { return {x-o.x, y-o.y, z-o.z}; }
|
||||
Vec3 operator*(float s) const { return {x*s, y*s, z*s}; }
|
||||
float dot(Vec3 o) const { return x*o.x + y*o.y + z*o.z; }
|
||||
Vec3 cross(Vec3 o) const { return {y*o.z - z*o.y, z*o.x - x*o.z, x*o.y - y*o.x}; }
|
||||
float length() const { return std::sqrt(x*x + y*y + z*z); }
|
||||
Vec3 normalized() const {
|
||||
float l = length();
|
||||
return l > 0 ? Vec3{x/l, y/l, z/l} : Vec3{0, 0, 0};
|
||||
}
|
||||
};
|
||||
|
||||
inline Vec3 lerp(Vec3 a, Vec3 b, float t) {
|
||||
return {a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t};
|
||||
}
|
||||
|
||||
inline float smoothstep(float t) {
|
||||
return t * t * (3.0f - 2.0f * t);
|
||||
}
|
||||
|
||||
struct Vec4 {
|
||||
float x = 0, y = 0, z = 0, w = 1;
|
||||
Vec3 xyz() const { return {x, y, z}; }
|
||||
Vec3 perspDiv() const {
|
||||
return w != 0 ? Vec3{x/w, y/w, z/w} : Vec3{x, y, z};
|
||||
}
|
||||
};
|
||||
|
||||
struct Mat4 {
|
||||
float m[4][4] = {};
|
||||
|
||||
static Mat4 identity() {
|
||||
Mat4 r;
|
||||
r.m[0][0] = r.m[1][1] = r.m[2][2] = r.m[3][3] = 1;
|
||||
return r;
|
||||
}
|
||||
|
||||
Vec4 operator*(Vec4 v) const {
|
||||
return {
|
||||
m[0][0]*v.x + m[0][1]*v.y + m[0][2]*v.z + m[0][3]*v.w,
|
||||
m[1][0]*v.x + m[1][1]*v.y + m[1][2]*v.z + m[1][3]*v.w,
|
||||
m[2][0]*v.x + m[2][1]*v.y + m[2][2]*v.z + m[2][3]*v.w,
|
||||
m[3][0]*v.x + m[3][1]*v.y + m[3][2]*v.z + m[3][3]*v.w,
|
||||
};
|
||||
}
|
||||
|
||||
Mat4 operator*(const Mat4& o) const {
|
||||
Mat4 r;
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int j = 0; j < 4; j++)
|
||||
for (int k = 0; k < 4; k++)
|
||||
r.m[i][j] += m[i][k] * o.m[k][j];
|
||||
return r;
|
||||
}
|
||||
|
||||
static Mat4 translate(float x, float y, float z) {
|
||||
Mat4 r = identity();
|
||||
r.m[0][3] = x; r.m[1][3] = y; r.m[2][3] = z;
|
||||
return r;
|
||||
}
|
||||
|
||||
static Mat4 scale(float sx, float sy, float sz) {
|
||||
Mat4 r = identity();
|
||||
r.m[0][0] = sx; r.m[1][1] = sy; r.m[2][2] = sz;
|
||||
return r;
|
||||
}
|
||||
|
||||
static Mat4 rotateX(float angle) {
|
||||
float c = std::cos(angle), s = std::sin(angle);
|
||||
Mat4 r = identity();
|
||||
r.m[1][1] = c; r.m[1][2] = -s;
|
||||
r.m[2][1] = s; r.m[2][2] = c;
|
||||
return r;
|
||||
}
|
||||
|
||||
static Mat4 rotateY(float angle) {
|
||||
float c = std::cos(angle), s = std::sin(angle);
|
||||
Mat4 r = identity();
|
||||
r.m[0][0] = c; r.m[0][2] = s;
|
||||
r.m[2][0] = -s; r.m[2][2] = c;
|
||||
return r;
|
||||
}
|
||||
|
||||
static Mat4 rotateZ(float angle) {
|
||||
float c = std::cos(angle), s = std::sin(angle);
|
||||
Mat4 r = identity();
|
||||
r.m[0][0] = c; r.m[0][1] = -s;
|
||||
r.m[1][0] = s; r.m[1][1] = c;
|
||||
return r;
|
||||
}
|
||||
|
||||
// Standard OpenGL-style perspective (right-handed, -Z forward)
|
||||
static Mat4 perspective(float fov, float aspect, float near, float far) {
|
||||
float t = std::tan(fov * 0.5f);
|
||||
Mat4 r;
|
||||
r.m[0][0] = 1.0f / (aspect * t);
|
||||
r.m[1][1] = 1.0f / t;
|
||||
r.m[2][2] = -(far + near) / (far - near);
|
||||
r.m[2][3] = -(2.0f * far * near) / (far - near);
|
||||
r.m[3][2] = -1.0f;
|
||||
return r;
|
||||
}
|
||||
|
||||
// Standard lookAt (right-handed)
|
||||
static Mat4 lookAt(Vec3 eye, Vec3 target, Vec3 up) {
|
||||
Vec3 f = (target - eye).normalized();
|
||||
Vec3 r = f.cross(up).normalized();
|
||||
Vec3 u = r.cross(f);
|
||||
Mat4 mat = identity();
|
||||
mat.m[0][0] = r.x; mat.m[0][1] = r.y; mat.m[0][2] = r.z; mat.m[0][3] = -r.dot(eye);
|
||||
mat.m[1][0] = u.x; mat.m[1][1] = u.y; mat.m[1][2] = u.z; mat.m[1][3] = -u.dot(eye);
|
||||
mat.m[2][0] = -f.x; mat.m[2][1] = -f.y; mat.m[2][2] = -f.z; mat.m[2][3] = f.dot(eye);
|
||||
return mat;
|
||||
}
|
||||
};
|
||||
129
include/pipeline.hpp
Normal file
129
include/pipeline.hpp
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/**
|
||||
* @file pipeline.hpp
|
||||
* @brief Render pipeline visualization state and interface
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "math3d.hpp"
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
struct GameContext;
|
||||
|
||||
constexpr int NUM_CUBE_VERTS = 8;
|
||||
constexpr int NUM_CUBE_EDGES = 12;
|
||||
constexpr int NUM_TRI_VERTS = 3;
|
||||
constexpr int NUM_TRI_EDGES = 3;
|
||||
|
||||
struct PipelineState {
|
||||
int current_stage = 0; // 0-5
|
||||
int prev_stage = 0;
|
||||
float transition_t = 1.0f; // 0→1 animation progress (1 = complete)
|
||||
float fade_alpha = 1.0f; // for 3D↔2D mode transitions
|
||||
|
||||
// Interpolated vertices for rendering during transitions
|
||||
Vec3 display_verts[NUM_CUBE_VERTS];
|
||||
|
||||
// Vertex selection
|
||||
int selected_vertex = -1; // -1 = none, 0-7 = selected vertex index
|
||||
bool pending_click = false;
|
||||
float click_x = 0, click_y = 0;
|
||||
|
||||
// Object transform parameters (user-adjustable)
|
||||
float obj_rot_y = 0.0f;
|
||||
float obj_pos_x = 2.0f;
|
||||
float obj_pos_y = 1.0f;
|
||||
float obj_pos_z = -3.0f;
|
||||
float obj_scale = 1.0f;
|
||||
bool auto_rotate = false;
|
||||
|
||||
// Display camera (orbit around scene for visualization)
|
||||
float cam_orbit_pitch = 25.0f; // degrees
|
||||
float cam_orbit_yaw = -30.0f; // degrees
|
||||
float cam_distance = 10.0f;
|
||||
|
||||
// Pipeline camera (the one being visualized in the pipeline)
|
||||
float pipe_cam_x = 0.0f;
|
||||
float pipe_cam_y = 2.0f;
|
||||
float pipe_cam_z = 5.0f;
|
||||
float pipe_cam_fov = 1.0f; // radians (~57 degrees)
|
||||
float pipe_cam_near = 0.1f;
|
||||
float pipe_cam_far = 100.0f;
|
||||
|
||||
// Mouse drag state
|
||||
bool mouse_down = false;
|
||||
float mouse_start_x = 0, mouse_start_y = 0;
|
||||
float orbit_start_pitch = 0, orbit_start_yaw = 0;
|
||||
|
||||
// Slider drag state
|
||||
int dragging_slider = -1; // -1 = none, 0+ = slider index
|
||||
bool show_sliders = true;
|
||||
|
||||
// First-person camera view (picture-in-picture)
|
||||
bool show_first_person = false;
|
||||
|
||||
// Matrix color breakdown
|
||||
bool show_matrix_breakdown = false;
|
||||
|
||||
// Vertex shader simulation
|
||||
bool shader_mode = false;
|
||||
float shader_amplitude = 0.3f;
|
||||
float shader_frequency = 2.0f;
|
||||
float shader_time = 0.0f;
|
||||
|
||||
// Help overlay
|
||||
bool show_help = false;
|
||||
|
||||
// Clipping visualizer
|
||||
bool show_clipping = false;
|
||||
struct ClippedFace {
|
||||
static constexpr int MAX_VERTS = 24;
|
||||
Vec4 verts[MAX_VERTS];
|
||||
int count = 0;
|
||||
bool was_clipped = false;
|
||||
};
|
||||
ClippedFace clipped_faces[6];
|
||||
|
||||
// Depth buffer / Z-fighting demo
|
||||
bool show_depth_viz = false;
|
||||
bool show_zfight_plane = false;
|
||||
float zfight_plane_z = -3.0f;
|
||||
static constexpr int NUM_PLANE_VERTS = 4;
|
||||
Vec4 plane_world[4];
|
||||
Vec3 plane_screen[4];
|
||||
Vec3 plane_display[4];
|
||||
|
||||
// Input flags (set per event, cleared after processing)
|
||||
bool key_left = false;
|
||||
bool key_right = false;
|
||||
bool key_space = false;
|
||||
bool key_r = false;
|
||||
bool key_num[6] = {};
|
||||
|
||||
// Computed transforms
|
||||
Mat4 model_matrix;
|
||||
Mat4 view_matrix;
|
||||
Mat4 proj_matrix;
|
||||
|
||||
// Transformed vertices at each pipeline stage (cube)
|
||||
Vec4 verts_object[NUM_CUBE_VERTS];
|
||||
Vec4 verts_world[NUM_CUBE_VERTS];
|
||||
Vec4 verts_view[NUM_CUBE_VERTS];
|
||||
Vec4 verts_clip[NUM_CUBE_VERTS];
|
||||
Vec3 verts_ndc[NUM_CUBE_VERTS];
|
||||
Vec3 verts_screen[NUM_CUBE_VERTS];
|
||||
|
||||
// Second shape: triangle
|
||||
bool show_triangle = false;
|
||||
Vec4 tri_object[NUM_TRI_VERTS];
|
||||
Vec4 tri_world[NUM_TRI_VERTS];
|
||||
Vec4 tri_view[NUM_TRI_VERTS];
|
||||
Vec4 tri_clip[NUM_TRI_VERTS];
|
||||
Vec3 tri_ndc[NUM_TRI_VERTS];
|
||||
Vec3 tri_screen[NUM_TRI_VERTS];
|
||||
Vec3 tri_display[NUM_TRI_VERTS];
|
||||
};
|
||||
|
||||
void pipeline_handle_event(PipelineState& ps, const SDL_Event& event);
|
||||
void pipeline_update(PipelineState& ps, GameContext& ctx);
|
||||
void pipeline_render(PipelineState& ps, GameContext& ctx);
|
||||
16
include/systems.hpp
Normal file
16
include/systems.hpp
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/**
|
||||
* @file systems.hpp
|
||||
* @brief ECS System registration
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <flecs.h>
|
||||
|
||||
// Forward declaration
|
||||
struct GameContext;
|
||||
|
||||
/**
|
||||
* @brief Register all components and systems with the ECS world
|
||||
*/
|
||||
void register_systems(flecs::world& ecs, GameContext* ctx);
|
||||
Loading…
Add table
Add a link
Reference in a new issue