use cgmath::{Deg, Matrix4, One, Quaternion, Rad, Rotation, Rotation3, Vector3, vec3, Vector4}; use winit::event::Event; use crate::config::LogConfig; use crate::input::InputState; use crate::vulkan::{Game, LinePoint, MeshHandle, VulkanRenderer}; use crate::vulkan::vs::ty::ObjectUniformData; use crate::gameobject::{GameObject, GameObjectHandle, Component, TestComponent}; mod vulkan; mod input; mod config; mod mesh; mod gameobject; struct TestGame { input: InputState, cam_position: Vector3, cam_rotation: Quaternion, meshes: Vec<(MeshHandle, usize)>, game_objects: Vec, log_config: LogConfig, texture_index_counter: usize, last_time: f32, components: Vec>, } impl Game for TestGame { fn on_window_event(self: &mut Self, event: &Event<()>) { self.input.on_window_event(event); } fn update(self: &mut Self, renderer: &mut VulkanRenderer) -> ObjectUniformData { self.input.frame_start(); let time = (renderer.game_data.start_time.elapsed().unwrap().as_micros() as f64 / 1000000.0) as f32; let frame_time = time - self.last_time; let input = &self.input; let components = &mut self.components; components.iter_mut().for_each(|component| { component.update(frame_time, &input, renderer); }); // User interaction if self.input.button_just_released("quit") { renderer.game_data.shutdown = true; } if self.input.button_just_released("test") { println!("{:?}", self.game_objects[0].get_game_object(renderer).unwrap().position); } if self.input.button_just_pressed("reload_shaders") { renderer.game_data.recreate_pipeline = true; } if self.input.button_down("print_framerate") { println!("{:.0} ms / {:.0} FPS", frame_time * 1000.0, 1.0 / frame_time); } let light_pos = vec3(f32::sin(time) * 2.0 + 2.0, f32::cos(time) * 2.0 + 2.0, 2.0); self.game_objects[2].get_game_object(renderer).unwrap().position = light_pos; self.cam_rotation = self.cam_rotation * Quaternion::from_angle_y(Deg(self.input.get_axis("look_horizontal") * 0.05)); self.cam_rotation = Quaternion::from_angle_x(Deg(self.input.get_axis("look_vertical") * 0.05)) * self.cam_rotation; self.cam_position += self.cam_rotation.invert().rotate_vector(Vector3::new( self.input.get_axis("move_sideways") * -0.05, 0.0, self.input.get_axis("move_forward") * 0.05)); let view = Matrix4::from(self.cam_rotation) * Matrix4::from_translation(self.cam_position); let mut proj = cgmath::perspective( Rad::from(Deg(45.0)), renderer.game_data.dimensions[0] as f32 / renderer.game_data.dimensions[1] as f32, 0.1, 100.0 ); proj.y.y *= -1.0; renderer.game_data.line_push_constants.view = view.into(); renderer.game_data.line_push_constants.projection = proj.into(); self.last_time = time; self.input.frame_end(); ObjectUniformData { view: view.into(), projection: proj.into(), time, light_position: light_pos.into(), camera_position: self.cam_position.into(), _dummy0: [0; 12], _dummy1: [0; 4], } } } fn _matrix_vector_mul(matrix: &Matrix4, vector: &Vector3) -> Vector3 { let v4 = Vector4::new(vector.x, vector.y, vector.z, 1.0); let out = matrix * v4; Vector3::new(out.x, out.y, out.z) } impl TestGame { fn game_start(self: &mut Self, renderer: &mut VulkanRenderer) { let mut test_comp = TestComponent { game_objects: vec![] }; let cube_meshes = self.load_gltf(renderer, "models/box.glb"); let sphere_meshes = self.load_gltf(renderer, "models/sphere.glb"); let plane_meshes = self.load_gltf(renderer, "models/plane.glb"); let cube = self.add_game_object(renderer, *cube_meshes.first().unwrap(), 0); cube.get_game_object(renderer).unwrap().position = vec3(3.0, 4.0, 5.0); test_comp.game_objects.push(cube.clone()); let sphere = self.add_game_object(renderer, *sphere_meshes.first().unwrap(), 0); sphere.get_game_object(renderer).unwrap().position = vec3(0.0, 0.0, 0.0); let light_sphere = self.add_game_object(renderer, *sphere_meshes.first().unwrap(), 0); light_sphere.get_game_object(renderer).unwrap().scale = vec3(0.1, 0.1, 0.1); let plane = self.add_game_object(renderer, *plane_meshes.first().unwrap(), 0); plane.get_game_object(renderer).unwrap().position = vec3(0.0, -1.0, 0.0); self.components.push(Box::new(test_comp)); println!("Game loaded!"); } fn load_gltf(&mut self, renderer: &mut VulkanRenderer, gltf_path: &str) -> Vec { let mut mesh_handles = Vec::new(); let (meshes, textures) = mesh::load_mesh(gltf_path, self.log_config.mesh_load_info).unwrap(); for cpu_mesh in meshes.into_iter() { let id = match cpu_mesh.texture_index { Some(tex_id) => tex_id + self.texture_index_counter, None => 0, }; self.texture_index_counter += 1; let mesh_handle = renderer.upload_mesh(cpu_mesh); self.meshes.push((mesh_handle, id)); mesh_handles.push(mesh_handle); } textures.iter().for_each(|tex| renderer.upload_texture(tex)); mesh_handles } fn add_game_object(&mut self, renderer: &mut VulkanRenderer, mesh: MeshHandle, texture_index: usize) -> &mut GameObjectHandle { let obj = GameObject::new(mesh, texture_index); let obj_handle = renderer.add_game_object(obj); self.game_objects.push(obj_handle); self.game_objects.last_mut().unwrap() } } fn main() { let log_config = LogConfig::from_file("config/log.toml"); let mut game = TestGame { input: InputState::new("config/input.toml", log_config), cam_rotation: Quaternion::one(), cam_position: Vector3::new(0.0, 3.0, -10.0), meshes: vec![], game_objects: vec![], log_config, texture_index_counter: 1, last_time: 0.0, components: vec![], }; let line_count = 30; let (mut renderer, event_loop) = VulkanRenderer::init( (-line_count..=line_count) .flat_map(|it| vec![ LinePoint { position: [it as f32, 0., -line_count as f32] }, LinePoint { position: [it as f32, 0., line_count as f32] }, LinePoint { position: [-line_count as f32, 0., it as f32] }, LinePoint { position: [line_count as f32, 0., it as f32] }, ]).collect(), log_config.vulkan_validation_layers, ); game.game_start(&mut renderer); vulkan::start_event_loop(renderer, Box::new(game), event_loop); }