hoplite/
ecs.rs

1//! ECS components for entity-based rendering.
2//!
3//! This module provides components for rendering entities using the `hecs` ECS library.
4//! Entities with [`Transform`](crate::Transform) and [`RenderMesh`] components are
5//! automatically rendered when [`Frame::render_world`](crate::Frame::render_world) is called.
6//!
7//! # Example
8//!
9//! ```ignore
10//! use hoplite::*;
11//!
12//! run(|ctx| {
13//!     ctx.enable_mesh_rendering();
14//!     let cube = ctx.mesh_cube();
15//!
16//!     // Spawn an entity with mesh components
17//!     ctx.world.spawn((
18//!         Transform::new().position(Vec3::new(0.0, 0.0, -5.0)),
19//!         RenderMesh::new(cube, Color::RED),
20//!     ));
21//!
22//!     move |frame| {
23//!         frame.render_world();
24//!     }
25//! });
26//! ```
27
28use crate::draw2d::Color;
29
30/// Type-safe handle to a mesh stored in the MeshQueue.
31///
32/// Obtained from mesh creation methods like [`SetupContext::mesh_cube`](crate::SetupContext::mesh_cube).
33/// This newtype wrapper prevents accidentally passing texture indices where mesh indices are expected.
34///
35/// # Example
36///
37/// ```ignore
38/// let cube: MeshId = ctx.mesh_cube();
39/// frame.mesh(cube).draw();  // Type-safe: can't pass a TextureId here
40/// ```
41#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
42pub struct MeshId(pub(crate) usize);
43
44/// Type-safe handle to a texture stored in the MeshQueue.
45///
46/// Obtained from texture creation methods like [`SetupContext::texture_from_file`](crate::SetupContext::texture_from_file).
47/// This newtype wrapper prevents accidentally passing mesh indices where texture indices are expected.
48///
49/// # Example
50///
51/// ```ignore
52/// let tex: TextureId = ctx.texture_from_file("brick.png")?;
53/// frame.mesh(cube).texture(tex).draw();  // Type-safe: can't pass a MeshId here
54/// ```
55#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
56pub struct TextureId(pub(crate) usize);
57
58// Keep MeshHandle and TextureHandle as aliases for backwards compatibility in ECS contexts
59/// Alias for [`MeshId`] - used in ECS components.
60pub type MeshHandle = MeshId;
61
62/// Alias for [`TextureId`] - used in ECS components.
63pub type TextureHandle = TextureId;
64
65/// Component for rendering a mesh on an entity.
66///
67/// Attach this component along with a [`Transform`](crate::Transform) to make an entity
68/// renderable. Call [`Frame::render_world`](crate::Frame::render_world) to render all
69/// entities with these components.
70///
71/// # Example
72///
73/// ```ignore
74/// // Untextured colored mesh
75/// world.spawn((
76///     Transform::new().position(Vec3::Y * 2.0),
77///     RenderMesh::new(MeshHandle(cube), Color::RED),
78/// ));
79///
80/// // Textured mesh
81/// world.spawn((
82///     Transform::new(),
83///     RenderMesh::with_texture(MeshHandle(cube), Color::WHITE, TextureHandle(tex)),
84/// ));
85/// ```
86#[derive(Clone, Copy, Debug)]
87pub struct RenderMesh {
88    /// Handle to the mesh geometry.
89    pub mesh: MeshHandle,
90    /// Color tint applied to the mesh.
91    pub color: Color,
92    /// Optional texture. If `None`, uses vertex colors only.
93    pub texture: Option<TextureHandle>,
94}
95
96impl RenderMesh {
97    /// Create a new render mesh component with a color tint.
98    pub fn new(mesh: MeshHandle, color: Color) -> Self {
99        Self {
100            mesh,
101            color,
102            texture: None,
103        }
104    }
105
106    /// Create a new render mesh component with a texture.
107    pub fn with_texture(mesh: MeshHandle, color: Color, texture: TextureHandle) -> Self {
108        Self {
109            mesh,
110            color,
111            texture: Some(texture),
112        }
113    }
114}