Skip to main content

mittens_engine/engine/graphics/
primitives.rs

1/// Mesh helpers / basic primitives placeholder.
2
3/// Column-major 4x4 transform matrix.
4pub type TransformMatrix = [[f32; 4]; 4];
5
6/// Minimal transform (placeholder).
7#[derive(Debug, Clone, Copy)]
8pub struct Transform {
9    pub translation: [f32; 3],
10    pub rotation: [f32; 4], // quat xyzw
11    pub scale: [f32; 3],
12
13    /// Cached model matrix (column-major). Keep this in sync with TRS.
14    pub model: TransformMatrix,
15
16    /// Cached world matrix (column-major).
17    ///
18    /// This is computed/maintained by `TransformSystem` by propagating parent transforms.
19    /// It should be treated as derived runtime state.
20    pub matrix_world: TransformMatrix,
21}
22
23impl Default for Transform {
24    fn default() -> Self {
25        let translation = [0.0; 3];
26        let rotation = [0.0, 0.0, 0.0, 1.0];
27        let scale = [1.0; 3];
28        let model = [
29            [scale[0], 0.0, 0.0, 0.0],
30            [0.0, scale[1], 0.0, 0.0],
31            [0.0, 0.0, scale[2], 0.0],
32            [translation[0], translation[1], translation[2], 1.0],
33        ];
34        Self {
35            translation,
36            rotation,
37            scale,
38            model,
39            matrix_world: model,
40        }
41    }
42}
43
44impl Transform {
45    /// Recompute `self.model` from translation/rotation/scale.
46    pub fn recompute_model(&mut self) {
47        let [tx, ty, tz] = self.translation;
48        let [sx, sy, sz] = self.scale;
49        let [x, y, z, w] = self.rotation;
50
51        // Normalize quat defensively.
52        let len2 = x * x + y * y + z * z + w * w;
53        let inv_len = if len2 > 0.0 { len2.sqrt().recip() } else { 1.0 };
54        let (x, y, z, w) = (x * inv_len, y * inv_len, z * inv_len, w * inv_len);
55
56        // Quaternion to rotation matrix (column-major).
57        let xx = x * x;
58        let yy = y * y;
59        let zz = z * z;
60        let xy = x * y;
61        let xz = x * z;
62        let yz = y * z;
63        let wx = w * x;
64        let wy = w * y;
65        let wz = w * z;
66
67        let r00 = 1.0 - 2.0 * (yy + zz);
68        let r01 = 2.0 * (xy + wz);
69        let r02 = 2.0 * (xz - wy);
70
71        let r10 = 2.0 * (xy - wz);
72        let r11 = 1.0 - 2.0 * (xx + zz);
73        let r12 = 2.0 * (yz + wx);
74
75        let r20 = 2.0 * (xz + wy);
76        let r21 = 2.0 * (yz - wx);
77        let r22 = 1.0 - 2.0 * (xx + yy);
78
79        // Apply scale by scaling the rotation columns.
80        let c0 = [r00 * sx, r01 * sx, r02 * sx, 0.0];
81        let c1 = [r10 * sy, r11 * sy, r12 * sy, 0.0];
82        let c2 = [r20 * sz, r21 * sz, r22 * sz, 0.0];
83        let c3 = [tx, ty, tz, 1.0];
84
85        self.model = [c0, c1, c2, c3];
86    }
87}
88
89/// Renderable component: references renderer-managed resources.
90/// Vulkan-minded: material -> pipeline/layout + descriptors.
91///
92/// The mesh here is a *CPU-side* asset handle. `RenderAssets` stores the actual `CpuMesh`
93/// and uploads it to the renderer on demand.
94#[derive(Debug, Clone)]
95pub struct Renderable {
96    /// The mesh actually used for rendering.
97    pub mesh: CpuMeshHandle,
98
99    /// The "base" mesh this renderable was derived from.
100    ///
101    /// For UV-baked variants (e.g. text glyphs), `mesh` is a dynamically-registered clone, while
102    /// `base_mesh` stays as the original (typically `CpuMeshHandle::QUAD_2D`).
103    ///
104    /// For normal renderables, `base_mesh == mesh`.
105    pub base_mesh: CpuMeshHandle,
106    pub material: MaterialHandle,
107}
108
109impl Renderable {
110    pub fn new(mesh: CpuMeshHandle, material: MaterialHandle) -> Self {
111        Self {
112            mesh,
113            base_mesh: mesh,
114            material,
115        }
116    }
117
118    pub fn with_base_mesh(mut self, base_mesh: CpuMeshHandle) -> Self {
119        self.base_mesh = base_mesh;
120        self
121    }
122}
123
124/// GPU-facing renderable record stored in `VisualWorld`.
125///
126/// This is intentionally a thin, renderer-ready version of `Renderable`.
127/// It avoids pulling any ECS concepts into `VisualWorld`.
128#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
129pub struct GpuRenderable {
130    pub mesh: MeshHandle,
131    pub material: MaterialHandle,
132}
133
134impl GpuRenderable {
135    pub fn new(mesh: MeshHandle, material: MaterialHandle) -> Self {
136        Self { mesh, material }
137    }
138}
139
140#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
141pub struct BufferHandle(pub u32);
142
143/// Vertex buffer layout description (API-agnostic placeholder).
144#[derive(Debug, Clone)]
145pub struct VertexLayout {
146    pub stride: u32,
147    pub attributes: &'static [VertexAttribute],
148}
149
150#[derive(Debug, Clone, Copy)]
151pub struct VertexAttribute {
152    pub location: u32,
153    pub offset: u32,
154    pub format: VertexFormat,
155}
156
157#[derive(Debug, Clone, Copy)]
158pub enum VertexFormat {
159    Float32x2,
160    Float32x3,
161    Float32x4,
162    Uint32,
163}
164
165// CPU-side mesh handles
166impl MeshHandle {
167    pub const TRIANGLE: MeshHandle = MeshHandle(2);
168    pub const SQUARE: MeshHandle = MeshHandle(3);
169
170    pub const CUBE: MeshHandle = MeshHandle(0);
171    pub const TETRAHEDRON: MeshHandle = MeshHandle(1);
172}
173
174/// Renderer-owned GPU mesh resource (looked up by `MeshHandle`).
175#[derive(Debug, Clone, Copy)]
176pub struct GpuMesh {
177    pub vertex_buffer: BufferHandle,
178    pub index_buffer: BufferHandle,
179    pub index_count: u32,
180    pub vertex_layout: &'static VertexLayout,
181}
182
183/// Renderer-owned resource handles (lightweight ids into renderer/asset tables).
184#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
185pub struct MeshHandle(pub u32);
186
187/// CPU-side mesh identity (owned by `RenderAssets`).
188#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
189pub struct CpuMeshHandle(pub u32);
190
191impl CpuMeshHandle {
192    // These constants are relied on by scene serialization and built-in inference.
193    // Keep in sync with `RenderAssets::register_builtin_meshes` order.
194    pub const TRIANGLE_2D: CpuMeshHandle = CpuMeshHandle(0);
195    pub const QUAD_2D: CpuMeshHandle = CpuMeshHandle(1);
196    pub const CUBE: CpuMeshHandle = CpuMeshHandle(2);
197    pub const TETRAHEDRON: CpuMeshHandle = CpuMeshHandle(3);
198    pub const SPHERE: CpuMeshHandle = CpuMeshHandle(4);
199
200    // Appended built-ins (keep stable and in sync with RenderAssets registration order).
201    pub const CONE: CpuMeshHandle = CpuMeshHandle(5);
202    pub const CIRCLE_2D: CpuMeshHandle = CpuMeshHandle(6);
203}
204
205#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
206pub struct MaterialHandle(pub u32);
207
208#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
209pub struct TextureHandle(pub u32);
210
211#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
212pub struct InstanceHandle(pub u32);
213
214/// Renderer-owned material definition (API-agnostic placeholder).
215/// For now we reference shaders by name/path; later this becomes pipeline state + descriptor layouts.
216#[derive(Debug, Clone)]
217pub struct Material {
218    pub vertex_shader: &'static str,
219    pub fragment_shader: &'static str,
220    // Later:
221    // pub pipeline_config: PipelineConfig,
222    // pub uniforms: MaterialUniforms,
223}
224
225// Optional convenience: built-in material names/paths.
226impl Material {
227    /// Unlit material intended for normal mesh rendering (vertex/index buffers + transforms).
228    pub const UNLIT_MESH: Material = Material {
229        vertex_shader: "assets/shaders/unlit-mesh.vert",
230        fragment_shader: "assets/shaders/unlit-mesh.frag",
231    };
232
233    /// Toon material used by the Vulkano renderer bring-up pipeline.
234    pub const TOON_MESH: Material = Material {
235        vertex_shader: "assets/shaders/toon-mesh.vert",
236        fragment_shader: "assets/shaders/toon-mesh.frag",
237    };
238
239    /// Skinned toon material (uses a skinned vertex shader).
240    pub const SKINNED_TOON_MESH: Material = Material {
241        vertex_shader: "assets/shaders/skinned-toon-mesh.vert",
242        fragment_shader: "assets/shaders/toon-mesh.frag",
243    };
244
245    /// Emissive toon material.
246    pub const EMISSIVE_TOON_MESH: Material = Material {
247        vertex_shader: "assets/shaders/toon-mesh.vert",
248        fragment_shader: "assets/shaders/emissive-toon-mesh.frag",
249    };
250
251    /// Skinned emissive toon material.
252    pub const SKINNED_EMISSIVE_TOON_MESH: Material = Material {
253        vertex_shader: "assets/shaders/skinned-toon-mesh.vert",
254        fragment_shader: "assets/shaders/emissive-toon-mesh.frag",
255    };
256
257    /// Procedural square grid material.
258    pub const GRID_MESH: Material = Material {
259        vertex_shader: "assets/shaders/grid.vert",
260        fragment_shader: "assets/shaders/grid-square.frag",
261    };
262
263    /// Planar mirror material.
264    pub const MIRROR: Material = Material {
265        vertex_shader: "assets/shaders/mirror-mesh.vert",
266        fragment_shader: "assets/shaders/mirror-mesh.frag",
267    };
268}
269
270impl MaterialHandle {
271    /// Unlit mesh material (see `Material::UNLIT_MESH`).
272    pub const UNLIT_MESH: MaterialHandle = MaterialHandle(0);
273
274    /// Toon mesh material (see `Material::TOON_MESH`).
275    pub const TOON_MESH: MaterialHandle = MaterialHandle(1);
276
277    /// Skinned toon mesh material (see `Material::SKINNED_TOON_MESH`).
278    pub const SKINNED_TOON_MESH: MaterialHandle = MaterialHandle(2);
279
280    /// Emissive toon mesh material (see `Material::EMISSIVE_TOON_MESH`).
281    pub const EMISSIVE_TOON_MESH: MaterialHandle = MaterialHandle(3);
282
283    /// Skinned emissive toon mesh material (see `Material::SKINNED_EMISSIVE_TOON_MESH`).
284    pub const SKINNED_EMISSIVE_TOON_MESH: MaterialHandle = MaterialHandle(4);
285
286    /// Procedural square grid material (see `Material::GRID_MESH`).
287    pub const GRID_MESH: MaterialHandle = MaterialHandle(5);
288
289    /// Mirror material for planar reflections.
290    pub const MIRROR: MaterialHandle = MaterialHandle(6);
291}