diff --git a/crates/components/src/map_view.rs b/crates/components/src/map_view.rs
index 5b7ef58b..cd603fcf 100644
--- a/crates/components/src/map_view.rs
+++ b/crates/components/src/map_view.rs
@@ -15,8 +15,6 @@
// You should have received a copy of the GNU General Public License
// along with Luminol. If not, see .
-use std::sync::Arc;
-
use itertools::Itertools;
pub struct MapView {
@@ -30,8 +28,9 @@ pub struct MapView {
/// The first sprite is for drawing on the tilemap,
/// and the second sprite is for the hover preview.
- pub preview_events: luminol_data::OptionVec>, // TODO only add events when they are being displayed as a preview
- pub map_view: luminol_graphics::MapView,
+ pub preview_events:
+ luminol_data::OptionVec>, // TODO only add events when they are being displayed as a preview
+ pub map_view: luminol_graphics::BundleRenderer,
pub selected_layer: SelectedLayer,
pub selected_event_id: Option,
@@ -87,13 +86,13 @@ impl MapView {
|x, y, passage| passages[(x, y)] = passage,
);
- let map_view = luminol_graphics::MapView::new(
+ let map_view = luminol_graphics::BundleRenderer::new(luminol_graphics::MapView::new(
&update_state.graphics,
update_state.filesystem,
&map,
tileset,
&passages,
- )?;
+ )?);
let preview_events = map
.events
@@ -105,7 +104,7 @@ impl MapView {
e,
map_view.atlas(),
)
- .map(|opt_e| opt_e.map(|e| (id, Arc::new(e))))
+ .map(|opt_e| opt_e.map(|e| (id, luminol_graphics::ArcRenderer::new(e))))
})
.flatten_ok()
.try_collect()?;
@@ -378,9 +377,15 @@ impl MapView {
}
}
+ let time = ui.input(|i| i.time);
+ self.map_view
+ .increment_animation_time(&graphics_state, time);
self.map_view
.paint(&graphics_state, ui.painter(), canvas_rect);
+ ui.ctx()
+ .request_repaint_after(std::time::Duration::from_secs_f32(1.0 / 16.0));
+
ui.painter().rect_stroke(
map_rect,
5.,
diff --git a/crates/graphics/src/event.rs b/crates/graphics/src/event.rs
index 609f40af..f45fd83f 100644
--- a/crates/graphics/src/event.rs
+++ b/crates/graphics/src/event.rs
@@ -119,37 +119,14 @@ impl Event {
pub fn set_proj(&self, render_state: &luminol_egui_wgpu::RenderState, proj: glam::Mat4) {
self.viewport.set_proj(render_state, proj);
}
+}
- pub fn draw<'rpass>(
+impl crate::Renderable for Event {
+ fn draw<'rpass>(
&'rpass self,
graphics_state: &'rpass GraphicsState,
render_pass: &mut impl wgpu::util::RenderEncoder<'rpass>,
) {
- self.sprite.draw(graphics_state, render_pass);
- }
-
- pub fn paint(
- self: Arc,
- graphics_state: Arc,
- painter: &egui::Painter,
- rect: egui::Rect,
- ) {
- struct Callback(Arc, Arc);
-
- impl luminol_egui_wgpu::CallbackTrait for Callback {
- fn paint<'a>(
- &'a self,
- _info: egui::PaintCallbackInfo,
- render_pass: &mut wgpu::RenderPass<'a>,
- _callback_resources: &'a luminol_egui_wgpu::CallbackResources,
- ) {
- self.0.draw(&self.1, render_pass);
- }
- }
-
- painter.add(luminol_egui_wgpu::Callback::new_paint_callback(
- rect,
- Callback(self, graphics_state),
- ));
+ self.sprite.draw(graphics_state, render_pass)
}
}
diff --git a/crates/graphics/src/lib.rs b/crates/graphics/src/lib.rs
index 1127682e..ee1853f7 100644
--- a/crates/graphics/src/lib.rs
+++ b/crates/graphics/src/lib.rs
@@ -35,6 +35,9 @@ pub mod event;
pub mod map;
pub mod plane;
+pub mod renderers;
+pub use renderers::{ArcRenderer, BundleRenderer, Renderable};
+
pub use event::Event;
pub use map::MapView;
pub use plane::Plane;
diff --git a/crates/graphics/src/map.rs b/crates/graphics/src/map.rs
index 0090c7ac..5b1cc44d 100644
--- a/crates/graphics/src/map.rs
+++ b/crates/graphics/src/map.rs
@@ -19,7 +19,6 @@ use color_eyre::eyre::Context;
use itertools::Itertools;
use std::sync::Arc;
-use std::time::Duration;
use crate::{Collision, Event, GraphicsState, Grid, Plane, Tiles, Viewport};
@@ -32,15 +31,13 @@ pub struct MapView {
pub events: luminol_data::OptionVec,
viewport: Arc,
- ani_time: Option,
+ ani_time: f64,
pub fog_enabled: bool,
pub pano_enabled: bool,
pub coll_enabled: bool,
pub grid_enabled: bool,
pub enabled_layers: Vec,
-
- render_bundle: Option>,
}
impl MapView {
@@ -142,15 +139,13 @@ impl MapView {
viewport,
- ani_time: None,
+ ani_time: 0.0,
fog_enabled: true,
pano_enabled: true,
coll_enabled: false,
grid_enabled: true,
enabled_layers: vec![true; map.data.zsize()],
-
- render_bundle: None,
})
}
@@ -180,101 +175,48 @@ impl MapView {
self.viewport.set_proj(render_state, proj);
}
- pub fn paint(
- &mut self,
- graphics_state: &GraphicsState,
- painter: &egui::Painter,
- rect: egui::Rect,
- ) {
- struct Callback(Arc);
-
- impl luminol_egui_wgpu::CallbackTrait for Callback {
- fn paint<'a>(
- &'a self,
- _: egui::PaintCallbackInfo,
- render_pass: &mut wgpu::RenderPass<'a>,
- _: &'a luminol_egui_wgpu::CallbackResources,
- ) {
- render_pass.execute_bundles(std::iter::once(self.0.as_ref()));
- }
+ pub fn increment_animation_time(&mut self, graphics_state: &GraphicsState, time: f64) {
+ if time - self.ani_time >= 16. / 60. {
+ self.ani_time = time;
+ self.tiles
+ .autotiles
+ .inc_ani_index(&graphics_state.render_state);
}
-
- let time = painter.ctx().input(|i| i.time);
- if let Some(ani_time) = self.ani_time {
- if time - ani_time >= 16. / 60. {
- self.ani_time = Some(time);
- self.tiles
- .autotiles
- .inc_ani_index(&graphics_state.render_state);
- }
- } else {
- self.ani_time = Some(time);
- }
-
- painter
- .ctx()
- .request_repaint_after(Duration::from_secs_f64(16. / 60.));
-
- let bundle = match self.render_bundle.clone() {
- Some(bundle) => bundle,
- None => {
- let render_bundle = self.make_render_bundle(graphics_state);
- self.render_bundle.insert(render_bundle).clone()
- }
- };
-
- painter.add(luminol_egui_wgpu::Callback::new_paint_callback(
- rect,
- Callback(bundle),
- ));
}
+}
- fn make_render_bundle(&self, graphics_state: &GraphicsState) -> Arc {
- let mut render_bundle_encoder = graphics_state
- .render_state
- .device
- .create_render_bundle_encoder(&wgpu::RenderBundleEncoderDescriptor {
- label: Some("luminol map view render bundle encoder"),
- color_formats: &[Some(graphics_state.render_state.target_format)],
- sample_count: 1,
- ..Default::default()
- });
-
+impl crate::Renderable for MapView {
+ fn draw<'rpass>(
+ &'rpass self,
+ graphics_state: &'rpass GraphicsState,
+ render_pass: &mut impl wgpu::util::RenderEncoder<'rpass>,
+ ) {
if self.pano_enabled {
if let Some(panorama) = &self.panorama {
- panorama.draw(graphics_state, &mut render_bundle_encoder);
+ panorama.draw(graphics_state, render_pass);
}
}
- self.tiles.draw(
- graphics_state,
- &self.enabled_layers,
- &mut render_bundle_encoder,
- );
+ self.tiles
+ .draw(graphics_state, &self.enabled_layers, render_pass);
for (_, event) in self.events.iter() {
- event.draw(graphics_state, &mut render_bundle_encoder);
+ event.draw(graphics_state, render_pass);
}
if self.fog_enabled {
if let Some(fog) = &self.fog {
- fog.draw(graphics_state, &mut render_bundle_encoder);
+ fog.draw(graphics_state, render_pass);
}
}
if self.coll_enabled {
- self.collision
- .draw(graphics_state, &mut render_bundle_encoder);
+ self.collision.draw(graphics_state, render_pass);
}
if self.grid_enabled {
// self.grid
// .draw(graphics_state, info, &mut render_bundle_encoder);
}
-
- let bundle = render_bundle_encoder.finish(&wgpu::RenderBundleDescriptor {
- label: Some("luminol map view render bundle"),
- });
- Arc::new(bundle)
}
}
diff --git a/crates/graphics/src/plane.rs b/crates/graphics/src/plane.rs
index b90a638e..52259e46 100644
--- a/crates/graphics/src/plane.rs
+++ b/crates/graphics/src/plane.rs
@@ -62,12 +62,14 @@ impl Plane {
Self { sprite }
}
+}
- pub fn draw<'rpass>(
+impl crate::Renderable for Plane {
+ fn draw<'rpass>(
&'rpass self,
graphics_state: &'rpass GraphicsState,
render_pass: &mut impl wgpu::util::RenderEncoder<'rpass>,
) {
- self.sprite.draw(graphics_state, render_pass);
+ self.sprite.draw(graphics_state, render_pass)
}
}
diff --git a/crates/graphics/src/primitives/sprite/mod.rs b/crates/graphics/src/primitives/sprite/mod.rs
index b7ddb209..96f9cac0 100644
--- a/crates/graphics/src/primitives/sprite/mod.rs
+++ b/crates/graphics/src/primitives/sprite/mod.rs
@@ -77,8 +77,10 @@ impl Sprite {
bytemuck::cast_slice(&vertices),
);
}
+}
- pub fn draw<'rpass>(
+impl crate::Renderable for Sprite {
+ fn draw<'rpass>(
&'rpass self,
graphics_state: &'rpass GraphicsState,
render_pass: &mut impl wgpu::util::RenderEncoder<'rpass>,
diff --git a/crates/graphics/src/renderers.rs b/crates/graphics/src/renderers.rs
new file mode 100644
index 00000000..6f626d26
--- /dev/null
+++ b/crates/graphics/src/renderers.rs
@@ -0,0 +1,173 @@
+// Copyright (C) 2024 Lily Lyons
+//
+// This file is part of Luminol.
+//
+// Luminol is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Luminol is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Luminol. If not, see .
+//
+// Additional permission under GNU GPL version 3 section 7
+//
+// If you modify this Program, or any covered work, by linking or combining
+// it with Steamworks API by Valve Corporation, containing parts covered by
+// terms of the Steamworks API by Valve Corporation, the licensors of this
+// Program grant you additional permission to convey the resulting work.
+
+use std::sync::Arc;
+
+use crate::GraphicsState;
+
+#[derive(Debug)]
+pub struct BundleRenderer {
+ renderable: T,
+ render_bundle: Option>,
+}
+
+impl Clone for BundleRenderer {
+ fn clone(&self) -> Self {
+ Self {
+ renderable: self.renderable.clone(),
+ render_bundle: None,
+ }
+ }
+}
+
+impl BundleRenderer {
+ pub fn new(renderable: T) -> Self {
+ Self {
+ renderable,
+ render_bundle: None,
+ }
+ }
+
+ pub fn paint(
+ &mut self,
+ graphics_state: &GraphicsState,
+ painter: &egui::Painter,
+ rect: egui::Rect,
+ ) {
+ struct Callback(Arc);
+
+ impl luminol_egui_wgpu::CallbackTrait for Callback {
+ fn paint<'a>(
+ &'a self,
+ _: egui::PaintCallbackInfo,
+ render_pass: &mut wgpu::RenderPass<'a>,
+ _: &'a luminol_egui_wgpu::CallbackResources,
+ ) {
+ let bundle = self.0.as_ref();
+ render_pass.execute_bundles(std::iter::once(bundle));
+ }
+ }
+
+ let bundle = self.render_bundle.get_or_insert_with(|| {
+ let mut encoder = graphics_state
+ .render_state
+ .device
+ .create_render_bundle_encoder(&wgpu::RenderBundleEncoderDescriptor {
+ color_formats: &[Some(graphics_state.render_state.target_format)],
+ sample_count: 1,
+ ..Default::default()
+ });
+
+ self.renderable.draw(graphics_state, &mut encoder);
+
+ let bundle = encoder.finish(&Default::default());
+ Arc::new(bundle)
+ });
+
+ painter.add(luminol_egui_wgpu::Callback::new_paint_callback(
+ rect,
+ Callback(bundle.clone()),
+ ));
+ }
+
+ pub fn mark_dirty(&mut self) {
+ self.render_bundle = None
+ }
+}
+
+impl std::ops::Deref for BundleRenderer {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ &self.renderable
+ }
+}
+
+impl std::ops::DerefMut for BundleRenderer {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.renderable
+ }
+}
+
+#[derive(Debug)]
+pub struct ArcRenderer {
+ renderable: Arc,
+}
+
+impl Clone for ArcRenderer {
+ fn clone(&self) -> Self {
+ Self {
+ renderable: self.renderable.clone(),
+ }
+ }
+}
+
+impl ArcRenderer {
+ pub fn new(renderable: T) -> Self {
+ Self {
+ renderable: Arc::new(renderable),
+ }
+ }
+
+ pub fn paint(
+ self,
+ graphics_state: Arc,
+ painter: &egui::Painter,
+ rect: egui::Rect,
+ ) {
+ struct Callback(Arc, Arc);
+
+ impl luminol_egui_wgpu::CallbackTrait for Callback {
+ fn paint<'a>(
+ &'a self,
+ _: egui::PaintCallbackInfo,
+ render_pass: &mut wgpu::RenderPass<'a>,
+ _: &'a luminol_egui_wgpu::CallbackResources,
+ ) {
+ self.0.draw(&self.1, render_pass)
+ }
+ }
+
+ painter.add(luminol_egui_wgpu::Callback::new_paint_callback(
+ rect,
+ Callback(self.renderable.clone(), graphics_state),
+ ));
+ }
+}
+
+impl std::ops::Deref for ArcRenderer {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ &self.renderable
+ }
+}
+
+pub trait Renderable {
+ fn draw<'rpass>(
+ &'rpass self,
+ graphics_state: &'rpass GraphicsState,
+ render_pass: &mut impl wgpu::util::RenderEncoder<'rpass>,
+ );
+}