use std::collections::HashMap;
use std::sync::Arc;
use astrelis_core::geometry::LogicalSize;
use astrelis_render::{GraphicsContext, WindowContext, WindowContextDescriptor, WindowManager};
use astrelis_winit::WindowId;
use astrelis_winit::window::Window;
use crate::plugin::Plugin;
use crate::resource::Resources;
pub struct RenderContexts {
graphics: Option<Arc<GraphicsContext>>,
contexts: HashMap<WindowId, WindowContext>,
}
impl Default for RenderContexts {
fn default() -> Self {
Self::new()
}
}
impl RenderContexts {
pub fn new() -> Self {
Self {
graphics: None,
contexts: HashMap::new(),
}
}
pub fn with_graphics(graphics: Arc<GraphicsContext>) -> Self {
Self {
graphics: Some(graphics),
contexts: HashMap::new(),
}
}
pub fn create_for_window(
&mut self,
window: Window,
) -> Result<&mut WindowContext, astrelis_render::GraphicsError> {
let graphics = self
.graphics
.as_ref()
.expect("RenderContexts must be initialized with a GraphicsContext")
.clone();
self.create_for_window_with(window, graphics, WindowContextDescriptor::default())
}
pub fn create_for_window_with(
&mut self,
window: Window,
graphics: Arc<GraphicsContext>,
descriptor: WindowContextDescriptor,
) -> Result<&mut WindowContext, astrelis_render::GraphicsError> {
let window_id = window.id();
if let std::collections::hash_map::Entry::Vacant(e) = self.contexts.entry(window_id) {
let context = WindowContext::new(window, graphics, descriptor)?;
e.insert(context);
}
Ok(self.contexts.get_mut(&window_id).unwrap())
}
pub fn get(&self, window_id: WindowId) -> Option<&WindowContext> {
self.contexts.get(&window_id)
}
pub fn get_mut(&mut self, window_id: WindowId) -> Option<&mut WindowContext> {
self.contexts.get_mut(&window_id)
}
pub fn remove(&mut self, window_id: WindowId) -> Option<WindowContext> {
self.contexts.remove(&window_id)
}
pub fn contains(&self, window_id: WindowId) -> bool {
self.contexts.contains_key(&window_id)
}
pub fn resized(&mut self, window_id: WindowId, new_size: LogicalSize<u32>) {
if let Some(context) = self.contexts.get_mut(&window_id) {
context.resized(new_size);
}
}
pub fn graphics(&self) -> Option<&GraphicsContext> {
self.graphics.as_deref()
}
}
pub struct RenderPlugin;
impl Plugin for RenderPlugin {
type Dependencies = ();
fn name(&self) -> &'static str {
"RenderPlugin"
}
fn build(&self, resources: &mut Resources) {
let graphics =
GraphicsContext::new_owned_sync().expect("Failed to create graphics context");
tracing::info!(
"RenderPlugin: GraphicsContext created (backend: {:?})",
graphics.info().backend
);
resources.insert(graphics.clone());
resources.insert(RenderContexts::with_graphics(graphics.clone()));
resources.insert(WindowManager::new(graphics));
tracing::debug!(
"RenderPlugin: Registered GraphicsContext, RenderContexts, and WindowManager"
);
}
}
#[cfg(test)]
mod tests {
#[test]
#[ignore = "Requires GPU"]
fn test_render_plugin() {
use super::*;
use crate::EngineBuilder;
let engine = EngineBuilder::new().add_plugin(RenderPlugin).build();
assert!(engine.get::<&'static GraphicsContext>().is_some());
assert!(engine.get::<RenderContexts>().is_some());
}
}