254 lines
7.5 KiB
Rust
254 lines
7.5 KiB
Rust
//! GPUState routines for drawing items in a systemsim
|
|
|
|
use bytemuck;
|
|
use galactica_system::data::ShipState;
|
|
use galactica_util::to_radians;
|
|
use nalgebra::{Point2, Point3};
|
|
|
|
use crate::{
|
|
globaluniform::ObjectData, vertexbuffer::types::ObjectInstance, GPUState, RenderInput,
|
|
};
|
|
|
|
impl GPUState {
|
|
pub(super) fn phys_push_ship(
|
|
&mut self,
|
|
state: &RenderInput,
|
|
// NE and SW corners of screen
|
|
screen_clip: (Point2<f32>, Point2<f32>),
|
|
) {
|
|
for ship in state.systemsim.iter_ships() {
|
|
// TODO: move collapse sequence here?
|
|
|
|
let ship_pos;
|
|
let ship_ang;
|
|
let ship_cnt;
|
|
match ship.get_data().get_state() {
|
|
ShipState::Dead | ShipState::Landed { .. } => continue,
|
|
|
|
ShipState::Collapsing { .. } | ShipState::Flying { .. } => {
|
|
let r = state.systemsim.get_rigid_body(ship.rigid_body).unwrap();
|
|
let pos = *r.translation();
|
|
ship_pos = Point3::new(pos.x, pos.y, 1.0);
|
|
let ship_rot = r.rotation();
|
|
ship_ang = ship_rot.angle();
|
|
ship_cnt = state.ct.get_ship(ship.get_data().get_content());
|
|
}
|
|
|
|
ShipState::UnLanding { current_z, .. } | ShipState::Landing { current_z, .. } => {
|
|
let r = state.systemsim.get_rigid_body(ship.rigid_body).unwrap();
|
|
let pos = *r.translation();
|
|
ship_pos = Point3::new(pos.x, pos.y, *current_z);
|
|
let ship_rot = r.rotation();
|
|
ship_ang = ship_rot.angle();
|
|
ship_cnt = state.ct.get_ship(ship.get_data().get_content());
|
|
}
|
|
}
|
|
|
|
// Position adjusted for parallax
|
|
// TODO: adjust parallax for zoom?
|
|
// 1.0 is z-coordinate, which is constant for ships
|
|
let pos: Point2<f32> =
|
|
(Point2::new(ship_pos.x, ship_pos.y) - state.camera_pos) / ship_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 = (ship_cnt.size / ship_pos.z) * 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.get_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: ship_pos.z,
|
|
angle: ship_ang,
|
|
size: ship_cnt.size,
|
|
parent: 0,
|
|
is_child: 0,
|
|
_padding: Default::default(),
|
|
}]),
|
|
);
|
|
|
|
// Push this object's instance
|
|
let anim_state = ship.get_anim_state();
|
|
self.state.push_object_buffer(ObjectInstance {
|
|
texture_index: anim_state.texture_index(),
|
|
texture_fade: anim_state.fade,
|
|
object_index: idx as u32,
|
|
});
|
|
|
|
if {
|
|
let is_flying = match ship.get_data().get_state() {
|
|
ShipState::Flying { .. }
|
|
| ShipState::UnLanding { .. }
|
|
| ShipState::Landing { .. } => true,
|
|
_ => false,
|
|
};
|
|
ship.get_controls().thrust && is_flying
|
|
} {
|
|
for (engine_point, anim) in ship.iter_engine_anim() {
|
|
self.state.queue.write_buffer(
|
|
&self.state.global_uniform.object_buffer,
|
|
ObjectData::SIZE * self.state.get_object_counter() as u64,
|
|
bytemuck::cast_slice(&[ObjectData {
|
|
// Note that we adjust the y-coordinate for half-height,
|
|
// not the x-coordinate, even though our ships point east
|
|
// at 0 degrees. This is because this is placed pre-rotation,
|
|
// and the parent rotation adjustment in our object shader
|
|
// automatically accounts for this.
|
|
xpos: engine_point.pos.x,
|
|
ypos: engine_point.pos.y - engine_point.size / 2.0,
|
|
zpos: 1.0,
|
|
// We still need an adjustment here, though,
|
|
// since engine sprites point north (with exhaust towards the south)
|
|
angle: to_radians(90.0),
|
|
size: engine_point.size,
|
|
parent: idx as u32,
|
|
is_child: 1,
|
|
_padding: Default::default(),
|
|
}]),
|
|
);
|
|
|
|
let anim_state = anim.get_texture_idx();
|
|
self.state.push_object_buffer(ObjectInstance {
|
|
texture_index: anim_state.texture_index(),
|
|
texture_fade: anim_state.fade,
|
|
object_index: self.state.get_object_counter() as u32,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(super) fn phys_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 = *r.translation();
|
|
let proj_rot = r.rotation();
|
|
let proj_ang = proj_rot.angle();
|
|
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 projectiles
|
|
let pos = (proj_pos - state.camera_pos) / 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.get_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,
|
|
size: 0f32.max(proj_cnt.size + p.size_rng),
|
|
parent: 0,
|
|
is_child: 0,
|
|
_padding: Default::default(),
|
|
}]),
|
|
);
|
|
|
|
let anim_state = p.get_anim_state();
|
|
self.state.push_object_buffer(ObjectInstance {
|
|
texture_index: anim_state.texture_index(),
|
|
texture_fade: anim_state.fade,
|
|
object_index: idx as u32,
|
|
});
|
|
}
|
|
}
|
|
|
|
pub(super) fn phys_push_system(
|
|
&mut self,
|
|
state: &RenderInput,
|
|
// NE and SW corners of screen
|
|
screen_clip: (Point2<f32>, Point2<f32>),
|
|
) {
|
|
let system = state.ct.get_system(state.current_system);
|
|
|
|
for o in &system.objects {
|
|
// Position adjusted for parallax
|
|
let pos: Point2<f32> = (Point2::new(o.pos.x, o.pos.y) - state.camera_pos) / 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.get_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,
|
|
size: o.size,
|
|
parent: 0,
|
|
is_child: 0,
|
|
_padding: Default::default(),
|
|
}]),
|
|
);
|
|
|
|
let sprite = state.ct.get_sprite(o.sprite);
|
|
let texture_a = sprite.get_section(sprite.default_section).frames[0]; // ANIMATE
|
|
|
|
// Push this object's instance
|
|
self.state.push_object_buffer(ObjectInstance {
|
|
texture_index: [texture_a, texture_a],
|
|
texture_fade: 1.0,
|
|
object_index: idx as u32,
|
|
});
|
|
}
|
|
}
|
|
}
|