//! GPUState routines for drawing the world use bytemuck; use cgmath::{EuclideanSpace, InnerSpace, Point2, Vector2}; use galactica_world::{ objects::{ProjectileWorldObject, ShipWorldObject}, util, }; use crate::{ globaluniform::ObjectData, vertexbuffer::{types::ObjectInstance, BufferObject}, GPUState, RenderState, }; impl GPUState { pub(super) fn world_push_ship( &mut self, state: &RenderState, // NE and SW corners of screen screen_clip: (Point2, Point2), s: &ShipWorldObject, ) { let r = state.world.get_rigid_body(s.rigid_body).unwrap(); let ship = state.data.get_ship(s.data_handle); let ship_pos = util::rigidbody_position(&r); let ship_rot = util::rigidbody_rotation(r); let ship_ang = -ship_rot.angle(Vector2 { x: 0.0, y: 1.0 }); // TODO: inconsistent angles. Fix! let ship_cnt = state.content.get_ship(s.data_handle.content_handle()); // Position adjusted for parallax // TODO: adjust parallax for zoom? // 1.0 is z-coordinate, which is constant for ships let pos: Point2 = (ship_pos - state.camera_pos.to_vec()) / 1.0; // Game dimensions of this sprite post-scale. // Post-scale width or height, whichever is larger. // This is in game units. // // We take the maximum to account for rotated sprites. let m = (ship_cnt.size / 1.0) * ship_cnt.sprite.aspect.max(1.0); // Don't draw sprites that are off the screen if pos.x < screen_clip.0.x - m || pos.y > screen_clip.0.y + m || pos.x > screen_clip.1.x + m || pos.y < screen_clip.1.y - m { return; } let idx = self.vertex_buffers.object_counter; // Write this object's location data self.queue.write_buffer( &self.global_uniform.object_buffer, ObjectData::SIZE * idx as u64, bytemuck::cast_slice(&[ObjectData { xpos: ship_pos.x, ypos: ship_pos.y, zpos: 1.0, angle: ship_ang.0, size: ship_cnt.size, parent: 0, is_child: 0, _padding: Default::default(), }]), ); // Enforce buffer limit if self.vertex_buffers.object_counter as u64 > galactica_constants::OBJECT_SPRITE_INSTANCE_LIMIT { // TODO: no panic, handle this better. panic!("Sprite limit exceeded!") } // Push this object's instance self.queue.write_buffer( &self.vertex_buffers.object.instances, ObjectInstance::SIZE * self.vertex_buffers.object_counter, bytemuck::cast_slice(&[ObjectInstance { sprite_index: ship_cnt.sprite.get_index(), object_index: idx as u32, }]), ); self.vertex_buffers.object_counter += 1; /* // Draw engine flares if necessary //if s.controls.thrust && !s.ship.is_dead() { if s.controls.thrust { for f in s.ship.outfits.iter_enginepoints() { let flare = match s.ship.outfits.get_flare_sprite() { None => continue, Some(s) => s, }; self.queue.write_buffer( &self.global_uniform.object_buffer, ObjectData::SIZE * self.vertex_buffers.object_counter as u64, bytemuck::cast_slice(&[ObjectData { xpos: f.pos.x, ypos: f.pos.y - f.size / 2.0, zpos: 1.0, angle: 0.0, size: f.size, parent: idx as u32, is_child: 1, _padding: Default::default(), }]), ); // Enforce buffer limit if self.vertex_buffers.object_counter as u64 > galactica_constants::OBJECT_SPRITE_INSTANCE_LIMIT { // TODO: no panic, handle this better. panic!("Sprite limit exceeded!") } self.queue.write_buffer( &self.vertex_buffers.object.instances, ObjectInstance::SIZE * self.vertex_buffers.object_counter, bytemuck::cast_slice(&[ObjectInstance { sprite_index: flare.get_index(), object_index: self.vertex_buffers.object_counter as u32, }]), ); self.vertex_buffers.object_counter += 1; } } */ } pub(super) fn world_push_projectile( &mut self, state: &RenderState, // NE and SW corners of screen screen_clip: (Point2, Point2), p: &ProjectileWorldObject, ) { let r = state.world.get_rigid_body(p.rigid_body).unwrap(); let proj_pos = util::rigidbody_position(&r); let proj_rot = util::rigidbody_rotation(r); let proj_ang = -proj_rot.angle(Vector2 { x: 1.0, y: 0.0 }); let proj_cnt = &p.content; // TODO: don't clone this? // Position adjusted for parallax // TODO: adjust parallax for zoom? // 1.0 is z-coordinate, which is constant for ships let pos: Point2 = (proj_pos - state.camera_pos.to_vec()) / 1.0; // Game dimensions of this sprite post-scale. // Post-scale width or height, whichever is larger. // This is in game units. // // We take the maximum to account for rotated sprites. let m = (proj_cnt.size / 1.0) * proj_cnt.sprite.aspect.max(1.0); // Don't draw sprites that are off the screen if pos.x < screen_clip.0.x - m || pos.y > screen_clip.0.y + m || pos.x > screen_clip.1.x + m || pos.y < screen_clip.1.y - m { return; } let idx = self.vertex_buffers.object_counter; // Write this object's location data self.queue.write_buffer( &self.global_uniform.object_buffer, ObjectData::SIZE * idx as u64, bytemuck::cast_slice(&[ObjectData { xpos: proj_pos.x, ypos: proj_pos.y, zpos: 1.0, angle: proj_ang.0, size: 0f32.max(proj_cnt.size + p.size_rng), parent: 0, is_child: 0, _padding: Default::default(), }]), ); // Enforce buffer limit if self.vertex_buffers.object_counter as u64 > galactica_constants::OBJECT_SPRITE_INSTANCE_LIMIT { // TODO: no panic, handle this better. panic!("Sprite limit exceeded!") } // Push this object's instance self.queue.write_buffer( &self.vertex_buffers.object.instances, ObjectInstance::SIZE * self.vertex_buffers.object_counter, bytemuck::cast_slice(&[ObjectInstance { sprite_index: proj_cnt.sprite.get_index(), object_index: idx as u32, }]), ); self.vertex_buffers.object_counter += 1; } }