goud_engine/rendering/
render_system.rs1use super::sprite_batch::{SpriteBatch, SpriteBatchConfig};
28use crate::assets::AssetServer;
29use crate::core::error::GoudResult;
30use crate::ecs::World;
31use crate::libs::graphics::backend::RenderBackend;
32
33pub struct SpriteRenderSystem<B: RenderBackend> {
45 sprite_batch: SpriteBatch<B>,
46}
47
48impl<B: RenderBackend> SpriteRenderSystem<B> {
49 pub fn new(backend: B) -> GoudResult<Self> {
51 let sprite_batch = SpriteBatch::new(backend, SpriteBatchConfig::default())?;
52 Ok(Self { sprite_batch })
53 }
54
55 pub fn with_config(backend: B, config: SpriteBatchConfig) -> GoudResult<Self> {
57 let sprite_batch = SpriteBatch::new(backend, config)?;
58 Ok(Self { sprite_batch })
59 }
60
61 pub fn run(&mut self, world: &World, asset_server: &AssetServer) -> GoudResult<()> {
77 self.sprite_batch.begin();
78 self.sprite_batch.draw_sprites(world, asset_server)?;
79 self.sprite_batch.end()?;
80 Ok(())
81 }
82
83 pub fn stats(&self) -> (usize, usize, f32) {
87 self.sprite_batch.stats()
88 }
89
90 pub fn sprite_batch(&self) -> &SpriteBatch<B> {
92 &self.sprite_batch
93 }
94
95 pub fn sprite_batch_mut(&mut self) -> &mut SpriteBatch<B> {
97 &mut self.sprite_batch
98 }
99}
100
101impl<B: RenderBackend> std::fmt::Debug for SpriteRenderSystem<B> {
102 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103 f.debug_struct("SpriteRenderSystem")
104 .field("sprite_batch", &"SpriteBatch { ... }")
105 .finish()
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112 use crate::assets::loaders::{TextureAsset, TextureFormat};
113 use crate::assets::AssetStorage;
114 use crate::core::math::{Color, Vec2};
115 use crate::ecs::components::{Sprite, Transform2D};
116 use crate::ecs::World;
117 use crate::libs::graphics::backend::opengl::OpenGLBackend;
118
119 #[test]
120 fn test_sprite_render_system_new() {
121 }
124
125 #[test]
126 fn test_sprite_render_system_debug() {
127 }
129
130 #[test]
131 #[ignore] fn test_sprite_render_system_run() {
133 let backend = OpenGLBackend::new().expect("Failed to create OpenGL backend");
135 let mut render_system =
136 SpriteRenderSystem::new(backend).expect("Failed to create render system");
137
138 let mut world = World::new();
140 let asset_server = AssetServer::new();
141
142 let texture_data = vec![255u8; 64 * 64 * 4]; let texture_asset = TextureAsset::new(texture_data, 64, 64, TextureFormat::Png);
145 let mut storage = AssetStorage::new();
146 let texture_handle = storage.insert(texture_asset);
147
148 let entity = world.spawn_empty();
150 world
151 .insert(entity, Sprite::new(texture_handle).with_color(Color::WHITE))
152 .expect("Failed to add Sprite");
153 world
154 .insert(entity, Transform2D::from_position(Vec2::new(100.0, 100.0)))
155 .expect("Failed to add Transform2D");
156
157 let result = render_system.run(&world, &asset_server);
159 assert!(result.is_ok(), "Render system should run successfully");
160
161 let (sprite_count, batch_count, _ratio) = render_system.stats();
163 assert_eq!(sprite_count, 1, "Should have rendered 1 sprite");
164 assert!(batch_count > 0, "Should have at least 1 batch");
165 }
166
167 #[test]
168 #[ignore] fn test_sprite_render_system_multiple_sprites() {
170 let backend = OpenGLBackend::new().expect("Failed to create OpenGL backend");
171 let mut render_system =
172 SpriteRenderSystem::new(backend).expect("Failed to create render system");
173
174 let mut world = World::new();
175 let asset_server = AssetServer::new();
176
177 let texture_data = vec![255u8; 64 * 64 * 4];
179 let texture_asset = TextureAsset::new(texture_data, 64, 64, TextureFormat::Png);
180 let mut storage = AssetStorage::new();
181 let texture_handle = storage.insert(texture_asset);
182
183 for i in 0..10 {
185 let entity = world.spawn_empty();
186 world
187 .insert(entity, Sprite::new(texture_handle).with_color(Color::WHITE))
188 .expect("Failed to add Sprite");
189 world
190 .insert(
191 entity,
192 Transform2D::from_position(Vec2::new(i as f32 * 50.0, 100.0)),
193 )
194 .expect("Failed to add Transform2D");
195 }
196
197 render_system
199 .run(&world, &asset_server)
200 .expect("Failed to run render system");
201
202 let (sprite_count, batch_count, ratio) = render_system.stats();
204 assert_eq!(sprite_count, 10, "Should have rendered 10 sprites");
205 assert!(batch_count > 0, "Should have at least 1 batch");
206 assert!(
207 ratio > 1.0,
208 "Should have good batching ratio with same texture"
209 );
210 }
211
212 #[test]
213 #[ignore] fn test_sprite_render_system_empty_world() {
215 let backend = OpenGLBackend::new().expect("Failed to create OpenGL backend");
216 let mut render_system =
217 SpriteRenderSystem::new(backend).expect("Failed to create render system");
218
219 let world = World::new();
220 let asset_server = AssetServer::new();
221
222 let result = render_system.run(&world, &asset_server);
224 assert!(result.is_ok(), "Should handle empty world gracefully");
225
226 let (sprite_count, batch_count, _ratio) = render_system.stats();
227 assert_eq!(sprite_count, 0, "Should have 0 sprites");
228 assert_eq!(batch_count, 0, "Should have 0 batches");
229 }
230
231 #[test]
232 fn test_sprite_render_system_accessors() {
233 }
236
237 #[test]
238 #[ignore] fn test_sprite_render_system_z_sorting() {
240 let backend = OpenGLBackend::new().expect("Failed to create OpenGL backend");
241 let mut render_system =
242 SpriteRenderSystem::new(backend).expect("Failed to create render system");
243
244 let mut world = World::new();
245 let asset_server = AssetServer::new();
246
247 let texture_data = vec![255u8; 64 * 64 * 4];
249 let texture_asset = TextureAsset::new(texture_data, 64, 64, TextureFormat::Png);
250 let mut storage = AssetStorage::new();
251 let texture_handle = storage.insert(texture_asset);
252
253 for i in 0..5 {
255 let entity = world.spawn_empty();
256 world
257 .insert(entity, Sprite::new(texture_handle).with_color(Color::WHITE))
258 .expect("Failed to add Sprite");
259 world
260 .insert(
261 entity,
262 Transform2D::from_position(Vec2::new(100.0, i as f32 * 50.0)),
263 )
264 .expect("Failed to add Transform2D");
265 }
266
267 render_system
269 .run(&world, &asset_server)
270 .expect("Failed to run render system");
271
272 let (sprite_count, _batch_count, _ratio) = render_system.stats();
273 assert_eq!(sprite_count, 5, "Should have rendered 5 sprites");
274 }
275}