|
|
@@ -1,15 +1,18 @@ |
|
|
|
use std::mem::size_of; |
|
|
|
|
|
|
|
use glc::{ |
|
|
|
matrix::Matrix4f, |
|
|
|
buffer::{Buffer, Usage}, |
|
|
|
misc::{BindGuard, Bindable}, |
|
|
|
shader::{Program, Type, Uniform}, |
|
|
|
texture::Texture, |
|
|
|
vector::Vector4f, |
|
|
|
vector::{Vector2f, Vector4f}, |
|
|
|
vertex_array::{DataType, VertexArray}, |
|
|
|
}; |
|
|
|
use space_crush_common::{ |
|
|
|
components::{Planet, Player, PlayerOwned, Position}, |
|
|
|
misc::LogResult, |
|
|
|
misc::{ComponentEvent, LogResult, StorageHelper, StorageHelperMut}, |
|
|
|
}; |
|
|
|
use specs::{prelude::*, ReadExpect, ReadStorage, System, World}; |
|
|
|
use specs::{prelude::*, ReadStorage, System, World}; |
|
|
|
|
|
|
|
use crate::{ |
|
|
|
constants::{ |
|
|
@@ -17,52 +20,77 @@ use crate::{ |
|
|
|
UNIFORM_BUFFER_INDEX_UNIFORM, |
|
|
|
}, |
|
|
|
misc::WorldHelper, |
|
|
|
resources::Geometry, |
|
|
|
Error, |
|
|
|
}; |
|
|
|
|
|
|
|
pub struct Planets { |
|
|
|
program: Program, |
|
|
|
texture: Texture, |
|
|
|
location_model: gl::GLint, |
|
|
|
location_glow_color: gl::GLint, |
|
|
|
vertex_array: VertexArray, |
|
|
|
reader_id: ReaderId<ComponentEvent<Planet>>, |
|
|
|
planet_count: usize, |
|
|
|
} |
|
|
|
|
|
|
|
#[repr(C, packed)] |
|
|
|
struct VertexData { |
|
|
|
pos: Vector2f, |
|
|
|
size: gl::GLfloat, |
|
|
|
color: Vector4f, |
|
|
|
} |
|
|
|
|
|
|
|
impl Planets { |
|
|
|
pub fn new(world: &World) -> Result<Self, Error> { |
|
|
|
pub fn new(world: &mut World) -> Result<Self, Error> { |
|
|
|
WriteStorage::<Planet>::setup(world); |
|
|
|
|
|
|
|
let program = world.load_program(vec![ |
|
|
|
(Type::Vertex, "resources/shader/planet/vert.glsl"), |
|
|
|
(Type::Geometry, "resources/shader/planet/geom.glsl"), |
|
|
|
(Type::Fragment, "resources/shader/planet/frag.glsl"), |
|
|
|
])?; |
|
|
|
|
|
|
|
program.uniform_block_binding("Camera", UNIFORM_BUFFER_INDEX_CAMERA)?; |
|
|
|
program.uniform_block_binding("Global", UNIFORM_BUFFER_INDEX_UNIFORM)?; |
|
|
|
|
|
|
|
let location_model = program.uniform_location("uModel")?; |
|
|
|
let location_glow_color = program.uniform_location("uGlowColor")?; |
|
|
|
|
|
|
|
program.bind(); |
|
|
|
program.uniform("uTexture", Uniform::Texture(0))?; |
|
|
|
program.unbind(); |
|
|
|
|
|
|
|
let texture = world.load_texture("resources/textures/planet01.png")?; |
|
|
|
|
|
|
|
const STRIDE: gl::GLsizei = size_of::<VertexData>() as gl::GLsizei; |
|
|
|
|
|
|
|
const OFFSET_POS: gl::GLsizei = 0; |
|
|
|
const OFFSET_SIZ: gl::GLsizei = OFFSET_POS + size_of::<Vector2f>() as gl::GLsizei; |
|
|
|
const OFFSET_CLR: gl::GLsizei = OFFSET_SIZ + size_of::<gl::GLfloat>() as gl::GLsizei; |
|
|
|
|
|
|
|
let vertex_array = VertexArray::builder() |
|
|
|
.bind_buffer(Buffer::new()?) |
|
|
|
.vertex_attrib_pointer(0, 2, DataType::Float, false, STRIDE, OFFSET_POS)? |
|
|
|
.vertex_attrib_pointer(1, 1, DataType::Float, false, STRIDE, OFFSET_SIZ)? |
|
|
|
.vertex_attrib_pointer(2, 4, DataType::Float, false, STRIDE, OFFSET_CLR)? |
|
|
|
.build()?; |
|
|
|
|
|
|
|
let reader_id = world |
|
|
|
.system_data::<WriteStorage<Planet>>() |
|
|
|
.register_event_reader(); |
|
|
|
let planet_count = 0; |
|
|
|
|
|
|
|
Ok(Self { |
|
|
|
program, |
|
|
|
texture, |
|
|
|
location_model, |
|
|
|
location_glow_color, |
|
|
|
vertex_array, |
|
|
|
reader_id, |
|
|
|
planet_count, |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#[derive(SystemData)] |
|
|
|
pub struct PlanetsData<'a> { |
|
|
|
geometry: ReadExpect<'a, Geometry>, |
|
|
|
position: ReadStorage<'a, Position>, |
|
|
|
planet: ReadStorage<'a, Planet>, |
|
|
|
positions: ReadStorage<'a, Position>, |
|
|
|
planets: ReadStorage<'a, Planet>, |
|
|
|
players: ReadStorage<'a, Player>, |
|
|
|
owned: ReadStorage<'a, PlayerOwned>, |
|
|
|
player: ReadStorage<'a, Player>, |
|
|
|
} |
|
|
|
|
|
|
|
impl<'a> System<'a> for Planets { |
|
|
@@ -70,46 +98,68 @@ impl<'a> System<'a> for Planets { |
|
|
|
|
|
|
|
fn run(&mut self, data: Self::SystemData) { |
|
|
|
let PlanetsData { |
|
|
|
geometry, |
|
|
|
position, |
|
|
|
planet, |
|
|
|
positions, |
|
|
|
planets, |
|
|
|
players, |
|
|
|
owned, |
|
|
|
player, |
|
|
|
} = data; |
|
|
|
|
|
|
|
gl::enable(gl::BLEND); |
|
|
|
gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); |
|
|
|
/* handle events */ |
|
|
|
let mut need_update = false; |
|
|
|
let events = planets.channel().read(&mut self.reader_id); |
|
|
|
for event in events { |
|
|
|
match event { |
|
|
|
ComponentEvent::Inserted(_, _) => { |
|
|
|
need_update = true; |
|
|
|
|
|
|
|
self.planet_count += 1; |
|
|
|
} |
|
|
|
ComponentEvent::Removed(_, _) => { |
|
|
|
need_update = true; |
|
|
|
|
|
|
|
self.planet_count -= 1; |
|
|
|
} |
|
|
|
ComponentEvent::Modified(_, _) => { |
|
|
|
unreachable!("Updates of the planet component should not be tracked!") |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* update vertex array */ |
|
|
|
let buffer = &mut self.vertex_array.buffers_mut()[0]; |
|
|
|
if need_update { |
|
|
|
buffer |
|
|
|
.buffer_size( |
|
|
|
Usage::StaticDraw, |
|
|
|
self.planet_count * size_of::<VertexData>(), |
|
|
|
) |
|
|
|
.panic("Unable to change buffer size for planet data"); |
|
|
|
|
|
|
|
let data = (&positions, &planets, owned.maybe()); |
|
|
|
let mut buffer = buffer |
|
|
|
.map_mut::<VertexData>(true) |
|
|
|
.panic("Unable to map buffer for planet data"); |
|
|
|
|
|
|
|
for (i, (position, _, owned)) in data.join().enumerate() { |
|
|
|
let mut d = &mut buffer[i]; |
|
|
|
|
|
|
|
d.pos = *position.pos(); |
|
|
|
d.size = position.shape().circle().unwrap_or(PLANET_SIZE); |
|
|
|
d.color = match owned.and_then(|owned| players.get(owned.owner())) { |
|
|
|
Some(pv) => *pv.color(), |
|
|
|
None => PLAYER_COLOR_DEFAULT, |
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* render planets */ |
|
|
|
let _guard = BindGuard::new(&self.program); |
|
|
|
let _guard = BindGuard::new(&self.vertex_array); |
|
|
|
let _guard = BindGuard::new(&self.texture); |
|
|
|
|
|
|
|
for (p, _, owned) in (&position, &planet, owned.maybe()).join() { |
|
|
|
let p_x = p.pos().x; |
|
|
|
let p_y = p.pos().y; |
|
|
|
let s = p.shape().circle().unwrap_or(PLANET_SIZE); |
|
|
|
|
|
|
|
let c = match owned.and_then(|owned| player.get(owned.owner())) { |
|
|
|
Some(pv) => &pv.color(), |
|
|
|
None => &PLAYER_COLOR_DEFAULT, |
|
|
|
}; |
|
|
|
|
|
|
|
let m = Matrix4f::new( |
|
|
|
Vector4f::new(s, 0.0, 0.0, 0.0), |
|
|
|
Vector4f::new(0.0, s, 0.0, 0.0), |
|
|
|
Vector4f::new(0.0, 0.0, s, 0.0), |
|
|
|
Vector4f::new(p_x, p_y, 0.0, 1.0), |
|
|
|
); |
|
|
|
|
|
|
|
self.program |
|
|
|
.uniform(self.location_glow_color, Uniform::Vector4f(&c)) |
|
|
|
.error("Error while updating glow color"); |
|
|
|
self.program |
|
|
|
.uniform(self.location_model, Uniform::Matrix4f(&m)) |
|
|
|
.error("Error while updating model matrix"); |
|
|
|
|
|
|
|
geometry.render_quad(); |
|
|
|
} |
|
|
|
|
|
|
|
gl::enable(gl::BLEND); |
|
|
|
gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); |
|
|
|
gl::draw_arrays(gl::POINTS, 0, self.planet_count as _); |
|
|
|
gl::disable(gl::BLEND); |
|
|
|
} |
|
|
|
} |