[oden] Some perhaps unadvised factoring

Traits for fun and profit. I was nervous about the amount of magic
"you have to get this right" coupling between runtime structures (the
draw mode) and types (the various instance types) and I didn't want to
get them wrong. So now some things are more generic than they were
before, and maybe that's good? Who can say in the end.
This commit is contained in:
John Doty 2023-08-27 09:28:14 -07:00
parent 40992f840f
commit df49143885

View file

@ -692,6 +692,34 @@ enum DrawMode {
Circles,
}
trait DrawModeInstance: Sized {
const MODE: DrawMode;
fn get_vertex_buffer<'a>(
state: &'a mut State,
vb: &VertexBufferHandle,
) -> &'a mut VertexBuffer<Self>;
}
impl DrawModeInstance for SpriteInstance {
const MODE: DrawMode = DrawMode::Sprites;
fn get_vertex_buffer<'a>(
state: &'a mut State,
vb: &VertexBufferHandle,
) -> &'a mut VertexBuffer<Self> {
state.sprite_instance_buffers.get_mut(&vb)
}
}
impl DrawModeInstance for CircleInstance {
const MODE: DrawMode = DrawMode::Circles;
fn get_vertex_buffer<'a>(
state: &'a mut State,
vb: &VertexBufferHandle,
) -> &'a mut VertexBuffer<Self> {
state.circle_instance_buffers.get_mut(&vb)
}
}
#[derive(Debug)]
struct DrawCall {
mode: DrawMode,
@ -891,7 +919,16 @@ impl<'a> FrameBuilder<'a> {
}
fn start_pass(&mut self, color: Option<[f64; 4]>, target: Rc<wgpu::TextureView>) {
// NOTE: We're not changing drawing modes here which means we can preserve the
// buffer tail if we want to.
let first_call = match self.draw_calls.last() {
Some(call) => call.new_at_buffer_tail(),
None => DrawCall::new(self.mode, self.new_instance_buffer(), 0),
};
self.flush();
self.draw_calls.push(first_call);
self.color = color;
self.target = target;
}
@ -935,19 +972,15 @@ impl<'a> FrameBuilder<'a> {
}
}
fn switch_mode(&mut self, mode: DrawMode) {
if self.mode != mode {
fn get_instance_buffer<T: DrawModeInstance>(&mut self) -> &mut VertexBuffer<T> {
if self.mode != T::MODE {
self.flush();
self.draw_calls.clear();
self.mode = mode;
self.mode = T::MODE;
}
}
fn get_sprite_instance_buffer(&mut self) -> &mut VertexBuffer<SpriteInstance> {
self.switch_mode(DrawMode::Sprites);
match self.draw_calls.last_mut() {
Some(call) => match call.allocate_capacity(1) {
Some(vb) => return self.state.sprite_instance_buffers.get_mut(&vb),
Some(vb) => return T::get_vertex_buffer(self.state, &vb),
None => {}
},
None => {}
@ -956,34 +989,19 @@ impl<'a> FrameBuilder<'a> {
let mut call = DrawCall::new(self.mode, self.new_instance_buffer(), 0);
let vb = call.allocate_capacity(1).unwrap();
self.draw_calls.push(call);
self.state.sprite_instance_buffers.get_mut(&vb)
T::get_vertex_buffer(self.state, &vb)
}
fn push_sprite(&mut self, si: SpriteInstance) {
let vertex_buffer = self.get_sprite_instance_buffer();
let vertex_buffer = self.get_instance_buffer();
vertex_buffer.vec.push(si);
}
fn get_circle_instance_buffer(&mut self) -> &mut VertexBuffer<CircleInstance> {
self.switch_mode(DrawMode::Circles);
match self.draw_calls.last_mut() {
Some(call) => match call.allocate_capacity(1) {
Some(vb) => return self.state.circle_instance_buffers.get_mut(&vb),
None => {}
},
None => {}
};
let mut call = DrawCall::new(self.mode, self.new_instance_buffer(), 0);
let vb = call.allocate_capacity(1).unwrap();
self.draw_calls.push(call);
self.state.circle_instance_buffers.get_mut(&vb)
}
fn push_circle(&mut self, cc: script::graphics::CircleCommand) {
let stroke_color = self.stroke_color.clone();
let fill_color = self.fill_color.clone();
let vertex_buffer = self.get_circle_instance_buffer();
let vertex_buffer = self.get_instance_buffer();
vertex_buffer.vec.push(CircleInstance {
center: cc.center,
radius: cc.radius,
@ -994,11 +1012,6 @@ impl<'a> FrameBuilder<'a> {
}
fn flush(&mut self) {
let first_call = match self.draw_calls.last() {
Some(call) => call.new_at_buffer_tail(),
None => DrawCall::new(self.mode, self.new_instance_buffer(), 0),
};
if self.draw_calls.len() > 0 {
let mut pass = self.encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Render Pass"),
@ -1034,7 +1047,6 @@ impl<'a> FrameBuilder<'a> {
self.color = None;
self.draw_calls.clear();
self.draw_calls.push(first_call);
}
}