| @@ -1510,6 +1510,7 @@ dependencies = [ | |||||
| "glc", | "glc", | ||||
| "glutin", | "glutin", | ||||
| "glyph_brush", | "glyph_brush", | ||||
| "lazy_static", | |||||
| "log", | "log", | ||||
| "log4rs", | "log4rs", | ||||
| "ordered-float 2.0.1", | "ordered-float 2.0.1", | ||||
| @@ -9,6 +9,7 @@ gl = { version = "0.1", features = [ "use_log_crate" ] } | |||||
| glc = "0.1" | glc = "0.1" | ||||
| glutin = { version = "0.25", features = [ "serde" ] } | glutin = { version = "0.25", features = [ "serde" ] } | ||||
| glyph_brush = "0.7" | glyph_brush = "0.7" | ||||
| lazy_static = "1.4" | |||||
| log = { version = "0.4", features = [ "max_level_trace", "release_max_level_warn" ] } | log = { version = "0.4", features = [ "max_level_trace", "release_max_level_warn" ] } | ||||
| log4rs = "0.13" | log4rs = "0.13" | ||||
| ordered-float = "2.0" | ordered-float = "2.0" | ||||
| @@ -4,6 +4,7 @@ | |||||
| #pragma include ../misc/glow.glsl | #pragma include ../misc/glow.glsl | ||||
| #pragma include ../misc/global.glsl | #pragma include ../misc/global.glsl | ||||
| const float GLOW_ALPHA = 0.20; | |||||
| const GlowArgs GLOW_ARGS = { | const GlowArgs GLOW_ARGS = { | ||||
| /* step0 */ 0.100, | /* step0 */ 0.100, | ||||
| /* step1 */ 1.900, | /* step1 */ 1.900, | ||||
| @@ -21,7 +22,7 @@ out vec4 outColor; | |||||
| void main() { | void main() { | ||||
| float alpha = glow(GLOW_ARGS, fragmentData.texCoords - vec2(0.5), uGlobal.time); | float alpha = glow(GLOW_ARGS, fragmentData.texCoords - vec2(0.5), uGlobal.time); | ||||
| vec4 glow = vec4(uGlowColor.rgb, uGlowColor.a * alpha); | |||||
| vec4 glow = vec4(uGlowColor.rgb, uGlowColor.a * alpha * GLOW_ALPHA); | |||||
| vec4 tex = texture(uTexture, fragmentData.texCoords); | vec4 tex = texture(uTexture, fragmentData.texCoords); | ||||
| outColor = tex * tex.a + glow * (1.0 - tex.a); | outColor = tex * tex.a + glow * (1.0 - tex.a); | ||||
| @@ -13,6 +13,13 @@ | |||||
| }, | }, | ||||
| null, | null, | ||||
| {}, | {}, | ||||
| null, | |||||
| { | |||||
| "owner": [ | |||||
| 4 | |||||
| ] | |||||
| }, | |||||
| null, | |||||
| null | null | ||||
| ] | ] | ||||
| }, | }, | ||||
| @@ -38,7 +45,14 @@ | |||||
| null, | null, | ||||
| { | { | ||||
| "type_": "Fighter" | "type_": "Fighter" | ||||
| } | |||||
| }, | |||||
| { | |||||
| "owner": [ | |||||
| 4 | |||||
| ] | |||||
| }, | |||||
| null, | |||||
| null | |||||
| ] | ] | ||||
| }, | }, | ||||
| { | { | ||||
| @@ -63,7 +77,14 @@ | |||||
| null, | null, | ||||
| { | { | ||||
| "type_": "Bomber" | "type_": "Bomber" | ||||
| } | |||||
| }, | |||||
| { | |||||
| "owner": [ | |||||
| 4 | |||||
| ] | |||||
| }, | |||||
| null, | |||||
| null | |||||
| ] | ] | ||||
| }, | }, | ||||
| { | { | ||||
| @@ -88,6 +109,34 @@ | |||||
| null, | null, | ||||
| { | { | ||||
| "type_": "Transporter" | "type_": "Transporter" | ||||
| }, | |||||
| { | |||||
| "owner": [ | |||||
| 4 | |||||
| ] | |||||
| }, | |||||
| null, | |||||
| null | |||||
| ] | |||||
| }, | |||||
| { | |||||
| "marker": [ | |||||
| 4 | |||||
| ], | |||||
| "components": [ | |||||
| null, | |||||
| null, | |||||
| null, | |||||
| null, | |||||
| null, | |||||
| {}, | |||||
| { | |||||
| "color": [ | |||||
| 0.0, | |||||
| 0.5, | |||||
| 1.0, | |||||
| 0.1 | |||||
| ] | |||||
| } | } | ||||
| ] | ] | ||||
| } | } | ||||
| @@ -0,0 +1,3 @@ | |||||
| mod player_visual; | |||||
| pub use player_visual::PlayerVisual; | |||||
| @@ -0,0 +1,12 @@ | |||||
| use glc::vector::Vector4f; | |||||
| use serde::{Deserialize, Serialize}; | |||||
| use specs::{Component, HashMapStorage}; | |||||
| #[derive(Clone, Debug, Serialize, Deserialize)] | |||||
| pub struct PlayerVisual { | |||||
| pub color: Vector4f, | |||||
| } | |||||
| impl Component for PlayerVisual { | |||||
| type Storage = HashMapStorage<Self>; | |||||
| } | |||||
| @@ -1,2 +1,9 @@ | |||||
| use glc::vector::Vector4f; | |||||
| use lazy_static::lazy_static; | |||||
| pub const UNIFORM_BUFFER_INDEX_CAMERA: gl::GLuint = 0; | pub const UNIFORM_BUFFER_INDEX_CAMERA: gl::GLuint = 0; | ||||
| pub const UNIFORM_BUFFER_INDEX_UNIFORM: gl::GLuint = 1; | pub const UNIFORM_BUFFER_INDEX_UNIFORM: gl::GLuint = 1; | ||||
| lazy_static! { | |||||
| pub static ref PLAYER_COLOR_DEFAULT: Vector4f = Vector4f::new(1.0, 1.0, 1.0, 0.1); | |||||
| } | |||||
| @@ -1,9 +1,10 @@ | |||||
| mod constants; | |||||
| mod error; | |||||
| mod misc; | |||||
| mod render; | |||||
| mod resources; | |||||
| mod systems; | |||||
| pub mod components; | |||||
| pub mod constants; | |||||
| pub mod error; | |||||
| pub mod misc; | |||||
| pub mod render; | |||||
| pub mod resources; | |||||
| pub mod systems; | |||||
| use specs::{Dispatcher, DispatcherBuilder, World}; | use specs::{Dispatcher, DispatcherBuilder, World}; | ||||
| @@ -50,16 +50,26 @@ fn run(vfs: Vfs) -> Result<(), Error> { | |||||
| } | } | ||||
| fn create_world(world: &mut World) { | fn create_world(world: &mut World) { | ||||
| use glc::vector::Vector2f; | |||||
| use glc::vector::{Vector2f, Vector4f}; | |||||
| use space_crush_app::{components::PlayerVisual, misc::PersistWorld}; | |||||
| use space_crush_common::{ | use space_crush_common::{ | ||||
| components::{Planet, Position, Ship, ShipType, Velocity}, | |||||
| misc::{PersistWorld, Persistence}, | |||||
| components::{Owned, Planet, Player, Position, Ship, ShipType, Velocity}, | |||||
| misc::Persistence, | |||||
| }; | }; | ||||
| use specs::{saveload::MarkedBuilder, Builder}; | use specs::{saveload::MarkedBuilder, Builder}; | ||||
| let player1 = world | |||||
| .create_entity() | |||||
| .with(Player {}) | |||||
| .with(PlayerVisual { | |||||
| color: Vector4f::new(0.0, 0.5, 1.0, 0.1), | |||||
| }) | |||||
| .build(); | |||||
| world | world | ||||
| .create_entity() | .create_entity() | ||||
| .marked::<<PersistWorld as Persistence>::Marker>() | .marked::<<PersistWorld as Persistence>::Marker>() | ||||
| .with(Owned { owner: player1 }) | |||||
| .with(Position { | .with(Position { | ||||
| pos: Vector2f::default(), | pos: Vector2f::default(), | ||||
| size: 500.0, | size: 500.0, | ||||
| @@ -74,9 +84,10 @@ fn create_world(world: &mut World) { | |||||
| world | world | ||||
| .create_entity() | .create_entity() | ||||
| .marked::<<PersistWorld as Persistence>::Marker>() | .marked::<<PersistWorld as Persistence>::Marker>() | ||||
| .with(Owned { owner: player1 }) | |||||
| .with(Position { | .with(Position { | ||||
| pos: Vector2f::new(250.0 * x, 250.0 * y), | pos: Vector2f::new(250.0 * x, 250.0 * y), | ||||
| size: 100.0, | |||||
| size: 30.0, | |||||
| }) | }) | ||||
| .with(Velocity { | .with(Velocity { | ||||
| dir: Vector2f::new(i as f32 - 1.0, 1.0).normalize(), | dir: Vector2f::new(i as f32 - 1.0, 1.0).normalize(), | ||||
| @@ -96,7 +107,8 @@ fn create_world(world: &mut World) { | |||||
| fn load_world(world: &mut World, path: &str) -> Result<bool, Error> { | fn load_world(world: &mut World, path: &str) -> Result<bool, Error> { | ||||
| use serde_json::de::{Deserializer, IoRead}; | use serde_json::de::{Deserializer, IoRead}; | ||||
| use space_crush_common::misc::{PersistWorld, Persistence, WorldHelper}; | |||||
| use space_crush_app::misc::PersistWorld; | |||||
| use space_crush_common::misc::{Persistence, WorldHelper}; | |||||
| PersistWorld::setup(world); | PersistWorld::setup(world); | ||||
| @@ -116,7 +128,8 @@ fn load_world(world: &mut World, path: &str) -> Result<bool, Error> { | |||||
| fn save_world(world: &mut World, path: &str) -> Result<(), Error> { | fn save_world(world: &mut World, path: &str) -> Result<(), Error> { | ||||
| use serde_json::Serializer; | use serde_json::Serializer; | ||||
| use space_crush_common::misc::{PersistWorld, WorldHelper}; | |||||
| use space_crush_app::misc::PersistWorld; | |||||
| use space_crush_common::misc::WorldHelper; | |||||
| let vfs = world.resource::<Vfs>()?; | let vfs = world.resource::<Vfs>()?; | ||||
| let mut file = vfs.join(path)?.create_file()?; | let mut file = vfs.join(path)?.create_file()?; | ||||
| @@ -6,4 +6,4 @@ mod world; | |||||
| pub use events::{Events, KeyboardEvent, MouseButton, MouseEvent, VirtualKeyCode, WindowEvent}; | pub use events::{Events, KeyboardEvent, MouseButton, MouseEvent, VirtualKeyCode, WindowEvent}; | ||||
| pub use text::{Text, TextCache, TextManager}; | pub use text::{Text, TextCache, TextManager}; | ||||
| pub use window::Window; | pub use window::Window; | ||||
| pub use world::WorldHelper; | |||||
| pub use world::{PersistWorld, WorldHelper}; | |||||
| @@ -5,10 +5,33 @@ use glc::{ | |||||
| shader::{Program, Shader, Type}, | shader::{Program, Shader, Type}, | ||||
| texture::{Data, FilterMag, FilterMin, Target, Texture, Wrap}, | texture::{Data, FilterMag, FilterMin, Target, Texture, Wrap}, | ||||
| }; | }; | ||||
| use space_crush_common::misc::Vfs; | |||||
| use specs::World; | |||||
| use space_crush_common::{ | |||||
| components::{Owned, Planet, Player, Position, Ship, Velocity}, | |||||
| misc::{Persistence, Vfs}, | |||||
| }; | |||||
| use specs::{saveload::SimpleMarker, World}; | |||||
| use crate::{components::PlayerVisual, Error}; | |||||
| /* PersistWorld */ | |||||
| pub struct PersistWorld; | |||||
| pub struct PersistWorldMarker; | |||||
| impl Persistence for PersistWorld { | |||||
| type Marker = SimpleMarker<PersistWorldMarker>; | |||||
| type Components = ( | |||||
| Position, | |||||
| Velocity, | |||||
| Planet, | |||||
| Ship, | |||||
| Owned, | |||||
| Player, | |||||
| PlayerVisual, | |||||
| ); | |||||
| } | |||||
| use crate::Error; | |||||
| /* WorldHelper */ | |||||
| pub trait WorldHelper { | pub trait WorldHelper { | ||||
| fn load_program<I>(&self, iter: I) -> Result<Program, Error> | fn load_program<I>(&self, iter: I) -> Result<Program, Error> | ||||
| @@ -1,16 +1,17 @@ | |||||
| use glc::{ | use glc::{ | ||||
| matrix::Matrix4f, | matrix::Matrix4f, | ||||
| misc::Bindable, | |||||
| misc::{BindGuard, Bindable}, | |||||
| shader::{Program, Type, Uniform}, | shader::{Program, Type, Uniform}, | ||||
| texture::Texture, | texture::Texture, | ||||
| vector::Vector4f, | vector::Vector4f, | ||||
| }; | }; | ||||
| use log::error; | use log::error; | ||||
| use space_crush_common::components::{Planet, Position}; | |||||
| use space_crush_common::components::{Owned, Planet, Position}; | |||||
| use specs::{prelude::*, ReadExpect, ReadStorage, System, World}; | use specs::{prelude::*, ReadExpect, ReadStorage, System, World}; | ||||
| use crate::{ | use crate::{ | ||||
| constants::{UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM}, | |||||
| components::PlayerVisual, | |||||
| constants::{PLAYER_COLOR_DEFAULT, UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM}, | |||||
| misc::WorldHelper, | misc::WorldHelper, | ||||
| resources::Geometry, | resources::Geometry, | ||||
| Error, | Error, | ||||
| @@ -19,7 +20,8 @@ use crate::{ | |||||
| pub struct Planets { | pub struct Planets { | ||||
| program: Program, | program: Program, | ||||
| texture: Texture, | texture: Texture, | ||||
| model_location: gl::GLint, | |||||
| location_model: gl::GLint, | |||||
| location_glow_color: gl::GLint, | |||||
| } | } | ||||
| impl Planets { | impl Planets { | ||||
| @@ -32,13 +34,11 @@ impl Planets { | |||||
| program.uniform_block_binding("Camera", UNIFORM_BUFFER_INDEX_CAMERA)?; | program.uniform_block_binding("Camera", UNIFORM_BUFFER_INDEX_CAMERA)?; | ||||
| program.uniform_block_binding("Global", UNIFORM_BUFFER_INDEX_UNIFORM)?; | program.uniform_block_binding("Global", UNIFORM_BUFFER_INDEX_UNIFORM)?; | ||||
| let glow_color = Vector4f::new(1.0, 1.0, 1.0, 0.1); | |||||
| let glow_color = Uniform::Vector4f(&glow_color); | |||||
| let model_location = program.uniform_location("uModel")?; | |||||
| let location_model = program.uniform_location("uModel")?; | |||||
| let location_glow_color = program.uniform_location("uGlowColor")?; | |||||
| program.bind(); | program.bind(); | ||||
| program.uniform("uTexture", Uniform::Texture(0))?; | program.uniform("uTexture", Uniform::Texture(0))?; | ||||
| program.uniform("uGlowColor", glow_color)?; | |||||
| program.unbind(); | program.unbind(); | ||||
| let texture = world.load_texture("resources/textures/planet01.png")?; | let texture = world.load_texture("resources/textures/planet01.png")?; | ||||
| @@ -46,7 +46,8 @@ impl Planets { | |||||
| Ok(Self { | Ok(Self { | ||||
| program, | program, | ||||
| texture, | texture, | ||||
| model_location, | |||||
| location_model, | |||||
| location_glow_color, | |||||
| }) | }) | ||||
| } | } | ||||
| } | } | ||||
| @@ -56,6 +57,8 @@ pub struct PlanetsData<'a> { | |||||
| geometry: ReadExpect<'a, Geometry>, | geometry: ReadExpect<'a, Geometry>, | ||||
| position: ReadStorage<'a, Position>, | position: ReadStorage<'a, Position>, | ||||
| planet: ReadStorage<'a, Planet>, | planet: ReadStorage<'a, Planet>, | ||||
| owned: ReadStorage<'a, Owned>, | |||||
| player_visual: ReadStorage<'a, PlayerVisual>, | |||||
| } | } | ||||
| impl<'a> System<'a> for Planets { | impl<'a> System<'a> for Planets { | ||||
| @@ -66,29 +69,43 @@ impl<'a> System<'a> for Planets { | |||||
| geometry, | geometry, | ||||
| position, | position, | ||||
| planet, | planet, | ||||
| owned, | |||||
| player_visual, | |||||
| } = data; | } = data; | ||||
| gl::enable(gl::BLEND); | gl::enable(gl::BLEND); | ||||
| gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); | gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); | ||||
| self.texture.bind(); | |||||
| self.program.bind(); | |||||
| let _guard = BindGuard::new(&self.program); | |||||
| let _guard = BindGuard::new(&self.texture); | |||||
| for (p, _) in (&position, &planet).join() { | |||||
| let x = p.pos.x; | |||||
| let y = p.pos.y; | |||||
| for (p, _, owned) in (&position, &planet, owned.maybe()).join() { | |||||
| let p_x = p.pos.x; | |||||
| let p_y = p.pos.y; | |||||
| let s = p.size; | let s = p.size; | ||||
| let c = match owned.and_then(|owned| player_visual.get(owned.owner)) { | |||||
| Some(pv) => &pv.color, | |||||
| None => &*PLAYER_COLOR_DEFAULT, | |||||
| }; | |||||
| let m = Matrix4f::new( | let m = Matrix4f::new( | ||||
| Vector4f::new(s, 0.0, 0.0, 0.0), | Vector4f::new(s, 0.0, 0.0, 0.0), | ||||
| Vector4f::new(0.0, s, 0.0, 0.0), | Vector4f::new(0.0, s, 0.0, 0.0), | ||||
| Vector4f::new(0.0, 0.0, s, 0.0), | Vector4f::new(0.0, 0.0, s, 0.0), | ||||
| Vector4f::new(x, y, 0.0, 1.0), | |||||
| Vector4f::new(p_x, p_y, 0.0, 1.0), | |||||
| ); | ); | ||||
| if let Err(err) = self | if let Err(err) = self | ||||
| .program | .program | ||||
| .uniform(self.model_location, Uniform::Matrix4f(&m)) | |||||
| .uniform(self.location_glow_color, Uniform::Vector4f(&c)) | |||||
| { | |||||
| error!("Error while updating glow color: {}", err); | |||||
| } | |||||
| if let Err(err) = self | |||||
| .program | |||||
| .uniform(self.location_model, Uniform::Matrix4f(&m)) | |||||
| { | { | ||||
| error!("Error while updating model matrix: {}", err); | error!("Error while updating model matrix: {}", err); | ||||
| } | } | ||||
| @@ -96,9 +113,6 @@ impl<'a> System<'a> for Planets { | |||||
| geometry.render_quad(); | geometry.render_quad(); | ||||
| } | } | ||||
| self.program.unbind(); | |||||
| self.texture.unbind(); | |||||
| gl::disable(gl::BLEND); | gl::disable(gl::BLEND); | ||||
| } | } | ||||
| } | } | ||||
| @@ -6,11 +6,12 @@ use glc::{ | |||||
| vector::Vector4f, | vector::Vector4f, | ||||
| }; | }; | ||||
| use log::error; | use log::error; | ||||
| use space_crush_common::components::{Position, Ship, ShipType, Velocity}; | |||||
| use space_crush_common::components::{Owned, Position, Ship, ShipType, Velocity}; | |||||
| use specs::{prelude::*, ReadExpect, ReadStorage, System, World}; | use specs::{prelude::*, ReadExpect, ReadStorage, System, World}; | ||||
| use crate::{ | use crate::{ | ||||
| constants::{UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM}, | |||||
| components::PlayerVisual, | |||||
| constants::{PLAYER_COLOR_DEFAULT, UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM}, | |||||
| misc::WorldHelper, | misc::WorldHelper, | ||||
| resources::Geometry, | resources::Geometry, | ||||
| Error, | Error, | ||||
| @@ -18,10 +19,11 @@ use crate::{ | |||||
| pub struct Ships { | pub struct Ships { | ||||
| program: Program, | program: Program, | ||||
| texture_fighter: Texture, | |||||
| texture_bomber: Texture, | texture_bomber: Texture, | ||||
| texture_fighter: Texture, | |||||
| texture_transporter: Texture, | texture_transporter: Texture, | ||||
| model_location: gl::GLint, | |||||
| location_model: gl::GLint, | |||||
| location_glow_color: gl::GLint, | |||||
| } | } | ||||
| impl Ships { | impl Ships { | ||||
| @@ -34,25 +36,24 @@ impl Ships { | |||||
| program.uniform_block_binding("Camera", UNIFORM_BUFFER_INDEX_CAMERA)?; | program.uniform_block_binding("Camera", UNIFORM_BUFFER_INDEX_CAMERA)?; | ||||
| program.uniform_block_binding("Global", UNIFORM_BUFFER_INDEX_UNIFORM)?; | 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")?; | |||||
| let location_model = program.uniform_location("uModel")?; | |||||
| let location_glow_color = program.uniform_location("uGlowColor")?; | |||||
| program.bind(); | program.bind(); | ||||
| program.uniform("uTexture", Uniform::Texture(0))?; | program.uniform("uTexture", Uniform::Texture(0))?; | ||||
| program.uniform("uGlowColor", glow_color)?; | |||||
| program.unbind(); | 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_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 texture_transporter = world.load_texture("resources/textures/ship_transporter.png")?; | ||||
| Ok(Self { | Ok(Self { | ||||
| program, | program, | ||||
| texture_fighter, | |||||
| texture_bomber, | texture_bomber, | ||||
| texture_fighter, | |||||
| texture_transporter, | texture_transporter, | ||||
| model_location, | |||||
| location_model, | |||||
| location_glow_color, | |||||
| }) | }) | ||||
| } | } | ||||
| } | } | ||||
| @@ -63,6 +64,8 @@ pub struct ShipsData<'a> { | |||||
| position: ReadStorage<'a, Position>, | position: ReadStorage<'a, Position>, | ||||
| velocity: ReadStorage<'a, Velocity>, | velocity: ReadStorage<'a, Velocity>, | ||||
| ship: ReadStorage<'a, Ship>, | ship: ReadStorage<'a, Ship>, | ||||
| owned: ReadStorage<'a, Owned>, | |||||
| player_visual: ReadStorage<'a, PlayerVisual>, | |||||
| } | } | ||||
| impl<'a> System<'a> for Ships { | impl<'a> System<'a> for Ships { | ||||
| @@ -74,6 +77,8 @@ impl<'a> System<'a> for Ships { | |||||
| position, | position, | ||||
| velocity, | velocity, | ||||
| ship, | ship, | ||||
| owned, | |||||
| player_visual, | |||||
| } = data; | } = data; | ||||
| gl::enable(gl::BLEND); | gl::enable(gl::BLEND); | ||||
| @@ -81,13 +86,18 @@ impl<'a> System<'a> for Ships { | |||||
| let _guard = BindGuard::new(&self.program); | let _guard = BindGuard::new(&self.program); | ||||
| for (p, v, ship) in (&position, &velocity, &ship).join() { | |||||
| for (p, v, ship, owned) in (&position, &velocity, &ship, owned.maybe()).join() { | |||||
| let _guard = match ship.type_ { | let _guard = match ship.type_ { | ||||
| ShipType::Fighter => BindGuard::new(&self.texture_fighter), | ShipType::Fighter => BindGuard::new(&self.texture_fighter), | ||||
| ShipType::Bomber => BindGuard::new(&self.texture_bomber), | ShipType::Bomber => BindGuard::new(&self.texture_bomber), | ||||
| ShipType::Transporter => BindGuard::new(&self.texture_transporter), | ShipType::Transporter => BindGuard::new(&self.texture_transporter), | ||||
| }; | }; | ||||
| let c = match owned.and_then(|owned| player_visual.get(owned.owner)) { | |||||
| Some(pv) => &pv.color, | |||||
| None => &*PLAYER_COLOR_DEFAULT, | |||||
| }; | |||||
| let p_x = p.pos.x; | let p_x = p.pos.x; | ||||
| let p_y = p.pos.y; | let p_y = p.pos.y; | ||||
| let d_x = v.dir.x; | let d_x = v.dir.x; | ||||
| @@ -103,7 +113,14 @@ impl<'a> System<'a> for Ships { | |||||
| if let Err(err) = self | if let Err(err) = self | ||||
| .program | .program | ||||
| .uniform(self.model_location, Uniform::Matrix4f(&m)) | |||||
| .uniform(self.location_glow_color, Uniform::Vector4f(&c)) | |||||
| { | |||||
| error!("Error while updating glow color: {}", err); | |||||
| } | |||||
| if let Err(err) = self | |||||
| .program | |||||
| .uniform(self.location_model, Uniform::Matrix4f(&m)) | |||||
| { | { | ||||
| error!("Error while updating model matrix: {}", err); | error!("Error while updating model matrix: {}", err); | ||||
| } | } | ||||
| @@ -1,9 +1,13 @@ | |||||
| mod owned; | |||||
| mod planet; | mod planet; | ||||
| mod player; | |||||
| mod position; | mod position; | ||||
| mod ship; | mod ship; | ||||
| mod velocity; | mod velocity; | ||||
| pub use owned::Owned; | |||||
| pub use planet::Planet; | pub use planet::Planet; | ||||
| pub use player::Player; | |||||
| pub use position::Position; | pub use position::Position; | ||||
| pub use ship::{Ship, Type as ShipType}; | pub use ship::{Ship, Type as ShipType}; | ||||
| pub use velocity::Velocity; | pub use velocity::Velocity; | ||||
| @@ -0,0 +1,46 @@ | |||||
| use serde::{Deserialize, Serialize}; | |||||
| use specs::{ | |||||
| error::NoError, | |||||
| saveload::{ConvertSaveload, Marker}, | |||||
| Component, Entity, VecStorage, | |||||
| }; | |||||
| #[derive(Clone, Debug)] | |||||
| pub struct Owned { | |||||
| pub owner: Entity, | |||||
| } | |||||
| #[derive(Serialize, Deserialize)] | |||||
| pub struct OwnedData<M> { | |||||
| pub owner: M, | |||||
| } | |||||
| impl Component for Owned { | |||||
| type Storage = VecStorage<Self>; | |||||
| } | |||||
| impl<M> ConvertSaveload<M> for Owned | |||||
| where | |||||
| for<'de> M: Marker + Serialize + Deserialize<'de>, | |||||
| { | |||||
| type Data = OwnedData<M>; | |||||
| type Error = NoError; | |||||
| fn convert_into<F>(&self, mut ids: F) -> Result<Self::Data, Self::Error> | |||||
| where | |||||
| F: FnMut(Entity) -> Option<M>, | |||||
| { | |||||
| let owner = ids(self.owner).unwrap(); | |||||
| Ok(OwnedData { owner }) | |||||
| } | |||||
| fn convert_from<F>(data: Self::Data, mut ids: F) -> Result<Self, Self::Error> | |||||
| where | |||||
| F: FnMut(M) -> Option<Entity>, | |||||
| { | |||||
| let owner = ids(data.owner).unwrap(); | |||||
| Ok(Owned { owner }) | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,9 @@ | |||||
| use serde::{Deserialize, Serialize}; | |||||
| use specs::{Component, NullStorage}; | |||||
| #[derive(Clone, Debug, Default, Serialize, Deserialize)] | |||||
| pub struct Player {} | |||||
| impl Component for Player { | |||||
| type Storage = NullStorage<Self>; | |||||
| } | |||||
| @@ -1,6 +1,7 @@ | |||||
| use specs::{Dispatcher as Inner, DispatcherBuilder, World}; | |||||
| use specs::{Dispatcher as Inner, DispatcherBuilder, World, WorldExt}; | |||||
| use crate::{ | use crate::{ | ||||
| components::Player, | |||||
| resources::Global, | resources::Global, | ||||
| systems::{Movement, Process}, | systems::{Movement, Process}, | ||||
| }; | }; | ||||
| @@ -13,6 +14,8 @@ impl<'a, 'b> Dispatcher<'a, 'b> { | |||||
| pub fn new(world: &mut World) -> Self { | pub fn new(world: &mut World) -> Self { | ||||
| world.insert(Global::default()); | world.insert(Global::default()); | ||||
| world.register::<Player>(); | |||||
| let mut dispatcher = DispatcherBuilder::new() | let mut dispatcher = DispatcherBuilder::new() | ||||
| .with(Process::default(), "process", &[]) | .with(Process::default(), "process", &[]) | ||||
| .with(Movement::default(), "movement", &[]) | .with(Movement::default(), "movement", &[]) | ||||
| @@ -1,9 +1,7 @@ | |||||
| mod log; | mod log; | ||||
| mod persistence; | |||||
| mod vfs; | mod vfs; | ||||
| mod world; | mod world; | ||||
| pub use self::log::init as init_logger; | pub use self::log::init as init_logger; | ||||
| pub use self::vfs::{Vfs, VfsError}; | pub use self::vfs::{Vfs, VfsError}; | ||||
| pub use persistence::PersistWorld; | |||||
| pub use world::{Persistence, WorldHelper}; | pub use world::{Persistence, WorldHelper}; | ||||
| @@ -1,13 +0,0 @@ | |||||
| use specs::saveload::SimpleMarker; | |||||
| use crate::components::{Planet, Position, Ship, Velocity}; | |||||
| use super::Persistence; | |||||
| pub struct PersistWorld; | |||||
| pub struct PersistWorldMarker; | |||||
| impl Persistence for PersistWorld { | |||||
| type Marker = SimpleMarker<PersistWorldMarker>; | |||||
| type Components = (Position, Velocity, Planet, Ship); | |||||
| } | |||||
| @@ -1,14 +1,11 @@ | |||||
| use std::any::type_name; | use std::any::type_name; | ||||
| use serde::{ | |||||
| de::{DeserializeOwned, Deserializer}, | |||||
| ser::{Serialize, Serializer}, | |||||
| }; | |||||
| use serde::{de::Deserializer, ser::Serializer}; | |||||
| use shred::{Fetch, FetchMut, Resource}; | use shred::{Fetch, FetchMut, Resource}; | ||||
| use shrev::{Event, EventChannel, ReaderId}; | use shrev::{Event, EventChannel, ReaderId}; | ||||
| use specs::{ | use specs::{ | ||||
| error::NoError, | error::NoError, | ||||
| saveload::{DeserializeComponents, Marker, SerializeComponents}, | |||||
| saveload::{ConvertSaveload, DeserializeComponents, Marker, SerializeComponents}, | |||||
| Component, Entities, ReadStorage, World, WorldExt, Write, WriteStorage, | Component, Entities, ReadStorage, World, WorldExt, Write, WriteStorage, | ||||
| }; | }; | ||||
| @@ -133,16 +130,31 @@ macro_rules! define_persistence_components { | |||||
| where | where | ||||
| M: Marker, | M: Marker, | ||||
| M::Allocator: Default, | M::Allocator: Default, | ||||
| $($T: Component + Serialize + DeserializeOwned + Clone,)+ | |||||
| $($T: Component + ConvertSaveload<M, Error = NoError>,)+ | |||||
| { | { | ||||
| fn serialize<S>(world: &World, serializer: S) -> Result<(), S::Error> | fn serialize<S>(world: &World, serializer: S) -> Result<(), S::Error> | ||||
| where | where | ||||
| S: Serializer, | S: Serializer, | ||||
| { | { | ||||
| let (entities, marker, $($T,)+) = | |||||
| world.system_data::<(Entities, ReadStorage<M>, $(ReadStorage<$T>,)+)>(); | |||||
| let ( | |||||
| entities, | |||||
| mut marker, | |||||
| mut allocator, | |||||
| $($T,)+ | |||||
| ) = world.system_data::<( | |||||
| Entities, | |||||
| WriteStorage<M>, | |||||
| Write<M::Allocator>, | |||||
| $(ReadStorage<$T>, | |||||
| )+)>(); | |||||
| SerializeComponents::<NoError, M>::serialize(&($($T,)+), &entities, &marker, serializer)?; | |||||
| SerializeComponents::<NoError, M>::serialize_recursive | |||||
| (&($($T,)+), | |||||
| &entities, | |||||
| &mut marker, | |||||
| &mut allocator, | |||||
| serializer, | |||||
| )?; | |||||
| Ok(()) | Ok(()) | ||||
| } | } | ||||
| @@ -151,7 +163,12 @@ macro_rules! define_persistence_components { | |||||
| where | where | ||||
| D: Deserializer<'de>, | D: Deserializer<'de>, | ||||
| { | { | ||||
| let (entities, mut marker, mut allocator, $($T,)+) = world.system_data::<( | |||||
| let ( | |||||
| entities, | |||||
| mut marker, | |||||
| mut allocator, | |||||
| $($T,)+ | |||||
| ) = world.system_data::<( | |||||
| Entities, | Entities, | ||||
| WriteStorage<M>, | WriteStorage<M>, | ||||
| Write<M::Allocator>, | Write<M::Allocator>, | ||||