269 lines
8.0 KiB
Rust
269 lines
8.0 KiB
Rust
//! GPUState routines for drawing items in a systemsim
|
|
|
|
use bytemuck;
|
|
use cgmath::{EuclideanSpace, InnerSpace, Point2, Vector2};
|
|
use galactica_systemsim::util;
|
|
use galactica_util::constants::OBJECT_SPRITE_INSTANCE_LIMIT;
|
|
|
|
use crate::{
|
|
globaluniform::ObjectData,
|
|
vertexbuffer::{types::ObjectInstance, BufferObject},
|
|
GPUState, RenderInput,
|
|
};
|
|
|
|
impl GPUState {
|
|
pub(super) fn sysim_push_ship(
|
|
&mut self,
|
|
state: &RenderInput,
|
|
// NE and SW corners of screen
|
|
screen_clip: (Point2<f32>, Point2<f32>),
|
|
) {
|
|
for s in state.systemsim.iter_ships() {
|
|
let r = state.systemsim.get_rigid_body(s.rigid_body).unwrap();
|
|
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<f32> = (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
|
|
{
|
|
continue;
|
|
}
|
|
|
|
let idx = self.state.vertex_buffers.object_counter;
|
|
// Write this object's location data
|
|
self.state.queue.write_buffer(
|
|
&self.state.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.state.vertex_buffers.object_counter as u64 > OBJECT_SPRITE_INSTANCE_LIMIT {
|
|
// TODO: no panic, handle this better.
|
|
panic!("Sprite limit exceeded!")
|
|
}
|
|
|
|
// Push this object's instance
|
|
self.state.queue.write_buffer(
|
|
&self.state.vertex_buffers.object.instances,
|
|
ObjectInstance::SIZE * self.state.vertex_buffers.object_counter,
|
|
bytemuck::cast_slice(&[ObjectInstance {
|
|
sprite_index: ship_cnt.sprite.get_index(),
|
|
object_index: idx as u32,
|
|
}]),
|
|
);
|
|
self.state.vertex_buffers.object_counter += 1;
|
|
|
|
// This will be None if this ship is dead.
|
|
// (physics object stays around to complete the death animation)
|
|
// If that is the case, we're done, no flares to draw anyway!
|
|
let ship = match state.data.get_ship(s.data_handle) {
|
|
None => continue,
|
|
Some(s) => s,
|
|
};
|
|
|
|
let flare = ship.get_outfits().get_flare_sprite(state.content);
|
|
if s.get_controls().thrust && flare.is_some() {
|
|
for engine_point in &ship_cnt.engines {
|
|
self.state.queue.write_buffer(
|
|
&self.state.global_uniform.object_buffer,
|
|
ObjectData::SIZE * self.state.vertex_buffers.object_counter as u64,
|
|
bytemuck::cast_slice(&[ObjectData {
|
|
xpos: engine_point.pos.x,
|
|
ypos: engine_point.pos.y - engine_point.size / 2.0,
|
|
zpos: 1.0,
|
|
angle: 0.0,
|
|
size: engine_point.size,
|
|
parent: idx as u32,
|
|
is_child: 1,
|
|
_padding: Default::default(),
|
|
}]),
|
|
);
|
|
|
|
// Enforce buffer limit
|
|
if self.state.vertex_buffers.object_counter as u64
|
|
> OBJECT_SPRITE_INSTANCE_LIMIT
|
|
{
|
|
// TODO: no panic, handle this better.
|
|
panic!("Sprite limit exceeded!")
|
|
}
|
|
|
|
self.state.queue.write_buffer(
|
|
&self.state.vertex_buffers.object.instances,
|
|
ObjectInstance::SIZE * self.state.vertex_buffers.object_counter,
|
|
bytemuck::cast_slice(&[ObjectInstance {
|
|
sprite_index: flare.unwrap().get_index(),
|
|
object_index: self.state.vertex_buffers.object_counter as u32,
|
|
}]),
|
|
);
|
|
self.state.vertex_buffers.object_counter += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(super) fn sysim_push_projectile(
|
|
&mut self,
|
|
state: &RenderInput,
|
|
// NE and SW corners of screen
|
|
screen_clip: (Point2<f32>, Point2<f32>),
|
|
) {
|
|
for p in state.systemsim.iter_projectiles() {
|
|
let r = state.systemsim.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<f32> = (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
|
|
{
|
|
continue;
|
|
}
|
|
|
|
let idx = self.state.vertex_buffers.object_counter;
|
|
// Write this object's location data
|
|
self.state.queue.write_buffer(
|
|
&self.state.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.state.vertex_buffers.object_counter as u64 > OBJECT_SPRITE_INSTANCE_LIMIT {
|
|
// TODO: no panic, handle this better.
|
|
panic!("Sprite limit exceeded!")
|
|
}
|
|
|
|
// Push this object's instance
|
|
self.state.queue.write_buffer(
|
|
&self.state.vertex_buffers.object.instances,
|
|
ObjectInstance::SIZE * self.state.vertex_buffers.object_counter,
|
|
bytemuck::cast_slice(&[ObjectInstance {
|
|
sprite_index: proj_cnt.sprite.get_index(),
|
|
object_index: idx as u32,
|
|
}]),
|
|
);
|
|
self.state.vertex_buffers.object_counter += 1;
|
|
}
|
|
}
|
|
|
|
pub(super) fn sysim_push_system(
|
|
&mut self,
|
|
state: &RenderInput,
|
|
// NE and SW corners of screen
|
|
screen_clip: (Point2<f32>, Point2<f32>),
|
|
) {
|
|
let system = state.content.get_system(state.current_system);
|
|
|
|
for o in &system.objects {
|
|
// Position adjusted for parallax
|
|
let pos: Point2<f32> = (Point2 {
|
|
x: o.pos.x,
|
|
y: o.pos.y,
|
|
} - state.camera_pos.to_vec())
|
|
/ o.pos.z;
|
|
|
|
// 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 = (o.size / o.pos.z) * o.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
|
|
{
|
|
continue;
|
|
}
|
|
|
|
let idx = self.state.vertex_buffers.object_counter;
|
|
// Write this object's location data
|
|
self.state.queue.write_buffer(
|
|
&self.state.global_uniform.object_buffer,
|
|
ObjectData::SIZE * idx as u64,
|
|
bytemuck::cast_slice(&[ObjectData {
|
|
xpos: o.pos.x,
|
|
ypos: o.pos.y,
|
|
zpos: o.pos.z,
|
|
angle: o.angle.0,
|
|
size: o.size,
|
|
parent: 0,
|
|
is_child: 0,
|
|
_padding: Default::default(),
|
|
}]),
|
|
);
|
|
|
|
// Enforce buffer limit
|
|
if self.state.vertex_buffers.object_counter as u64 > OBJECT_SPRITE_INSTANCE_LIMIT {
|
|
// TODO: no panic, handle this better.
|
|
panic!("Sprite limit exceeded!")
|
|
}
|
|
|
|
// Push this object's instance
|
|
self.state.queue.write_buffer(
|
|
&self.state.vertex_buffers.object.instances,
|
|
ObjectInstance::SIZE * self.state.vertex_buffers.object_counter,
|
|
bytemuck::cast_slice(&[ObjectInstance {
|
|
sprite_index: o.sprite.get_index(),
|
|
object_index: idx as u32,
|
|
}]),
|
|
);
|
|
self.state.vertex_buffers.object_counter += 1;
|
|
}
|
|
}
|
|
}
|