diff --git a/space-crush-app/resources/shader/planet/frag.glsl b/space-crush-app/resources/shader/planet/frag.glsl index 1cfa7c0..bfb8f6b 100644 --- a/space-crush-app/resources/shader/planet/frag.glsl +++ b/space-crush-app/resources/shader/planet/frag.glsl @@ -14,15 +14,14 @@ const GlowArgs GLOW_ARGS = { in FragmentData fragmentData; -uniform vec4 uGlowColor; uniform sampler2D uTexture; out vec4 outColor; void main() { - float alpha = glow(GLOW_ARGS, fragmentData.texCoords - vec2(0.5), uGlobal.time); - vec4 glow = vec4(uGlowColor.rgb, uGlowColor.a * alpha); - vec4 tex = texture(uTexture, fragmentData.texCoords); + float alpha = glow(GLOW_ARGS, fragmentData.texCoords, uGlobal.time); + vec4 glow = vec4(fragmentData.color.rgb, fragmentData.color.a * alpha); + vec4 tex = texture(uTexture, 0.5 * GLOW_SIZE * fragmentData.texCoords + vec2(0.5)); outColor = tex * tex.a + glow * (1.0 - tex.a); } diff --git a/space-crush-app/resources/shader/planet/geom.glsl b/space-crush-app/resources/shader/planet/geom.glsl new file mode 100644 index 0000000..7c5a087 --- /dev/null +++ b/space-crush-app/resources/shader/planet/geom.glsl @@ -0,0 +1,44 @@ +#version 450 core + +#pragma include ./shared.glsl +#pragma include ../misc/camera.glsl + +in VertexData vertexData[]; + +layout (points) in; +layout (triangle_strip, max_vertices = 4) out; + +out FragmentData fragmentData; + +void main() { + VertexData d = vertexData[0]; + + vec2 pos = d.pos; + float size = d.size * GLOW_SIZE; + + mat4 m = uCamera.projection * uCamera.view * mat4( + vec4( size, 0.0, 0.0, 0.0), + vec4( 0.0, size, 0.0, 0.0), + vec4( 0.0, 0.0, 0.0, 0.0), + vec4(pos.x, pos.y, 0.0, 1.0)); + + fragmentData.color = d.color; + + gl_Position = m * vec4(-1.0, -1.0, 0.0, 1.0); + fragmentData.texCoords = vec2(-1.0, 1.0); + EmitVertex(); + + gl_Position = m * vec4(-1.0, 1.0, 0.0, 1.0); + fragmentData.texCoords = vec2(-1.0, -1.0); + EmitVertex(); + + gl_Position = m * vec4( 1.0, -1.0, 0.0, 1.0); + fragmentData.texCoords = vec2( 1.0, 1.0); + EmitVertex(); + + gl_Position = m * vec4( 1.0, 1.0, 0.0, 1.0); + fragmentData.texCoords = vec2( 1.0, -1.0); + EmitVertex(); + + EndPrimitive(); +} diff --git a/space-crush-app/resources/shader/planet/shared.glsl b/space-crush-app/resources/shader/planet/shared.glsl index e72b165..8269fe3 100644 --- a/space-crush-app/resources/shader/planet/shared.glsl +++ b/space-crush-app/resources/shader/planet/shared.glsl @@ -1,3 +1,12 @@ struct FragmentData { vec2 texCoords; + vec4 color; }; + +struct VertexData { + vec2 pos; + float size; + vec4 color; +}; + +const float GLOW_SIZE = 2.0; // relative to planet size diff --git a/space-crush-app/resources/shader/planet/vert.glsl b/space-crush-app/resources/shader/planet/vert.glsl index d629730..692841e 100644 --- a/space-crush-app/resources/shader/planet/vert.glsl +++ b/space-crush-app/resources/shader/planet/vert.glsl @@ -3,15 +3,14 @@ #pragma include ./shared.glsl #pragma include ../misc/camera.glsl -const float GLOW_SIZE_FACTOR = 2.00; +layout (location = 0) in vec2 inPosition; +layout (location = 1) in float inSize; +layout (location = 2) in vec4 inColor; -in vec3 inPosition; - -uniform mat4 uModel; - -out FragmentData fragmentData; +out VertexData vertexData; void main() { - fragmentData.texCoords = inPosition.xy * GLOW_SIZE_FACTOR + vec2(0.5); - gl_Position = uCamera.projection * uCamera.view * uModel * vec4(2.0 * inPosition * GLOW_SIZE_FACTOR, 1.0); + vertexData.pos = inPosition; + vertexData.size = inSize; + vertexData.color = inColor; } diff --git a/space-crush-app/resources/shader/ship/frag.glsl b/space-crush-app/resources/shader/ship/frag.glsl index cf6471d..43d99b8 100644 --- a/space-crush-app/resources/shader/ship/frag.glsl +++ b/space-crush-app/resources/shader/ship/frag.glsl @@ -4,7 +4,6 @@ #pragma include ../misc/glow.glsl #pragma include ../misc/global.glsl -const float GLOW_ALPHA = 0.20; const GlowArgs GLOW_ARGS = { /* step0 */ 0.100, /* step1 */ 0.900, @@ -23,7 +22,7 @@ out vec4 outColor; void main() { float alpha = glow(GLOW_ARGS, fragmentData.texCoords, uGlobal.time); vec4 glow = vec4(fragmentData.color.rgb, fragmentData.color.a * alpha * GLOW_ALPHA); - vec4 tex = texture(uTexture[textureId], fragmentData.texCoords / SHIP_SIZE + vec2(0.5)); + vec4 tex = texture(uTexture[textureId], 0.5 * GLOW_SIZE * fragmentData.texCoords + vec2(0.5)); outColor = tex * tex.a + glow * (1.0 - tex.a); } diff --git a/space-crush-app/resources/shader/ship/geom.glsl b/space-crush-app/resources/shader/ship/geom.glsl index b3d9821..bb44c39 100644 --- a/space-crush-app/resources/shader/ship/geom.glsl +++ b/space-crush-app/resources/shader/ship/geom.glsl @@ -15,7 +15,7 @@ void main() { VertexData d = vertexData[0]; vec2 pos = d.pos; - vec2 dir = d.dir * QUAD_SIZE; + vec2 dir = d.dir * SHIP_SIZE * GLOW_SIZE; mat4 m = uCamera.projection * uCamera.view * mat4( vec4(dir.y, -dir.x, 0.0, 0.0), diff --git a/space-crush-app/resources/shader/ship/shared.glsl b/space-crush-app/resources/shader/ship/shared.glsl index 9a3c27b..39842f7 100644 --- a/space-crush-app/resources/shader/ship/shared.glsl +++ b/space-crush-app/resources/shader/ship/shared.glsl @@ -10,5 +10,6 @@ struct VertexData { int texture; }; -const float QUAD_SIZE = 150.00; // absolute -const float SHIP_SIZE = 0.50; // relative to QUAD_SIZE +const float SHIP_SIZE = 25.0; // absolute ship size +const float GLOW_SIZE = 4.0; // relative to ship size +const float GLOW_ALPHA = 0.5; diff --git a/space-crush-app/src/render/planets.rs b/space-crush-app/src/render/planets.rs index 3c5cf8b..a97655f 100644 --- a/space-crush-app/src/render/planets.rs +++ b/space-crush-app/src/render/planets.rs @@ -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>, + planet_count: usize, +} + +#[repr(C, packed)] +struct VertexData { + pos: Vector2f, + size: gl::GLfloat, + color: Vector4f, } impl Planets { - pub fn new(world: &World) -> Result { + pub fn new(world: &mut World) -> Result { + WriteStorage::::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::() as gl::GLsizei; + + const OFFSET_POS: gl::GLsizei = 0; + const OFFSET_SIZ: gl::GLsizei = OFFSET_POS + size_of::() as gl::GLsizei; + const OFFSET_CLR: gl::GLsizei = OFFSET_SIZ + size_of::() 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::>() + .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::(), + ) + .panic("Unable to change buffer size for planet data"); + + let data = (&positions, &planets, owned.maybe()); + let mut buffer = buffer + .map_mut::(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); } } diff --git a/space-crush-app/src/render/ships.rs b/space-crush-app/src/render/ships.rs index f80e864..3bab420 100644 --- a/space-crush-app/src/render/ships.rs +++ b/space-crush-app/src/render/ships.rs @@ -167,7 +167,7 @@ impl<'a> System<'a> for Ships { let _guard = BindGuard::new(&self.texture_fighter); gl::enable(gl::BLEND); - gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); + gl::blend_func(gl::SRC_ALPHA, gl::ONE); gl::draw_arrays(gl::POINTS, 0, self.ship_count as _); gl::disable(gl::BLEND); } diff --git a/space-crush-common/src/components/planet.rs b/space-crush-common/src/components/planet.rs index 1acbfd4..1fd59ad 100644 --- a/space-crush-common/src/components/planet.rs +++ b/space-crush-common/src/components/planet.rs @@ -1,9 +1,11 @@ use serde::{Deserialize, Serialize}; use specs::{Component, NullStorage}; +use crate::misc::FlaggedStorage; + #[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct Planet {} impl Component for Planet { - type Storage = NullStorage; + type Storage = FlaggedStorage>; }