Selaa lähdekoodia

Use vertex array and geometry shader to render ships

master
Bergmann89 5 vuotta sitten
vanhempi
commit
e26c7dbfd3
10 muutettua tiedostoa jossa 223 lisäystä ja 100 poistoa
  1. +2
    -0
      glc/src/shader.rs
  2. +30
    -14
      glc/src/vertex_array.rs
  3. +8
    -8
      space-crush-app/resources/shader/ship/frag.glsl
  4. +46
    -0
      space-crush-app/resources/shader/ship/geom.glsl
  5. +11
    -0
      space-crush-app/resources/shader/ship/shared.glsl
  6. +9
    -9
      space-crush-app/resources/shader/ship/vert.glsl
  7. +0
    -1
      space-crush-app/src/constants.rs
  8. +0
    -2
      space-crush-app/src/misc/text.rs
  9. +105
    -60
      space-crush-app/src/render/ships.rs
  10. +12
    -6
      space-crush-common/src/misc/flagged_storage.rs

+ 2
- 0
glc/src/shader.rs Näytä tiedosto

@@ -87,6 +87,7 @@ impl Program {
Uniform::Vector2f(v) => gl::uniform_2fv(location, 1, v.as_ptr()),
Uniform::Float(v) => gl::uniform_1f(location, v),
Uniform::Texture(i) => gl::uniform_1i(location, i),
Uniform::TextureVec(i) => gl::uniform_1iv(location, i.len() as _, i.as_ptr()),
}

Ok(())
@@ -285,6 +286,7 @@ pub enum Uniform<'a> {
Vector2f(&'a Vector2f),
Float(f32),
Texture(gl::GLint),
TextureVec(&'a [gl::GLint]),
}

/* IntoUniformLocation */


+ 30
- 14
glc/src/vertex_array.rs Näytä tiedosto

@@ -79,20 +79,36 @@ impl Builder {
for pointer in binding.pointers {
Error::checked(|| gl::enable_vertex_attrib_array(pointer.index))?;

Error::checked(|| {
gl::vertex_attrib_pointer(
pointer.index,
pointer.size,
pointer.type_.as_enum(),
if pointer.normalize {
gl::TRUE
} else {
gl::FALSE
},
pointer.stride,
pointer.offset as *const _,
)
})?;
match pointer.type_ {
DataType::Byte
| DataType::UnsignedByte
| DataType::Short
| DataType::UnsignedShort
| DataType::Int
| DataType::UnsignedInt => Error::checked(|| {
gl::vertex_attrib_i_pointer(
pointer.index,
pointer.size,
pointer.type_.as_enum(),
pointer.stride,
pointer.offset as *const _,
)
})?,
_ => Error::checked(|| {
gl::vertex_attrib_pointer(
pointer.index,
pointer.size,
pointer.type_.as_enum(),
if pointer.normalize {
gl::TRUE
} else {
gl::FALSE
},
pointer.stride,
pointer.offset as *const _,
)
})?,
}

if let Some(divisor) = pointer.divisor {
Error::checked(|| gl::vertex_attrib_divisor(pointer.index, divisor))?;


+ 8
- 8
space-crush-app/resources/shader/ship/frag.glsl Näytä tiedosto

@@ -7,23 +7,23 @@
const float GLOW_ALPHA = 0.20;
const GlowArgs GLOW_ARGS = {
/* step0 */ 0.100,
/* step1 */ 1.900,
/* step1 */ 0.900,
/* pulseSize0 */ 0.050,
/* pulseSize1 */ 0.200,
/* pulseSize1 */ 0.100,
/* pulseTime */ 2.000,
};

in FragmentData fragmentData;
in FragmentData fragmentData;
flat in int textureId;

uniform vec4 uGlowColor;
uniform sampler2D uTexture;
uniform sampler2D uTexture[3];

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 * GLOW_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 * GLOW_ALPHA);
vec4 tex = texture(uTexture[textureId], fragmentData.texCoords / SHIP_SIZE + vec2(0.5));

outColor = tex * tex.a + glow * (1.0 - tex.a);
}

+ 46
- 0
space-crush-app/resources/shader/ship/geom.glsl Näytä tiedosto

@@ -0,0 +1,46 @@
#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;
flat out int textureId;

void main() {
VertexData d = vertexData[0];

vec2 pos = d.pos;
vec2 dir = d.dir * QUAD_SIZE;

mat4 m = uCamera.projection * uCamera.view * mat4(
vec4(dir.y, -dir.x, 0.0, 0.0),
vec4(dir.x, dir.y, 0.0, 0.0),
vec4( 0.0, 0.0, 0.0, 0.0),
vec4(pos.x, pos.y, 0.0, 1.0));

textureId = d.texture;
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();
}

+ 11
- 0
space-crush-app/resources/shader/ship/shared.glsl Näytä tiedosto

@@ -1,3 +1,14 @@
struct FragmentData {
vec2 texCoords;
vec4 color;
};

struct VertexData {
vec2 pos;
vec2 dir;
vec4 color;
int texture;
};

const float QUAD_SIZE = 150.00; // absolute
const float SHIP_SIZE = 0.50; // relative to QUAD_SIZE

+ 9
- 9
space-crush-app/resources/shader/ship/vert.glsl Näytä tiedosto

@@ -1,17 +1,17 @@
#version 450 core

#pragma include ./shared.glsl
#pragma include ../misc/camera.glsl

const float GLOW_SIZE_FACTOR = 4.00;
layout (location = 0) in vec2 inPosition;
layout (location = 1) in vec2 inDirection;
layout (location = 2) in vec4 inColor;
layout (location = 3) in int inTexture;

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.dir = inDirection;
vertexData.color = inColor;
vertexData.texture = inTexture;
}

+ 0
- 1
space-crush-app/src/constants.rs Näytä tiedosto

@@ -5,7 +5,6 @@ use glc::vector::Vector4f;
pub const UNIFORM_BUFFER_INDEX_CAMERA: gl::GLuint = 0;
pub const UNIFORM_BUFFER_INDEX_UNIFORM: gl::GLuint = 1;

pub const SHIP_SIZE: f32 = 25.0;
pub const PLANET_SIZE: f32 = 200.0;
pub const ASTEROID_SIZE: f32 = 100.0;



+ 0
- 2
space-crush-app/src/misc/text.rs Näytä tiedosto

@@ -643,9 +643,7 @@ impl Text {
.uniform(2, Uniform::Vector2f(pos))
.warn("Unable to update text offset");

// gl::draw_arrays(gl::POINTS, 0, inner.vertex_count as _);
gl::draw_arrays(gl::POINTS, 0, inner.vertex_count as _);
// gl::draw_arrays_instanced(gl::POINTS, 0, 1, inner.vertex_count as _);
}

pub fn update<S>(&mut self, mut index: usize, text: S) -> Result<&Self, Error>


+ 105
- 60
space-crush-app/src/render/ships.rs Näytä tiedosto

@@ -1,74 +1,101 @@
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::{Player, PlayerOwned, Position, Ship, ShipType, Velocity},
misc::LogResult,
misc::{ComponentEvent, LogResult, StorageHelper, StorageHelperMut},
};
use specs::{prelude::*, ReadExpect, ReadStorage, System, World};
use specs::{prelude::*, ReadStorage, System, World};

