use std::any::Any;
use std::sync::Arc;
use crate::{
core::{Entity, System, SystemContext, SystemError, SystemId},
runtime::AssetManager,
};
use super::{
gpu::{GraphicsContext, RenderPipeline},
pipeline::{SpriteBatch, RenderCommands},
resources::TextureCache,
};
pub struct RenderSystem {
id: SystemId,
graphics: Option<GraphicsContext>,
render_pipeline: Option<RenderPipeline>,
sprite_batch: SpriteBatch,
texture_cache: Option<TextureCache>,
initialized: bool,
}
impl RenderSystem {
pub fn new() -> Self {
Self {
id: SystemId::from_str("RenderSystem"),
graphics: None,
render_pipeline: None,
sprite_batch: SpriteBatch::new(800.0, 600.0), texture_cache: None,
initialized: false,
}
}
pub async fn initialize(&mut self, window: Arc<winit::window::Window>) -> Result<(), SystemError> {
let graphics = GraphicsContext::new(window).await
.map_err(|e| SystemError::InitializationFailed(e))?;
let render_pipeline = RenderPipeline::new_sprite_pipeline(
graphics.device(),
graphics.config().format
);
let texture_cache = TextureCache::new(
Arc::new(graphics.device().clone()),
Arc::new(graphics.queue().clone()),
);
self.graphics = Some(graphics);
self.render_pipeline = Some(render_pipeline);
self.texture_cache = Some(texture_cache);
self.initialized = true;
println!("✅ RenderSystem 초기화 완료");
Ok(())
}
fn render_entities_with_textures(
&mut self,
entities: &[Entity],
camera: &crate::runtime::Camera,
asset_manager: &mut AssetManager,
) -> Result<(), SystemError> {
if !self.initialized {
return Err(SystemError::RuntimeError("RenderSystem not initialized. Call initialize() first.".to_string()));
}
let Some(graphics) = &self.graphics else {
return Err(SystemError::RuntimeError("Graphics not initialized".to_string()));
};
let Some(render_pipeline) = &self.render_pipeline else {
return Err(SystemError::RuntimeError("Render pipeline not initialized".to_string()));
};
let Some(texture_cache) = &mut self.texture_cache else {
return Err(SystemError::RuntimeError("Texture cache not initialized".to_string()));
};
self.sprite_batch.begin_frame();
self.sprite_batch.collect_sprites(entities, camera);
if self.sprite_batch.is_empty() {
return Ok(());
}
let output = graphics.get_current_frame()
.map_err(|e| SystemError::RuntimeError(format!("Surface texture: {}", e)))?;
let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
let mut encoder = graphics.device().create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Render Encoder"),
});
let render_commands = RenderCommands::new(
graphics,
render_pipeline,
);
render_commands.execute_render_pass_with_textures(
&mut encoder,
&view,
&self.sprite_batch,
texture_cache,
asset_manager,
);
graphics.queue().submit(std::iter::once(encoder.finish()));
output.present();
Ok(())
}
}
impl System for RenderSystem {
fn id(&self) -> SystemId {
self.id
}
fn update(&mut self, context: &mut SystemContext) -> Result<(), SystemError> {
self.render_entities_with_textures(
context.entities,
context.camera,
context.asset_manager,
)
}
fn name(&self) -> &'static str {
"RenderSystem"
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}