From 34794e7a3fb460ae7c63097ba335c72b7b279154 Mon Sep 17 00:00:00 2001 From: Bergmann89 Date: Wed, 9 Dec 2020 16:34:41 +0100 Subject: [PATCH] Implemented rendering system for ships --- glc/src/vector.rs | 36 ++++++ .../resources/shader/planet/frag.glsl | 2 +- .../resources/shader/ship/frag.glsl | 28 +++++ .../resources/shader/ship/shared.glsl | 3 + .../resources/shader/ship/vert.glsl | 17 +++ .../resources/textures/ship_bomber.png | Bin 0 -> 18062 bytes .../resources/textures/ship_fighter.png | Bin 0 -> 13235 bytes .../resources/textures/ship_transporter.png | Bin 0 -> 13219 bytes space-crush-app/resources/world.json | 95 +++++++++++++- space-crush-app/src/lib.rs | 3 +- space-crush-app/src/main.rs | 60 ++++++++- space-crush-app/src/misc/window.rs | 4 +- space-crush-app/src/render/mod.rs | 2 + space-crush-app/src/render/ships.rs | 116 ++++++++++++++++++ space-crush-app/src/resources/state.rs | 2 +- space-crush-common/src/components/mod.rs | 2 + space-crush-common/src/components/ship.rs | 18 +++ space-crush-common/src/components/velocity.rs | 23 +--- space-crush-common/src/dispatcher.rs | 6 +- space-crush-common/src/misc/persistence.rs | 4 +- space-crush-common/src/systems/mod.rs | 2 + space-crush-common/src/systems/movement.rs | 36 ++++++ space-crush-common/src/systems/process.rs | 2 +- 23 files changed, 429 insertions(+), 32 deletions(-) create mode 100644 space-crush-app/resources/shader/ship/frag.glsl create mode 100644 space-crush-app/resources/shader/ship/shared.glsl create mode 100644 space-crush-app/resources/shader/ship/vert.glsl create mode 100644 space-crush-app/resources/textures/ship_bomber.png create mode 100644 space-crush-app/resources/textures/ship_fighter.png create mode 100644 space-crush-app/resources/textures/ship_transporter.png create mode 100644 space-crush-app/src/render/ships.rs create mode 100644 space-crush-common/src/components/ship.rs create mode 100644 space-crush-common/src/systems/movement.rs diff --git a/glc/src/vector.rs b/glc/src/vector.rs index e20c540..8392d4e 100644 --- a/glc/src/vector.rs +++ b/glc/src/vector.rs @@ -304,6 +304,18 @@ where } } +impl Mul for Vector2 +where + T: Element, +{ + type Output = Self; + + #[inline] + fn mul(self, rhs: T) -> Self::Output { + self.multiply(rhs) + } +} + /* Vector3 */ impl Vector3 @@ -403,6 +415,18 @@ where } } +impl Mul for Vector3 +where + T: Element, +{ + type Output = Self; + + #[inline] + fn mul(self, rhs: T) -> Self::Output { + self.multiply(rhs) + } +} + /* Vector4 */ impl Vector4 @@ -513,6 +537,18 @@ where } } +impl Mul for Vector4 +where + T: Element, +{ + type Output = Self; + + #[inline] + fn mul(self, rhs: T) -> Self::Output { + self.multiply(rhs) + } +} + impl From<(Vector3, T)> for Vector4 { fn from((vec3, w): (Vector3, T)) -> Self { Self { diff --git a/space-crush-app/resources/shader/planet/frag.glsl b/space-crush-app/resources/shader/planet/frag.glsl index e8db1ff..1cfa7c0 100644 --- a/space-crush-app/resources/shader/planet/frag.glsl +++ b/space-crush-app/resources/shader/planet/frag.glsl @@ -8,7 +8,7 @@ const GlowArgs GLOW_ARGS = { /* step0 */ 0.480, /* step1 */ 0.975, /* pulseSize0 */ 0.010, - /* pulseSize1 */ 0.025, + /* pulseSize1 */ 0.050, /* pulseTime */ 2.000, }; diff --git a/space-crush-app/resources/shader/ship/frag.glsl b/space-crush-app/resources/shader/ship/frag.glsl new file mode 100644 index 0000000..3284f5b --- /dev/null +++ b/space-crush-app/resources/shader/ship/frag.glsl @@ -0,0 +1,28 @@ +#version 450 core + +#pragma include ./shared.glsl +#pragma include ../misc/glow.glsl +#pragma include ../misc/global.glsl + +const GlowArgs GLOW_ARGS = { + /* step0 */ 0.100, + /* step1 */ 1.900, + /* pulseSize0 */ 0.050, + /* pulseSize1 */ 0.200, + /* pulseTime */ 2.000, +}; + +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); + + outColor = tex * tex.a + glow * (1.0 - tex.a); +} diff --git a/space-crush-app/resources/shader/ship/shared.glsl b/space-crush-app/resources/shader/ship/shared.glsl new file mode 100644 index 0000000..e72b165 --- /dev/null +++ b/space-crush-app/resources/shader/ship/shared.glsl @@ -0,0 +1,3 @@ +struct FragmentData { + vec2 texCoords; +}; diff --git a/space-crush-app/resources/shader/ship/vert.glsl b/space-crush-app/resources/shader/ship/vert.glsl new file mode 100644 index 0000000..88fad03 --- /dev/null +++ b/space-crush-app/resources/shader/ship/vert.glsl @@ -0,0 +1,17 @@ +#version 450 core + +#pragma include ./shared.glsl +#pragma include ../misc/camera.glsl + +const float GLOW_SIZE_FACTOR = 4.00; + +in vec3 inPosition; + +uniform mat4 uModel; + +out FragmentData fragmentData; + +void main() { + fragmentData.texCoords = inPosition.xy * GLOW_SIZE_FACTOR + vec2(0.5); + gl_Position = uCamera.projection * uCamera.view * uModel * vec4(inPosition * GLOW_SIZE_FACTOR, 1.0); +} diff --git a/space-crush-app/resources/textures/ship_bomber.png b/space-crush-app/resources/textures/ship_bomber.png new file mode 100644 index 0000000000000000000000000000000000000000..965709fe3dcc030f922d5355163af7e8d5108899 GIT binary patch literal 18062 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 literal 0 HcmV?d00001 diff --git a/space-crush-app/resources/textures/ship_fighter.png b/space-crush-app/resources/textures/ship_fighter.png new file mode 100644 index 0000000000000000000000000000000000000000..af2e986a3cd643e59af11806a90c96ed2c642716 GIT binary patch literal 13235 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 z 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 literal 0 HcmV?d00001 diff --git a/space-crush-app/resources/textures/ship_transporter.png b/space-crush-app/resources/textures/ship_transporter.png new file mode 100644 index 0000000000000000000000000000000000000000..c6a938171376d8ed87fafb5a3a5ec36085f601c5 GIT binary patch literal 13219 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 F{{zFz39 App<'a, 'b> { .with(StateUpdate::new(world)?, "state_update", &[]) .with_thread_local(Init::new(world)?) .with_thread_local(Planets::new(world)?) + .with_thread_local(Ships::new(world)?) .with_thread_local(Debug::new(&text_manager)?) .build(); dispatcher.setup(world); diff --git a/space-crush-app/src/main.rs b/space-crush-app/src/main.rs index ec3eed0..f93fd4f 100644 --- a/space-crush-app/src/main.rs +++ b/space-crush-app/src/main.rs @@ -33,7 +33,9 @@ fn run(vfs: Vfs) -> Result<(), Error> { let mut common = Dispatcher::new(&mut world); let mut app = App::new(&mut world)?; - load_world(&mut world, WORLD_FILEPATH)?; + if !load_world(&mut world, WORLD_FILEPATH)? { + create_world(&mut world); + } while app.is_running() { world.maintain(); @@ -47,19 +49,69 @@ fn run(vfs: Vfs) -> Result<(), Error> { Ok(()) } -fn load_world(world: &mut World, path: &str) -> Result<(), Error> { +fn create_world(world: &mut World) { + use glc::vector::Vector2f; + use space_crush_common::{ + components::{Planet, Position, Ship, ShipType, Velocity}, + misc::{PersistWorld, Persistence}, + }; + use specs::{saveload::MarkedBuilder, Builder}; + + world + .create_entity() + .marked::<::Marker>() + .with(Position { + pos: Vector2f::default(), + size: 500.0, + }) + .with(Planet {}) + .build(); + + for i in 0..3 { + let x = if i & 1 == 0 { 1.0 } else { -1.0 }; + let y = if i & 2 == 0 { 1.0 } else { -1.0 }; + + world + .create_entity() + .marked::<::Marker>() + .with(Position { + pos: Vector2f::new(250.0 * x, 250.0 * y), + size: 100.0, + }) + .with(Velocity { + dir: Vector2f::new(i as f32 - 1.0, 1.0).normalize(), + speed: 0.0, + }) + .with(Ship { + type_: match i { + 0 => ShipType::Fighter, + 1 => ShipType::Bomber, + 2 => ShipType::Transporter, + _ => unreachable!(), + }, + }) + .build(); + } +} + +fn load_world(world: &mut World, path: &str) -> Result { use serde_json::de::{Deserializer, IoRead}; use space_crush_common::misc::{PersistWorld, Persistence, WorldHelper}; PersistWorld::setup(world); let vfs = world.resource::()?; - let mut file = vfs.join(path)?.open_file()?; + let path = vfs.join(path)?; + if !path.exists() { + return Ok(false); + } + + let mut file = path.open_file()?; let mut read = IoRead::new(&mut file); let mut deserializer = Deserializer::new(&mut read); world.deserialize(PersistWorld, &mut deserializer)?; - Ok(()) + Ok(true) } fn save_world(world: &mut World, path: &str) -> Result<(), Error> { diff --git a/space-crush-app/src/misc/window.rs b/space-crush-app/src/misc/window.rs index e37f03b..cca7ca8 100644 --- a/space-crush-app/src/misc/window.rs +++ b/space-crush-app/src/misc/window.rs @@ -7,9 +7,7 @@ use glutin::{ }; use log::{error, info}; -use crate::Error; - -use super::super::resources::Config; +use crate::{resources::Config, Error}; pub struct Window { context: ContextWrapper, diff --git a/space-crush-app/src/render/mod.rs b/space-crush-app/src/render/mod.rs index 3e2f46f..b04910b 100644 --- a/space-crush-app/src/render/mod.rs +++ b/space-crush-app/src/render/mod.rs @@ -1,7 +1,9 @@ mod debug; mod init; mod planets; +mod ships; pub use debug::Debug; pub use init::Init; pub use planets::Planets; +pub use ships::Ships; diff --git a/space-crush-app/src/render/ships.rs b/space-crush-app/src/render/ships.rs new file mode 100644 index 0000000..a7aa125 --- /dev/null +++ b/space-crush-app/src/render/ships.rs @@ -0,0 +1,116 @@ +use glc::{ + matrix::Matrix4f, + misc::{BindGuard, Bindable}, + shader::{Program, Type, Uniform}, + texture::Texture, + vector::Vector4f, +}; +use log::error; +use space_crush_common::components::{Position, Ship, ShipType, Velocity}; +use specs::{prelude::*, ReadExpect, ReadStorage, System, World}; + +use crate::{ + constants::{UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM}, + misc::WorldHelper, + resources::Geometry, + Error, +}; + +pub struct Ships { + program: Program, + texture_fighter: Texture, + texture_bomber: Texture, + texture_transporter: Texture, + model_location: gl::GLint, +} + +impl Ships { + pub fn new(world: &World) -> Result { + let program = world.load_program(vec![ + (Type::Vertex, "resources/shader/ship/vert.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 glow_color = Vector4f::new(1.0, 1.0, 1.0, 0.02); + let glow_color = Uniform::Vector4f(&glow_color); + let model_location = program.uniform_location("uModel")?; + + program.bind(); + program.uniform("uTexture", Uniform::Texture(0))?; + program.uniform("uGlowColor", glow_color)?; + program.unbind(); + + let texture_fighter = world.load_texture("resources/textures/ship_fighter.png")?; + let texture_bomber = world.load_texture("resources/textures/ship_bomber.png")?; + let texture_transporter = world.load_texture("resources/textures/ship_transporter.png")?; + + Ok(Self { + program, + texture_fighter, + texture_bomber, + texture_transporter, + model_location, + }) + } +} + +#[derive(SystemData)] +pub struct ShipsData<'a> { + geometry: ReadExpect<'a, Geometry>, + position: ReadStorage<'a, Position>, + velocity: ReadStorage<'a, Velocity>, + ship: ReadStorage<'a, Ship>, +} + +impl<'a> System<'a> for Ships { + type SystemData = ShipsData<'a>; + + fn run(&mut self, data: Self::SystemData) { + let ShipsData { + geometry, + position, + velocity, + ship, + } = data; + + gl::enable(gl::BLEND); + gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); + + let _guard = BindGuard::new(&self.program); + + for (p, v, ship) in (&position, &velocity, &ship).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 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 = p.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), + ); + + if let Err(err) = self + .program + .uniform(self.model_location, Uniform::Matrix4f(&m)) + { + error!("Error while updating model matrix: {}", err); + } + + geometry.render_quad(); + } + + gl::disable(gl::BLEND); + } +} diff --git a/space-crush-app/src/resources/state.rs b/space-crush-app/src/resources/state.rs index 3fc7cc2..93dbe48 100644 --- a/space-crush-app/src/resources/state.rs +++ b/space-crush-app/src/resources/state.rs @@ -3,7 +3,7 @@ use std::collections::HashSet; use std::iter::IntoIterator; -use super::super::misc::{MouseButton, VirtualKeyCode}; +use crate::misc::{MouseButton, VirtualKeyCode}; #[derive(Default)] pub struct State { diff --git a/space-crush-common/src/components/mod.rs b/space-crush-common/src/components/mod.rs index 0911c30..58ad4e8 100644 --- a/space-crush-common/src/components/mod.rs +++ b/space-crush-common/src/components/mod.rs @@ -1,7 +1,9 @@ mod planet; mod position; +mod ship; mod velocity; pub use planet::Planet; pub use position::Position; +pub use ship::{Ship, Type as ShipType}; pub use velocity::Velocity; diff --git a/space-crush-common/src/components/ship.rs b/space-crush-common/src/components/ship.rs new file mode 100644 index 0000000..8d79774 --- /dev/null +++ b/space-crush-common/src/components/ship.rs @@ -0,0 +1,18 @@ +use serde::{Deserialize, Serialize}; +use specs::{Component, VecStorage}; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Ship { + pub type_: Type, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum Type { + Fighter, + Bomber, + Transporter, +} + +impl Component for Ship { + type Storage = VecStorage; +} diff --git a/space-crush-common/src/components/velocity.rs b/space-crush-common/src/components/velocity.rs index 8109620..1f6f97a 100644 --- a/space-crush-common/src/components/velocity.rs +++ b/space-crush-common/src/components/velocity.rs @@ -1,24 +1,13 @@ -use std::ops::{Deref, DerefMut}; - use glc::vector::Vector2f; +use serde::{Deserialize, Serialize}; use specs::{Component, VecStorage}; -pub struct Velocity(pub Vector2f); +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +pub struct Velocity { + pub dir: Vector2f, + pub speed: f32, +} impl Component for Velocity { type Storage = VecStorage; } - -impl Deref for Velocity { - type Target = Vector2f; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for Velocity { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} diff --git a/space-crush-common/src/dispatcher.rs b/space-crush-common/src/dispatcher.rs index 2db32b5..3147fef 100644 --- a/space-crush-common/src/dispatcher.rs +++ b/space-crush-common/src/dispatcher.rs @@ -1,6 +1,9 @@ use specs::{Dispatcher as Inner, DispatcherBuilder, World}; -use crate::{resources::Global, systems::Process}; +use crate::{ + resources::Global, + systems::{Movement, Process}, +}; pub struct Dispatcher<'a, 'b> { dispatcher: Inner<'a, 'b>, @@ -12,6 +15,7 @@ impl<'a, 'b> Dispatcher<'a, 'b> { let mut dispatcher = DispatcherBuilder::new() .with(Process::default(), "process", &[]) + .with(Movement::default(), "movement", &[]) .build(); dispatcher.setup(world); diff --git a/space-crush-common/src/misc/persistence.rs b/space-crush-common/src/misc/persistence.rs index 39b18e6..06fdeeb 100644 --- a/space-crush-common/src/misc/persistence.rs +++ b/space-crush-common/src/misc/persistence.rs @@ -1,6 +1,6 @@ use specs::saveload::SimpleMarker; -use crate::components::{Planet, Position}; +use crate::components::{Planet, Position, Ship, Velocity}; use super::Persistence; @@ -9,5 +9,5 @@ pub struct PersistWorldMarker; impl Persistence for PersistWorld { type Marker = SimpleMarker; - type Components = (Position, Planet); + type Components = (Position, Velocity, Planet, Ship); } diff --git a/space-crush-common/src/systems/mod.rs b/space-crush-common/src/systems/mod.rs index f4dc0e2..e2bdf5f 100644 --- a/space-crush-common/src/systems/mod.rs +++ b/space-crush-common/src/systems/mod.rs @@ -1,3 +1,5 @@ +mod movement; mod process; +pub use movement::Movement; pub use process::Process; diff --git a/space-crush-common/src/systems/movement.rs b/space-crush-common/src/systems/movement.rs new file mode 100644 index 0000000..dc0d736 --- /dev/null +++ b/space-crush-common/src/systems/movement.rs @@ -0,0 +1,36 @@ +#![allow(dead_code)] + +use specs::{prelude::*, ParJoin, Read, ReadStorage, System, WriteStorage}; + +use crate::{ + components::{Position, Velocity}, + resources::Global, +}; + +#[derive(Default)] +pub struct Movement; + +#[derive(SystemData)] +pub struct MovementData<'a> { + position: WriteStorage<'a, Position>, + velocity: ReadStorage<'a, Velocity>, + global: Read<'a, Global>, +} + +impl<'a> System<'a> for Movement { + type SystemData = MovementData<'a>; + + fn run(&mut self, data: Self::SystemData) { + let MovementData { + mut position, + velocity, + global, + } = data; + + (&mut position, &velocity) + .par_join() + .for_each(|(position, velocity)| { + position.pos = position.pos + velocity.dir * velocity.speed * global.delta; + }); + } +} diff --git a/space-crush-common/src/systems/process.rs b/space-crush-common/src/systems/process.rs index b9f7215..f813f9a 100644 --- a/space-crush-common/src/systems/process.rs +++ b/space-crush-common/src/systems/process.rs @@ -5,7 +5,7 @@ use std::time::Instant; use specs::{System, Write}; -use super::super::resources::Global; +use crate::resources::Global; pub struct Process { last_frame: Instant,