diff --git a/space-crush-app/resources/shader/asteroid/frag.glsl b/space-crush-app/resources/shader/asteroid/frag.glsl new file mode 100644 index 0000000..1cfa7c0 --- /dev/null +++ b/space-crush-app/resources/shader/asteroid/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.480, + /* step1 */ 0.975, + /* pulseSize0 */ 0.010, + /* pulseSize1 */ 0.050, + /* 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/asteroid/shared.glsl b/space-crush-app/resources/shader/asteroid/shared.glsl new file mode 100644 index 0000000..e72b165 --- /dev/null +++ b/space-crush-app/resources/shader/asteroid/shared.glsl @@ -0,0 +1,3 @@ +struct FragmentData { + vec2 texCoords; +}; diff --git a/space-crush-app/resources/shader/asteroid/vert.glsl b/space-crush-app/resources/shader/asteroid/vert.glsl new file mode 100644 index 0000000..d629730 --- /dev/null +++ b/space-crush-app/resources/shader/asteroid/vert.glsl @@ -0,0 +1,17 @@ +#version 450 core + +#pragma include ./shared.glsl +#pragma include ../misc/camera.glsl + +const float GLOW_SIZE_FACTOR = 2.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(2.0 * inPosition * GLOW_SIZE_FACTOR, 1.0); +} diff --git a/space-crush-app/resources/textures/asteroid_crystal.png b/space-crush-app/resources/textures/asteroid_crystal.png new file mode 100644 index 0000000..02910d4 Binary files /dev/null and b/space-crush-app/resources/textures/asteroid_crystal.png differ diff --git a/space-crush-app/resources/textures/asteroid_metal.png b/space-crush-app/resources/textures/asteroid_metal.png new file mode 100644 index 0000000..b2011e9 Binary files /dev/null and b/space-crush-app/resources/textures/asteroid_metal.png differ diff --git a/space-crush-app/src/lib.rs b/space-crush-app/src/lib.rs index 08a0166..23e9690 100644 --- a/space-crush-app/src/lib.rs +++ b/space-crush-app/src/lib.rs @@ -12,7 +12,7 @@ pub use error::Error; use debug::{Fleets as DebugFleets, Ships as DebugShips, Summary as DebugSummary}; use misc::{Events, TextManager, Window}; -use render::{Init, Planets, Ships}; +use render::{Asteroids, Init, Planets, Ships}; use resources::{Camera, Config, Geometry, State, Uniform}; use systems::StateUpdate; @@ -46,6 +46,7 @@ impl<'a, 'b> App<'a, 'b> { .with(StateUpdate::new(world)?, "state_update", &[]) .with_thread_local(Init::new(world)?) .with_thread_local(Planets::new(world)?) + .with_thread_local(Asteroids::new(world)?) .with_thread_local(Ships::new(world)?) .with_thread_local(DebugShips::default()) .with_thread_local(DebugFleets::default()) diff --git a/space-crush-app/src/main.rs b/space-crush-app/src/main.rs index 23d18e3..76683b1 100644 --- a/space-crush-app/src/main.rs +++ b/space-crush-app/src/main.rs @@ -28,6 +28,8 @@ fn main() -> Result<(), Error> { } fn run(vfs: Vfs) -> Result<(), Error> { + info!("Application initialization"); + let mut world = World::new(); world.insert(vfs); @@ -38,6 +40,8 @@ fn run(vfs: Vfs) -> Result<(), Error> { create_world(&mut world); } + info!("Application initialized"); + while app.is_running() { world.maintain(); @@ -56,7 +60,10 @@ fn create_world(world: &mut World) { vector::{Vector2f, Vector4f}, }; use space_crush_common::{ - components::{Fleet, Owned, Planet, Player, Position, Ship, ShipType, Velocity}, + components::{ + Asteroid, AsteroidType, Fleet, Owned, Planet, Player, Position, Ship, ShipType, + Velocity, + }, misc::{PersistWorld, Persistence}, }; use specs::{saveload::MarkedBuilder, Builder}; @@ -68,6 +75,38 @@ fn create_world(world: &mut World) { }) .build(); + world + .create_entity() + .marked::<::Marker>() + .with(Position { + pos: Vector2f::new(500.0, -500.0), + size: 100.0, + }) + .with(Fleet { + orbit_min: 125.0, + orbit_max: 175.0, + }) + .with(Asteroid { + type_: AsteroidType::Metal, + }) + .build(); + + world + .create_entity() + .marked::<::Marker>() + .with(Position { + pos: Vector2f::new(500.0, 500.0), + size: 100.0, + }) + .with(Fleet { + orbit_min: 125.0, + orbit_max: 175.0, + }) + .with(Asteroid { + type_: AsteroidType::Crystal, + }) + .build(); + let planet = world .create_entity() .marked::<::Marker>() diff --git a/space-crush-app/src/render/asteroids.rs b/space-crush-app/src/render/asteroids.rs new file mode 100644 index 0000000..69332bf --- /dev/null +++ b/space-crush-app/src/render/asteroids.rs @@ -0,0 +1,119 @@ +use glc::{ + matrix::Matrix4f, + misc::{BindGuard, Bindable}, + shader::{Program, Type, Uniform}, + texture::Texture, + vector::Vector4f, +}; +use space_crush_common::{ + components::{Asteroid, AsteroidType, Owned, Player, Position}, + misc::LogResult, +}; +use specs::{prelude::*, ReadExpect, ReadStorage, System, World}; + +use crate::{ + constants::{PLAYER_COLOR_DEFAULT, UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM}, + misc::WorldHelper, + resources::Geometry, + Error, +}; + +pub struct Asteroids { + program: Program, + texture_metal: Texture, + texture_crystal: Texture, + location_model: gl::GLint, + location_glow_color: gl::GLint, +} + +impl Asteroids { + pub fn new(world: &World) -> Result { + let program = world.load_program(vec![ + (Type::Vertex, "resources/shader/asteroid/vert.glsl"), + (Type::Fragment, "resources/shader/asteroid/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_metal = world.load_texture("resources/textures/asteroid_metal.png")?; + let texture_crystal = world.load_texture("resources/textures/asteroid_crystal.png")?; + + Ok(Self { + program, + texture_metal, + texture_crystal, + location_model, + location_glow_color, + }) + } +} + +#[derive(SystemData)] +pub struct AsteroidsData<'a> { + geometry: ReadExpect<'a, Geometry>, + position: ReadStorage<'a, Position>, + asteroid: ReadStorage<'a, Asteroid>, + owned: ReadStorage<'a, Owned>, + player: ReadStorage<'a, Player>, +} + +impl<'a> System<'a> for Asteroids { + type SystemData = AsteroidsData<'a>; + + fn run(&mut self, data: Self::SystemData) { + let AsteroidsData { + geometry, + position, + asteroid, + owned, + player, + } = data; + + gl::enable(gl::BLEND); + gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); + + let _guard = BindGuard::new(&self.program); + + for (position, asteroid, owned) in (&position, &asteroid, owned.maybe()).join() { + let p_x = position.pos.x; + let p_y = position.pos.y; + let s = position.size; + + let _guard = match asteroid.type_ { + AsteroidType::Metal => BindGuard::new(&self.texture_metal), + AsteroidType::Crystal => BindGuard::new(&self.texture_crystal), + }; + + 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::disable(gl::BLEND); + } +} diff --git a/space-crush-app/src/render/mod.rs b/space-crush-app/src/render/mod.rs index e049e93..0034b9c 100644 --- a/space-crush-app/src/render/mod.rs +++ b/space-crush-app/src/render/mod.rs @@ -1,7 +1,9 @@ +mod asteroids; mod init; mod planets; mod ships; +pub use asteroids::Asteroids; pub use init::Init; pub use planets::Planets; pub use ships::Ships; diff --git a/space-crush-common/src/components/asteroid.rs b/space-crush-common/src/components/asteroid.rs new file mode 100644 index 0000000..f0191a2 --- /dev/null +++ b/space-crush-common/src/components/asteroid.rs @@ -0,0 +1,17 @@ +use serde::{Deserialize, Serialize}; +use specs::{Component, HashMapStorage}; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Asteroid { + pub type_: Type, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum Type { + Metal, + Crystal, +} + +impl Component for Asteroid { + type Storage = HashMapStorage; +} diff --git a/space-crush-common/src/components/mod.rs b/space-crush-common/src/components/mod.rs index d63623e..2b04d23 100644 --- a/space-crush-common/src/components/mod.rs +++ b/space-crush-common/src/components/mod.rs @@ -1,3 +1,4 @@ +mod asteroid; mod fleet; mod owned; mod planet; @@ -6,6 +7,7 @@ mod position; mod ship; mod velocity; +pub use asteroid::{Asteroid, Type as AsteroidType}; pub use fleet::Fleet; pub use owned::Owned; pub use planet::Planet;