use std::path::Path;
use glam::{UVec2, Vec2};
use winit::{event::MouseButton, keyboard::KeyCode, window::Window};
use crate::{
input::InputState,
render::{
render2d::{Instance2d, IntoRawInstance, MESH_CIRCLE, MESH_RECT},
BufferItem, Camera, Color, Line2d, Mesh, View, PIPELINE_FILL, TEXTURE_EMPTY,
},
Handle, RenderCommand, RenderState, ViewportState,
};
pub struct Context<'a> {
pub render_commands: &'a mut Vec<RenderCommand>,
pub render_state: &'a mut RenderState,
pub input_state: &'a InputState,
}
impl Context<'_> {
pub fn set_camera(&mut self, camera: Camera) {
let resolution = self.render_state.resolution();
self.render_state
.buffers
.get_mut::<View>()
.unwrap()
.append_temporary(vec![camera.view(resolution)]);
self.render_commands.push(RenderCommand::SetCamera);
}
pub fn draw<I: BufferItem>(
&mut self,
_pipeline_id: u32,
mesh_id: impl Into<Handle>,
material_id: u32,
instances: Vec<I>,
) {
let instance_range = self
.render_state
.buffers
.get_mut::<I>()
.unwrap()
.append_temporary(instances);
let instance_range = instance_range.start..instance_range.end;
self.render_commands.push(RenderCommand::Draw {
mesh_handle: mesh_id.into(),
material_handle: Handle::Persistent(material_id),
instance_range,
});
}
#[inline]
pub fn draw_fill<T: IntoRawInstance>(
&mut self,
mesh_id: impl Into<Handle>,
texture_id: u32,
instances: impl IntoIterator<Item = T>,
) {
let texture_size = match self.render_state.textures.get(texture_id) {
Some(texture) => texture.size(),
None => return,
};
let instances = instances
.into_iter()
.map(|obj| obj.into_raw(texture_size))
.collect();
self.draw(PIPELINE_FILL, mesh_id, texture_id, instances);
}
pub fn draw_lines(&mut self, lines: impl IntoIterator<Item = Line2d>) {
self.draw_fill(MESH_RECT, TEXTURE_EMPTY, lines);
}
pub fn draw_rects(&mut self, instances: impl IntoIterator<Item = Instance2d>) {
self.draw_fill(MESH_RECT, TEXTURE_EMPTY, instances);
}
pub fn draw_circles(&mut self, instances: impl IntoIterator<Item = Instance2d>) {
self.draw_fill(MESH_CIRCLE, TEXTURE_EMPTY, instances);
}
pub fn draw_sprites(
&mut self,
texture_id: u32,
instances: impl IntoIterator<Item = Instance2d>,
) {
self.draw_fill(MESH_RECT, texture_id, instances);
}
pub fn register_mesh<V: BufferItem>(&mut self, mesh_id: u32, mesh: Mesh<V>) {
self.render_state.register_mesh(mesh_id, mesh);
}
pub fn register_mesh_temporary<V: BufferItem>(&mut self, mesh: Mesh<V>) -> Handle {
self.render_state.register_mesh_temporary(mesh)
}
pub fn register_texture(&mut self, texture_id: u32, image: image::DynamicImage) {
self.render_state.register_texture(texture_id, image);
}
pub fn key_pressed(&self, keycode: KeyCode) -> bool {
self.input_state.pressed_keys.contains(&keycode)
}
pub fn key_just_pressed(&self, keycode: KeyCode) -> bool {
self.input_state.just_pressed_keys.contains(&keycode)
}
pub fn key_just_released(&self, keycode: KeyCode) -> bool {
self.input_state.just_released_keys.contains(&keycode)
}
pub fn clicked(&self) -> bool {
self.input_state
.clicked_mouse_buttons
.contains(&MouseButton::Left)
}
pub fn mouse_button_pressed(&self, button: MouseButton) -> bool {
self.input_state.pressed_mouse_buttons.contains(&button)
}
pub fn mouse_button_clicked(&self, button: MouseButton) -> bool {
self.input_state.clicked_mouse_buttons.contains(&button)
}
pub fn cursor_position(&self) -> Option<Vec2> {
self.input_state.cursor_position
}
pub fn mouse_wheel_delta(&self) -> Option<Vec2> {
self.input_state.mouse_wheel_delta
}
pub fn mouse_drage_delta(&self) -> Option<Vec2> {
self.input_state.mouse_drag_delta
}
pub fn window(&self) -> &Window {
&self.render_state.window
}
pub fn set_background_color(&mut self, color: Color) {
self.render_state.background_color = color.into();
}
pub fn set_resolution(&mut self, resolution: Option<UVec2>) {
let render_state = &mut self.render_state;
let fixed_viewport_size = resolution.map(|v| wgpu::Extent3d {
width: v.x,
height: v.y,
depth_or_array_layers: 1,
});
render_state.viewport = ViewportState::new(
&render_state.device,
&render_state.surface_config,
fixed_viewport_size,
);
}
pub fn save_screen_shot(&mut self, path: impl AsRef<Path>) {
self.render_state.capture_target = Some(path.as_ref().to_path_buf());
}
}