use crate::{
constants::{
PLAYER_COLOR_DEFAULT, SHIP_SIZE, UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM,
},
constants::{PLAYER_COLOR_DEFAULT, UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM},
misc::WorldHelper,
resources::Geometry,
Error,
};

pub struct Ships {
program: Program,
vertex_array: VertexArray,
texture_bomber: Texture,
texture_fighter: Texture,
texture_transporter: Texture,
location_model: gl::GLint,
location_glow_color: gl::GLint,
reader_id: ReaderId<ComponentEvent<Ship>>,
ship_count: usize,
}

#[repr(C, packed)]
struct VertexData {
pos: Vector2f,
dir: Vector2f,
color: Vector4f,
texture: gl::GLint,
}

impl Ships {
pub fn new(world: &World) -> Result<Self, Error> {
let program = world.load_program(vec![
(Type::Vertex, "resources/shader/ship/vert.glsl"),
(Type::Geometry, "resources/shader/ship/geom.glsl"),
(Type::Fragment, "resources/shader/ship/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.uniform("uTexture", Uniform::TextureVec(&[0, 1, 2]))?;
program.unbind();

const STRIDE: gl::GLsizei = size_of::<VertexData>() as gl::GLsizei;

const OFFSET_POS: gl::GLsizei = 0;
const OFFSET_DIR: gl::GLsizei = OFFSET_POS + size_of::<Vector2f>() as gl::GLsizei;
const OFFSET_CLR: gl::GLsizei = OFFSET_DIR + size_of::<Vector2f>() as gl::GLsizei;
const OFFSET_TEX: gl::GLsizei = OFFSET_CLR + size_of::<Vector4f>() 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, 2, DataType::Float, false, STRIDE, OFFSET_DIR)?
.vertex_attrib_pointer(2, 4, DataType::Float, false, STRIDE, OFFSET_CLR)?
.vertex_attrib_pointer(3, 1, DataType::Int, false, STRIDE, OFFSET_TEX)?
.build()?;

let texture_bomber = world.load_texture("resources/textures/ship_bomber.png")?;
let texture_fighter = world.load_texture("resources/textures/ship_fighter.png")?;
let texture_transporter = world.load_texture("resources/textures/ship_transporter.png")?;

let reader_id = world
.system_data::<WriteStorage<Ship>>()
.register_event_reader();
let ship_count = 0;

Ok(Self {
program,
vertex_array,
texture_bomber,
texture_fighter,
texture_transporter,
location_model,
location_glow_color,
reader_id,
ship_count,
})
}
}

#[derive(SystemData)]
pub struct ShipsData<'a> {
geometry: ReadExpect<'a, Geometry>,
position: ReadStorage<'a, Position>,
velocity: ReadStorage<'a, Velocity>,
ship: ReadStorage<'a, Ship>,
positions: ReadStorage<'a, Position>,
velocities: ReadStorage<'a, Velocity>,
players: ReadStorage<'a, Player>,
owned: ReadStorage<'a, PlayerOwned>,
player: ReadStorage<'a, Player>,
ships: ReadStorage<'a, Ship>,
}

impl<'a> System<'a> for Ships {
@@ -76,54 +103,72 @@ impl<'a> System<'a> for Ships {

fn run(&mut self, data: Self::SystemData) {
let ShipsData {
geometry,
position,
velocity,
ship,
positions,
velocities,
players,
owned,
player,
ships,
} = data;

gl::enable(gl::BLEND);
gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
/* handle events */
let old_count = self.ship_count;
let events = ships.channel().read(&mut self.reader_id);
for event in events {
match event {
ComponentEvent::Inserted(_, _) => self.ship_count += 1,
ComponentEvent::Removed(_, _) => self.ship_count -= 1,
ComponentEvent::Modified(_, _) => {
unreachable!("Updates of the ship component should not be tracked!")
}
}
}

let _guard = BindGuard::new(&self.program);
/* update vertex array */
let buffer = &mut self.vertex_array.buffers_mut()[0];
if old_count != self.ship_count {
buffer
.buffer_size(Usage::StaticDraw, self.ship_count * size_of::<VertexData>())
.panic("Unable to change buffer size for ship data");
}

for (p, v, ship, owned) in (&position, &velocity, &ship, owned.maybe()).join() {
let _guard = match ship.type_() {
ShipType::Fighter => BindGuard::new(&self.texture_fighter),
ShipType::Bomber => BindGuard::new(&self.texture_bomber),
ShipType::Transporter => BindGuard::new(&self.texture_transporter),
let data = (&positions, &velocities, &ships, owned.maybe());
let mut buffer = buffer
.map_mut::<VertexData>(true)
.panic("Unable to map buffer for ship data");
for (i, (position, velocity, ship, owned)) in data.join().enumerate() {
let mut d = &mut buffer[i];

d.pos = *position.pos();
d.dir = *velocity.dir();
d.color = match owned.and_then(|owned| players.get(owned.owner())) {
Some(pv) => *pv.color(),
None => PLAYER_COLOR_DEFAULT,
};

let c = match owned.and_then(|owned| player.get(owned.owner())) {
Some(pv) => pv.color(),
None => &PLAYER_COLOR_DEFAULT,
d.texture = match ship.type_() {
ShipType::Fighter => 0,
ShipType::Bomber => 1,
ShipType::Transporter => 2,
};

let p_x = p.pos().x;
let p_y = p.pos().y;
let d_x = v.dir().x;
let d_y = v.dir().y;
let s = SHIP_SIZE;

let m = Matrix4f::new(
Vector4f::new(-s * d_y, s * d_x, 0.0, 0.0),
Vector4f::new(-s * d_x, -s * d_y, 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();
}

drop(buffer);

/* render ships */
let _guard = BindGuard::new(&self.program);
let _guard = BindGuard::new(&self.vertex_array);

gl::active_texture(gl::TEXTURE2);
let _guard = BindGuard::new(&self.texture_transporter);

gl::active_texture(gl::TEXTURE1);
let _guard = BindGuard::new(&self.texture_bomber);

gl::active_texture(gl::TEXTURE0);
let _guard = BindGuard::new(&self.texture_fighter);

gl::enable(gl::BLEND);
gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
gl::draw_arrays(gl::POINTS, 0, self.ship_count as _);
gl::disable(gl::BLEND);
}
}

+ 12
- 6
space-crush-common/src/misc/flagged_storage.rs Näytä tiedosto

@@ -63,8 +63,10 @@ where
unsafe fn get_mut(&mut self, id: Index) -> &mut C {
let component = self.storage.get_mut(id);

self.channel
.single_write(ComponentEvent::Modified(id, component.clone()));
if self.event_emission {
self.channel
.single_write(ComponentEvent::Modified(id, component.clone()));
}

component
}
@@ -72,15 +74,19 @@ where
unsafe fn insert(&mut self, id: Index, component: C) {
self.storage.insert(id, component.clone());

self.channel
.single_write(ComponentEvent::Inserted(id, component));
if self.event_emission {
self.channel
.single_write(ComponentEvent::Inserted(id, component));
}
}

unsafe fn remove(&mut self, id: Index) -> C {
let component = self.storage.remove(id);

self.channel
.single_write(ComponentEvent::Removed(id, component.clone()));
if self.event_emission {
self.channel
.single_write(ComponentEvent::Removed(id, component.clone()));
}

component
}


Ladataan…
Peruuta
Tallenna