206 lines
5.8 KiB
Rust

//! 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<f32>, Point2<f32>),
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<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
{
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<f32>, Point2<f32>),
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<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
{
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;
}
}