Renderer should either be a Trait or something that lets me pass two type or renderers, an EverythingRenderer that is actually used to render anything that is contained in the scene (I'm not getting into the details as that's probably not needed) and a TagRenderer that renders only items that have a certain tag.
I thought that since there's no OOP I might define Renderer as a Trait and have EverythingRenderer and TagRenderer just implement that trait but then the trait has no size so I can't actually store it into that Vec.
Another option could be to pass a generic to Scene along the line of struct Scene<R> where R: Renderer + Sized but since that Scene object it going to contain other stuff with similar needs I might end up having a struct that requires a lot of generics and I'm not sure that's good, especially when I later need to pass Scene to some functions.
I thought about using an Enum since I know in advance the renderers that I'm implementing, but that would cut me off with the chance of adding a new renderer in some user code outside of my library unless there's a way to extend an Enum.
Any hint at what would be the correct idiomatic way to implement this kind of pattern in Rust?
Cheers!
it works but I really do not like this. And I can't use this to implement a default render_end inside the Renderer trait itself because the trait isn't sized and the compiler would keep throwing errors at me.
Is there a reason you're making Scene generic on Renderer and requiring that it be Sized? I'd have thought, based on your previous post, that Scene is not generic and just stores Renderer trait objects (i.e. the Vec<Rc<Renderer>>).
pub trait Renderer {
fn before_render() {
}
fn render_begin <'sb>(renderer: &'sb mut Canvas<Window>, camera: &'sb mut Camera<ViewportAdapter>, spritebatch: &'sb mut SpriteBatch, shader: Shader) {
// Sets the current camera viewport if the camera has one
match camera.get_viewport_adapter() {
&Some(ViewportAdapter) => {
let r = camera.get_viewport_adapter();
let rr = r.unwrap().get_viewport();
let vp = Rect::new(rr.x as i32, rr.y as i32, rr.w as u32, rr.h as u32);
renderer.set_viewport(vp);
},
_ => {}
}
// MonoGame resets the Viewport to the RT size without asking so we have to let the Camera know to update itself
camera.force_matrix_update();
let m = camera.get_transform_matrix();
spritebatch.begin(renderer, SpriteSortMode::SpriteSortModeDeferred, Some(shader), Some(m));
}
fn render_end <'sb>(scene: &Scene, renderer: &'sb mut Canvas<Window>, spritebatch: &'sb mut SpriteBatch);
fn after_render() {
}
}
But then I get the following compiler error:
error[E0038]: the trait `renderer::Renderer` cannot be made into an object
--> src/scene.rs:48:5
|
48 | renderers: Vec<Rc<Renderer>>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `renderer::Renderer` cannot be made into an object
|
= note: method `before_render` has no receiver
= note: method `render_begin` has no receiver
= note: method `render_end` has no receiver
= note: method `after_render` has no receiver