├── .gitignore ├── src ├── atlas.png ├── atlas.xcf ├── components │ ├── expiry.rs │ ├── team.rs │ ├── caster.rs │ ├── player.rs │ ├── projectile.rs │ ├── emitter.rs │ ├── mod.rs │ ├── health.rs │ ├── make_entities.rs │ ├── spawn_list.rs │ ├── melee_damage.rs │ ├── render.rs │ ├── ai.rs │ └── physics.rs ├── basic.frag ├── uv.frag ├── basic.vert ├── uv.vert ├── how.md ├── particles.rs ├── main.rs ├── manifest.rs ├── victory.rs ├── tutorial.rs ├── spawner.rs ├── spell_menu.rs ├── renderer.rs ├── kgui.rs ├── rendererUV.rs ├── kimg.rs ├── actual_entity_definitions.rs ├── application.rs ├── entity.rs ├── entity_definitions.rs ├── kmath.rs ├── spell.rs └── wave_game.rs ├── .cargo └── config.toml ├── Cargo.toml ├── license.md ├── README.md └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /src/atlas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThePJB/wizrad/HEAD/src/atlas.png -------------------------------------------------------------------------------- /src/atlas.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThePJB/wizrad/HEAD/src/atlas.xcf -------------------------------------------------------------------------------- /src/components/expiry.rs: -------------------------------------------------------------------------------- 1 | #[derive(Clone)] 2 | pub struct Expiry { 3 | pub expiry: f32, 4 | } -------------------------------------------------------------------------------- /src/components/team.rs: -------------------------------------------------------------------------------- 1 | use crate::kmath::*; 2 | 3 | #[derive(Clone)] 4 | pub struct Team { 5 | pub team: u32, 6 | } -------------------------------------------------------------------------------- /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [target.x86_64-unknown-linux-musl] 2 | linker = "rust-lld" 3 | rustflags = ["-C", "target-feature=+crt-static"] -------------------------------------------------------------------------------- /src/basic.frag: -------------------------------------------------------------------------------- 1 | in vec3 vert_colour; 2 | 3 | out vec4 frag_colour; 4 | 5 | void main() { 6 | frag_colour = vec4(vert_colour, 1.0); 7 | } -------------------------------------------------------------------------------- /src/components/caster.rs: -------------------------------------------------------------------------------- 1 | #[derive(Clone)] 2 | pub struct Caster { 3 | pub mana: f32, 4 | pub mana_max: f32, 5 | pub mana_regen: f32, 6 | pub last_cast: f32, 7 | } -------------------------------------------------------------------------------- /src/components/player.rs: -------------------------------------------------------------------------------- 1 | use crate::spell::*; 2 | 3 | #[derive(Clone)] 4 | pub struct Player { 5 | pub spellbook: Vec, 6 | pub spell_cursor: i32, 7 | pub speed: f32, 8 | pub kills: i32, 9 | } -------------------------------------------------------------------------------- /src/components/projectile.rs: -------------------------------------------------------------------------------- 1 | #[derive(Clone)] 2 | pub struct Projectile { 3 | pub source: u32, 4 | pub damage: f32, 5 | pub aoe: f32, 6 | pub splat_duration: f32, 7 | pub lifesteal_percent: f32, 8 | } -------------------------------------------------------------------------------- /src/components/emitter.rs: -------------------------------------------------------------------------------- 1 | use crate::kmath::*; 2 | 3 | #[derive(Clone)] 4 | pub struct Emitter { 5 | pub interval: f32, 6 | pub last: f32, 7 | pub colour: Vec3, 8 | pub size: Vec2, 9 | pub speed: f32, 10 | pub lifespan: f32, 11 | } -------------------------------------------------------------------------------- /src/components/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod ai; 2 | pub mod caster; 3 | pub mod team; 4 | pub mod health; 5 | pub mod projectile; 6 | pub mod render; 7 | pub mod expiry; 8 | pub mod melee_damage; 9 | pub mod emitter; 10 | pub mod player; 11 | pub mod physics; 12 | pub mod spawn_list; 13 | pub mod make_entities; -------------------------------------------------------------------------------- /src/uv.frag: -------------------------------------------------------------------------------- 1 | in vec3 vert_colour; 2 | in vec2 uv; 3 | 4 | out vec4 frag_colour; 5 | 6 | uniform sampler2D atlas; 7 | 8 | void main() { 9 | // frag_colour = vec4(1.0, 0.0, 0.0, 1.0); 10 | // frag_colour = vec4(uv.x, 0.0, uv.y, 1.0); 11 | frag_colour = texture(atlas, uv); 12 | // frag_colour = vec4(vert_colour, 1.0); 13 | } -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wizrad" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | glow = "0.11.0" 10 | glutin = "0.28" 11 | winit = "0.26.1" 12 | 13 | serde_json = "1.0.59" 14 | serde = { version = "1.0.117", features = ["derive"] } 15 | 16 | png = "0.17.1" 17 | palette = "0.2.1" 18 | assert_hex = "0.2.2" 19 | 20 | itertools = "0.10.3" 21 | 22 | ordered-float = "2.0" -------------------------------------------------------------------------------- /src/components/health.rs: -------------------------------------------------------------------------------- 1 | use crate::manifest::*; 2 | 3 | #[derive(Clone)] 4 | pub struct Health { 5 | pub current: f32, 6 | pub max: f32, 7 | pub regen: f32, 8 | pub invul_time: f32, 9 | } 10 | 11 | impl Health { 12 | pub fn damage(&mut self, amount: f32, t: f32) -> bool { 13 | if t - self.invul_time > INVUL_TIME { 14 | if amount > INVUL_DAMAGE_THRESHOLD { 15 | self.invul_time = t; 16 | } 17 | self.current -= amount; 18 | } 19 | self.current <= 0.0 20 | } 21 | } -------------------------------------------------------------------------------- /src/components/make_entities.rs: -------------------------------------------------------------------------------- 1 | use crate::kgui::FrameInputState; 2 | use crate::kmath::*; 3 | use crate::entity::*; 4 | use crate::wave_game::*; 5 | // MakeEntitiesOnDamage, fn ptr that takes like amount of damage, position, returns a vec of entities 6 | 7 | #[derive(Clone)] 8 | pub struct MakeEntitiesOnDamage { 9 | pub acc: f32, 10 | pub thresh: f32, 11 | pub f: fn(wg: &mut WaveGame, inputs: &FrameInputState, id: u32, new_entities: &mut Vec), 12 | } 13 | 14 | #[derive(Clone)] 15 | pub struct MakeEntitiesOnDeath { 16 | pub f: fn(wg: &mut WaveGame, inputs: &FrameInputState, id: u32, new_entities: &mut Vec), 17 | } -------------------------------------------------------------------------------- /src/basic.vert: -------------------------------------------------------------------------------- 1 | layout (location = 0) in vec3 in_pos; 2 | layout (location = 1) in vec3 in_colour; 3 | 4 | // uniform mat4 projection; 5 | const mat4 projection = mat4( 6 | 2, 0, 0, 0, 7 | 0, -2, 0, 0, 8 | 0, 0, -0.001, 0, 9 | -1, 1, 1, 1 10 | ); 11 | // mat4 projection = [ 12 | // 2, 0, 0, -1, 13 | // 0, -2, 0, 1, 14 | // 0, 0, -0.001, 1, 15 | // 0, 0, 0, 1, 16 | // ]; 17 | // const mat4 projection = mat4( 18 | // 1, 0, 0, 0, 19 | // 0, 1, 0, 0, 20 | // 0, 0, 1, 0, 21 | // 0, 0, 0, 1 22 | // ); 23 | 24 | out vec3 vert_colour; 25 | 26 | void main() { 27 | vert_colour = in_colour; 28 | gl_Position = projection * vec4(in_pos, 1.0); 29 | } -------------------------------------------------------------------------------- /src/components/spawn_list.rs: -------------------------------------------------------------------------------- 1 | use crate::actual_entity_definitions::*; 2 | use crate::entity::*; 3 | use crate::kmath::*; 4 | 5 | #[derive(Clone)] 6 | pub struct SpawnList { 7 | pub t: f32, 8 | pub list: Vec<(f32, Box)>, 9 | } 10 | 11 | impl SpawnList { 12 | pub fn builder() -> SpawnList { 13 | SpawnList { 14 | t: 0.0, 15 | list: Vec::new(), 16 | } 17 | } 18 | 19 | pub fn spawn_entity(&mut self, e: Entity) { 20 | self.list.push((self.t, Box::new(e))); 21 | } 22 | 23 | pub fn wait(&mut self, amount: f32) { 24 | self.t += amount; 25 | } 26 | 27 | pub fn build(&mut self) { 28 | self.t = 0.0; 29 | } 30 | } -------------------------------------------------------------------------------- /src/uv.vert: -------------------------------------------------------------------------------- 1 | layout (location = 0) in vec3 in_pos; 2 | layout (location = 1) in vec3 in_colour; 3 | layout (location = 2) in vec2 in_uv; 4 | 5 | // uniform mat4 projection; 6 | const mat4 projection = mat4( 7 | 2, 0, 0, 0, 8 | 0, -2, 0, 0, 9 | 0, 0, -0.001, 0, 10 | -1, 1, 1, 1 11 | ); 12 | // mat4 projection = [ 13 | // 2, 0, 0, -1, 14 | // 0, -2, 0, 1, 15 | // 0, 0, -0.001, 1, 16 | // 0, 0, 0, 1, 17 | // ]; 18 | // const mat4 projection = mat4( 19 | // 1, 0, 0, 0, 20 | // 0, 1, 0, 0, 21 | // 0, 0, 1, 0, 22 | // 0, 0, 0, 1 23 | // ); 24 | 25 | out vec3 vert_colour; 26 | out vec2 uv; 27 | 28 | void main() { 29 | vert_colour = in_colour; 30 | uv = in_uv; 31 | gl_Position = projection * vec4(in_pos, 1.0); 32 | } -------------------------------------------------------------------------------- /src/how.md: -------------------------------------------------------------------------------- 1 | # What is a game 2 | * Simulation with discrete timesteps (frames) 3 | * Store some state (99% entities and then some timers, bools for menu etc) 4 | ## Every frame 5 | * if supposed to show spell menu, show spell menu 6 | * ... 7 | * if player pressed w, set velocity 8 | * ... 9 | * AIs move toward nearest enemy 10 | * AIs shoot at nearest enemy 11 | * ... 12 | * move entities according to their velocity 13 | * compute list of collisions 14 | * move entities back according to collisions 15 | * move entities back according to leaving arena 16 | * now update velocities based on the final position -- important 17 | * ... 18 | * handle projectile impacts (deal out damage, mark projectiles for deletion) 19 | * ... 20 | * remove everything marked for deletion 21 | * draw everything -------------------------------------------------------------------------------- /src/components/melee_damage.rs: -------------------------------------------------------------------------------- 1 | use crate::components::physics::CollisionEvent; 2 | use crate::wave_game::*; 3 | use crate::manifest::*; 4 | 5 | #[derive(Clone)] 6 | pub struct MeleeDamage { 7 | pub amount: f32, 8 | } 9 | 10 | impl WaveGame { 11 | pub fn resolve_melee_damage(&mut self, collisions: &[CollisionEvent], t: f32) { 12 | for ce in collisions { 13 | if let Some(md) = self.melee_damage.get(&ce.subject) { 14 | if self.team.contains_key(&ce.subject) && self.team.contains_key(&ce.object) 15 | && self.team.get(&ce.subject).unwrap().team != self.team.get(&ce.object).unwrap().team { 16 | if let Some(obj_health) = self.health.get_mut(&ce.object) { 17 | obj_health.damage(md.amount, t); 18 | } 19 | } 20 | } 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /src/particles.rs: -------------------------------------------------------------------------------- 1 | use crate::kmath::*; 2 | use crate::renderer::*; 3 | 4 | pub struct Particle { 5 | pub expiry: f32, 6 | pub velocity: Vec2, 7 | pub rect: Rect, 8 | pub colour: Vec3, 9 | } 10 | 11 | pub struct ParticleSystem { 12 | pub particles: Vec, 13 | } 14 | 15 | impl ParticleSystem { 16 | pub fn add_particle(&mut self, p: Particle) { 17 | self.particles.push(p); 18 | } 19 | 20 | pub fn update(&mut self, t: f32, dt: f32) { 21 | self.particles.retain(|p| p.expiry > t); 22 | 23 | for particle in self.particles.iter_mut() { 24 | particle.rect.x += particle.velocity.x * dt; 25 | particle.rect.y += particle.velocity.y * dt; 26 | } 27 | } 28 | 29 | pub fn draw(&self, buf: &mut TriangleBuffer) { 30 | for particle in self.particles.iter() { 31 | buf.draw_rect(particle.rect, particle.colour, 100.0); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /license.md: -------------------------------------------------------------------------------- 1 | Copyright 2022 kennoath 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | mod renderer; 2 | mod rendererUV; 3 | mod kimg; 4 | mod kmath; 5 | mod application; 6 | mod manifest; 7 | mod kgui; 8 | mod components; 9 | mod particles; 10 | mod entity_definitions; 11 | mod actual_entity_definitions; 12 | mod entity; 13 | mod spell; 14 | mod spawner; 15 | mod spell_menu; 16 | 17 | mod wave_game; 18 | mod tutorial; 19 | mod victory; 20 | 21 | use application::*; 22 | use glutin::event::{Event, WindowEvent}; 23 | use glutin::event_loop::ControlFlow; 24 | use std::env; 25 | 26 | 27 | 28 | 29 | fn main() { 30 | env::set_var("RUST_BACKTRACE", "1"); 31 | 32 | let event_loop = glutin::event_loop::EventLoop::new(); 33 | let mut application = Application::new(&event_loop); 34 | 35 | event_loop.run(move |event, _, control_flow| { 36 | application.handle_event(&event); 37 | match event { 38 | Event::LoopDestroyed | 39 | Event::WindowEvent {event: WindowEvent::CloseRequested, ..} 40 | => { 41 | *control_flow = ControlFlow::Exit; 42 | }, 43 | _ => (), 44 | } 45 | }); 46 | } -------------------------------------------------------------------------------- /src/manifest.rs: -------------------------------------------------------------------------------- 1 | pub const ICON_FIRE: i32 = 0; 2 | pub const ICON_MAGIC_MISSILE: i32 = 1; 3 | pub const ICON_PULSE: i32 = 2; 4 | pub const ICON_BLOOD_MISSILE: i32 = 3; 5 | pub const ICON_BLOOD_ACOLYTES: i32 = 4; 6 | pub const ICON_SUMMON_ZERGS: i32 = 5; 7 | pub const ICON_FIREBALL: i32 = 6; 8 | pub const ICON_WATER: i32 = 7; 9 | pub const ICON_HOMING: i32 = 8; 10 | pub const ICON_FIRESTORM: i32 = 9; 11 | pub const ICON_HEALING: i32 = 10; 12 | pub const ICON_DEATHRAY: i32 = 10; 13 | 14 | pub const BOOK_LEFT: i32 = 20; 15 | pub const BOOK_RIGHT: i32 = 21; 16 | pub const VESSEL: i32 = 22; 17 | 18 | pub const TUT_WASD: i32 = 40; 19 | pub const TUT_DODGE: i32 = 41; 20 | 21 | pub const WINNER: i32 = 42; 22 | 23 | pub const TUT_QE: i32 = 60; 24 | pub const TUT_BROWSE: i32 = 61; 25 | 26 | pub const TUT_LMB: i32 = 80; 27 | pub const TUT_CAST: i32 = 81; 28 | 29 | pub const TUT_R: i32 = 100; 30 | pub const TUT_RESET: i32 = 101; 31 | 32 | pub const ATLAS_W: i32 = 20; 33 | pub const ATLAS_H: i32 = 20; 34 | 35 | pub const TEAM_PLAYER: u32 = 0; 36 | pub const TEAM_ENEMIES: u32 = 1; 37 | 38 | pub const INVUL_TIME: f32 = 0.2; 39 | pub const INVUL_DAMAGE_THRESHOLD: f32 = 10.0; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # How to compile / run 2 | * There shouldnt be any dependancies other than a rust toolchian 3 | * Probably get rustup and use that to install cargo etc. 4 | * Might need nightly rust (`rustup default nightly`?) 5 | * Im sorry, the only thing nightly is for is casting arrays of float to arrays of u8 for openGL which shouldnt be so hard but it is 6 | * cargo run --release 7 | 8 | # How to play 9 | * WASD movement 10 | * QE flip through spellbook 11 | * left click to cast current spell 12 | * Escape quit, R reset 13 | 14 | <<<<<<< HEAD 15 | 16 | it sucks specifying events, conditions, actions. 17 | have events: condition fn ptr, action: e.g. make events 18 | triggers can let you capture context I spose 19 | 20 | e.g. if player hasnt got 2 spells: spell menu 21 | if player has got 2 spells: start wave1 portal, insert dead portal event 22 | if wave1 portal is dead: 23 | 24 | 25 | its gettin there 26 | probably if spawnlist is done 27 | 28 | event system is actually really good. closeures are fine if they are fn ptrs. mm segregated state, composition 29 | no capture but its fine for those global things 30 | 31 | 32 | 33 | maybe spells could be function pointers 34 | ======= 35 | ints for entities would make things much better 36 | >>>>>>> continuous 37 | -------------------------------------------------------------------------------- /src/victory.rs: -------------------------------------------------------------------------------- 1 | use crate::kgui::*; 2 | use crate::kmath::*; 3 | use crate::application::*; 4 | use crate::manifest::*; 5 | use crate::wave_game::*; 6 | use crate::renderer::*; 7 | use crate::rendererUV::*; 8 | 9 | pub struct Victory { 10 | pub t: f32, 11 | } 12 | 13 | impl Scene for Victory { 14 | fn handle_signal(&mut self, signal: SceneSignal) -> SceneOutcome { 15 | SceneOutcome::None 16 | } 17 | 18 | fn frame(&mut self, inputs: FrameInputState) -> (SceneOutcome, TriangleBuffer, Option) { 19 | let mut buf = TriangleBuffer::new(inputs.screen_rect); 20 | let mut buf_uv = TriangleBufferUV::new(inputs.screen_rect, ATLAS_W, ATLAS_H); 21 | let info_pane = inputs.screen_rect.dilate(-0.3).fit_center_square(); 22 | 23 | self.t += inputs.dt as f32; 24 | 25 | buf.draw_rect(inputs.screen_rect, Vec3::new(0.0, 0.0, 0.0), 1.0); 26 | buf_uv.draw_sprite(info_pane, WINNER, 2.0); 27 | 28 | if self.t > 0.5 && inputs.events.iter().any(|e| match e { 29 | KEvent::MouseLeft(false) => true, 30 | KEvent::Keyboard(_, false) => true, 31 | _ => false, 32 | }) { 33 | return (SceneOutcome::Push(Box::new(WaveGame::new(inputs.t as f32))), buf, Some(buf_uv)); 34 | } 35 | 36 | (SceneOutcome::None, buf, Some(buf_uv)) 37 | } 38 | } -------------------------------------------------------------------------------- /src/tutorial.rs: -------------------------------------------------------------------------------- 1 | use crate::kgui::*; 2 | use crate::kmath::*; 3 | use crate::application::*; 4 | use crate::manifest::*; 5 | use crate::renderer::*; 6 | use crate::rendererUV::*; 7 | 8 | pub struct Tutorial { 9 | 10 | } 11 | 12 | impl Scene for Tutorial { 13 | fn handle_signal(&mut self, signal: SceneSignal) -> SceneOutcome { 14 | SceneOutcome::None 15 | } 16 | 17 | fn frame(&mut self, inputs: FrameInputState) -> (SceneOutcome, TriangleBuffer, Option) { 18 | let mut buf = TriangleBuffer::new(inputs.screen_rect); 19 | let mut buf_uv = TriangleBufferUV::new(inputs.screen_rect, ATLAS_W, ATLAS_H); 20 | let info_pane = inputs.screen_rect.dilate(-0.3).fit_aspect_ratio(2.0 / 3.0); 21 | 22 | buf.draw_rect(inputs.screen_rect, Vec3::new(0.0, 0.0, 0.0), 1.0); 23 | buf_uv.draw_sprite(info_pane.grid_child(0, 0, 2, 3), TUT_WASD, 2.0); 24 | buf_uv.draw_sprite(info_pane.grid_child(1, 0, 2, 3), TUT_DODGE, 2.0); 25 | buf_uv.draw_sprite(info_pane.grid_child(0, 1, 2, 3), TUT_QE, 2.0); 26 | buf_uv.draw_sprite(info_pane.grid_child(1, 1, 2, 3), TUT_BROWSE, 2.0); 27 | buf_uv.draw_sprite(info_pane.grid_child(0, 2, 2, 3), TUT_LMB, 2.0); 28 | buf_uv.draw_sprite(info_pane.grid_child(1, 2, 2, 3), TUT_CAST, 2.0); 29 | 30 | if inputs.events.iter().any(|e| match e { 31 | KEvent::Keyboard(_, false) => true, 32 | KEvent::MouseLeft(false) => true, 33 | _ => false, 34 | }) { 35 | return (SceneOutcome::Pop(SceneSignal::JustPop), buf, Some(buf_uv)); 36 | } 37 | 38 | (SceneOutcome::None, buf, Some(buf_uv)) 39 | } 40 | } -------------------------------------------------------------------------------- /src/spawner.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use crate::kgui::*; 3 | use crate::kmath::*; 4 | use crate::entity::*; 5 | 6 | pub struct Spawner { 7 | spawner_t: f64, 8 | entity_counter: u32, 9 | entities: HashMap, 10 | intervals: HashMap, 11 | // interval min times etc 12 | next_spawns: HashMap, 13 | } 14 | 15 | pub fn enemy_position(seed: u32) -> Vec2 { 16 | let level_min = -19.5; 17 | let level_max = 19.5; 18 | 19 | match khash(seed * 123415) % 4 { 20 | 0 => Vec2::new(level_min, kuniform(seed * 138971377, level_min, level_max)), 21 | 1 => Vec2::new(level_max, kuniform(seed * 138971377, level_min, level_max)), 22 | 2 => Vec2::new(kuniform(seed * 138971377, level_min, level_max), level_min), 23 | 3 => Vec2::new(kuniform(seed * 138971377, level_min, level_max), level_max), 24 | _ => panic!("unreachable"), 25 | } 26 | } 27 | 28 | impl Spawner { 29 | pub fn new() -> Spawner { 30 | Spawner { 31 | spawner_t: 0.0, 32 | entity_counter: 0, 33 | entities: HashMap::new(), 34 | intervals: HashMap::new(), 35 | next_spawns: HashMap::new(), 36 | } 37 | } 38 | 39 | pub fn add_spawn_entity(&mut self, entity: Entity, interval: f32) { 40 | self.entities.insert(self.entity_counter, entity); 41 | self.intervals.insert(self.entity_counter, interval); 42 | self.next_spawns.insert(self.entity_counter, interval); 43 | 44 | self.entity_counter += 1; 45 | } 46 | 47 | pub fn frame(&mut self, inputs: &FrameInputState) -> Option { 48 | self.spawner_t += inputs.dt; 49 | for (id, next_spawn) in self.next_spawns.iter_mut() { 50 | if self.spawner_t as f32 > *next_spawn { 51 | *next_spawn += self.intervals.get(id).unwrap(); 52 | return Some(self.entities.get(id).unwrap().clone().with_position(enemy_position(inputs.seed))); 53 | } 54 | } 55 | None 56 | } 57 | } -------------------------------------------------------------------------------- /src/spell_menu.rs: -------------------------------------------------------------------------------- 1 | use crate::spell::*; 2 | use crate::kmath::*; 3 | use crate::kgui::*; 4 | use crate::renderer::*; 5 | use crate::rendererUV::*; 6 | 7 | pub struct SpellMenu { 8 | click_after: f32, 9 | choices: [Spell; 3], 10 | } 11 | 12 | fn shuffle_vec(vec: &mut Vec, mut seed: u32) { 13 | for i in 0..vec.len() { 14 | seed = khash(seed); 15 | let swap_idx = i + (seed % (vec.len() - i) as u32) as usize; 16 | vec.swap(i, swap_idx); 17 | } 18 | } 19 | 20 | impl SpellMenu { 21 | pub fn new(seed: u32, current_spells: &[Spell], t: f32) -> SpellMenu { 22 | let mut spell_list = vec![ 23 | Spell::Missile, 24 | Spell::Fireball, 25 | Spell::ConeFlames, 26 | Spell::Pulse, 27 | Spell::Firestorm, 28 | Spell::Lifesteal, 29 | Spell::SummonBloodcasters, 30 | Spell::SummonRushers, 31 | Spell::Homing, 32 | Spell::Healing, 33 | ]; 34 | 35 | spell_list.retain(|s| !current_spells.contains(s)); 36 | shuffle_vec(&mut spell_list, seed); 37 | 38 | SpellMenu { 39 | choices: spell_list[0..3].try_into().unwrap(), 40 | click_after: t + 0.3, 41 | } 42 | 43 | } 44 | 45 | pub fn frame(&self, inputs: &FrameInputState, buf: &mut TriangleBuffer, buf_uv: &mut TriangleBufferUV) -> Option { 46 | 47 | let spell_menu = inputs.screen_rect.dilate(-0.35).fit_aspect_ratio(3.0);//.translate(Vec2::new(0.0, 0.2)); 48 | // buf.draw_rect(spell_menu, Vec3::new(0.2, 0.2, 0.2), 15.0); 49 | for i in 0..3 { 50 | let btn_rect = spell_menu.grid_child(i, 0, 3, 1).dilate(-0.01); 51 | buf.draw_rect(btn_rect, Vec3::new(0.1, 0.1, 0.1), 25.0); 52 | buf.draw_rect(btn_rect.dilate(-0.01), Vec3::new(0.3, 0.3, 0.3), 25.5); 53 | let spell_rect = btn_rect.dilate(-0.01); 54 | if spell_rect.contains(inputs.mouse_pos) { 55 | buf.draw_rect(spell_rect, Vec3::new(1.0, 1.0, 1.0), 26.0); 56 | if inputs.t as f32 > self.click_after && inputs.events.iter().any(|event| match event { 57 | KEvent::MouseLeft(false) => true, 58 | _ => false, 59 | }) { 60 | return Some(self.choices[i as usize]); 61 | } 62 | } 63 | buf_uv.draw_sprite(spell_rect, spell_sprite(self.choices[i as usize]), 27.0); 64 | } 65 | None 66 | } 67 | } -------------------------------------------------------------------------------- /src/components/render.rs: -------------------------------------------------------------------------------- 1 | use crate::kmath::*; 2 | use crate::manifest::INVUL_TIME; 3 | use crate::renderer::TriangleBuffer; 4 | use crate::wave_game::*; 5 | 6 | #[derive(Clone)] 7 | pub enum Render { 8 | Colour(Vec3), 9 | FOfT(FOfT), 10 | FireSplat(f32), 11 | } 12 | 13 | #[derive(Clone)] 14 | pub struct FOfT { 15 | pub f: fn(f32) -> Vec3, 16 | pub t_start: f32, 17 | pub t_end: f32, 18 | } 19 | 20 | impl WaveGame { 21 | pub fn draw_entities(&self, buf: &mut TriangleBuffer, t: f32, frame: u32) { 22 | for (id, er) in self.render.iter() { 23 | let rect = *self.rect.get(id).unwrap(); 24 | match er { 25 | Render::Colour(colour) => { 26 | // if iframe 27 | if let Some(health) = self.health.get(id) { 28 | if t as f32 - health.invul_time < INVUL_TIME { 29 | buf.draw_rect(rect, Vec3::new(1.0, 1.0, 1.0), 3.0) 30 | } else { 31 | buf.draw_rect(rect, *colour, 3.0) 32 | } 33 | } 34 | buf.draw_rect(rect, *colour, 3.0) 35 | }, 36 | Render::FOfT(f_of_t) => { 37 | let t = unlerp(t as f32, f_of_t.t_start, f_of_t.t_end); 38 | let c = (f_of_t.f)(t); 39 | buf.draw_rect(rect, c, 3.0); 40 | }, 41 | Render::FireSplat(r) => { 42 | let mut seed = frame * 123171717 + id * 123553; 43 | let pos = rect.centroid(); 44 | let mut draw_rect = |w, h, c, d| buf.draw_rect(Rect::new_centered(pos.x, pos.y, w, h), c, d); 45 | draw_rect(kuniform(seed, r/4.0, *r), r - kuniform(seed+1, r/4.0, *r), Vec3::new(1.0, 0.0, 0.0), 50.0); 46 | seed *= 1711457123; 47 | draw_rect(kuniform(seed, r/4.0, *r), r - kuniform(seed+1, r/4.0, *r), Vec3::new(1.0, 0.0, 0.0), 50.0); 48 | seed *= 1711457123; 49 | draw_rect(kuniform(seed, r/4.0, *r), r - kuniform(seed+1, r/4.0, *r), Vec3::new(1.0, 0.0, 0.0), 50.0); 50 | seed *= 1711457123; 51 | draw_rect(kuniform(seed, r/8.0, *r/2.0), r - kuniform(seed+1, r/8.0, *r/2.0), Vec3::new(1.0, 1.0, 0.0), 60.0); 52 | seed *= 1711457123; 53 | draw_rect(kuniform(seed, r/8.0, *r/2.0), r - kuniform(seed+1, r/8.0, *r/2.0), Vec3::new(1.0, 1.0, 0.0), 60.0); 54 | seed *= 1711457123; 55 | draw_rect(kuniform(seed, r/8.0, *r/2.0), r - kuniform(seed+1, r/8.0, *r/2.0), Vec3::new(1.0, 1.0, 0.0), 60.0); 56 | }, 57 | } 58 | } 59 | } 60 | 61 | } -------------------------------------------------------------------------------- /src/components/ai.rs: -------------------------------------------------------------------------------- 1 | use crate::kmath::*; 2 | use crate::spell::*; 3 | use crate::wave_game::*; 4 | use ordered_float::*; 5 | 6 | #[derive(Clone)] 7 | pub struct AI { 8 | pub dir: Vec2, 9 | pub acquisition_range: f32, 10 | pub flee_range: f32, 11 | pub speed: f32, 12 | pub accel: f32, 13 | } 14 | 15 | #[derive(Clone)] 16 | pub struct AICaster { 17 | pub spell: Spell, 18 | pub acquisition_range: f32, 19 | pub rising: bool, 20 | pub unleasher: bool, 21 | } 22 | 23 | impl WaveGame { 24 | pub fn update_movement_ai(&mut self, t: f32, dt: f32, frame: u32, level_rect: Rect) { 25 | for (id, ai) in self.ai.iter_mut() { 26 | let my_team = self.team.get(id).unwrap().team; 27 | let my_phys = self.physics.get(id).unwrap(); 28 | let my_pos = self.rect.get(id).unwrap().centroid(); 29 | 30 | let target = self.entity_ids.iter() 31 | .filter(|id| self.team.contains_key(id) && self.team.get(id).unwrap().team != my_team) 32 | .filter(|id| !self.projectile.contains_key(id)) 33 | .filter(|id| self.physics.contains_key(id)) 34 | .map(|id| self.rect.get(id).unwrap().centroid()) 35 | .filter(|&pos| my_pos.dist(pos) < ai.acquisition_range) 36 | .min_by_key(|&pos| OrderedFloat(my_pos.dist(pos))); 37 | 38 | if let Some(pos) = target { 39 | ai.dir = (pos - my_pos).normalize(); 40 | let dist = pos.dist(my_pos); 41 | if dist < ai.flee_range { 42 | ai.dir = -ai.dir; 43 | } 44 | let speed = ai.speed.min(dist/dt as f32); // potential bug butshould be fine 45 | let mut_phys = self.physics.get_mut(id).unwrap(); 46 | let target_velocity = speed * ai.dir; 47 | mut_phys.velocity = mut_phys.velocity + ai.accel * dt * (target_velocity - mut_phys.velocity); 48 | // mut_phys.velocity = target_velocity; 49 | } else { 50 | let seed = frame * 123123 + id * 17236; 51 | ai.dir = (ai.dir + dt * 0.02 * Vec2::new(kuniform(seed, -1.0, 1.0), kuniform(seed+13131313, -1.0, 1.0)).normalize()).normalize(); 52 | if !level_rect.contains(my_pos + Vec2::new(ai.dir.x, 0.0).normalize() * 1.0) { 53 | ai.dir.x = -ai.dir.x; 54 | } 55 | if !level_rect.contains(my_pos + Vec2::new(0.0, ai.dir.y).normalize() * 1.0) { 56 | ai.dir.y = -ai.dir.y; 57 | } 58 | let mut_phys = self.physics.get_mut(id).unwrap(); 59 | let target_velocity = 0.25 * ai.speed * ai.dir; 60 | mut_phys.velocity = target_velocity; 61 | mut_phys.velocity = mut_phys.velocity + ai.accel * dt * (target_velocity - mut_phys.velocity); 62 | } 63 | } 64 | } 65 | 66 | pub fn update_casting_ai(&mut self, t: f32, commands: &mut Vec) { 67 | for (id, aic) in self.ai_caster.iter_mut() { 68 | let my_pos = self.rect.get(id).unwrap().centroid(); 69 | let my_team = self.team.get(id).unwrap().team; 70 | 71 | if aic.unleasher { 72 | let caster = self.caster.get(id).unwrap(); 73 | if caster.mana == caster.mana_max { 74 | aic.rising = false; 75 | } 76 | if caster.mana < 5.0 { 77 | aic.rising = true; 78 | } 79 | } 80 | if aic.unleasher && aic.rising { continue; } 81 | 82 | let target = self.entity_ids.iter() 83 | .filter(|id| self.team.contains_key(id) && self.team.get(id).unwrap().team != my_team) 84 | .filter(|id| !self.projectile.contains_key(id)) 85 | .filter(|id| self.physics.contains_key(id)) 86 | .map(|id| self.rect.get(id).unwrap().centroid()) 87 | .filter(|&pos| my_pos.dist(pos) < aic.acquisition_range) 88 | .min_by_key(|&pos| OrderedFloat(my_pos.dist(pos))); 89 | 90 | if let Some(pos) = target { 91 | commands.push(Command::Cast(*id, pos, aic.spell, false)); 92 | } 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /src/renderer.rs: -------------------------------------------------------------------------------- 1 | use crate::kmath::*; 2 | use glow::*; 3 | use std::fmt; 4 | 5 | pub struct TriangleBuffer { 6 | pub screen_rect: Rect, 7 | pub tris: Vec, 8 | } 9 | 10 | impl TriangleBuffer { 11 | pub fn new(screen_rect: Rect) -> TriangleBuffer { 12 | TriangleBuffer { screen_rect, tris: Vec::new() } 13 | } 14 | 15 | fn push_triangle(&mut self, mut tri: Triangle3) { 16 | tri.a.pos.x = (tri.a.pos.x - self.screen_rect.x) / self.screen_rect.w; 17 | tri.a.pos.y = (tri.a.pos.y - self.screen_rect.y) / self.screen_rect.h; 18 | 19 | tri.b.pos.x = (tri.b.pos.x - self.screen_rect.x) / self.screen_rect.w; 20 | tri.b.pos.y = (tri.b.pos.y - self.screen_rect.y) / self.screen_rect.h; 21 | 22 | tri.c.pos.x = (tri.c.pos.x - self.screen_rect.x) / self.screen_rect.w; 23 | tri.c.pos.y = (tri.c.pos.y - self.screen_rect.y) / self.screen_rect.h; 24 | 25 | self.tris.push(tri); 26 | } 27 | 28 | pub fn draw_rect(&mut self, r: Rect, colour: Vec3, depth: f32) { 29 | let v1 = Vert3 { 30 | pos: Vec3::new(r.x, r.y, depth), 31 | colour, 32 | }; 33 | let v2 = Vert3 { 34 | pos: Vec3::new(r.x, r.y + r.h, depth), 35 | colour, 36 | }; 37 | let v3 = Vert3 { 38 | pos: Vec3::new(r.x + r.w, r.y + r.h, depth), 39 | colour, 40 | }; 41 | let v4 = Vert3 { 42 | pos: Vec3::new(r.x + r.w, r.y, depth), 43 | colour, 44 | }; 45 | self.push_triangle(Triangle3{ a: v1, b: v4, c: v3 }); 46 | self.push_triangle(Triangle3{ a: v1, b: v3, c: v2 }); 47 | } 48 | 49 | pub fn draw_tri(&mut self, tri: Triangle, colour: Vec3, depth: f32) { 50 | let a = Vert3 { 51 | pos: Vec3::new(tri.a.x, tri.a.y, depth), 52 | colour, 53 | }; 54 | let b = Vert3 { 55 | pos: Vec3::new(tri.b.x, tri.b.y, depth), 56 | colour, 57 | }; 58 | let c = Vert3 { 59 | pos: Vec3::new(tri.c.x, tri.c.y, depth), 60 | colour, 61 | }; 62 | self.push_triangle(Triangle3 {a, b, c}); 63 | } 64 | } 65 | 66 | 67 | #[derive(Clone, Copy)] 68 | #[repr(C)] 69 | pub struct Triangle3 { 70 | a: Vert3, 71 | b: Vert3, 72 | c: Vert3, 73 | } 74 | 75 | impl fmt::Debug for Triangle3 { 76 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 77 | write!(f, "pos: ({},{},{}), ({},{},{}), ({},{},{}) colour: ({},{},{})", 78 | self.a.pos.x, 79 | self.a.pos.y, 80 | self.a.pos.z, 81 | self.b.pos.x, 82 | self.b.pos.y, 83 | self.b.pos.z, 84 | self.c.pos.x, 85 | self.c.pos.y, 86 | self.c.pos.z, 87 | self.a.colour.x, 88 | self.a.colour.y, 89 | self.a.colour.z, 90 | ) 91 | } 92 | } 93 | 94 | #[derive(Clone, Copy, Debug)] 95 | #[repr(C)] 96 | struct Vert3 { 97 | pos: Vec3, 98 | colour: Vec3, 99 | } 100 | 101 | pub struct Renderer { 102 | vbo: NativeBuffer, 103 | vao: NativeVertexArray, 104 | shader: NativeProgram, 105 | } 106 | 107 | impl Renderer { 108 | pub fn new(gl: &glow::Context, shader: NativeProgram) -> Renderer { 109 | unsafe { 110 | 111 | // We construct a buffer and upload the data 112 | let vbo = gl.create_buffer().unwrap(); 113 | gl.bind_buffer(glow::ARRAY_BUFFER, Some(vbo)); 114 | 115 | // We now construct a vertex array to describe the format of the input buffer 116 | let vao = gl.create_vertex_array().unwrap(); 117 | gl.bind_vertex_array(Some(vao)); 118 | 119 | gl.vertex_attrib_pointer_f32(0, 3, glow::FLOAT, false, 4*2*3, 0); 120 | gl.enable_vertex_attrib_array(0); 121 | gl.vertex_attrib_pointer_f32(1, 3, glow::FLOAT, false, 4*2*3, 4*3); 122 | gl.enable_vertex_attrib_array(1); 123 | 124 | Renderer { 125 | vao, 126 | vbo, 127 | shader, 128 | } 129 | } 130 | } 131 | 132 | pub fn present(&mut self, gl: &glow::Context, triangles: TriangleBuffer) { 133 | unsafe { 134 | gl.use_program(Some(self.shader)); 135 | let gpu_bytes: &[u8] = core::slice::from_raw_parts( 136 | triangles.tris.as_ptr() as *const u8, 137 | 3 * 4 * 6 * triangles.tris.len(), 138 | ); // 3 for points in triangle, 4 for bytes in float, 6 for floats in vertex 139 | gl.bind_vertex_array(Some(self.vao)); 140 | gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.vbo)); 141 | gl.buffer_data_u8_slice(glow::ARRAY_BUFFER, gpu_bytes, glow::DYNAMIC_DRAW); 142 | gl.draw_arrays(glow::TRIANGLES, 0, triangles.tris.len() as i32 * 3); 143 | //gl.draw_arrays(glow::TRIANGLES, 0, 6); 144 | } 145 | } 146 | 147 | pub fn destroy(&self, gl: &glow::Context) { 148 | unsafe { 149 | gl.delete_buffer(self.vbo); 150 | gl.delete_vertex_array(self.vao); 151 | } 152 | } 153 | } -------------------------------------------------------------------------------- /src/components/physics.rs: -------------------------------------------------------------------------------- 1 | use crate::kmath::*; 2 | use crate::entity::*; 3 | use crate::wave_game::*; 4 | use itertools::Itertools; 5 | 6 | // Position based dynamics 7 | #[derive(Debug)] 8 | pub struct CollisionEvent { 9 | pub subject: u32, 10 | pub object: u32, 11 | pub penetration: Vec2, 12 | } 13 | 14 | #[derive(Clone)] 15 | pub struct Physics { 16 | pub mass: f32, 17 | pub velocity: Vec2, 18 | pub old_pos: Vec2, 19 | } 20 | 21 | // 5 cases: both a in b, both b in a, a left in b, b left in a, no overlap 22 | fn overlap_amount(a1: f32, a2: f32, b1: f32, b2: f32) -> f32 { 23 | let a1_in_b = a1 >= b1 && a1 <= b2; 24 | let a2_in_b = a2 >= b1 && a2 <= b2; 25 | let b1_in_a = b1 >= a1 && b1 <= a2; 26 | let b2_in_a = b2 >= a1 && b2 <= a2; 27 | 28 | let a_left = (a1 + a2) < (b1 + b2); 29 | 30 | if !a1_in_b && !a2_in_b && !b1_in_a && !b2_in_a {return 0.0;} // no overlap 31 | if a1_in_b && a2_in_b && a_left {return a2 - b1;} // a fully within b // maybe better to do distance to outside still 32 | if a1_in_b && a2_in_b && !a_left {return b2 - a1;} // a fully within b // maybe better to do distance to outside still 33 | if b1_in_a && b2_in_a && a_left {return a2 - b1;} // b fully within a 34 | if b1_in_a && b2_in_a && !a_left {return b2 - a1;} // b fully within a 35 | if a1_in_b {return b2 - a1;} // a to right of b 36 | if b1_in_a {return -(a2 - b1);} // b to right of a 37 | panic!("unreachable overlap"); 38 | } 39 | // enum: subject_within, subject_touching, subject_outside 40 | // if touching the pen vector is overlap amount in dir 41 | // if within maybe need distance to outside as well 42 | // distance to outside = 43 | 44 | // if theres a collision return axis and amount of least penetration 45 | fn collide_rects(a: Rect, b: Rect) -> Option { 46 | let x_overlap = overlap_amount(a.left(), a.right(), b.left(), b.right()); 47 | let y_overlap = overlap_amount(a.top(), a.bot(), b.top(), b.bot()); 48 | 49 | if x_overlap == 0.0 || y_overlap == 0.0 {return None}; 50 | 51 | if x_overlap.abs() < y_overlap.abs() { 52 | return Some(Vec2::new(x_overlap, 0.0)); 53 | } 54 | return Some(Vec2::new(0.0, y_overlap)); 55 | } 56 | 57 | impl WaveGame { 58 | pub fn move_entities(&mut self, dt: f32) { 59 | for (id, phys) in self.physics.iter_mut() { 60 | let rect = self.rect.get_mut(id).unwrap(); 61 | phys.old_pos = rect.centroid(); 62 | *rect = rect.translate(phys.velocity * dt); 63 | } 64 | } 65 | 66 | pub fn collisions(&self) -> Vec { 67 | self.physics.iter().cartesian_product(self.physics.iter()) 68 | .filter(|((sid, sphys), (oid, ophys))| sid != oid) 69 | .filter_map(|((&sid, sphys), (&oid, ophys))| collide_rects(*self.rect.get(&sid).unwrap(), *self.rect.get(&oid).unwrap()).map(|pen| CollisionEvent {subject: sid, object: oid, penetration: pen})) 70 | .collect() 71 | } 72 | 73 | pub fn fix_overlaps(&mut self, cols: &[CollisionEvent], proportion: f32) { 74 | for col in cols { 75 | let omass = self.physics.get(&col.object).unwrap().mass; 76 | let sphys = self.physics.get(&col.subject).unwrap(); 77 | let sw = sphys.mass / (sphys.mass + omass); 78 | // let ow = ophys.mass / denom; 79 | // what way is penetration 80 | let mut rect = self.rect.get_mut(&col.subject).unwrap(); 81 | *rect = rect.translate((1.0 - sw) * col.penetration * proportion); 82 | } 83 | } 84 | 85 | pub fn fix_velocities(&mut self, dt: f32) { 86 | for (id, val) in self.physics.iter_mut() { 87 | let rect = self.rect.get_mut(&id).unwrap(); 88 | 89 | val.velocity = (rect.centroid() - val.old_pos) / dt; 90 | } 91 | } 92 | 93 | } 94 | 95 | 96 | #[test] 97 | fn test_overlap_amount() { 98 | assert_eq!(overlap_amount(-0.4, 0.6, -1.0, 1.0), 1.4); 99 | assert_eq!(overlap_amount(-0.5, 0.5, -1.0, 1.0), 1.5); 100 | assert_eq!(overlap_amount(-0.6, 0.4, -1.0, 1.0), 1.4); 101 | 102 | assert_eq!(overlap_amount(-1.0, 1.0, -0.4, 0.6), 1.4);// oh shit not reflective symmetry 103 | assert_eq!(overlap_amount(-1.0, 1.0, -0.5, 0.5), 1.5); 104 | assert_eq!(overlap_amount(-1.0, 1.0, -0.6, 0.4), 1.4); 105 | } 106 | 107 | // still the case where they exactly overlap is problematic 108 | 109 | // i hope the axis of penetration is opposite directions. yes it is 110 | // exact overlap: maybe it would be good to handle and make it opposite. 111 | // maybe substeps, if i move a smaller amount of the total distance to move 112 | // other physics improvements; canonical overlaps 113 | // i thought my noise wqould fiox it, would be good to check 114 | #[test] 115 | fn test_axis_pen() { 116 | let mut wg = WaveGame::new(0.0); 117 | 118 | wg.add_entity(&Entity::new() 119 | .with_rect(Rect::new_centered(0.0, 0.0, 2.0, 2.0)) 120 | .with_physics(1.0, Vec2::new(0.0, 0.0)) 121 | ); 122 | 123 | wg.add_entity(&Entity::new() 124 | .with_rect(Rect::new_centered(0.1, 0.05, 1.0, 1.0)) 125 | .with_physics(1.0, Vec2::new(0.0, 0.0)) 126 | ); 127 | 128 | let cols = wg.collisions(); 129 | println!("cols: {:?}", cols); 130 | } -------------------------------------------------------------------------------- /src/kgui.rs: -------------------------------------------------------------------------------- 1 | use crate::kmath::*; 2 | 3 | use std::collections::HashSet; 4 | use std::time::{SystemTime, Instant, Duration}; 5 | 6 | use glutin::event::VirtualKeyCode; 7 | 8 | use glutin::event::ElementState; 9 | use glutin::event::MouseButton; 10 | use glutin::event::Event; 11 | use glutin::event::WindowEvent::KeyboardInput; 12 | use glutin::event::WindowEvent::MouseInput; 13 | use glutin::event::WindowEvent::CursorMoved; 14 | use glutin::event::WindowEvent::Resized; 15 | 16 | // Do I dare??? 17 | #[derive(Clone, Copy)] 18 | pub enum KEvent { 19 | Keyboard(VirtualKeyCode, bool), 20 | MouseLeft(bool), 21 | MouseRight(bool), 22 | MouseMiddle(bool), 23 | MouseMotion(Vec2), 24 | } 25 | 26 | #[derive(Clone)] 27 | pub struct FrameInputState { 28 | pub screen_rect: Rect, 29 | pub mouse_pos: Vec2, 30 | pub held_keys: HashSet, 31 | pub held_lmb: bool, 32 | pub held_rmb: bool, 33 | pub held_mmb: bool, 34 | pub events: Vec, 35 | pub t: f64, 36 | pub dt: f64, 37 | pub frame: u32, 38 | pub seed: u32, 39 | } 40 | 41 | pub struct EventAggregator { 42 | xres: f32, 43 | yres: f32, 44 | t_last: Instant, 45 | current: FrameInputState, 46 | } 47 | 48 | impl EventAggregator { 49 | pub fn new(xres: f32, yres: f32) -> EventAggregator { 50 | EventAggregator { 51 | xres, 52 | yres, 53 | t_last: Instant::now(), 54 | current: FrameInputState { 55 | screen_rect: Rect::new(0.0, 0.0, xres/yres, 1.0, ), 56 | mouse_pos: Vec2::new(0.0, 0.0), 57 | held_keys: HashSet::new(), 58 | held_lmb: false, 59 | held_rmb: false, 60 | held_mmb: false, 61 | events: Vec::new(), 62 | t: 0.0, 63 | dt: 0.0, 64 | frame: 0, 65 | seed: SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap_or(Duration::from_nanos(34123123)).subsec_nanos(), 66 | } 67 | } 68 | } 69 | 70 | pub fn handle_event(&mut self, event: &Event<()>) -> Option { 71 | match event { 72 | Event::WindowEvent {event, ..} => match event { 73 | KeyboardInput { 74 | input: glutin::event::KeyboardInput { 75 | virtual_keycode: Some(virtual_code), 76 | state, 77 | ..}, 78 | ..} => { 79 | self.current.events.push(KEvent::Keyboard(*virtual_code, *state == ElementState::Pressed)); 80 | if *state == ElementState::Pressed { 81 | self.current.held_keys.insert(*virtual_code); 82 | } else { 83 | self.current.held_keys.remove(&virtual_code); 84 | } 85 | }, 86 | 87 | 88 | MouseInput { button: glutin::event::MouseButton::Left, state, ..} => { 89 | self.current.events.push(KEvent::MouseLeft(*state == ElementState::Pressed)); 90 | if *state == ElementState::Pressed { 91 | self.current.held_lmb = true; 92 | } else { 93 | self.current.held_lmb = false; 94 | } 95 | }, 96 | MouseInput { button: glutin::event::MouseButton::Middle, state, ..} => { 97 | self.current.events.push(KEvent::MouseMiddle(*state == ElementState::Pressed)); 98 | if *state == ElementState::Pressed { 99 | self.current.held_mmb = true; 100 | } else { 101 | self.current.held_mmb = false; 102 | } 103 | }, 104 | MouseInput { button: glutin::event::MouseButton::Right, state, ..} => { 105 | self.current.events.push(KEvent::MouseRight(*state == ElementState::Pressed)); 106 | if *state == ElementState::Pressed { 107 | self.current.held_rmb = true; 108 | } else { 109 | self.current.held_rmb = false; 110 | } 111 | }, 112 | 113 | 114 | // Mouse motion 115 | CursorMoved { 116 | position: pos, 117 | .. 118 | } => { 119 | let old_cursor_pos = self.current.mouse_pos; 120 | let new_cursor_pos = Vec2::new(pos.x as f32 / self.yres, pos.y as f32 / self.yres); 121 | self.current.events.push(KEvent::MouseMotion(new_cursor_pos - old_cursor_pos)); 122 | self.current.mouse_pos = new_cursor_pos; 123 | }, 124 | 125 | // Resize 126 | Resized(physical_size) => { 127 | self.xres = physical_size.width as f32; 128 | self.yres = physical_size.height as f32; 129 | self.current.screen_rect = Rect::new(0.0, 0.0, self.xres / self.yres, 1.0); 130 | }, 131 | 132 | 133 | // (resize and quit need to be handled by the application) 134 | _ => {}, 135 | 136 | }, 137 | Event::MainEventsCleared => { 138 | let t_now = Instant::now(); 139 | let dt = t_now.duration_since(self.t_last).as_secs_f64(); 140 | self.current.dt = dt; 141 | self.current.t += dt; 142 | self.t_last = t_now; 143 | self.current.frame += 1; 144 | let state = self.current.clone(); 145 | self.current.events = Vec::new(); 146 | self.current.seed = khash(self.current.seed * 196513497); 147 | return Some(state); 148 | }, 149 | _ => {}, 150 | } 151 | 152 | None 153 | } 154 | } -------------------------------------------------------------------------------- /src/rendererUV.rs: -------------------------------------------------------------------------------- 1 | use crate::kmath::*; 2 | use crate::kimg::*; 3 | 4 | use glow::*; 5 | 6 | use std::fmt; 7 | 8 | #[derive(Debug)] 9 | pub struct TriangleBufferUV { 10 | screen_rect: Rect, 11 | pub tris: Vec, 12 | atlas_w: i32, 13 | atlas_h: i32, 14 | } 15 | 16 | impl TriangleBufferUV { 17 | pub fn new(screen_rect: Rect, atlas_w: i32, atlas_h: i32) -> TriangleBufferUV { 18 | TriangleBufferUV { screen_rect, tris: Vec::new(), atlas_w, atlas_h } 19 | } 20 | 21 | fn push_triangle(&mut self, mut tri: Triangle3UV) { 22 | tri.a.pos.x = (tri.a.pos.x - self.screen_rect.x) / self.screen_rect.w; 23 | tri.a.pos.y = (tri.a.pos.y - self.screen_rect.y) / self.screen_rect.h; 24 | 25 | tri.b.pos.x = (tri.b.pos.x - self.screen_rect.x) / self.screen_rect.w; 26 | tri.b.pos.y = (tri.b.pos.y - self.screen_rect.y) / self.screen_rect.h; 27 | 28 | tri.c.pos.x = (tri.c.pos.x - self.screen_rect.x) / self.screen_rect.w; 29 | tri.c.pos.y = (tri.c.pos.y - self.screen_rect.y) / self.screen_rect.h; 30 | 31 | self.tris.push(tri); 32 | } 33 | 34 | pub fn draw_sprite(&mut self, r: Rect, i: i32, depth: f32) { 35 | let colour = Vec3::new(1.0, 1.0, 1.0); 36 | let x = i / self.atlas_w; 37 | let y = i % self.atlas_h; 38 | let uv_w = 1.0 / self.atlas_w as f32; 39 | let uv_h = 1.0 / self.atlas_h as f32; 40 | let uv = Rect::new(x as f32 * uv_w, y as f32 * uv_h, uv_w, uv_h); 41 | 42 | let v1 = Vert3UV { 43 | pos: Vec3::new(r.x, r.y, depth), 44 | colour: colour, 45 | uv: uv.tl(), 46 | }; 47 | let v2 = Vert3UV { 48 | pos: Vec3::new(r.x, r.y + r.h, depth), 49 | colour: colour, 50 | uv: uv.tr(), 51 | }; 52 | let v3 = Vert3UV { 53 | pos: Vec3::new(r.x + r.w, r.y + r.h, depth), 54 | colour: colour, 55 | uv: uv.br(), 56 | }; 57 | let v4 = Vert3UV { 58 | pos: Vec3::new(r.x + r.w, r.y, depth), 59 | colour: colour, 60 | uv: uv.bl(), 61 | }; 62 | self.push_triangle(Triangle3UV{ a: v1, b: v4, c: v3 }); 63 | self.push_triangle(Triangle3UV{ a: v1, b: v3, c: v2 }); 64 | } 65 | } 66 | 67 | 68 | #[derive(Clone, Copy)] 69 | #[repr(C)] 70 | pub struct Triangle3UV { 71 | a: Vert3UV, 72 | b: Vert3UV, 73 | c: Vert3UV, 74 | } 75 | 76 | impl fmt::Debug for Triangle3UV { 77 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 78 | write!(f, "pos: ({},{},{}), ({},{},{}), ({},{},{}) colour: ({},{},{})", 79 | self.a.pos.x, 80 | self.a.pos.y, 81 | self.a.pos.z, 82 | self.b.pos.x, 83 | self.b.pos.y, 84 | self.b.pos.z, 85 | self.c.pos.x, 86 | self.c.pos.y, 87 | self.c.pos.z, 88 | self.a.colour.x, 89 | self.a.colour.y, 90 | self.a.colour.z, 91 | ) 92 | } 93 | } 94 | 95 | #[derive(Clone, Copy, Debug)] 96 | #[repr(C)] 97 | struct Vert3UV { 98 | pos: Vec3, 99 | colour: Vec3, 100 | uv: Vec2, 101 | } 102 | 103 | pub struct RendererUV { 104 | vbo: NativeBuffer, 105 | vao: NativeVertexArray, 106 | shader: NativeProgram, 107 | 108 | atlas: NativeTexture, 109 | 110 | } 111 | 112 | impl RendererUV { 113 | pub fn new(gl: &glow::Context, shader: NativeProgram, atlas: ImageBufferA) -> RendererUV { 114 | 115 | unsafe { 116 | let texture = gl.create_texture().unwrap(); 117 | gl.bind_texture(glow::TEXTURE_2D, Some(texture)); 118 | gl.tex_image_2d(glow::TEXTURE_2D, 0, glow::RGBA as i32, atlas.w as i32, atlas.h as i32, 0, RGBA, glow::UNSIGNED_BYTE, Some(&atlas.bytes_transpose())); 119 | gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MIN_FILTER, glow::NEAREST as i32); 120 | gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MAG_FILTER, glow::NEAREST as i32); 121 | gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_S, glow::CLAMP_TO_EDGE as i32); 122 | gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_T, glow::CLAMP_TO_EDGE as i32); 123 | gl.generate_mipmap(glow::TEXTURE_2D); 124 | 125 | // We construct a buffer and upload the data 126 | let vbo = gl.create_buffer().unwrap(); 127 | gl.bind_buffer(glow::ARRAY_BUFFER, Some(vbo)); 128 | 129 | // We now construct a vertex array to describe the format of the input buffer 130 | let vao = gl.create_vertex_array().unwrap(); 131 | gl.bind_vertex_array(Some(vao)); 132 | 133 | gl.vertex_attrib_pointer_f32(0, 3, glow::FLOAT, false, 4*2*3 + 4*2, 0); 134 | gl.enable_vertex_attrib_array(0); 135 | gl.vertex_attrib_pointer_f32(1, 3, glow::FLOAT, false, 4*2*3 + 4*2, 4*3); 136 | gl.enable_vertex_attrib_array(1); 137 | gl.vertex_attrib_pointer_f32(2, 2, glow::FLOAT, false, 4*2*3 + 4*2, 2*4*3); 138 | gl.enable_vertex_attrib_array(2); 139 | 140 | RendererUV { 141 | vao, 142 | vbo, 143 | shader, 144 | atlas: texture, 145 | } 146 | } 147 | } 148 | 149 | pub fn present(&mut self, gl: &glow::Context, triangles: TriangleBufferUV) { 150 | unsafe { 151 | gl.use_program(Some(self.shader)); 152 | gl.bind_texture(glow::TEXTURE_2D, Some(self.atlas)); 153 | 154 | let gpu_bytes: &[u8] = core::slice::from_raw_parts( 155 | triangles.tris.as_ptr() as *const u8, 156 | 3 * 4 * 8 * triangles.tris.len(), 157 | ); // 3 for points in triangle, 4 for bytes in float, 6 for floats in vertex 158 | gl.bind_vertex_array(Some(self.vao)); 159 | gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.vbo)); 160 | gl.buffer_data_u8_slice(glow::ARRAY_BUFFER, gpu_bytes, glow::DYNAMIC_DRAW); 161 | gl.draw_arrays(glow::TRIANGLES, 0, triangles.tris.len() as i32 * 3); 162 | //gl.draw_arrays(glow::TRIANGLES, 0, 6); 163 | } 164 | } 165 | 166 | pub fn destroy(&self, gl: &glow::Context) { 167 | unsafe { 168 | gl.delete_buffer(self.vbo); 169 | gl.delete_vertex_array(self.vao); 170 | gl.delete_texture(self.atlas); 171 | } 172 | } 173 | } -------------------------------------------------------------------------------- /src/kimg.rs: -------------------------------------------------------------------------------- 1 | use std::path::Path; 2 | use std::fs::File; 3 | use std::io::BufWriter; 4 | 5 | 6 | pub struct ImageBuffer { 7 | pub w: usize, 8 | pub h: usize, 9 | pub pixels: Vec<(u8,u8,u8)>, 10 | } 11 | 12 | // should actually just use a vec u8 internally so no need to convert back and forth 13 | 14 | impl ImageBuffer { 15 | pub fn new(w: usize, h: usize) -> ImageBuffer { 16 | ImageBuffer { 17 | w, 18 | h, 19 | pixels: vec![(0,0,0); w*h], 20 | } 21 | } 22 | pub fn set_px(&mut self, x: usize, y: usize, val: (u8, u8, u8)) { 23 | self.pixels[y*self.w + x] = val; 24 | } 25 | pub fn get_px(&self, x: usize, y: usize) -> (u8, u8, u8) { 26 | self.pixels[y*self.w + x] 27 | } 28 | 29 | pub fn new_from_file(path_str: &str) -> ImageBuffer { 30 | let decoder = png::Decoder::new(File::open(path_str).unwrap()); 31 | let mut reader = decoder.read_info().unwrap(); 32 | // Allocate the output buffer. 33 | let mut buf = vec![0; reader.output_buffer_size()]; 34 | // Read the next frame. An APNG might contain multiple frames. 35 | let info = reader.next_frame(&mut buf).unwrap(); 36 | // Grab the bytes of the image. 37 | let bytes = &buf[..info.buffer_size()]; 38 | let mut bytes_idx = 0; 39 | // extra copy whatever idgaf 40 | let mut image_buffer = ImageBuffer::new(info.width as usize, info.height as usize); 41 | for j in 0..image_buffer.h { 42 | for i in 0..image_buffer.w { 43 | image_buffer.set_px(i, j, (bytes[bytes_idx], bytes[bytes_idx + 1], bytes[bytes_idx + 2])); 44 | bytes_idx += 3; 45 | } 46 | } 47 | image_buffer 48 | } 49 | pub fn dump_to_file(&self, path_str: &str) { 50 | let path = Path::new(path_str); 51 | let file = File::create(path).unwrap(); 52 | let ref mut buf_writer = BufWriter::new(file); 53 | 54 | let mut data = vec![0u8; (3*self.w*self.h)]; 55 | let mut data_index = 0; 56 | for px in self.pixels.iter() { 57 | data[data_index] = px.0; 58 | data_index += 1; 59 | data[data_index] = px.1; 60 | data_index += 1; 61 | data[data_index] = px.2; 62 | data_index += 1; 63 | } 64 | 65 | let mut encoder = png::Encoder::new(buf_writer, self.w as u32, self.h as u32); 66 | encoder.set_color(png::ColorType::Rgb); 67 | encoder.set_depth(png::BitDepth::Eight); 68 | encoder.set_trns(vec!(0xFFu8, 0xFFu8, 0xFFu8)); 69 | encoder.set_source_gamma(png::ScaledFloat::from_scaled(45455)); // 1.0 / 2.2, scaled by 100000 70 | encoder.set_source_gamma(png::ScaledFloat::new(1.0 / 2.2)); // 1.0 / 2.2, unscaled, but rounded 71 | let source_chromaticities = png::SourceChromaticities::new( // Using unscaled instantiation here 72 | (0.31270, 0.32900), 73 | (0.64000, 0.33000), 74 | (0.30000, 0.60000), 75 | (0.15000, 0.06000) 76 | ); 77 | encoder.set_source_chromaticities(source_chromaticities); 78 | let mut writer = encoder.write_header().unwrap(); 79 | 80 | writer.write_image_data(&data).unwrap(); // Save 81 | } 82 | } 83 | 84 | pub struct ImageBufferA { 85 | pub w: usize, 86 | pub h: usize, 87 | pub pixels: Vec<(u8,u8,u8,u8)>, 88 | } 89 | 90 | // should actually just use a vec u8 internally so no need to convert back and forth 91 | 92 | impl ImageBufferA { 93 | pub fn new(w: usize, h: usize) -> ImageBufferA { 94 | ImageBufferA { 95 | w, 96 | h, 97 | pixels: vec![(0,0,0,0); w*h], 98 | } 99 | } 100 | pub fn set_px(&mut self, x: usize, y: usize, val: (u8, u8, u8, u8)) { 101 | self.pixels[y*self.w + x] = val; 102 | } 103 | pub fn get_px(&self, x: usize, y: usize) -> (u8, u8, u8, u8) { 104 | self.pixels[y*self.w + x] 105 | } 106 | 107 | pub fn new_from_file(path_str: &str) -> Option { 108 | let result_file = File::open(path_str); 109 | if result_file.is_err() {return None}; 110 | let file = result_file.unwrap(); 111 | let decoder = png::Decoder::new(file); 112 | let mut reader = decoder.read_info().unwrap(); 113 | // Allocate the output buffer. 114 | let mut buf = vec![0; reader.output_buffer_size()]; 115 | // Read the next frame. An APNG might contain multiple frames. 116 | let info = reader.next_frame(&mut buf).unwrap(); 117 | // Grab the bytes of the image. 118 | let bytes = &buf[..info.buffer_size()]; 119 | let mut bytes_idx = 0; 120 | // extra copy whatever idgaf 121 | let mut image_buffer = ImageBufferA::new(info.width as usize, info.height as usize); 122 | for j in 0..image_buffer.h { 123 | for i in 0..image_buffer.w { 124 | image_buffer.set_px(i, j, (bytes[bytes_idx], bytes[bytes_idx + 1], bytes[bytes_idx + 2], bytes[bytes_idx + 3])); 125 | bytes_idx += 4; 126 | } 127 | } 128 | Some(image_buffer) 129 | } 130 | // just copy lmao 131 | pub fn bytes(&self) -> Vec { 132 | let mut bytes_vec = Vec::new(); 133 | for px in self.pixels.iter() { 134 | bytes_vec.push(px.0); 135 | bytes_vec.push(px.1); 136 | bytes_vec.push(px.2); 137 | bytes_vec.push(px.3); 138 | } 139 | bytes_vec 140 | } 141 | pub fn bytes_transpose(&self) -> Vec { 142 | let mut bytes_vec = Vec::new(); 143 | for i in 0..self.w { 144 | for j in 0..self.h { 145 | let px = self.pixels[j*self.w + i]; 146 | bytes_vec.push(px.0); 147 | bytes_vec.push(px.1); 148 | bytes_vec.push(px.2); 149 | bytes_vec.push(px.3); 150 | } 151 | } 152 | bytes_vec 153 | } 154 | pub fn dump_to_file(&self, path_str: &str) { 155 | let path = Path::new(path_str); 156 | let file = File::create(path).unwrap(); 157 | let ref mut buf_writer = BufWriter::new(file); 158 | 159 | let mut data = vec![0u8; (4*self.w*self.h)]; 160 | let mut data_index = 0; 161 | for px in self.pixels.iter() { 162 | data[data_index] = px.0; 163 | data_index += 1; 164 | data[data_index] = px.1; 165 | data_index += 1; 166 | data[data_index] = px.2; 167 | data_index += 1; 168 | data[data_index] = px.3; 169 | data_index += 1; 170 | } 171 | 172 | let mut encoder = png::Encoder::new(buf_writer, self.w as u32, self.h as u32); 173 | encoder.set_color(png::ColorType::Rgba); 174 | encoder.set_depth(png::BitDepth::Eight); 175 | // encoder.set_trns(vec!(0xFFu8, 0xFFu8, 0xFFu8)); // maybe dont need lol 176 | encoder.set_source_gamma(png::ScaledFloat::from_scaled(45455)); // 1.0 / 2.2, scaled by 100000 177 | encoder.set_source_gamma(png::ScaledFloat::new(1.0 / 2.2)); // 1.0 / 2.2, unscaled, but rounded 178 | let source_chromaticities = png::SourceChromaticities::new( // Using unscaled instantiation here 179 | (0.31270, 0.32900), 180 | (0.64000, 0.33000), 181 | (0.30000, 0.60000), 182 | (0.15000, 0.06000) 183 | ); 184 | encoder.set_source_chromaticities(source_chromaticities); 185 | let mut writer = encoder.write_header().unwrap(); 186 | 187 | writer.write_image_data(&data).unwrap(); // Save 188 | } 189 | } -------------------------------------------------------------------------------- /src/actual_entity_definitions.rs: -------------------------------------------------------------------------------- 1 | use std::f32::consts::PI; 2 | 3 | use crate::components::make_entities::*; 4 | use crate::components::spawn_list::SpawnList; 5 | use crate::entity::*; 6 | use crate::kmath::*; 7 | use crate::spell::*; 8 | 9 | // new components 10 | // MakeEntitiesOnDeath, fn ptr that takes position and returns vec of entities 11 | // MakeEntitiesPeriodically fn ptr that takes position and returns vec of entities 12 | // SpawnList big vec of entities and times to spawn them 13 | // roam 14 | 15 | pub fn portal1(pos: Vec2, team: u32) -> Entity { 16 | let mut portal = Entity::new() 17 | .with_rect(Rect::new_centered(pos.x, pos.y, 1.0, 2.0)) 18 | .with_render_solid(Vec3::new(0.0, 1.0, 0.0)); 19 | 20 | let mut s = SpawnList::builder(); 21 | for i in 0..=40 { 22 | s.spawn_entity(zerg(pos, team)); 23 | 24 | if i % 2 == 0 { 25 | s.spawn_entity(deathspawner(pos, team)); 26 | } 27 | if i % 10 == 0 { 28 | s.spawn_entity(barrager(pos, team)); 29 | } 30 | s.wait(0.5); 31 | } 32 | s.build(); 33 | 34 | portal.spawn_list = Some(s); 35 | portal 36 | } 37 | 38 | pub fn portal2(pos: Vec2, team: u32) -> Entity { 39 | let mut portal = Entity::new() 40 | .with_rect(Rect::new_centered(pos.x, pos.y, 1.0, 2.0)) 41 | .with_render_solid(Vec3::new(0.8, 0.0, 1.0)); 42 | 43 | let mut s = SpawnList::builder(); 44 | for i in 0..=40 { 45 | if i % 2 == 0 { 46 | s.spawn_entity(magic_missile_caster(pos, team)) 47 | } 48 | s.spawn_entity(zerg(pos, team)); 49 | s.wait(0.5); 50 | } 51 | s.build(); 52 | 53 | portal.spawn_list = Some(s); 54 | portal 55 | } 56 | 57 | pub fn portal3(pos: Vec2, team: u32) -> Entity { 58 | let mut portal = Entity::new() 59 | .with_rect(Rect::new_centered(pos.x, pos.y, 1.0, 2.0)) 60 | .with_render_solid(Vec3::new(0.8, 0.0, 0.0)); 61 | 62 | let mut s = SpawnList::builder(); 63 | for i in 0..=40 { 64 | if i % 4 == 0 { 65 | s.spawn_entity(summoner(pos, team)); 66 | } 67 | if i % 10 == 0 { 68 | s.spawn_entity(summoner_summoner(pos, team)); 69 | s.spawn_entity(barrager(pos, team)); 70 | } 71 | s.wait(0.75); 72 | } 73 | s.build(); 74 | 75 | portal.spawn_list = Some(s); 76 | portal 77 | } 78 | 79 | pub fn goon(pos: Vec2, team: u32) -> Entity { 80 | Entity::new() 81 | .with_team(team) 82 | .with_physics(1.0, Vec2::new(0.0, 0.0)) 83 | .with_rect(Rect::new_centered(pos.x, pos.y, 1.0, 1.0)) 84 | .with_melee_damage(20.0) 85 | .with_health(50.0, 1.0) 86 | .with_ai(10.0, 0.0, 4.0, 6.0) 87 | .with_render_solid(Vec3::new(1.0, 0.0, 0.0)) 88 | } 89 | 90 | pub fn retalliator(pos: Vec2, team: u32) -> Entity { 91 | let mut r = Entity::new() 92 | .with_team(team) 93 | .with_physics(1.0, Vec2::new(0.0, 0.0)) 94 | .with_rect(Rect::new_centered(pos.x, pos.y, 1.5, 1.5)) 95 | .with_health(60.0, 1.0) 96 | .with_ai(10.0, 0.0, 3.0, 6.0) 97 | .with_render_solid(Vec3::new(1.0, 0.5, 0.0)); 98 | 99 | r.make_on_damage = Some(MakeEntitiesOnDamage { 100 | acc: 0.0, 101 | thresh: 20.0, 102 | f: |wg, inputs, id, buf| { 103 | let team = wg.team.get(&id).unwrap().team; 104 | let pos = wg.rect.get(&id).unwrap().centroid(); 105 | let retalliations: Vec = (0..8_i32).map(|i| i as f32 * 2.0 * PI / 8.0) 106 | .map(|theta| Vec2::new(theta.cos(), theta.sin())) 107 | .map(|vhat| retalliator_projectile(pos, id, team, vhat)) 108 | .collect(); 109 | for e in retalliations { 110 | buf.push(e); 111 | } 112 | } 113 | }); 114 | 115 | r 116 | } 117 | 118 | pub fn zerg(pos: Vec2, team: u32) -> Entity { 119 | Entity::new() 120 | .with_team(team) 121 | .with_physics(0.25, Vec2::new(0.0, 0.0)) 122 | .with_rect(Rect::new_centered(pos.x, pos.y, 0.5, 0.5)) 123 | .with_melee_damage(20.0) 124 | .with_health(20.0, 1.0) 125 | .with_ai(10.0, 0.0, 7.0, 6.0) 126 | .with_render_solid(Vec3::new(0.7, 0.0, 0.0)) 127 | } 128 | 129 | pub fn summoner(pos: Vec2, team: u32) -> Entity { 130 | Entity::new() 131 | .with_team(team) 132 | .with_physics(2.0, Vec2::new(0.0, 0.0)) 133 | .with_rect(Rect::new_centered(pos.x, pos.y, 1.2, 1.2)) 134 | .with_health(100.0, 1.0) 135 | .with_ai(10.0, 0.0, 2.0, 6.0) 136 | .with_render_solid(Vec3::new(0.5, 0.0, 0.0)) 137 | .with_ai_caster(10.0, Spell::SummonRushers) 138 | .with_caster(20.0, 2.0) 139 | } 140 | 141 | pub fn summoner_summoner(pos: Vec2, team: u32) -> Entity { 142 | Entity::new() 143 | .with_team(team) 144 | .with_physics(4.0, Vec2::new(0.0, 0.0)) 145 | .with_rect(Rect::new_centered(pos.x, pos.y, 1.8, 1.8)) 146 | .with_health(200.0, 1.0) 147 | .with_ai(10.0, 0.0, 1.6, 6.0) 148 | .with_render_solid(Vec3::new(0.3, 0.0, 0.0)) 149 | .with_ai_caster(12.0, Spell::SummonSummoners) 150 | .with_caster(100.0, 3.0) 151 | } 152 | 153 | pub fn magic_missile_caster(pos: Vec2, team: u32) -> Entity { 154 | Entity::new() 155 | .with_team(team) 156 | .with_physics(0.7, Vec2::new(0.0, 0.0)) 157 | .with_rect(Rect::new_centered(pos.x, pos.y, 0.9, 0.9)) 158 | .with_health(20.0, 1.0) 159 | .with_ai(10.0, 5.0, 3.0, 6.0) 160 | .with_render_solid(Vec3::new(0.0, 0.8, 0.8)) 161 | .with_ai_caster(9.0, Spell::Missile) 162 | .with_caster(10.0, 3.0) 163 | } 164 | 165 | pub fn retalliator_projectile(pos: Vec2, source: u32, team: u32, vhat: Vec2) -> Entity { 166 | Entity::new() 167 | .with_team(team) 168 | .with_physics(10.0, vhat * 10.0) 169 | .with_rect(Rect::new_centered(pos.x, pos.y, 0.4, 0.4)) 170 | .with_projectile(source, 20.0) 171 | .with_render_solid(Vec3::new(1.0, 0.5, 0.0)) 172 | } 173 | 174 | pub fn barrager(pos: Vec2, team: u32) -> Entity { 175 | Entity::new() 176 | .with_team(team) 177 | .with_physics(2.0, Vec2::new(0.0, 0.0)) 178 | .with_rect(Rect::new_centered(pos.x, pos.y, 1.2, 1.2)) 179 | .with_health(60.0, 1.0) 180 | .with_ai(20.0, 10.0, 3.0, 6.0) 181 | .with_render_solid(Vec3::new(0.6, 0.0, 0.8)) 182 | .with_ai_caster_unleasher(15.0, Spell::Barrage) 183 | .with_caster(50.0, 6.0) 184 | } 185 | 186 | pub fn deathspawner(pos: Vec2, team: u32) -> Entity { 187 | let mut d = Entity::new() 188 | .with_team(team) 189 | .with_physics(2.0, Vec2::new(0.0, 0.0)) 190 | .with_rect(Rect::new_centered(pos.x, pos.y, 1.1, 1.1)) 191 | .with_melee_damage(20.0) 192 | .with_health(60.0, 1.0) 193 | .with_ai(10.0, 0.0, 3.5, 6.0) 194 | .with_render_solid(Vec3::new(1.0, 0.4, 0.3)); 195 | 196 | d.make_on_death = Some(MakeEntitiesOnDeath { 197 | f: |wg, inputs, id, buf| { 198 | let team = wg.team.get(&id).unwrap().team; 199 | let pos = wg.rect.get(&id).unwrap().centroid(); 200 | let retalliations: Vec = (0..3_i32).map(|i| i as f32 * 2.0 * PI / 8.0) 201 | .map(|theta| zerg(pos.offset_r_theta(0.3, theta), team)) 202 | .collect(); 203 | for e in retalliations { 204 | buf.push(e); 205 | } 206 | } 207 | }); 208 | 209 | d 210 | } 211 | 212 | // plaguebearer: also need a dot component with uid, bool stacking 213 | // and periodic summon component -------------------------------------------------------------------------------- /src/application.rs: -------------------------------------------------------------------------------- 1 | use glow::*; 2 | use crate::kgui::EventAggregator; 3 | use crate::kgui::FrameInputState; 4 | use crate::renderer::*; 5 | use crate::rendererUV::*; 6 | use crate::kimg::*; 7 | use crate::wave_game::*; 8 | use crate::tutorial::*; 9 | use crate::victory::*; 10 | use crate::spell::*; 11 | use glutin::event::{Event, WindowEvent}; 12 | 13 | pub enum SceneOutcome { 14 | Push(Box), 15 | Pop(SceneSignal), 16 | QuitProgram, 17 | None, 18 | } 19 | 20 | pub enum SceneSignal { 21 | JustPop, 22 | } 23 | 24 | pub trait Scene { 25 | fn handle_signal(&mut self, signal: SceneSignal) -> SceneOutcome; 26 | fn frame(&mut self, inputs: FrameInputState) -> (SceneOutcome, TriangleBuffer, Option); 27 | } 28 | 29 | pub struct Application { 30 | gl: glow::Context, 31 | window: glutin::WindowedContext, 32 | 33 | renderer: Renderer, 34 | renderer_uv: RendererUV, 35 | event_aggregator: EventAggregator, 36 | 37 | pub xres: f32, 38 | pub yres: f32, 39 | 40 | scene_stack: Vec>, 41 | } 42 | 43 | pub fn load_file(paths: &[&str]) -> String { 44 | for path in paths { 45 | if let Ok(s) = std::fs::read_to_string(path) { 46 | return s 47 | } 48 | } 49 | panic!("couldn't find any of {:?}", paths) 50 | } 51 | 52 | impl Application { 53 | pub fn new(event_loop: &glutin::event_loop::EventLoop<()>) -> Application { 54 | let default_xres = 1920.0; 55 | let default_yres = 1080.0; 56 | 57 | let (gl, window) = unsafe { opengl_boilerplate(default_xres, default_yres, event_loop) }; 58 | 59 | let bv = &[ 60 | "src/basic.vert", 61 | "../../src/basic.vert", 62 | "basic.vert", 63 | ]; 64 | let bf = &[ 65 | "src/basic.frag", 66 | "../../src/basic.frag", 67 | "basic.frag", 68 | ]; 69 | 70 | let uvv = &[ 71 | "src/uv.vert", 72 | "../../src/uv.vert", 73 | "uv.vert", 74 | ]; 75 | let uvf = &[ 76 | "src/uv.frag", 77 | "../../src/uv.frag", 78 | "uv.frag", 79 | ]; 80 | 81 | let basic_shader = make_shader(&gl, bv, bf); 82 | let uv_shader = make_shader(&gl, uvv, uvf); 83 | 84 | let atlas = ImageBufferA::new_from_file("src/atlas.png") 85 | .or(ImageBufferA::new_from_file("../../src/atlas.png") 86 | .or(ImageBufferA::new_from_file("atlas.png"))) 87 | .expect("couldn't load atlas from ./atlas.png"); 88 | 89 | let renderer = Renderer::new(&gl, basic_shader); 90 | let renderer_uv = RendererUV::new(&gl, uv_shader, atlas); 91 | 92 | let mut scene_stack: Vec> = Vec::new(); 93 | scene_stack.push(Box::new(Victory{t: 0.0})); 94 | scene_stack.push(Box::new(WaveGame::new(0.0))); 95 | scene_stack.push(Box::new(Tutorial{})); 96 | 97 | Application { 98 | gl, 99 | window, 100 | renderer, 101 | renderer_uv, 102 | event_aggregator: EventAggregator::new(default_xres, default_yres), 103 | 104 | xres: default_xres, 105 | yres: default_yres, 106 | 107 | scene_stack, 108 | } 109 | } 110 | 111 | 112 | 113 | pub fn handle_scene_outcome(&mut self, so: SceneOutcome) { 114 | match so { 115 | SceneOutcome::Push(scene) => { 116 | self.scene_stack.push(scene); 117 | }, 118 | SceneOutcome::Pop(signal) => { 119 | self.scene_stack.pop(); 120 | if self.scene_stack.len() == 0 { 121 | self.destroy(); 122 | std::process::exit(0); 123 | } else { 124 | let stack_idx = self.scene_stack.len() - 1; 125 | let so = self.scene_stack[stack_idx].handle_signal(signal); 126 | self.handle_scene_outcome(so); 127 | } 128 | }, 129 | SceneOutcome::QuitProgram => { 130 | self.destroy(); 131 | std::process::exit(0); 132 | } 133 | SceneOutcome::None => {}, 134 | } 135 | } 136 | 137 | pub fn handle_event(&mut self, event: &glutin::event::Event<()>) { 138 | match event { 139 | Event::WindowEvent { ref event, .. } => match event { 140 | WindowEvent::Resized(physical_size) => { 141 | self.window.resize(*physical_size); 142 | self.xres = physical_size.width as f32; 143 | self.yres = physical_size.height as f32; 144 | unsafe {self.gl.viewport(0, 0, physical_size.width as i32, physical_size.height as i32)}; 145 | }, 146 | _ => {}, 147 | _ => {}, 148 | } 149 | _ => {}, 150 | } 151 | 152 | if let Some(inputs) = self.event_aggregator.handle_event(event) { 153 | let stack_idx = self.scene_stack.len()-1; 154 | 155 | unsafe { self.gl.clear(glow::COLOR_BUFFER_BIT | glow::DEPTH_BUFFER_BIT); } 156 | 157 | let (so, tris, op_triuvs) = self.scene_stack[stack_idx].frame(inputs); 158 | self.renderer.present(&self.gl, tris); 159 | if let Some(tri_uvs) = op_triuvs { 160 | self.renderer_uv.present(&self.gl, tri_uvs); 161 | } 162 | self.window.swap_buffers().unwrap(); 163 | 164 | self.handle_scene_outcome(so); 165 | } 166 | } 167 | 168 | pub fn destroy(&mut self) { 169 | self.renderer.destroy(&self.gl); 170 | } 171 | } 172 | 173 | fn make_shader(gl: &glow::Context, vert_paths: &[&str], frag_paths: &[&str]) -> glow::Program { 174 | unsafe { 175 | let program = gl.create_program().expect("Cannot create program"); 176 | let shader_version = "#version 410"; 177 | let shader_sources = [ 178 | (glow::VERTEX_SHADER, load_file(vert_paths)), 179 | (glow::FRAGMENT_SHADER, load_file(frag_paths)), 180 | ]; 181 | let mut shaders = Vec::with_capacity(shader_sources.len()); 182 | for (shader_type, shader_source) in shader_sources.iter() { 183 | let shader = gl 184 | .create_shader(*shader_type) 185 | .expect("Cannot create shader"); 186 | gl.shader_source(shader, &format!("{}\n{}", shader_version, shader_source)); 187 | gl.compile_shader(shader); 188 | if !gl.get_shader_compile_status(shader) { 189 | panic!("{}", gl.get_shader_info_log(shader)); 190 | } 191 | gl.attach_shader(program, shader); 192 | shaders.push(shader); 193 | } 194 | gl.link_program(program); 195 | if !gl.get_program_link_status(program) { 196 | panic!("{}", gl.get_program_info_log(program)); 197 | } 198 | for shader in shaders { 199 | gl.detach_shader(program, shader); 200 | gl.delete_shader(shader); 201 | } 202 | 203 | program 204 | } 205 | } 206 | 207 | unsafe fn opengl_boilerplate(xres: f32, yres: f32, event_loop: &glutin::event_loop::EventLoop<()>) -> (glow::Context, glutin::WindowedContext) { 208 | let window_builder = glutin::window::WindowBuilder::new() 209 | .with_title("wizrad") 210 | .with_inner_size(glutin::dpi::PhysicalSize::new(xres, yres)); 211 | let window = glutin::ContextBuilder::new() 212 | // .with_depth_buffer(0) 213 | // .with_srgb(true) 214 | // .with_stencil_buffer(0) 215 | .with_vsync(true) 216 | .build_windowed(window_builder, &event_loop) 217 | .unwrap() 218 | .make_current() 219 | .unwrap(); 220 | 221 | 222 | let gl = glow::Context::from_loader_function(|s| window.get_proc_address(s) as *const _); 223 | gl.enable(DEPTH_TEST); 224 | // gl.enable(CULL_FACE); 225 | gl.blend_func(SRC_ALPHA, ONE_MINUS_SRC_ALPHA); 226 | gl.enable(BLEND); 227 | gl.debug_message_callback(|a, b, c, d, msg| { 228 | println!("{} {} {} {} msg: {}", a, b, c, d, msg); 229 | }); 230 | 231 | (gl, window) 232 | } -------------------------------------------------------------------------------- /src/entity.rs: -------------------------------------------------------------------------------- 1 | use crate::components::make_entities::*; 2 | use crate::kmath::*; 3 | 4 | use crate::wave_game::*; 5 | use crate::spell::*; 6 | 7 | use crate::components::team::*; 8 | use crate::components::ai::*; 9 | use crate::components::health::*; 10 | use crate::components::caster::*; 11 | use crate::components::projectile::*; 12 | use crate::components::render::*; 13 | use crate::components::expiry::*; 14 | use crate::components::emitter::*; 15 | use crate::components::player::*; 16 | use crate::components::physics::*; 17 | use crate::components::melee_damage::*; 18 | use crate::components::spawn_list::*; 19 | 20 | #[derive(Clone)] 21 | pub struct Entity { 22 | pub ai: Option, 23 | pub ai_caster: Option, 24 | pub team: Option, 25 | pub caster: Option, 26 | pub emitter: Option, 27 | pub health: Option, 28 | pub melee_damage: Option, 29 | pub projectile: Option, 30 | pub render: Option, 31 | pub expiry: Option, 32 | pub physics: Option, 33 | pub player: Option, 34 | pub rect: Option, 35 | pub spawn_list: Option, 36 | pub make_on_damage: Option, 37 | pub make_on_death: Option, 38 | } 39 | 40 | // there could be such a ncie builder 41 | 42 | impl Entity { 43 | pub fn new() -> Entity { 44 | Entity { 45 | ai: None, 46 | ai_caster: None, 47 | team: None, 48 | caster: None, 49 | emitter: None, 50 | health: None, 51 | melee_damage: None, 52 | projectile: None, 53 | render: None, 54 | expiry: None, 55 | physics: None, 56 | player: None, 57 | rect: None, 58 | spawn_list: None, 59 | make_on_damage: None, 60 | make_on_death: None, 61 | } 62 | } 63 | 64 | pub fn with_ai(mut self, acquisition_range: f32, flee_range: f32, speed: f32, accel: f32) -> Entity { 65 | self.ai = Some(AI { 66 | acquisition_range, 67 | flee_range, 68 | speed, 69 | accel, 70 | dir: Vec2::new(0.0, 0.0), 71 | }); 72 | self 73 | } 74 | 75 | pub fn with_team(mut self, team: u32) -> Entity { 76 | self.team = Some(Team { 77 | team 78 | }); 79 | self 80 | } 81 | 82 | pub fn with_emitter(mut self, interval: f32, colour: Vec3, speed: f32, lifespan: f32, size: f32) -> Entity { 83 | self.emitter = Some(Emitter { 84 | interval, 85 | colour, 86 | speed, 87 | lifespan, 88 | size: Vec2::new(size, size), 89 | last: 0.0, 90 | }); 91 | self 92 | } 93 | 94 | pub fn with_health(mut self, max: f32, regen: f32) -> Entity { 95 | self.health = Some(Health { 96 | max, 97 | current: max, 98 | regen, 99 | invul_time: -1.0, 100 | }); 101 | self 102 | } 103 | 104 | pub fn with_melee_damage(mut self, amount: f32) -> Entity { 105 | self.melee_damage = Some(MeleeDamage { 106 | amount 107 | }); 108 | self 109 | } 110 | 111 | pub fn with_projectile(mut self, source: u32, damage: f32) -> Entity { 112 | self.projectile = Some(Projectile { 113 | source, 114 | damage, 115 | aoe: 0.0, 116 | splat_duration: 0.0, 117 | lifesteal_percent: 0.0, 118 | }); 119 | self 120 | } 121 | 122 | pub fn with_projectile_ex(mut self, source: u32, damage: f32, aoe: f32, splat_duration: f32, lifesteal_percent: f32) -> Entity { 123 | self.projectile = Some(Projectile { 124 | source, 125 | damage, 126 | aoe, 127 | splat_duration, 128 | lifesteal_percent, 129 | }); 130 | self 131 | } 132 | 133 | pub fn with_render_solid(mut self, colour: Vec3) -> Entity { 134 | self.render = Some(Render::Colour(colour)); 135 | self 136 | } 137 | 138 | pub fn with_expiry(mut self, when: f32) -> Entity { 139 | self.expiry = Some(Expiry { 140 | expiry: when, 141 | }); 142 | self 143 | } 144 | 145 | pub fn with_physics(mut self, mass: f32, velocity: Vec2) -> Entity { 146 | self.physics = Some(Physics { 147 | mass, 148 | old_pos: Vec2::new(0.0, 0.0), // ruh roh shraggy 149 | velocity, 150 | }); 151 | self 152 | } 153 | 154 | pub fn with_rect(mut self, rect: Rect) -> Entity { 155 | self.rect = Some(rect); 156 | self 157 | } 158 | 159 | pub fn with_position(mut self, pos: Vec2) -> Entity { 160 | let r = self.rect.unwrap(); 161 | self.rect = Some(Rect::new_centered(pos.x, pos.y, r.w, r.h)); 162 | self 163 | } 164 | 165 | pub fn with_ai_caster(mut self, acquisition_range: f32, spell: Spell) -> Entity { 166 | self.ai_caster = Some(AICaster { 167 | acquisition_range, 168 | spell, 169 | unleasher: false, 170 | rising: false, 171 | }); 172 | self 173 | } 174 | pub fn with_ai_caster_unleasher(mut self, acquisition_range: f32, spell: Spell) -> Entity { 175 | self.ai_caster = Some(AICaster { 176 | acquisition_range, 177 | spell, 178 | unleasher: true, 179 | rising: false, 180 | }); 181 | self 182 | } 183 | 184 | pub fn with_caster(mut self, mana_max: f32, mana_regen: f32) -> Entity { 185 | self.caster = Some(Caster { 186 | mana_max, 187 | mana: mana_max, 188 | mana_regen, 189 | last_cast: -10000.0, 190 | }); 191 | self 192 | } 193 | 194 | pub fn with_player(mut self, speed: f32, spellbook: Vec) -> Entity { 195 | self.player = Some(Player { 196 | spellbook, 197 | speed, 198 | spell_cursor: 0, 199 | kills: 0, 200 | }); 201 | self 202 | } 203 | } 204 | 205 | impl WaveGame { 206 | pub fn add_entity(&mut self, entity: &Entity) { 207 | let id = self.entity_id_counter; 208 | self.entity_id_counter += 1; 209 | self.entity_ids.insert(id); 210 | 211 | if let Some(player) = entity.player.clone() { 212 | self.player.insert(id, player); 213 | } 214 | if let Some(caster) = entity.caster.clone() { 215 | self.caster.insert(id, caster); 216 | } 217 | if let Some(expiry) = entity.expiry.clone() { 218 | self.expiry.insert(id, expiry); 219 | } 220 | if let Some(ai) = entity.ai.clone() { 221 | self.ai.insert(id, ai); 222 | } 223 | if let Some(ai_caster) = entity.ai_caster.clone() { 224 | self.ai_caster.insert(id, ai_caster); 225 | } 226 | if let Some(physics) = entity.physics.clone() { 227 | self.physics.insert(id, physics); 228 | } 229 | if let Some(render) = entity.render.clone() { 230 | self.render.insert(id, render); 231 | } 232 | if let Some(team) = entity.team.clone() { 233 | self.team.insert(id, team); 234 | } 235 | if let Some(emitter) = entity.emitter.clone() { 236 | self.emitter.insert(id, emitter); 237 | } 238 | if let Some(projectile) = entity.projectile.clone() { 239 | self.projectile.insert(id, projectile); 240 | } 241 | if let Some(melee_damage) = entity.melee_damage.clone() { 242 | self.melee_damage.insert(id, melee_damage); 243 | } 244 | if let Some(health) = entity.health.clone() { 245 | self.health.insert(id, health); 246 | } 247 | if let Some(rect) = entity.rect { 248 | self.rect.insert(id, rect); 249 | } 250 | if let Some(spawn_list) = entity.spawn_list.clone() { 251 | self.spawn_list.insert(id, spawn_list); 252 | } 253 | if let Some(make_on_damage) = entity.make_on_damage.clone() { 254 | self.make_on_damage.insert(id, make_on_damage); 255 | } 256 | if let Some(make_on_death) = entity.make_on_death.clone() { 257 | self.make_on_death.insert(id, make_on_death); 258 | } 259 | } 260 | } -------------------------------------------------------------------------------- /src/entity_definitions.rs: -------------------------------------------------------------------------------- 1 | use crate::kmath::*; 2 | use crate::spell::*; 3 | use crate::wave_game::*; 4 | use crate::manifest::*; 5 | use crate::entity::*; 6 | 7 | use crate::components::team::*; 8 | use crate::components::ai::*; 9 | use crate::components::health::*; 10 | use crate::components::caster::*; 11 | use crate::components::projectile::*; 12 | use crate::components::render::*; 13 | use crate::components::expiry::*; 14 | use crate::components::emitter::*; 15 | use crate::components::player::*; 16 | use crate::components::melee_damage::*; 17 | use crate::components::physics::*; 18 | 19 | const acquisition_range: f32 = 30.0; 20 | 21 | pub fn entity_player(pos: Vec2) -> Entity { 22 | Entity::new() 23 | // .with_player(10.0, vec![Spell::Missile, Spell::Pulse, Spell::ConeFlames, Spell::Water, Spell::Fireball, Spell::SummonRushers, Spell::Lifesteal, Spell::SummonBloodcasters, Spell::Homing]) 24 | .with_player(10.0, vec![]) 25 | .with_caster(100.0, 30.0) 26 | .with_team(TEAM_PLAYER) 27 | .with_physics(1.0, Vec2::new(0.0, 0.0)) 28 | .with_rect(Rect::new_centered(pos.x, pos.y, 1.0, 1.0)) 29 | .with_health(100.0, 1.0) 30 | .with_render_solid(Vec3::new(1.0, 0.0, 1.0)) 31 | } 32 | 33 | pub fn entity_basic(pos: Vec2) -> Entity { 34 | Entity::new() 35 | .with_team(TEAM_ENEMIES) 36 | .with_physics(1.0, Vec2::new(0.0, 0.0)) 37 | .with_rect(Rect::new_centered(pos.x, pos.y, 1.0, 1.0)) 38 | .with_melee_damage(20.0) 39 | .with_health(50.0, 1.0) 40 | .with_ai(acquisition_range, 0.0, 4.0, 6.0) 41 | .with_render_solid(Vec3::new(1.0, 0.0, 0.0)) 42 | } 43 | 44 | pub fn entity_zerg(team: u32, pos: Vec2) -> Entity { 45 | Entity::new() 46 | .with_team(team) 47 | .with_physics(0.25, Vec2::new(0.0, 0.0)) 48 | .with_rect(Rect::new_centered(pos.x, pos.y, 0.5, 0.5)) 49 | .with_melee_damage(20.0) 50 | .with_health(20.0, 1.0) 51 | .with_ai(acquisition_range, 0.0, 7.0, 6.0) 52 | .with_render_solid(Vec3::new(0.7, 0.0, 0.0)) 53 | } 54 | 55 | pub fn entity_caster(pos: Vec2) -> Entity { 56 | Entity::new() 57 | .with_team(TEAM_ENEMIES) 58 | .with_physics(0.7, Vec2::new(0.0, 0.0)) 59 | .with_rect(Rect::new_centered(pos.x, pos.y, 0.9, 0.9)) 60 | .with_health(20.0, 1.0) 61 | .with_ai(acquisition_range, 5.0, 3.0, 6.0) 62 | .with_render_solid(Vec3::new(0.0, 0.8, 0.8)) 63 | .with_ai_caster(9.0, Spell::Missile) 64 | .with_caster(10.0, 3.0) 65 | } 66 | 67 | pub fn entity_pulsecaster(pos: Vec2) -> Entity { 68 | Entity::new() 69 | .with_team(TEAM_ENEMIES) 70 | .with_physics(0.7, Vec2::new(0.0, 0.0)) 71 | .with_rect(Rect::new_centered(pos.x, pos.y, 0.9, 0.9)) 72 | 73 | .with_health(30.0, 1.0) 74 | .with_ai(acquisition_range, 2.0, 5.0, 6.0) 75 | .with_render_solid(Vec3::new(0.8, 0.6, 0.8)) 76 | .with_ai_caster(3.0, Spell::Pulse) 77 | .with_caster(50.0, 12.0) 78 | } 79 | 80 | pub fn entity_bloodcaster(team: u32, pos: Vec2) -> Entity{ 81 | Entity::new() 82 | .with_team(team) 83 | .with_physics(0.7, Vec2::new(0.0, 0.0)) 84 | .with_rect(Rect::new_centered(pos.x, pos.y, 0.9, 0.9)) 85 | .with_health(40.0, 1.0) 86 | .with_ai(acquisition_range, 5.0, 5.0, 6.0) 87 | .with_render_solid(Vec3::new(0.4, 0.3, 0.3)) 88 | .with_ai_caster(7.0, Spell::Lifesteal) 89 | .with_caster(0.0, 0.0) 90 | } 91 | 92 | pub fn entity_summoner(team: u32, pos: Vec2) -> Entity { 93 | Entity::new() 94 | .with_team(team) 95 | .with_physics(2.0, Vec2::new(0.0, 0.0)) 96 | .with_rect(Rect::new_centered(pos.x, pos.y, 1.2, 1.2)) 97 | .with_health(100.0, 1.0) 98 | .with_ai(acquisition_range, 0.0, 2.0, 6.0) 99 | .with_render_solid(Vec3::new(0.5, 0.0, 0.0)) 100 | .with_ai_caster(10.0, Spell::SummonRushers) 101 | .with_caster(20.0, 2.0) 102 | } 103 | 104 | pub fn entity_summoner_summoner(team: u32, pos: Vec2) -> Entity { 105 | Entity::new() 106 | .with_team(team) 107 | .with_physics(4.0, Vec2::new(0.0, 0.0)) 108 | .with_rect(Rect::new_centered(pos.x, pos.y, 1.8, 1.8)) 109 | .with_health(200.0, 1.0) 110 | .with_ai(acquisition_range, 0.0, 1.6, 6.0) 111 | .with_render_solid(Vec3::new(0.3, 0.0, 0.0)) 112 | .with_ai_caster(12.0, Spell::SummonSummoners) 113 | .with_caster(100.0, 3.0) 114 | } 115 | 116 | 117 | 118 | impl WaveGame { 119 | pub fn add_flame_projectile(&mut self, caster: u32, target: Vec2, t: f32) { 120 | let id = self.entity_id_counter; 121 | self.entity_id_counter += 1; 122 | self.entity_ids.insert(id); 123 | 124 | let lifespan = kuniform(id * 4234777, 0.6, 0.8); 125 | 126 | let (team, pos, v) = { 127 | let caster_comp = self.team.get(&caster).unwrap(); 128 | let caster_phys = self.physics.get(&caster).unwrap(); 129 | let caster_pos = self.rect.get(&caster).unwrap().centroid(); 130 | let v = (target - caster_pos).normalize() * 10.0; 131 | let team = caster_comp.team; 132 | (team, caster_pos, v) 133 | }; 134 | let spray = 0.25; 135 | let spray_angle = kuniform(id * 4134123, -spray, spray); 136 | let v = v.rotate(spray_angle); 137 | 138 | self.team.insert(id, Team { 139 | team: team, 140 | }); 141 | self.physics.insert(id, Physics { 142 | velocity: v, 143 | mass: 0.0, 144 | old_pos: Vec2::new(0.0, 0.0), 145 | }); 146 | self.rect.insert(id, Rect::new_centered(pos.x, pos.y, 0.2, 0.2)); 147 | self.projectile.insert(id, Projectile { 148 | source: caster, 149 | damage: 2.0, 150 | aoe: 0.0, 151 | splat_duration: 0.0, 152 | lifesteal_percent: 0.0, 153 | }); 154 | 155 | self.render.insert(id, Render::FOfT(FOfT { 156 | f: |t| { 157 | let fire_gradient = vec![ 158 | (Vec3::new(1.0, 1.0, 1.0), 0.0), 159 | (Vec3::new(1.0, 1.0, 0.0), 0.3), 160 | (Vec3::new(1.0, 0.0, 0.0), 0.6), 161 | (Vec3::new(0.0, 0.0, 0.0), 1.0), 162 | ]; 163 | gradient(t, fire_gradient) 164 | }, 165 | t_start: t, 166 | t_end: t + lifespan, 167 | })); 168 | self.expiry.insert(id, Expiry {expiry: t + lifespan}); 169 | } 170 | 171 | pub fn add_water_projectile(&mut self, caster: u32, target: Vec2, t: f32) { 172 | let id = self.entity_id_counter; 173 | self.entity_id_counter += 1; 174 | self.entity_ids.insert(id); 175 | 176 | let lifespan = kuniform(id * 4234777, 0.6, 0.8); 177 | 178 | let (team, pos, v) = { 179 | let caster_comp = self.team.get(&caster).unwrap(); 180 | let caster_phys = self.physics.get(&caster).unwrap(); 181 | let caster_pos = self.rect.get(&caster).unwrap().centroid(); 182 | let v = (target - caster_pos).normalize() * 6.0; 183 | let team = caster_comp.team; 184 | (team, caster_pos, v) 185 | }; 186 | let spray = 0.6; 187 | let spray_angle = kuniform(id * 4134123, -spray, spray); 188 | let v = v.rotate(spray_angle); 189 | 190 | self.team.insert(id, Team { 191 | team: team, 192 | }); 193 | self.physics.insert(id, Physics { 194 | velocity: v, 195 | mass: 20.0, 196 | old_pos: Vec2::new(0.0, 0.0), 197 | }); 198 | self.rect.insert(id, Rect::new_centered(pos.x, pos.y, 0.2, 0.2)); 199 | self.projectile.insert(id, Projectile { 200 | source: caster, 201 | damage: 0.0, 202 | aoe: 0.0, 203 | splat_duration: 0.0, 204 | lifesteal_percent: 0.0, 205 | }); 206 | 207 | self.render.insert(id, Render::FOfT(FOfT { 208 | f: |t| { 209 | let water_gradient = vec![ 210 | (Vec3::new(0.1, 0.3, 1.0), 0.0), 211 | (Vec3::new(0.1, 0.3, 1.0), 0.8), 212 | (Vec3::new(1.0, 1.0, 1.0), 1.0), 213 | ]; 214 | gradient(t, water_gradient) 215 | }, 216 | t_start: t, 217 | t_end: t + lifespan, 218 | })); 219 | self.expiry.insert(id, Expiry {expiry: t + lifespan}); 220 | } 221 | pub fn add_fireball(&mut self, caster: u32, target: Vec2, t: f32) { 222 | let id = self.entity_id_counter; 223 | self.entity_id_counter += 1; 224 | self.entity_ids.insert(id); 225 | 226 | let (team, pos, v) = { 227 | let caster_comp = self.team.get(&caster).unwrap(); 228 | let caster_phys = self.physics.get(&caster).unwrap(); 229 | let caster_pos = self.rect.get(&caster).unwrap().centroid(); 230 | let v = (target - caster_pos).normalize() * 10.0; 231 | let team = caster_comp.team; 232 | (team, caster_pos, v) 233 | }; 234 | self.team.insert(id, Team { 235 | team: team, 236 | }); 237 | self.physics.insert(id, Physics { 238 | velocity: v, 239 | mass: 1.0, 240 | old_pos: Vec2::new(0.0, 0.0), 241 | }); 242 | self.rect.insert(id, Rect::new_centered(pos.x, pos.y, 0.5, 0.5)); 243 | self.projectile.insert(id, Projectile { 244 | source: caster, 245 | damage: 50.0, 246 | aoe: 4.0, 247 | splat_duration: 0.7, 248 | lifesteal_percent: 0.0, 249 | }); 250 | self.render.insert(id, Render::Colour(Vec3::new(1.0, 0.1, 0.0))); 251 | self.emitter.insert(id, Emitter { 252 | interval: 0.2, 253 | last: 0.0, 254 | size: Vec2::new(0.15, 0.15), 255 | speed: 0.3, 256 | colour: Vec3::new(0.3, 0.3, 0.3), 257 | lifespan: 0.5, 258 | }); 259 | self.expiry.insert(id, Expiry {expiry: t + 10.0}); 260 | } 261 | pub fn add_firesplat(&mut self, target: Vec2, t: f32) { 262 | let id = self.entity_id_counter; 263 | self.entity_id_counter += 1; 264 | self.entity_ids.insert(id); 265 | self.rect.insert(id, Rect::new_centered(target.x, target.y, 0.5, 0.5)); 266 | self.render.insert(id, Render::FireSplat(6.0)); 267 | self.expiry.insert(id, Expiry {expiry: t + 0.4}); 268 | } 269 | } -------------------------------------------------------------------------------- /src/kmath.rs: -------------------------------------------------------------------------------- 1 | use itertools::Itertools; 2 | 3 | /*************************************************** 4 | * Easing 5 | ***************************************************/ 6 | pub fn unlerp(x: f32, t1: f32, t2: f32) -> f32 { 7 | (x - t1) / (t2 - t1) 8 | } 9 | 10 | pub fn gradient(t: f32, colours: Vec<(Vec3, f32)>) -> Vec3 { 11 | // find nearest 2 neighbours in colours vec and interp between them 12 | for ((c1, t1), (c2, t2)) in colours.iter().tuple_windows() { 13 | if t >= *t1 && t <= *t2 { 14 | return c1.lerp(*c2, unlerp(t, *t1, *t2)); 15 | } 16 | } 17 | 18 | Vec3::new(1.0, 1.0, 1.0) 19 | } 20 | 21 | /*************************************************** 22 | * RNG 23 | ***************************************************/ 24 | 25 | pub fn khash(mut state: u32) -> u32 { 26 | state = (state ^ 2747636419) * 2654435769; 27 | state = (state ^ (state >> 16)) * 2654435769; 28 | state = (state ^ (state >> 16)) * 2654435769; 29 | state 30 | } 31 | 32 | pub fn krand(seed: u32) -> f32 { 33 | khash(seed) as f32 / 4294967295.0 34 | } 35 | 36 | pub fn kuniform(seed: u32, min: f32, max: f32) -> f32 { 37 | min + (khash(seed) as f32 / 4294967295.0) * (max - min) 38 | } 39 | 40 | /*************************************************** 41 | * Vec 42 | ***************************************************/ 43 | 44 | #[derive(Copy, Clone, Debug, PartialEq)] 45 | pub struct Vec2 { 46 | pub x: f32, 47 | pub y: f32, 48 | } 49 | 50 | impl Vec2 { 51 | pub const fn new(x: f32, y: f32) -> Vec2 { Vec2{x, y} } 52 | pub fn mul_scalar(&self, scalar: f32) -> Vec2 { Vec2::new(self.x * scalar, self.y * scalar) } 53 | pub fn div_scalar(&self, scalar: f32) -> Vec2 { Vec2::new(self.x / scalar, self.y / scalar) } 54 | pub fn magnitude(&self) -> f32 { (self.x*self.x + self.y*self.y).sqrt() } 55 | pub fn dist(&self, other: Vec2) -> f32 { (*self - other).magnitude() } 56 | pub fn normalize(&self) -> Vec2 { let m = self.magnitude(); if m == 0.0 { *self } else { self.div_scalar(self.magnitude()) }} 57 | pub fn lerp(&self, other: Vec2, t: f32) -> Vec2 { Vec2::new(self.x*(1.0-t) + other.x*(t), self.y*(1.0-t) + other.y*(t)) } 58 | pub fn rotate(&self, radians: f32) -> Vec2 { 59 | Vec2::new( 60 | self.x * radians.cos() - self.y * radians.sin(), 61 | self.x * radians.sin() + self.y * radians.cos() 62 | ) 63 | } 64 | pub fn offset_r_theta(&self, r: f32, theta: f32) -> Vec2 { 65 | *self + Vec2::new(r, 0.0).rotate(theta) 66 | } 67 | } 68 | 69 | impl std::ops::Sub for Vec2 { 70 | type Output = Vec2; 71 | 72 | fn sub(self, _rhs: Vec2) -> Vec2 { 73 | Vec2 { x: self.x - _rhs.x, y: self.y - _rhs.y } 74 | } 75 | } 76 | 77 | impl std::ops::Add for Vec2 { 78 | type Output = Vec2; 79 | 80 | fn add(self, _rhs: Vec2) -> Vec2 { 81 | Vec2 { x: self.x + _rhs.x, y: self.y + _rhs.y } 82 | } 83 | } 84 | 85 | impl std::ops::Mul for Vec2 { 86 | type Output = Vec2; 87 | 88 | fn mul(self, _rhs: f32) -> Vec2 { 89 | self.mul_scalar(_rhs) 90 | } 91 | } 92 | 93 | impl std::ops::Mul for f32 { 94 | type Output = Vec2; 95 | 96 | fn mul(self, _rhs: Vec2) -> Vec2 { 97 | _rhs.mul_scalar(self) 98 | } 99 | } 100 | 101 | impl std::ops::Div for Vec2 { 102 | type Output = Vec2; 103 | 104 | fn div(self, _rhs: f32) -> Vec2 { 105 | self.div_scalar(_rhs) 106 | } 107 | } 108 | 109 | impl std::ops::Neg for Vec2 { 110 | type Output = Vec2; 111 | 112 | fn neg(self) -> Vec2 { 113 | self.mul_scalar(-1.0) 114 | } 115 | } 116 | 117 | #[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] 118 | pub struct Vec3 { 119 | pub x: f32, 120 | pub y: f32, 121 | pub z: f32, 122 | } 123 | 124 | impl Vec3 { 125 | pub const fn new(x: f32, y: f32, z: f32) -> Vec3 { Vec3{x, y, z} } 126 | pub fn mul_scalar(&self, scalar: f32) -> Vec3 { Vec3::new(self.x * scalar, self.y * scalar, self.z * scalar) } 127 | pub fn div_scalar(&self, scalar: f32) -> Vec3 { Vec3::new(self.x / scalar, self.y / scalar, self.z / scalar) } 128 | pub fn magnitude(&self) -> f32 { (self.x*self.x + self.y*self.y + self.z*self.z).sqrt() } 129 | pub fn square_distance(&self) -> f32 { self.x*self.x + self.y*self.y + self.z*self.z } 130 | pub fn normalize(&self) -> Vec3 { self.div_scalar(self.magnitude()) } 131 | pub fn lerp(&self, other: Vec3, t: f32) -> Vec3 { Vec3::new(self.x*(1.0-t) + other.x*(t), self.y*(1.0-t) + other.y*(t), self.z*(1.0-t) + other.z*(t)) } 132 | pub fn dist(&self, other: Vec3) -> f32 {(*self - other).magnitude().sqrt()} 133 | pub fn dot(&self, other: Vec3) -> f32 {self.x*other.x + self.y*other.y + self.z*other.z} // is squ dist lol 134 | pub fn cross(&self, other: Vec3) -> Vec3 { 135 | Vec3::new( 136 | self.y*other.z - self.z*other.y, 137 | self.z*other.x - self.x*other.z, 138 | self.x*other.y - self.y*other.x, 139 | ) 140 | } 141 | pub fn rotate_about_vec3(&self, axis: Vec3, theta: f32) -> Vec3 { 142 | *self*theta.cos() + (axis.cross(*self)*theta.sin()) + axis * (axis.dot(*self)*(1.0 - theta.cos())) 143 | } 144 | } 145 | 146 | impl std::ops::Sub for Vec3 { 147 | type Output = Vec3; 148 | 149 | fn sub(self, _rhs: Vec3) -> Vec3 { 150 | Vec3 { x: self.x - _rhs.x, y: self.y - _rhs.y, z: self.z - _rhs.z } 151 | } 152 | } 153 | 154 | impl std::ops::Add for Vec3 { 155 | type Output = Vec3; 156 | 157 | fn add(self, _rhs: Vec3) -> Vec3 { 158 | Vec3 { x: self.x + _rhs.x, y: self.y + _rhs.y, z: self.z + _rhs.z} 159 | } 160 | } 161 | 162 | impl std::ops::Mul for Vec3 { 163 | type Output = Vec3; 164 | 165 | fn mul(self, _rhs: f32) -> Vec3 { 166 | self.mul_scalar(_rhs) 167 | } 168 | } 169 | 170 | impl std::ops::Mul for f32 { 171 | type Output = Vec3; 172 | 173 | fn mul(self, _rhs: Vec3) -> Vec3 { 174 | _rhs.mul_scalar(self) 175 | } 176 | } 177 | 178 | impl std::ops::Div for Vec3 { 179 | type Output = Vec3; 180 | 181 | fn div(self, _rhs: f32) -> Vec3 { 182 | self.div_scalar(_rhs) 183 | } 184 | } 185 | 186 | impl std::ops::Neg for Vec3 { 187 | type Output = Vec3; 188 | 189 | fn neg(self) -> Vec3 { 190 | self.mul_scalar(-1.0) 191 | } 192 | } 193 | 194 | impl std::ops::AddAssign for Vec3 { 195 | 196 | fn add_assign(&mut self, rhs: Vec3) { 197 | self.x += rhs.x; 198 | self.y += rhs.y; 199 | self.z += rhs.z; 200 | } 201 | } 202 | 203 | impl std::fmt::Display for Vec3 { 204 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 205 | let decimals = f.precision().unwrap_or(2); 206 | let string = format!("[{:.*}, {:.*}, {:.*}]", decimals, self.x, decimals, self.y, decimals, self.z); 207 | f.pad_integral(true, "", &string) 208 | } 209 | } 210 | 211 | 212 | /*************************************************** 213 | * Shapes 214 | ***************************************************/ 215 | 216 | #[derive(Debug, Clone, Copy)] 217 | pub struct Rect { 218 | pub x: f32, 219 | pub y: f32, 220 | pub w: f32, 221 | pub h: f32, 222 | } 223 | 224 | impl Rect { 225 | pub fn new(x: f32, y: f32, w: f32, h: f32) -> Rect { 226 | Rect{x,y,w,h} 227 | } 228 | pub fn child(&self, x: f32, y: f32, w: f32, h: f32) -> Rect { 229 | Rect::new( 230 | self.x + x*self.w, 231 | self.y + y*self.h, 232 | self.w * w, 233 | self.h * h, 234 | ) 235 | } 236 | pub fn grid_child(&self, x: i32, y: i32, w: i32, h: i32) -> Rect { 237 | let r_w = self.w / w as f32; 238 | let r_h = self.h / h as f32; 239 | 240 | Rect::new( 241 | self.x + r_w * x as f32, 242 | self.y + r_h * y as f32, 243 | r_w, 244 | r_h, 245 | ) 246 | } 247 | pub fn fit_center_square(&self) -> Rect { 248 | let s = self.w.min(self.h); 249 | Rect::new_centered(self.x + self.w / 2.0, self.y + self.h / 2.0, s, s) 250 | } 251 | pub fn fit_aspect_ratio(&self, a: f32) -> Rect { 252 | let our_a = self.w / self.h; 253 | if our_a < a { 254 | // big a means wide 255 | // they want wider 256 | let other_h = our_a / a * self.h; 257 | let other_y = self.y + (self.h - other_h) / 2.0; 258 | Rect::new(self.x, other_y, self.w, other_h) 259 | } else { 260 | // they want taller 261 | let other_w = a / our_a * self.w; 262 | let other_x = self.x + (self.w - other_w) / 2.0; 263 | Rect::new(other_x, self.y, other_w, self.h) 264 | } 265 | } 266 | pub fn centroid(&self) -> Vec2 { 267 | Vec2::new(self.x + self.w/2.0, self.y + self.h/2.0) 268 | } 269 | pub fn new_centered(x: f32, y: f32, w: f32, h: f32) -> Rect { 270 | Rect::new(x-w/2.0, y-h/2.0, w, h) 271 | } 272 | pub fn translate(&self, v: Vec2) -> Rect { 273 | return Rect::new(self.x + v.x, self.y + v.y, self.w, self.h); 274 | } 275 | pub fn dilate(&self, d: f32) -> Rect { 276 | return Rect::new(self.x - d, self.y - d, self.w + 2.0*d, self.h + 2.0*d); 277 | } 278 | pub fn left(self) -> f32 { 279 | self.x 280 | } 281 | pub fn right(self) -> f32 { 282 | self.x + self.w 283 | } 284 | pub fn top(self) -> f32 { 285 | self.y 286 | } 287 | pub fn bot(self) -> f32 { 288 | self.y + self.h 289 | } 290 | pub fn tl(self) -> Vec2 { 291 | Vec2::new(self.x, self.y) 292 | } 293 | pub fn tr(self) -> Vec2 { 294 | Vec2::new(self.x + self.w, self.y) 295 | } 296 | pub fn bl(self) -> Vec2 { 297 | Vec2::new(self.x, self.y + self.h) 298 | } 299 | pub fn br(self) -> Vec2 { 300 | Vec2::new(self.x + self.w, self.y + self.h) 301 | } 302 | pub fn contains(self, point: Vec2) -> bool { 303 | self.x < point.x && self.x + self.w > point.x && 304 | self.y < point.y && self.y + self.h > point.y 305 | } 306 | pub fn relative_point(self, point: Vec2) -> Vec2 { 307 | Vec2::new((point.x - self.x) / self.w, (point.y - self.y) / self.h) 308 | } 309 | pub fn grid_square(self, point: Vec2, w: i32, h: i32) -> (i32, i32) { 310 | ((w as f32 * point.x) as i32, (h as f32 * point.y) as i32) 311 | } 312 | pub fn tri_child(&self, which: usize) -> Triangle { 313 | match which { 314 | 0 => Triangle::new(self.tl(), self.tr(), self.centroid()), 315 | 1 => Triangle::new(self.tr(), self.br(), self.centroid()), 316 | 2 => Triangle::new(self.br(), self.bl(), self.centroid()), 317 | 3 => Triangle::new(self.bl(), self.tl(), self.centroid()), 318 | _ => panic!("bad triangle number"), 319 | } 320 | } 321 | } 322 | 323 | pub struct Triangle { 324 | pub a: Vec2, 325 | pub b: Vec2, 326 | pub c: Vec2, 327 | } 328 | 329 | impl Triangle { 330 | pub fn new(a: Vec2, b: Vec2, c: Vec2) -> Triangle { 331 | Triangle {a, b, c} 332 | } 333 | 334 | pub fn dilate(&self, d: f32) -> Triangle { 335 | let centroid = Vec2::new((self.a.x + self.b.x + self.c.x) / 3.0, (self.a.y + self.b.y + self.c.y) / 3.0); 336 | Triangle::new( 337 | self.a + (self.a - centroid) * d, 338 | self.b + (self.b - centroid) * d, 339 | self.c + (self.c - centroid) * d, 340 | ) 341 | } 342 | 343 | pub fn contains(&self, p: Vec2) -> bool { 344 | let denom = self.a.x * (self.b.y - self.c.y) + self.a.y * (self.c.x - self.b.x) + self.b.x*self.c.y - self.b.y * self.c.x; 345 | let t1 = (p.x * (self.c.y - self.a.y) + p.y * (self.a.x - self.c.x) - self.a.x*self.c.y + self.a.y*self.c.x) / denom; 346 | let t2 = (p.x * (self.b.y - self.a.y) + p.y * (self.a.x - self.b.x) - self.a.x*self.b.y + self.a.y*self.b.x) / -denom; 347 | let s = t1 + t2; 348 | 349 | return 0.0 <= t1 && t1 <= 1.0 && 0.0 <= t2 && t2 <= 1.0 && s <= 1.0; 350 | } 351 | } -------------------------------------------------------------------------------- /src/spell.rs: -------------------------------------------------------------------------------- 1 | use std::f32::consts::PI; 2 | 3 | use crate::kmath::*; 4 | use crate::manifest::*; 5 | use crate::wave_game::*; 6 | use crate::entity_definitions::*; 7 | use crate::entity::*; 8 | 9 | #[derive(Clone, Copy, PartialEq, Eq, Hash)] 10 | pub enum Spell { 11 | Missile, 12 | Pulse, 13 | Lifesteal, 14 | SummonBloodcasters, 15 | ConeFlames, 16 | SummonRushers, 17 | SummonSummoners, 18 | Fireball, 19 | Firestorm, 20 | Water, 21 | Healing, 22 | Homing, 23 | Barrage, 24 | } 25 | 26 | impl WaveGame { 27 | pub fn cast_spell(&mut self, t: f32, caster_id: u32, target: Vec2, spell: Spell, repeat: bool, seed: u32, dt: f32) { 28 | let caster_team = self.team.get(&caster_id).unwrap().team; 29 | let caster_pos = self.rect.get(&caster_id).unwrap().centroid(); 30 | if let Some(cc) = self.caster.get_mut(&caster_id) { 31 | match spell { 32 | Spell::ConeFlames => { 33 | // frame rate dependent...... needs to emit a certain amount per unit time 34 | let cost = 1.0; 35 | if cc.mana >= cost { 36 | cc.mana -= cost; 37 | self.add_flame_projectile(caster_id, target, t); 38 | self.add_flame_projectile(caster_id, target, t); 39 | self.add_flame_projectile(caster_id, target, t); 40 | self.add_flame_projectile(caster_id, target, t); 41 | } 42 | }, 43 | Spell::Barrage => { 44 | if cc.last_cast + 0.1 > t { return ; } 45 | cc.last_cast = t; 46 | 47 | 48 | let cost = 5.0; 49 | if cc.mana >= cost { 50 | cc.mana -= cost; 51 | let spread = 0.6; 52 | let vhat = (target - caster_pos).normalize().rotate(kuniform(seed * 12351, -spread, spread)); 53 | self.add_entity(&Entity::new() 54 | .with_team(caster_team) 55 | .with_physics(10.0, vhat * 9.0) 56 | .with_rect(Rect::new_centered(caster_pos.x, caster_pos.y, 0.5, 0.5)) 57 | .with_projectile(caster_id, 30.0) 58 | .with_emitter(0.05, Vec3::new(0.6, 0.0, 0.8), 2.0, 0.7, 0.1) 59 | .with_render_solid(Vec3::new(0.8, 0.0, 0.8))); 60 | } 61 | }, 62 | Spell::Water => { 63 | // frame rate dependent...... needs to emit a certain amount per unit time 64 | let cost = 0.4; 65 | if cc.mana >= cost { 66 | cc.mana -= cost; 67 | self.add_water_projectile(caster_id, target, t); 68 | self.add_water_projectile(caster_id, target, t); 69 | self.add_water_projectile(caster_id, target, t); 70 | self.add_water_projectile(caster_id, target, t); 71 | self.add_water_projectile(caster_id, target, t); 72 | self.add_water_projectile(caster_id, target, t); 73 | self.add_water_projectile(caster_id, target, t); 74 | } 75 | }, 76 | Spell::Missile => { 77 | if repeat { return; } 78 | if cc.last_cast + 0.3 > t { return ; } 79 | cc.last_cast = t; 80 | let cost = 10.0; 81 | if cc.mana >= cost { 82 | cc.mana -= cost; 83 | let missile = Entity::new() 84 | .with_team(caster_team) 85 | .with_physics(10.0, (target - caster_pos).normalize() * 15.0) 86 | .with_rect(Rect::new_centered(caster_pos.x, caster_pos.y, 0.4, 0.4)) 87 | .with_projectile(caster_id, 34.0) 88 | .with_emitter(0.05, Vec3::new(0.8, 0.0, 0.8), 2.0, 0.7, 0.1) 89 | .with_render_solid(Vec3::new(0.8, 0.0, 0.8)); 90 | self.add_entity(&missile); 91 | } 92 | }, 93 | Spell::Homing => { 94 | let colour = Vec3::new(0.0, 0.4, 1.0); 95 | let speed = 5.0; 96 | 97 | if repeat { return; } 98 | if cc.last_cast + 0.3 > t { return ; } 99 | cc.last_cast = t; 100 | let cost = 25.0; 101 | if cc.mana >= cost { 102 | cc.mana -= cost; 103 | let m1 = Entity::new() 104 | .with_team(caster_team) 105 | .with_physics(10.0, (target - caster_pos).normalize() * speed) 106 | .with_rect(Rect::new_centered(caster_pos.x, caster_pos.y, 0.5, 0.5)) 107 | .with_projectile(caster_id, 20.0) 108 | .with_emitter(0.05, colour, 2.0, 0.7, 0.1) 109 | .with_ai(999999.0, 0.0, speed, 0.8) // see if it works lmao 110 | .with_render_solid(colour); 111 | let m2 = m1.clone() 112 | .with_physics(10.0, (target - caster_pos).normalize().rotate(-1.0) * speed); 113 | let m3 = m1.clone() 114 | .with_physics(10.0, (target - caster_pos).normalize().rotate(1.0) * speed); 115 | 116 | self.add_entity(&m1); 117 | self.add_entity(&m2); 118 | self.add_entity(&m3); 119 | } 120 | }, 121 | Spell::Pulse => { 122 | if cc.last_cast + 0.1 > t { return ; } 123 | cc.last_cast = t; 124 | let cost = 6.0; 125 | if cc.mana >= cost { 126 | cc.mana -= cost; 127 | let missile = Entity::new() 128 | .with_team(caster_team) 129 | .with_physics(4.0, (target - caster_pos).normalize() * 25.0) 130 | .with_rect(Rect::new_centered(caster_pos.x, caster_pos.y, 0.4, 0.4)) 131 | .with_projectile(caster_id, 34.0) 132 | .with_emitter(0.05, Vec3::new(0.0, 0.8, 0.0), 3.0, 0.3, 0.1) 133 | .with_render_solid(Vec3::new(0.0, 0.8, 0.0)) 134 | .with_expiry(t + (4.0 / 25.0)); 135 | self.add_entity(&missile); 136 | } 137 | }, 138 | Spell::Lifesteal => { 139 | if cc.last_cast + 0.5 > t { return ; } 140 | cc.last_cast = t; 141 | let cost = 10.0; 142 | let mut hp = self.health.get_mut(&caster_id).unwrap(); 143 | if hp.current >= cost { 144 | hp.current -= cost; 145 | let missile = Entity::new() 146 | .with_team(caster_team) 147 | .with_physics(4.0, (target - caster_pos).normalize() * 10.0) 148 | .with_rect(Rect::new_centered(caster_pos.x, caster_pos.y, 0.4, 0.4)) 149 | .with_projectile_ex(caster_id, 20.0, 0.0, 0.0, 0.7) 150 | .with_emitter(0.05, Vec3::new(0.8, 0.0, 0.0), 2.0, 0.7, 0.1) 151 | .with_render_solid(Vec3::new(0.8, 0.0, 0.0)); 152 | self.add_entity(&missile); 153 | } 154 | }, 155 | Spell::Fireball => { 156 | if repeat { return; } 157 | if cc.last_cast + 0.3 > t { return ; } 158 | cc.last_cast = t; 159 | let cost = 30.0; 160 | if cc.mana >= cost { 161 | cc.mana -= cost; 162 | self.add_fireball(caster_id, target, t); 163 | } 164 | }, 165 | Spell::Firestorm => { 166 | if cc.last_cast + 0.25 > t { return ; } 167 | cc.last_cast = t; 168 | let cost = 8.0; 169 | if cc.mana >= cost { 170 | cc.mana -= cost; 171 | self.add_entity(&Entity::new() 172 | .with_team(caster_team) 173 | .with_physics(4.0, (target - caster_pos).normalize() * 15.0) 174 | .with_rect(Rect::new_centered(caster_pos.x, caster_pos.y, 0.5, 0.5)) 175 | .with_projectile_ex(caster_id, 18.0, 2.0, 0.0, 0.0) 176 | .with_emitter(0.05, Vec3::new(1.0, 0.0, 0.0), 2.0, 0.7, 0.15) 177 | .with_render_solid(Vec3::new(1.0, 0.0, 0.0))); 178 | } 179 | }, 180 | Spell::SummonRushers => { 181 | if repeat { return; } 182 | if cc.last_cast + 0.3 > t { return ; } 183 | cc.last_cast = t; 184 | let cost = 20.0; 185 | if cc.mana >= cost { 186 | cc.mana -= cost; 187 | let pos = self.rect.get(&caster_id).unwrap().centroid(); 188 | let team = self.team.get(&caster_id).unwrap().team; 189 | 190 | self.add_entity(&entity_zerg(team, pos.offset_r_theta(1.0, 0.0))); 191 | self.add_entity(&entity_zerg(team, pos.offset_r_theta(1.0, 2.0*PI / 3.0))); 192 | self.add_entity(&entity_zerg(team, pos.offset_r_theta(1.0, 4.0*PI / 3.0))); 193 | } 194 | }, 195 | Spell::SummonBloodcasters => { 196 | if repeat { return; } 197 | if cc.last_cast + 0.3 > t { return ; } 198 | cc.last_cast = t; 199 | let cost = 50.0; 200 | let mut hp = self.health.get_mut(&caster_id).unwrap(); 201 | if hp.current >= cost { 202 | hp.current -= cost; 203 | let pos = self.rect.get(&caster_id).unwrap().centroid(); 204 | let team = self.team.get(&caster_id).unwrap().team; 205 | 206 | self.add_entity(&entity_bloodcaster(team, pos.offset_r_theta(1.0, 0.0))); 207 | self.add_entity(&entity_bloodcaster(team, pos.offset_r_theta(1.0, PI))); 208 | } 209 | }, 210 | Spell::SummonSummoners => { 211 | if repeat { return; } 212 | if cc.last_cast + 0.3 > t { return ; } 213 | cc.last_cast = t; 214 | let cost = 100.0; 215 | if cc.mana >= cost { 216 | cc.mana -= cost; 217 | let pos = self.rect.get(&caster_id).unwrap().centroid(); 218 | let team = self.team.get(&caster_id).unwrap().team; 219 | 220 | self.add_entity(&entity_summoner(team, pos.offset_r_theta(2.0, 0.0))); 221 | self.add_entity(&entity_summoner(team, pos.offset_r_theta(2.0, 2.0*PI / 3.0))); 222 | self.add_entity(&entity_summoner(team, pos.offset_r_theta(2.0, 4.0*PI / 3.0))); 223 | } 224 | }, 225 | Spell::Healing => { 226 | let health = self.health.get_mut(&caster_id).unwrap(); 227 | 228 | let cost = 30.0; 229 | let healing = 30.0; 230 | if cc.mana >= cost * dt { 231 | health.current += healing * dt; 232 | cc.mana -= cost * dt; 233 | cc.last_cast = t; 234 | } 235 | } 236 | } 237 | } 238 | } 239 | } 240 | 241 | pub fn spell_sprite(spell: Spell) -> i32 { 242 | match spell { 243 | Spell::ConeFlames => ICON_FIRE, 244 | Spell::Missile => ICON_MAGIC_MISSILE, 245 | Spell::Pulse => ICON_PULSE, 246 | Spell::Firestorm => ICON_FIRESTORM, 247 | Spell::Lifesteal => ICON_BLOOD_MISSILE, 248 | Spell::SummonBloodcasters => ICON_BLOOD_ACOLYTES, 249 | Spell::SummonRushers => ICON_SUMMON_ZERGS, 250 | Spell::Fireball => ICON_FIREBALL, 251 | Spell::Water => ICON_WATER, 252 | 253 | Spell::Homing => ICON_HOMING, 254 | 255 | Spell::Healing => ICON_HEALING, 256 | Spell::SummonSummoners => 0, 257 | Spell::Barrage => 0, 258 | } 259 | } -------------------------------------------------------------------------------- /src/wave_game.rs: -------------------------------------------------------------------------------- 1 | use crate::application::*; 2 | use crate::components::make_entities::*; 3 | use crate::components::melee_damage::MeleeDamage; 4 | use crate::particles::*; 5 | use crate::renderer::*; 6 | use crate::rendererUV::*; 7 | use crate::kgui::*; 8 | use crate::kmath::*; 9 | use crate::spell::*; 10 | use crate::manifest::*; 11 | use crate::entity_definitions::*; 12 | use crate::actual_entity_definitions::*; 13 | use crate::spawner::*; 14 | use crate::spell_menu::*; 15 | use crate::entity::*; 16 | 17 | use crate::components::team::*; 18 | use crate::components::ai::*; 19 | use crate::components::health::*; 20 | use crate::components::caster::*; 21 | use crate::components::projectile::*; 22 | use crate::components::render::*; 23 | use crate::components::expiry::*; 24 | use crate::components::emitter::*; 25 | use crate::components::player::*; 26 | use crate::components::physics::*; 27 | use crate::components::spawn_list::*; 28 | 29 | use std::collections::HashMap; 30 | use std::collections::HashSet; 31 | use std::time::Instant; 32 | 33 | use glutin::event::VirtualKeyCode; 34 | 35 | pub struct Event { 36 | pub condition: fn(&WaveGame, &FrameInputState) -> bool, 37 | pub effect: fn(&mut WaveGame, &FrameInputState), 38 | } 39 | 40 | pub struct DamageEvent { 41 | amount: f32, 42 | src: u32, 43 | target: u32, 44 | } 45 | 46 | pub enum Command { 47 | Cast(u32, Vec2, Spell, bool), 48 | } 49 | 50 | pub const LOOK_STRENGTH: f32 = 0.2; 51 | pub const SCALE: f32 = 20.0; 52 | 53 | pub struct WaveGame { 54 | pub wave: i32, 55 | 56 | pub last_spawn: f32, 57 | 58 | pub t: f64, 59 | pub look_center: Vec2, 60 | pub pause: bool, 61 | 62 | pub particle_system: ParticleSystem, 63 | pub spawn_system: Spawner, 64 | 65 | pub entity_id_counter: u32, 66 | pub entity_ids: HashSet, 67 | 68 | pub player: HashMap, 69 | pub team: HashMap, 70 | pub caster: HashMap, 71 | pub health: HashMap, 72 | pub ai: HashMap, 73 | pub projectile: HashMap, 74 | pub render: HashMap, 75 | pub expiry: HashMap, 76 | pub melee_damage: HashMap, 77 | pub emitter: HashMap, 78 | pub ai_caster: HashMap, 79 | pub physics: HashMap, 80 | pub rect: HashMap, 81 | pub spawn_list: HashMap, 82 | pub make_on_damage: HashMap, 83 | pub make_on_death: HashMap, 84 | 85 | pub spell_menu: Option, 86 | 87 | pub events: Vec, 88 | } 89 | 90 | impl WaveGame { 91 | pub fn new(time: f32) -> WaveGame { 92 | let mut spawner = Spawner::new(); 93 | // spawner.add_spawn_entity(entity_basic(Vec2::new(0.0, 0.0)), 4.0); 94 | // spawner.add_spawn_entity(entity_zerg(TEAM_ENEMIES, Vec2::new(0.0, 0.0)), 2.5); 95 | // // spawner.add_spawn_entity(entity_bloodcaster(TEAM_ENEMIES, Vec2::new(0.0, 0.0)), 7.0); 96 | // spawner.add_spawn_entity(entity_caster(Vec2::new(0.0, 0.0)), 5.0); 97 | // // spawner.add_spawn_entity(entity_pulsecaster(Vec2::new(0.0, 0.0)), 9.5); 98 | // spawner.add_spawn_entity(entity_summoner(TEAM_ENEMIES, Vec2::new(0.0, 0.0)), 10.0); 99 | // spawner.add_spawn_entity(entity_summoner_summoner(TEAM_ENEMIES, Vec2::new(0.0, 0.0)), 20.0); 100 | 101 | let mut wg = WaveGame { 102 | wave: 0, 103 | last_spawn: 0.0, 104 | pause: false, 105 | 106 | t: 0.0, 107 | look_center: Vec2::new(0.0, 0.0), 108 | particle_system: ParticleSystem{particles: Vec::new()}, 109 | spawn_system: spawner, 110 | 111 | entity_id_counter: 0, 112 | entity_ids: HashSet::new(), 113 | 114 | player: HashMap::new(), 115 | team: HashMap::new(), 116 | caster: HashMap::new(), 117 | health: HashMap::new(), 118 | ai: HashMap::new(), 119 | projectile: HashMap::new(), 120 | render: HashMap::new(), 121 | expiry: HashMap::new(), 122 | melee_damage: HashMap::new(), 123 | emitter: HashMap::new(), 124 | ai_caster: HashMap::new(), 125 | physics: HashMap::new(), 126 | rect: HashMap::new(), 127 | spawn_list: HashMap::new(), 128 | make_on_damage: HashMap::new(), 129 | make_on_death: HashMap::new(), 130 | 131 | events: Vec::new(), 132 | 133 | spell_menu: None, 134 | }; 135 | 136 | // wg.add_player(Vec2::new(0.0, 5.0)); old 137 | 138 | wg.events.push(Event { 139 | condition: |wg, inputs| { 140 | wg.player.values().nth(0).unwrap().spellbook.len() == 0 141 | }, effect: |wg, inputs| { 142 | let current_spells = &wg.player.values().nth(0).unwrap().spellbook; 143 | wg.spell_menu = Some(SpellMenu::new(inputs.seed * 172137163, current_spells, inputs.t as f32)); 144 | } 145 | }); 146 | 147 | wg.events.push(Event { 148 | condition: |wg, inputs| { 149 | wg.player.values().nth(0).unwrap().spellbook.len() == 1 150 | }, effect: |wg, inputs| { 151 | let current_spells = &wg.player.values().nth(0).unwrap().spellbook; 152 | wg.spell_menu = Some(SpellMenu::new(inputs.seed * 3487498743, current_spells, inputs.t as f32)); 153 | } 154 | }); 155 | 156 | wg.events.push(Event { 157 | condition: |wg, inputs| { 158 | wg.player.values().nth(0).unwrap().spellbook.len() == 2 159 | }, effect: |wg, inputs| { 160 | wg.add_entity(&portal3(Vec2::new(0.0, 0.0), TEAM_ENEMIES)); 161 | wg.wave = 1; 162 | } 163 | }); 164 | 165 | wg.events.push(Event { 166 | condition: |wg, inputs| { 167 | if wg.spawn_list.values().nth(0).is_none() {return false}; 168 | let spawnlist_component = wg.spawn_list.values().nth(0).unwrap(); 169 | let n_enemies = wg.team.iter().filter(|(id, com)| com.team == TEAM_ENEMIES).count() as i32; 170 | wg.wave == 1 && 171 | n_enemies == 0 && 172 | spawnlist_component.t > spawnlist_component.list[spawnlist_component.list.len() - 1].0 173 | 174 | }, effect: |wg, inputs| { 175 | let id = wg.spawn_list.keys().nth(0).unwrap(); 176 | wg.remove_entity(*id); 177 | wg.add_entity(&portal2(Vec2::new(0.0, 0.0), TEAM_ENEMIES)); 178 | wg.wave = 2; 179 | } 180 | }); 181 | wg.add_entity(&entity_player(Vec2::new(0.0, 0.0))); 182 | 183 | println!("Welcome to WAVE GAME. Controls are WASD movement, Q-E spellbook page, Left click to cast. Survive all rounds. "); 184 | 185 | wg 186 | } 187 | 188 | // p is in world space, how to make it into screen space 189 | pub fn screen_to_world(p: Vec2, world_tether: Vec2, look_offset: Vec2, screen_rect: Rect) -> Vec2 { 190 | let dims = SCALE * screen_rect.br(); 191 | let look_vec = SCALE * look_offset - dims/2.0; 192 | let screen_center = world_tether + LOOK_STRENGTH * look_vec; 193 | let cam_rect = Rect::new_centered(screen_center.x, screen_center.y, dims.x, dims.y); 194 | 195 | // the rect that represents where the camera is in world space 196 | // maybe the child function 197 | 198 | Vec2::new( 199 | cam_rect.x + cam_rect.w * p.x / screen_rect.w, 200 | cam_rect.y + cam_rect.h * p.y / screen_rect.h, 201 | ) 202 | } 203 | 204 | pub fn damage_entity(&mut self, inputs: &FrameInputState, id: u32, amount: f32, buf: &mut Vec) { 205 | if !self.health.contains_key(&id) { return }; 206 | let health = self.health.get_mut(&id).unwrap(); 207 | health.damage(amount, inputs.t as f32); 208 | 209 | if let Some(make_on_damage) = self.make_on_damage.get_mut(&id) { 210 | make_on_damage.acc += amount; 211 | if make_on_damage.acc > make_on_damage.thresh { 212 | make_on_damage.acc = 0.0; 213 | (make_on_damage.f)(self, inputs, id, buf); 214 | } 215 | } 216 | } 217 | 218 | 219 | pub fn remove_entity(&mut self, entity_id: u32) { 220 | self.entity_ids.remove(&entity_id); 221 | self.ai.remove(&entity_id); 222 | self.health.remove(&entity_id); 223 | self.player.remove(&entity_id); 224 | self.team.remove(&entity_id); 225 | self.caster.remove(&entity_id); 226 | self.projectile.remove(&entity_id); 227 | self.render.remove(&entity_id); 228 | self.expiry.remove(&entity_id); 229 | self.melee_damage.remove(&entity_id); 230 | self.emitter.remove(&entity_id); 231 | self.ai_caster.remove(&entity_id); 232 | self.physics.remove(&entity_id); 233 | self.rect.remove(&entity_id); 234 | self.make_on_damage.remove(&entity_id); 235 | self.make_on_death.remove(&entity_id); 236 | self.spawn_list.remove(&entity_id); 237 | } 238 | 239 | fn update(&mut self, inputs: &FrameInputState, mut commands: Vec) { 240 | let mut dead_list = Vec::new(); 241 | let mut commands = Vec::new(); 242 | let mut new_entities = Vec::new(); 243 | let level_rect = Rect::new_centered(0.0, 0.0, 40.0, 40.0); 244 | 245 | self.t += inputs.dt; 246 | 247 | // emit particles 248 | for (id, ec) in self.emitter.iter_mut() { 249 | let mut iter_count = 0; 250 | if ec.last + ec.interval < self.t as f32 { 251 | iter_count += 1; 252 | ec.last += ec.interval; 253 | let pos = self.rect.get(&id).unwrap().centroid(); 254 | let seed = inputs.frame * 12315 + *id * 1412337 + iter_count; 255 | self.particle_system.add_particle(Particle { 256 | expiry: self.t as f32 + ec.lifespan, 257 | velocity: Vec2::new(kuniform(seed, -1.0, 1.0), kuniform(seed * 1771715, -1.0, 1.0)).normalize() * ec.speed, 258 | rect: Rect::new_centered(pos.x, pos.y, ec.size.x, ec.size.y), 259 | colour: ec.colour, 260 | }); 261 | } 262 | } 263 | 264 | self.particle_system.update(self.t as f32, inputs.dt as f32); 265 | 266 | // AI 267 | self.update_movement_ai(self.t as f32, inputs.dt as f32, inputs.frame, level_rect); 268 | self.update_casting_ai(self.t as f32, &mut commands); 269 | 270 | for command in commands { 271 | match command { 272 | Command::Cast(caster_id, target, spell, repeat) => { 273 | self.cast_spell(self.t as f32, caster_id, target, spell, repeat, inputs.seed, inputs.dt as f32); 274 | }, 275 | } 276 | } 277 | 278 | 279 | // update entities 280 | self.move_entities(inputs.dt as f32); 281 | let mut collision_events = self.collisions(); 282 | // let mut collision_events = Vec::new(); 283 | // collide_entity_entity(&self.common, &mut collision_events, inputs.dt as f32); 284 | 285 | collision_events.retain(|ce| { 286 | if !self.team.contains_key(&ce.subject) {return false;} 287 | if !self.team.contains_key(&ce.object) {return false;} 288 | 289 | let steam = self.team.get(&ce.subject).unwrap().team; 290 | let oteam = self.team.get(&ce.object).unwrap().team; 291 | let sproj = self.projectile.get(&ce.subject).is_some(); 292 | let oproj = self.projectile.get(&ce.object).is_some(); 293 | 294 | if steam == oteam && (oproj || sproj) { 295 | return false; 296 | } 297 | if oproj && sproj { 298 | return false; 299 | } 300 | 301 | return true 302 | }); 303 | 304 | // maybe I should get damage events, that would make the code a bit nicer 305 | // in some sense collision events -> damage events 306 | let mut damage_events = Vec::new(); 307 | 308 | // handle projectile impacts 309 | for ce in collision_events.iter() { 310 | if let Some(proj) = self.projectile.get(&ce.subject) { 311 | let impact_location = self.rect.get(&ce.object).unwrap().centroid(); 312 | let proj_team = self.team.get(&ce.subject).unwrap().team; 313 | let target_team = self.team.get(&ce.object).unwrap().team; 314 | if proj.aoe > 0.0 { 315 | for (id, _) in self.physics.iter().filter(|(id, com)| self.rect.get(id).unwrap().centroid().dist(impact_location) <= proj.aoe && proj_team != target_team) { 316 | if let Some(health) = self.health.get_mut(&id) { 317 | damage_events.push(DamageEvent{amount: proj.damage, src: proj.source, target: *id}); 318 | // self.damage_entity(&inputs, *id, proj.damage); 319 | // health.damage(proj.damage, inputs.t as f32); 320 | if let Some(caster_hp) = self.health.get_mut(&proj.source) { 321 | caster_hp.current += proj.lifesteal_percent * proj.damage; 322 | caster_hp.current = caster_hp.current.min(caster_hp.max); 323 | } 324 | } 325 | } 326 | } else { 327 | if let Some(health) = self.health.get_mut(&ce.object) { 328 | damage_events.push(DamageEvent{amount: proj.damage, src: proj.source, target: ce.object}); 329 | // health.damage(proj.damage, inputs.t as f32); 330 | if let Some(caster_hp) = self.health.get_mut(&proj.source) { 331 | caster_hp.current += proj.lifesteal_percent * proj.damage; 332 | caster_hp.current = caster_hp.current.min(caster_hp.max); 333 | } 334 | } 335 | } 336 | let pos = self.rect.get(&ce.subject).unwrap().centroid(); 337 | if proj.splat_duration > 0.0 { 338 | self.add_firesplat(pos, self.t as f32); 339 | } 340 | dead_list.push(ce.subject); 341 | } 342 | } 343 | 344 | // handle melee damage 345 | let melee_damage_events: Vec = collision_events.iter() 346 | .filter(|ce| self.team.contains_key(&ce.subject) && self.team.contains_key(&ce.object) && self.team.get(&ce.subject).unwrap().team != self.team.get(&ce.object).unwrap().team) 347 | .filter_map(|ce| { 348 | if let Some(md) = self.melee_damage.get(&ce.subject) { 349 | Some(DamageEvent {src: ce.subject, target: ce.object, amount: md.amount}) 350 | } else { 351 | None 352 | } 353 | }).collect(); 354 | 355 | // filter iframes. actually its done in health. could clean up 356 | // assign credit for kills here too 357 | for damage in damage_events.iter().chain(melee_damage_events.iter()) { 358 | self.damage_entity(&inputs, damage.target, damage.amount, &mut new_entities); 359 | } 360 | 361 | // self.resolve_melee_damage(&collision_events, inputs.t as f32); 362 | 363 | // expire timed lives 364 | for (id, timed) in self.expiry.iter() { 365 | if timed.expiry < self.t as f32 { 366 | dead_list.push(*id); 367 | } 368 | } 369 | 370 | // kill 0 hp 371 | for (&id, hc) in self.health.iter() { 372 | if hc.current <= 0.0 { 373 | dead_list.push(id); 374 | } 375 | } 376 | 377 | self.fix_overlaps(&collision_events, 1.0); 378 | 379 | // constrain to arena 380 | for (id, rect) in self.rect.iter_mut() { 381 | 382 | if rect.top() < level_rect.top() { 383 | rect.y += level_rect.top() - rect.top(); 384 | if self.projectile.contains_key(id) { 385 | dead_list.push(*id); 386 | } 387 | } 388 | if rect.bot() > level_rect.bot() { 389 | rect.y += level_rect.bot() - rect.bot(); 390 | if self.projectile.contains_key(id) { 391 | dead_list.push(*id); 392 | } 393 | } 394 | if rect.left() < level_rect.left() { 395 | rect.x += level_rect.left() - rect.left(); 396 | if self.projectile.contains_key(id) { 397 | dead_list.push(*id); 398 | } 399 | } 400 | if rect.right() > level_rect.right() { 401 | rect.x += level_rect.right() - rect.right(); 402 | if self.projectile.contains_key(id) { 403 | dead_list.push(*id); 404 | } 405 | } 406 | } 407 | 408 | self.fix_velocities(inputs.dt as f32); 409 | 410 | for dead in dead_list { 411 | if let Some(make_on_death) = self.make_on_death.get(&dead) { 412 | (make_on_death.f)(self, &inputs, dead, &mut new_entities); 413 | } 414 | self.remove_entity(dead); 415 | } 416 | 417 | if let Some((id, _)) = self.player.iter().nth(0) { 418 | self.look_center = self.rect.get(id).unwrap().centroid(); 419 | } 420 | 421 | // regen 422 | for caster in self.caster.values_mut() { 423 | caster.mana = caster.mana_max.min(caster.mana + caster.mana_regen * inputs.dt as f32) 424 | } 425 | for health in self.health.values_mut() { 426 | health.current = health.max.min(health.current + health.regen * inputs.dt as f32) 427 | } 428 | } 429 | } 430 | 431 | impl Scene for WaveGame { 432 | fn handle_signal(&mut self, signal: SceneSignal) -> SceneOutcome { 433 | SceneOutcome::None 434 | } 435 | 436 | fn frame(&mut self, inputs: FrameInputState) -> (SceneOutcome, TriangleBuffer, Option) { 437 | let start = Instant::now(); 438 | let mut reset = false; 439 | let mut commands = Vec::new(); 440 | let mut dead_list = Vec::new(); 441 | let mut new_entities = Vec::new(); 442 | let mouse_world = WaveGame::screen_to_world(inputs.mouse_pos, self.look_center, inputs.mouse_pos, inputs.screen_rect); 443 | let level_rect = Rect::new_centered(0.0, 0.0, 30.0, 30.0); 444 | 445 | // Events 446 | let trigger_events: Vec = self.events.iter().enumerate().filter_map(|(idx, e)| if (e.condition)(&self, &inputs) {Some(idx)} else {None}).collect(); 447 | for idx in trigger_events.iter() { 448 | (self.events[*idx].effect)(self, &inputs); 449 | } 450 | for idx in trigger_events.iter() { 451 | self.events.swap_remove(*idx); 452 | } 453 | 454 | // Inputs 455 | if inputs.events.iter().any(|e| match e { KEvent::Keyboard(VirtualKeyCode::Escape, true) => {true}, _ => {false}}) { 456 | return (SceneOutcome::QuitProgram, TriangleBuffer::new(inputs.screen_rect), None); 457 | } 458 | if inputs.events.iter().any(|e| match e { KEvent::Keyboard(VirtualKeyCode::R, true) => {true}, _ => {false}}) { 459 | if self.player.iter().nth(0).is_none() { 460 | reset = true; 461 | } 462 | } 463 | if inputs.events.iter().any(|e| match e { KEvent::Keyboard(VirtualKeyCode::M, true) => {true}, _ => {false}}) { 464 | for (id, com) in self.team.iter() { 465 | if com.team == TEAM_ENEMIES { 466 | dead_list.push(*id); 467 | } 468 | } 469 | } 470 | 471 | for (id, cc) in self.player.iter_mut() { 472 | let mut player_move_dir = Vec2::new(0.0, 0.0); 473 | if inputs.held_keys.contains(&VirtualKeyCode::W) { 474 | player_move_dir.y -= 1.0; 475 | } 476 | if inputs.held_keys.contains(&VirtualKeyCode::S) { 477 | player_move_dir.y += 1.0; 478 | } 479 | if inputs.held_keys.contains(&VirtualKeyCode::A) { 480 | player_move_dir.x -= 1.0; 481 | } 482 | if inputs.held_keys.contains(&VirtualKeyCode::D) { 483 | player_move_dir.x += 1.0; 484 | } 485 | if inputs.events.iter().any(|e| match e { KEvent::Keyboard(VirtualKeyCode::Q, true) => {true}, _ => {false}}) { 486 | if cc.spell_cursor > 0 { cc.spell_cursor -= 1 } 487 | let mut player_caster = self.caster.get_mut(id).unwrap(); 488 | player_caster.last_cast = 0.0; 489 | } 490 | if inputs.events.iter().any(|e| match e { KEvent::Keyboard(VirtualKeyCode::E, true) => {true}, _ => {false}}) { 491 | if cc.spell_cursor < cc.spellbook.len() as i32 - 1 { cc.spell_cursor += 1 } 492 | let mut player_caster = self.caster.get_mut(id).unwrap(); 493 | player_caster.last_cast = 0.0; 494 | } 495 | let p_phys = self.physics.entry(*id); 496 | p_phys.and_modify(|e| e.velocity = player_move_dir.normalize() * cc.speed); 497 | 498 | if self.spell_menu.is_none() { 499 | if inputs.events.iter().any(|e| match e { KEvent::MouseLeft(true) => {true}, _ => {false}}) { 500 | commands.push(Command::Cast(*id, mouse_world, cc.spellbook[cc.spell_cursor as usize], false)); 501 | } else if inputs.held_lmb { 502 | commands.push(Command::Cast(*id, mouse_world, cc.spellbook[cc.spell_cursor as usize], true)); 503 | } 504 | } 505 | } 506 | 507 | if reset { 508 | *self = WaveGame::new(inputs.t as f32); 509 | } 510 | 511 | // refactor this, own t, pause if spell menu 512 | // maybe have a update game routine 513 | 514 | 515 | 516 | let start = Instant::now(); 517 | 518 | let mut commands = Vec::new(); 519 | 520 | let mouse_world = WaveGame::screen_to_world(inputs.mouse_pos, self.look_center, inputs.mouse_pos, inputs.screen_rect); 521 | 522 | 523 | let level_rect = Rect::new_centered(0.0, 0.0, 40.0, 40.0); 524 | 525 | 526 | let mut reset = false; 527 | 528 | if let Some(player) = self.player.values().nth(0) { 529 | if player.spellbook.len() < 1 || 530 | (player.kills > 10 && player.spellbook.len() < 2) || 531 | (player.kills > 100 && player.spellbook.len() < 3) || 532 | (player.kills > 300 && player.spellbook.len() < 4) || 533 | (player.kills > 600 && player.spellbook.len() < 5) 534 | { 535 | if self.spell_menu.is_none() { 536 | self.spell_menu = Some(SpellMenu::new(inputs.seed, &player.spellbook, inputs.t as f32)); 537 | } 538 | } else { 539 | // spawning 540 | if let Some(ent) = self.spawn_system.frame(&inputs) { 541 | self.add_entity(&ent); 542 | } 543 | } 544 | } 545 | 546 | 547 | // Inputs 548 | if inputs.events.iter().any(|e| match e { KEvent::Keyboard(VirtualKeyCode::Escape, true) => {true}, _ => {false}}) { 549 | return (SceneOutcome::QuitProgram, TriangleBuffer::new(inputs.screen_rect), None); 550 | } 551 | if inputs.events.iter().any(|e| match e { KEvent::Keyboard(VirtualKeyCode::R, true) => {true}, _ => {false}}) { 552 | // if self.player.iter().nth(0).is_none() { 553 | reset = true; 554 | // } 555 | } 556 | if inputs.events.iter().any(|e| match e { KEvent::Keyboard(VirtualKeyCode::P, true) => {true}, _ => {false}}) { 557 | self.pause = !self.pause; 558 | } 559 | 560 | for (id, cc) in self.player.iter_mut() { 561 | let mut player_move_dir = Vec2::new(0.0, 0.0); 562 | if inputs.held_keys.contains(&VirtualKeyCode::W) { 563 | player_move_dir.y -= 1.0; 564 | } 565 | if inputs.held_keys.contains(&VirtualKeyCode::S) { 566 | player_move_dir.y += 1.0; 567 | } 568 | if inputs.held_keys.contains(&VirtualKeyCode::A) { 569 | player_move_dir.x -= 1.0; 570 | } 571 | if inputs.held_keys.contains(&VirtualKeyCode::D) { 572 | player_move_dir.x += 1.0; 573 | } 574 | if inputs.events.iter().any(|e| match e { KEvent::Keyboard(VirtualKeyCode::Q, true) => {true}, _ => {false}}) { 575 | if cc.spell_cursor > 0 { cc.spell_cursor -= 1 } 576 | let mut player_caster = self.caster.get_mut(id).unwrap(); 577 | player_caster.last_cast = 0.0; 578 | } 579 | if inputs.events.iter().any(|e| match e { KEvent::Keyboard(VirtualKeyCode::E, true) => {true}, _ => {false}}) { 580 | if cc.spell_cursor < cc.spellbook.len() as i32 - 1 { cc.spell_cursor += 1 } 581 | let mut player_caster = self.caster.get_mut(id).unwrap(); 582 | player_caster.last_cast = 0.0; 583 | } 584 | let p_phys = self.physics.entry(*id); 585 | p_phys.and_modify(|e| e.velocity = player_move_dir.normalize() * cc.speed); 586 | 587 | if self.spell_menu.is_none() { 588 | if inputs.events.iter().any(|e| match e { KEvent::MouseLeft(true) => {true}, _ => {false}}) { 589 | commands.push(Command::Cast(*id, mouse_world, cc.spellbook[cc.spell_cursor as usize], false)); 590 | } else if inputs.held_lmb { 591 | commands.push(Command::Cast(*id, mouse_world, cc.spellbook[cc.spell_cursor as usize], true)); 592 | } 593 | } 594 | } 595 | 596 | if reset { 597 | *self = WaveGame::new(inputs.t as f32); 598 | } 599 | 600 | if self.spell_menu.is_none() && self.pause == false { 601 | self.update(&inputs, commands); 602 | } 603 | 604 | 605 | 606 | // spawn list stuff 607 | for (id, spawn_list) in self.spawn_list.iter_mut() { 608 | spawn_list.t += inputs.dt as f32; 609 | for (t_spawn, e_spawn) in spawn_list.list.iter() { 610 | if *t_spawn < spawn_list.t && *t_spawn > spawn_list.t - inputs.dt as f32 { 611 | new_entities.push(*e_spawn.clone()); 612 | } 613 | } 614 | } 615 | 616 | for (i, entity) in new_entities.iter_mut().enumerate() { 617 | entity.rect.unwrap().x += kuniform(i as u32 * 17231653 + inputs.seed, -0.05, 0.05); 618 | entity.rect.unwrap().y += kuniform(i as u32 * 12983715 + inputs.seed, -0.05, 0.05); 619 | self.add_entity(entity); 620 | } 621 | 622 | { // trying to separate so they dont get physics kick 623 | // it actually gets more cooked the more you do lol 624 | // maybe its just when they spawn exactly on top of one another. 625 | // yeah this is just fucked, what if it is exactly on top case? or one within 626 | 627 | // i reckon within just do centroid, some amount, and if centroid is equal, random direction, just make sure its opposite 628 | // just not enough noise 629 | for i in 0..4 { 630 | let mut cols = self.collisions(); 631 | 632 | // filter projectils etc 633 | cols.retain(|ce| { 634 | if !self.team.contains_key(&ce.subject) {return false;} 635 | if !self.team.contains_key(&ce.object) {return false;} 636 | 637 | let steam = self.team.get(&ce.subject).unwrap().team; 638 | let oteam = self.team.get(&ce.object).unwrap().team; 639 | let sproj = self.projectile.get(&ce.subject).is_some(); 640 | let oproj = self.projectile.get(&ce.object).is_some(); 641 | 642 | if steam == oteam && (oproj || sproj) { 643 | return false; 644 | } 645 | if oproj && sproj { 646 | return false; 647 | } 648 | 649 | return true 650 | }); 651 | self.fix_overlaps(&cols, 0.25); 652 | } 653 | } 654 | 655 | // Camera 656 | let scale = 20.0; 657 | let dims = scale * inputs.screen_rect.br(); 658 | let look_vec = scale * inputs.mouse_pos - dims/2.0; 659 | let screen_center = self.look_center + 0.2 * look_vec; 660 | let cam_rect = Rect::new_centered(screen_center.x, screen_center.y, dims.x, dims.y); 661 | let mut buf = TriangleBuffer::new(cam_rect); 662 | let mut buf_uv = TriangleBufferUV::new(inputs.screen_rect, ATLAS_W, ATLAS_H); 663 | 664 | // draw entities 665 | self.draw_entities(&mut buf, self.t as f32, inputs.frame); 666 | 667 | // draw level 668 | buf.draw_rect(level_rect, Vec3::new(0.3, 0.3, 0.3), 1.0); 669 | for i in 0..20 { 670 | for j in 0..20 { 671 | buf.draw_rect(level_rect.grid_child(i, j, 20, 20).dilate(-0.1), Vec3::new(0.1, 0.1, 0.1), 1.5); 672 | } 673 | } 674 | 675 | // draw particles 676 | self.particle_system.draw(&mut buf); 677 | 678 | // draw gui 679 | buf.screen_rect = inputs.screen_rect; 680 | 681 | let hmsize = 0.1; 682 | 683 | let health_rect = inputs.screen_rect.child(0.0, 1.0 - hmsize, hmsize, hmsize).fit_center_square(); 684 | let mana_rect = inputs.screen_rect.child(1.0 - hmsize, 1.0 - hmsize, hmsize, hmsize).fit_center_square(); 685 | 686 | buf.draw_rect(health_rect, Vec3::new(0.0, 0.0, 0.0), 10.0); 687 | buf.draw_rect(mana_rect, Vec3::new(0.0, 0.0, 0.0), 10.0); 688 | 689 | if let Some((player_id, _)) = self.player.iter().nth(0) { 690 | let player_health = self.health.get(player_id).unwrap(); 691 | let player_cast = self.caster.get(player_id).unwrap(); 692 | 693 | let player_health_amount = player_health.current / player_health.max; 694 | let player_mana_amount = player_cast.mana / player_cast.mana_max; 695 | 696 | buf.draw_rect(health_rect.child(0.0, 1.0 - player_health_amount, 1.0, player_health_amount), Vec3::new(1.0, 0.0, 0.0), 11.0); 697 | buf.draw_rect(mana_rect.child(0.0, 1.0 - player_mana_amount, 1.0, player_mana_amount), Vec3::new(0.0, 0.0, 1.0), 11.0); 698 | } 699 | buf_uv.draw_sprite(health_rect, VESSEL, 12.0); 700 | buf_uv.draw_sprite(mana_rect, VESSEL, 12.0); 701 | 702 | let spell_rect = inputs.screen_rect.child(0.5 - hmsize/2.0, 1.0 - hmsize, hmsize, hmsize).fit_center_square(); 703 | let book_left_rect = spell_rect.translate(Vec2::new(-spell_rect.w/2.0, 0.0)); 704 | let book_right_rect = spell_rect.translate(Vec2::new(spell_rect.w/2.0, 0.0)); 705 | buf_uv.draw_sprite(book_left_rect, BOOK_LEFT, 11.0); 706 | buf_uv.draw_sprite(book_right_rect, BOOK_RIGHT, 11.0); 707 | if let Some(player) = self.player.values_mut().nth(0) { 708 | if player.spellbook.len() != 0 { 709 | buf_uv.draw_sprite(spell_rect, spell_sprite(player.spellbook[player.spell_cursor as usize]), 12.0); 710 | } 711 | 712 | // spell menu 713 | if let Some(spell_menu) = &self.spell_menu { 714 | if let Some(learned_spell) = spell_menu.frame(&inputs, &mut buf, &mut buf_uv) { 715 | player.spellbook.push(learned_spell); 716 | self.spell_menu = None; 717 | } 718 | } 719 | } 720 | 721 | if self.player.iter().nth(0).is_none() { 722 | let reset_pane = inputs.screen_rect.child(0.4, 0.7, 0.2, 0.15).fit_aspect_ratio(2.0); 723 | buf_uv.draw_sprite(reset_pane.child(0.0, 0.0, 0.5, 1.0), TUT_R, 12.0); 724 | buf_uv.draw_sprite(reset_pane.child(0.5, 0.0, 0.5, 1.0), TUT_RESET, 12.0); 725 | } 726 | 727 | let frametime_ms = start.elapsed().as_secs_f32() * 1000.0; 728 | if frametime_ms > 1.0 { 729 | // println!("whoa that frame took forever: {}ms", frametime_ms); 730 | } 731 | 732 | (SceneOutcome::None, buf, Some(buf_uv)) 733 | } 734 | 735 | } 736 | 737 | 738 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "adler" 7 | version = "1.0.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 10 | 11 | [[package]] 12 | name = "adler32" 13 | version = "1.2.0" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" 16 | 17 | [[package]] 18 | name = "android_glue" 19 | version = "0.2.3" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407" 22 | 23 | [[package]] 24 | name = "approx" 25 | version = "0.1.1" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "08abcc3b4e9339e33a3d0a5ed15d84a687350c05689d825e0f6655eef9e76a94" 28 | 29 | [[package]] 30 | name = "assert_hex" 31 | version = "0.2.2" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "bc782823ed0b8133960a4525e1064b6c30473ca6554d00f697af2b5b520dc723" 34 | 35 | [[package]] 36 | name = "autocfg" 37 | version = "0.1.8" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78" 40 | dependencies = [ 41 | "autocfg 1.1.0", 42 | ] 43 | 44 | [[package]] 45 | name = "autocfg" 46 | version = "1.1.0" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 49 | 50 | [[package]] 51 | name = "bitflags" 52 | version = "1.3.2" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 55 | 56 | [[package]] 57 | name = "block" 58 | version = "0.1.6" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" 61 | 62 | [[package]] 63 | name = "bumpalo" 64 | version = "3.9.1" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" 67 | 68 | [[package]] 69 | name = "calloop" 70 | version = "0.9.3" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | checksum = "bf2eec61efe56aa1e813f5126959296933cf0700030e4314786c48779a66ab82" 73 | dependencies = [ 74 | "log", 75 | "nix", 76 | ] 77 | 78 | [[package]] 79 | name = "cc" 80 | version = "1.0.73" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" 83 | 84 | [[package]] 85 | name = "cfg-if" 86 | version = "0.1.10" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 89 | 90 | [[package]] 91 | name = "cfg-if" 92 | version = "1.0.0" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 95 | 96 | [[package]] 97 | name = "cgl" 98 | version = "0.3.2" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | checksum = "0ced0551234e87afee12411d535648dd89d2e7f34c78b753395567aff3d447ff" 101 | dependencies = [ 102 | "libc", 103 | ] 104 | 105 | [[package]] 106 | name = "cloudabi" 107 | version = "0.0.3" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" 110 | dependencies = [ 111 | "bitflags", 112 | ] 113 | 114 | [[package]] 115 | name = "cocoa" 116 | version = "0.24.0" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | checksum = "6f63902e9223530efb4e26ccd0cf55ec30d592d3b42e21a28defc42a9586e832" 119 | dependencies = [ 120 | "bitflags", 121 | "block", 122 | "cocoa-foundation", 123 | "core-foundation 0.9.3", 124 | "core-graphics 0.22.3", 125 | "foreign-types", 126 | "libc", 127 | "objc", 128 | ] 129 | 130 | [[package]] 131 | name = "cocoa-foundation" 132 | version = "0.1.0" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318" 135 | dependencies = [ 136 | "bitflags", 137 | "block", 138 | "core-foundation 0.9.3", 139 | "core-graphics-types", 140 | "foreign-types", 141 | "libc", 142 | "objc", 143 | ] 144 | 145 | [[package]] 146 | name = "core-foundation" 147 | version = "0.7.0" 148 | source = "registry+https://github.com/rust-lang/crates.io-index" 149 | checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" 150 | dependencies = [ 151 | "core-foundation-sys 0.7.0", 152 | "libc", 153 | ] 154 | 155 | [[package]] 156 | name = "core-foundation" 157 | version = "0.9.3" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" 160 | dependencies = [ 161 | "core-foundation-sys 0.8.3", 162 | "libc", 163 | ] 164 | 165 | [[package]] 166 | name = "core-foundation-sys" 167 | version = "0.7.0" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" 170 | 171 | [[package]] 172 | name = "core-foundation-sys" 173 | version = "0.8.3" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" 176 | 177 | [[package]] 178 | name = "core-graphics" 179 | version = "0.19.2" 180 | source = "registry+https://github.com/rust-lang/crates.io-index" 181 | checksum = "b3889374e6ea6ab25dba90bb5d96202f61108058361f6dc72e8b03e6f8bbe923" 182 | dependencies = [ 183 | "bitflags", 184 | "core-foundation 0.7.0", 185 | "foreign-types", 186 | "libc", 187 | ] 188 | 189 | [[package]] 190 | name = "core-graphics" 191 | version = "0.22.3" 192 | source = "registry+https://github.com/rust-lang/crates.io-index" 193 | checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" 194 | dependencies = [ 195 | "bitflags", 196 | "core-foundation 0.9.3", 197 | "core-graphics-types", 198 | "foreign-types", 199 | "libc", 200 | ] 201 | 202 | [[package]] 203 | name = "core-graphics-types" 204 | version = "0.1.1" 205 | source = "registry+https://github.com/rust-lang/crates.io-index" 206 | checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" 207 | dependencies = [ 208 | "bitflags", 209 | "core-foundation 0.9.3", 210 | "foreign-types", 211 | "libc", 212 | ] 213 | 214 | [[package]] 215 | name = "core-video-sys" 216 | version = "0.1.4" 217 | source = "registry+https://github.com/rust-lang/crates.io-index" 218 | checksum = "34ecad23610ad9757664d644e369246edde1803fcb43ed72876565098a5d3828" 219 | dependencies = [ 220 | "cfg-if 0.1.10", 221 | "core-foundation-sys 0.7.0", 222 | "core-graphics 0.19.2", 223 | "libc", 224 | "objc", 225 | ] 226 | 227 | [[package]] 228 | name = "crc32fast" 229 | version = "1.3.2" 230 | source = "registry+https://github.com/rust-lang/crates.io-index" 231 | checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" 232 | dependencies = [ 233 | "cfg-if 1.0.0", 234 | ] 235 | 236 | [[package]] 237 | name = "cty" 238 | version = "0.2.2" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" 241 | 242 | [[package]] 243 | name = "darling" 244 | version = "0.13.4" 245 | source = "registry+https://github.com/rust-lang/crates.io-index" 246 | checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" 247 | dependencies = [ 248 | "darling_core", 249 | "darling_macro", 250 | ] 251 | 252 | [[package]] 253 | name = "darling_core" 254 | version = "0.13.4" 255 | source = "registry+https://github.com/rust-lang/crates.io-index" 256 | checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" 257 | dependencies = [ 258 | "fnv", 259 | "ident_case", 260 | "proc-macro2", 261 | "quote", 262 | "strsim", 263 | "syn", 264 | ] 265 | 266 | [[package]] 267 | name = "darling_macro" 268 | version = "0.13.4" 269 | source = "registry+https://github.com/rust-lang/crates.io-index" 270 | checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" 271 | dependencies = [ 272 | "darling_core", 273 | "quote", 274 | "syn", 275 | ] 276 | 277 | [[package]] 278 | name = "deflate" 279 | version = "1.0.0" 280 | source = "registry+https://github.com/rust-lang/crates.io-index" 281 | checksum = "c86f7e25f518f4b81808a2cf1c50996a61f5c2eb394b2393bd87f2a4780a432f" 282 | dependencies = [ 283 | "adler32", 284 | ] 285 | 286 | [[package]] 287 | name = "dispatch" 288 | version = "0.2.0" 289 | source = "registry+https://github.com/rust-lang/crates.io-index" 290 | checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" 291 | 292 | [[package]] 293 | name = "dlib" 294 | version = "0.5.0" 295 | source = "registry+https://github.com/rust-lang/crates.io-index" 296 | checksum = "ac1b7517328c04c2aa68422fc60a41b92208182142ed04a25879c26c8f878794" 297 | dependencies = [ 298 | "libloading", 299 | ] 300 | 301 | [[package]] 302 | name = "downcast-rs" 303 | version = "1.2.0" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" 306 | 307 | [[package]] 308 | name = "either" 309 | version = "1.6.1" 310 | source = "registry+https://github.com/rust-lang/crates.io-index" 311 | checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" 312 | 313 | [[package]] 314 | name = "fnv" 315 | version = "1.0.7" 316 | source = "registry+https://github.com/rust-lang/crates.io-index" 317 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 318 | 319 | [[package]] 320 | name = "foreign-types" 321 | version = "0.3.2" 322 | source = "registry+https://github.com/rust-lang/crates.io-index" 323 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 324 | dependencies = [ 325 | "foreign-types-shared", 326 | ] 327 | 328 | [[package]] 329 | name = "foreign-types-shared" 330 | version = "0.1.1" 331 | source = "registry+https://github.com/rust-lang/crates.io-index" 332 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 333 | 334 | [[package]] 335 | name = "fuchsia-cprng" 336 | version = "0.1.1" 337 | source = "registry+https://github.com/rust-lang/crates.io-index" 338 | checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" 339 | 340 | [[package]] 341 | name = "gl_generator" 342 | version = "0.14.0" 343 | source = "registry+https://github.com/rust-lang/crates.io-index" 344 | checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" 345 | dependencies = [ 346 | "khronos_api", 347 | "log", 348 | "xml-rs", 349 | ] 350 | 351 | [[package]] 352 | name = "glow" 353 | version = "0.11.2" 354 | source = "registry+https://github.com/rust-lang/crates.io-index" 355 | checksum = "d8bd5877156a19b8ac83a29b2306fe20537429d318f3ff0a1a2119f8d9c61919" 356 | dependencies = [ 357 | "js-sys", 358 | "slotmap", 359 | "wasm-bindgen", 360 | "web-sys", 361 | ] 362 | 363 | [[package]] 364 | name = "glutin" 365 | version = "0.28.0" 366 | source = "registry+https://github.com/rust-lang/crates.io-index" 367 | checksum = "00ea9dbe544bc8a657c4c4a798c2d16cd01b549820e47657297549d28371f6d2" 368 | dependencies = [ 369 | "android_glue", 370 | "cgl", 371 | "cocoa", 372 | "core-foundation 0.9.3", 373 | "glutin_egl_sys", 374 | "glutin_emscripten_sys", 375 | "glutin_gles2_sys", 376 | "glutin_glx_sys", 377 | "glutin_wgl_sys", 378 | "lazy_static", 379 | "libloading", 380 | "log", 381 | "objc", 382 | "osmesa-sys", 383 | "parking_lot", 384 | "wayland-client", 385 | "wayland-egl", 386 | "winapi", 387 | "winit", 388 | ] 389 | 390 | [[package]] 391 | name = "glutin_egl_sys" 392 | version = "0.1.5" 393 | source = "registry+https://github.com/rust-lang/crates.io-index" 394 | checksum = "2abb6aa55523480c4adc5a56bbaa249992e2dddb2fc63dc96e04a3355364c211" 395 | dependencies = [ 396 | "gl_generator", 397 | "winapi", 398 | ] 399 | 400 | [[package]] 401 | name = "glutin_emscripten_sys" 402 | version = "0.1.1" 403 | source = "registry+https://github.com/rust-lang/crates.io-index" 404 | checksum = "80de4146df76e8a6c32b03007bc764ff3249dcaeb4f675d68a06caf1bac363f1" 405 | 406 | [[package]] 407 | name = "glutin_gles2_sys" 408 | version = "0.1.5" 409 | source = "registry+https://github.com/rust-lang/crates.io-index" 410 | checksum = "e8094e708b730a7c8a1954f4f8a31880af00eb8a1c5b5bf85d28a0a3c6d69103" 411 | dependencies = [ 412 | "gl_generator", 413 | "objc", 414 | ] 415 | 416 | [[package]] 417 | name = "glutin_glx_sys" 418 | version = "0.1.7" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "7e393c8fc02b807459410429150e9c4faffdb312d59b8c038566173c81991351" 421 | dependencies = [ 422 | "gl_generator", 423 | "x11-dl", 424 | ] 425 | 426 | [[package]] 427 | name = "glutin_wgl_sys" 428 | version = "0.1.5" 429 | source = "registry+https://github.com/rust-lang/crates.io-index" 430 | checksum = "3da5951a1569dbab865c6f2a863efafff193a93caf05538d193e9e3816d21696" 431 | dependencies = [ 432 | "gl_generator", 433 | ] 434 | 435 | [[package]] 436 | name = "ident_case" 437 | version = "1.0.1" 438 | source = "registry+https://github.com/rust-lang/crates.io-index" 439 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 440 | 441 | [[package]] 442 | name = "instant" 443 | version = "0.1.12" 444 | source = "registry+https://github.com/rust-lang/crates.io-index" 445 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 446 | dependencies = [ 447 | "cfg-if 1.0.0", 448 | "js-sys", 449 | "wasm-bindgen", 450 | "web-sys", 451 | ] 452 | 453 | [[package]] 454 | name = "itertools" 455 | version = "0.10.3" 456 | source = "registry+https://github.com/rust-lang/crates.io-index" 457 | checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" 458 | dependencies = [ 459 | "either", 460 | ] 461 | 462 | [[package]] 463 | name = "itoa" 464 | version = "1.0.1" 465 | source = "registry+https://github.com/rust-lang/crates.io-index" 466 | checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" 467 | 468 | [[package]] 469 | name = "jni-sys" 470 | version = "0.3.0" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" 473 | 474 | [[package]] 475 | name = "js-sys" 476 | version = "0.3.57" 477 | source = "registry+https://github.com/rust-lang/crates.io-index" 478 | checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" 479 | dependencies = [ 480 | "wasm-bindgen", 481 | ] 482 | 483 | [[package]] 484 | name = "khronos_api" 485 | version = "3.1.0" 486 | source = "registry+https://github.com/rust-lang/crates.io-index" 487 | checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" 488 | 489 | [[package]] 490 | name = "lazy_static" 491 | version = "1.4.0" 492 | source = "registry+https://github.com/rust-lang/crates.io-index" 493 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 494 | 495 | [[package]] 496 | name = "libc" 497 | version = "0.2.124" 498 | source = "registry+https://github.com/rust-lang/crates.io-index" 499 | checksum = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50" 500 | 501 | [[package]] 502 | name = "libloading" 503 | version = "0.7.3" 504 | source = "registry+https://github.com/rust-lang/crates.io-index" 505 | checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" 506 | dependencies = [ 507 | "cfg-if 1.0.0", 508 | "winapi", 509 | ] 510 | 511 | [[package]] 512 | name = "lock_api" 513 | version = "0.4.7" 514 | source = "registry+https://github.com/rust-lang/crates.io-index" 515 | checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" 516 | dependencies = [ 517 | "autocfg 1.1.0", 518 | "scopeguard", 519 | ] 520 | 521 | [[package]] 522 | name = "log" 523 | version = "0.4.16" 524 | source = "registry+https://github.com/rust-lang/crates.io-index" 525 | checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" 526 | dependencies = [ 527 | "cfg-if 1.0.0", 528 | ] 529 | 530 | [[package]] 531 | name = "malloc_buf" 532 | version = "0.0.6" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" 535 | dependencies = [ 536 | "libc", 537 | ] 538 | 539 | [[package]] 540 | name = "memchr" 541 | version = "2.4.1" 542 | source = "registry+https://github.com/rust-lang/crates.io-index" 543 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 544 | 545 | [[package]] 546 | name = "memmap2" 547 | version = "0.3.1" 548 | source = "registry+https://github.com/rust-lang/crates.io-index" 549 | checksum = "00b6c2ebff6180198788f5db08d7ce3bc1d0b617176678831a7510825973e357" 550 | dependencies = [ 551 | "libc", 552 | ] 553 | 554 | [[package]] 555 | name = "memoffset" 556 | version = "0.6.5" 557 | source = "registry+https://github.com/rust-lang/crates.io-index" 558 | checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" 559 | dependencies = [ 560 | "autocfg 1.1.0", 561 | ] 562 | 563 | [[package]] 564 | name = "minimal-lexical" 565 | version = "0.2.1" 566 | source = "registry+https://github.com/rust-lang/crates.io-index" 567 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 568 | 569 | [[package]] 570 | name = "miniz_oxide" 571 | version = "0.5.1" 572 | source = "registry+https://github.com/rust-lang/crates.io-index" 573 | checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082" 574 | dependencies = [ 575 | "adler", 576 | ] 577 | 578 | [[package]] 579 | name = "mio" 580 | version = "0.8.2" 581 | source = "registry+https://github.com/rust-lang/crates.io-index" 582 | checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9" 583 | dependencies = [ 584 | "libc", 585 | "log", 586 | "miow", 587 | "ntapi", 588 | "wasi", 589 | "winapi", 590 | ] 591 | 592 | [[package]] 593 | name = "miow" 594 | version = "0.3.7" 595 | source = "registry+https://github.com/rust-lang/crates.io-index" 596 | checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" 597 | dependencies = [ 598 | "winapi", 599 | ] 600 | 601 | [[package]] 602 | name = "ndk" 603 | version = "0.5.0" 604 | source = "registry+https://github.com/rust-lang/crates.io-index" 605 | checksum = "96d868f654c72e75f8687572699cdabe755f03effbb62542768e995d5b8d699d" 606 | dependencies = [ 607 | "bitflags", 608 | "jni-sys", 609 | "ndk-sys", 610 | "num_enum", 611 | "thiserror", 612 | ] 613 | 614 | [[package]] 615 | name = "ndk-context" 616 | version = "0.1.1" 617 | source = "registry+https://github.com/rust-lang/crates.io-index" 618 | checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" 619 | 620 | [[package]] 621 | name = "ndk-glue" 622 | version = "0.5.2" 623 | source = "registry+https://github.com/rust-lang/crates.io-index" 624 | checksum = "c71bee8ea72d685477e28bd004cfe1bf99c754d688cd78cad139eae4089484d4" 625 | dependencies = [ 626 | "lazy_static", 627 | "libc", 628 | "log", 629 | "ndk", 630 | "ndk-context", 631 | "ndk-macro", 632 | "ndk-sys", 633 | ] 634 | 635 | [[package]] 636 | name = "ndk-macro" 637 | version = "0.3.0" 638 | source = "registry+https://github.com/rust-lang/crates.io-index" 639 | checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c" 640 | dependencies = [ 641 | "darling", 642 | "proc-macro-crate", 643 | "proc-macro2", 644 | "quote", 645 | "syn", 646 | ] 647 | 648 | [[package]] 649 | name = "ndk-sys" 650 | version = "0.2.2" 651 | source = "registry+https://github.com/rust-lang/crates.io-index" 652 | checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121" 653 | 654 | [[package]] 655 | name = "nix" 656 | version = "0.22.3" 657 | source = "registry+https://github.com/rust-lang/crates.io-index" 658 | checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf" 659 | dependencies = [ 660 | "bitflags", 661 | "cc", 662 | "cfg-if 1.0.0", 663 | "libc", 664 | "memoffset", 665 | ] 666 | 667 | [[package]] 668 | name = "nom" 669 | version = "7.1.1" 670 | source = "registry+https://github.com/rust-lang/crates.io-index" 671 | checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" 672 | dependencies = [ 673 | "memchr", 674 | "minimal-lexical", 675 | ] 676 | 677 | [[package]] 678 | name = "ntapi" 679 | version = "0.3.7" 680 | source = "registry+https://github.com/rust-lang/crates.io-index" 681 | checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" 682 | dependencies = [ 683 | "winapi", 684 | ] 685 | 686 | [[package]] 687 | name = "num" 688 | version = "0.1.42" 689 | source = "registry+https://github.com/rust-lang/crates.io-index" 690 | checksum = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" 691 | dependencies = [ 692 | "num-bigint", 693 | "num-complex", 694 | "num-integer", 695 | "num-iter", 696 | "num-rational", 697 | "num-traits", 698 | ] 699 | 700 | [[package]] 701 | name = "num-bigint" 702 | version = "0.1.44" 703 | source = "registry+https://github.com/rust-lang/crates.io-index" 704 | checksum = "e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1" 705 | dependencies = [ 706 | "num-integer", 707 | "num-traits", 708 | "rand 0.4.6", 709 | "rustc-serialize", 710 | ] 711 | 712 | [[package]] 713 | name = "num-complex" 714 | version = "0.1.43" 715 | source = "registry+https://github.com/rust-lang/crates.io-index" 716 | checksum = "b288631d7878aaf59442cffd36910ea604ecd7745c36054328595114001c9656" 717 | dependencies = [ 718 | "num-traits", 719 | "rustc-serialize", 720 | ] 721 | 722 | [[package]] 723 | name = "num-integer" 724 | version = "0.1.44" 725 | source = "registry+https://github.com/rust-lang/crates.io-index" 726 | checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" 727 | dependencies = [ 728 | "autocfg 1.1.0", 729 | "num-traits", 730 | ] 731 | 732 | [[package]] 733 | name = "num-iter" 734 | version = "0.1.42" 735 | source = "registry+https://github.com/rust-lang/crates.io-index" 736 | checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" 737 | dependencies = [ 738 | "autocfg 1.1.0", 739 | "num-integer", 740 | "num-traits", 741 | ] 742 | 743 | [[package]] 744 | name = "num-rational" 745 | version = "0.1.42" 746 | source = "registry+https://github.com/rust-lang/crates.io-index" 747 | checksum = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e" 748 | dependencies = [ 749 | "num-bigint", 750 | "num-integer", 751 | "num-traits", 752 | "rustc-serialize", 753 | ] 754 | 755 | [[package]] 756 | name = "num-traits" 757 | version = "0.2.14" 758 | source = "registry+https://github.com/rust-lang/crates.io-index" 759 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 760 | dependencies = [ 761 | "autocfg 1.1.0", 762 | ] 763 | 764 | [[package]] 765 | name = "num_enum" 766 | version = "0.5.7" 767 | source = "registry+https://github.com/rust-lang/crates.io-index" 768 | checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9" 769 | dependencies = [ 770 | "num_enum_derive", 771 | ] 772 | 773 | [[package]] 774 | name = "num_enum_derive" 775 | version = "0.5.7" 776 | source = "registry+https://github.com/rust-lang/crates.io-index" 777 | checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" 778 | dependencies = [ 779 | "proc-macro-crate", 780 | "proc-macro2", 781 | "quote", 782 | "syn", 783 | ] 784 | 785 | [[package]] 786 | name = "objc" 787 | version = "0.2.7" 788 | source = "registry+https://github.com/rust-lang/crates.io-index" 789 | checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" 790 | dependencies = [ 791 | "malloc_buf", 792 | ] 793 | 794 | [[package]] 795 | name = "once_cell" 796 | version = "1.10.0" 797 | source = "registry+https://github.com/rust-lang/crates.io-index" 798 | checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" 799 | 800 | [[package]] 801 | name = "ordered-float" 802 | version = "2.10.0" 803 | source = "registry+https://github.com/rust-lang/crates.io-index" 804 | checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87" 805 | dependencies = [ 806 | "num-traits", 807 | ] 808 | 809 | [[package]] 810 | name = "osmesa-sys" 811 | version = "0.1.2" 812 | source = "registry+https://github.com/rust-lang/crates.io-index" 813 | checksum = "88cfece6e95d2e717e0872a7f53a8684712ad13822a7979bc760b9c77ec0013b" 814 | dependencies = [ 815 | "shared_library", 816 | ] 817 | 818 | [[package]] 819 | name = "palette" 820 | version = "0.2.1" 821 | source = "registry+https://github.com/rust-lang/crates.io-index" 822 | checksum = "f73fae0ce32bdcf4da5747adda9dbfd5a02e3a439631020ab98258991ebb488d" 823 | dependencies = [ 824 | "approx", 825 | "num", 826 | "phf", 827 | "phf_codegen", 828 | ] 829 | 830 | [[package]] 831 | name = "parking_lot" 832 | version = "0.11.2" 833 | source = "registry+https://github.com/rust-lang/crates.io-index" 834 | checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" 835 | dependencies = [ 836 | "instant", 837 | "lock_api", 838 | "parking_lot_core", 839 | ] 840 | 841 | [[package]] 842 | name = "parking_lot_core" 843 | version = "0.8.5" 844 | source = "registry+https://github.com/rust-lang/crates.io-index" 845 | checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" 846 | dependencies = [ 847 | "cfg-if 1.0.0", 848 | "instant", 849 | "libc", 850 | "redox_syscall", 851 | "smallvec", 852 | "winapi", 853 | ] 854 | 855 | [[package]] 856 | name = "percent-encoding" 857 | version = "2.1.0" 858 | source = "registry+https://github.com/rust-lang/crates.io-index" 859 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 860 | 861 | [[package]] 862 | name = "phf" 863 | version = "0.7.24" 864 | source = "registry+https://github.com/rust-lang/crates.io-index" 865 | checksum = "b3da44b85f8e8dfaec21adae67f95d93244b2ecf6ad2a692320598dcc8e6dd18" 866 | dependencies = [ 867 | "phf_shared", 868 | ] 869 | 870 | [[package]] 871 | name = "phf_codegen" 872 | version = "0.7.24" 873 | source = "registry+https://github.com/rust-lang/crates.io-index" 874 | checksum = "b03e85129e324ad4166b06b2c7491ae27fe3ec353af72e72cd1654c7225d517e" 875 | dependencies = [ 876 | "phf_generator", 877 | "phf_shared", 878 | ] 879 | 880 | [[package]] 881 | name = "phf_generator" 882 | version = "0.7.24" 883 | source = "registry+https://github.com/rust-lang/crates.io-index" 884 | checksum = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662" 885 | dependencies = [ 886 | "phf_shared", 887 | "rand 0.6.5", 888 | ] 889 | 890 | [[package]] 891 | name = "phf_shared" 892 | version = "0.7.24" 893 | source = "registry+https://github.com/rust-lang/crates.io-index" 894 | checksum = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0" 895 | dependencies = [ 896 | "siphasher", 897 | ] 898 | 899 | [[package]] 900 | name = "pkg-config" 901 | version = "0.3.25" 902 | source = "registry+https://github.com/rust-lang/crates.io-index" 903 | checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" 904 | 905 | [[package]] 906 | name = "png" 907 | version = "0.17.5" 908 | source = "registry+https://github.com/rust-lang/crates.io-index" 909 | checksum = "dc38c0ad57efb786dd57b9864e5b18bae478c00c824dc55a38bbc9da95dde3ba" 910 | dependencies = [ 911 | "bitflags", 912 | "crc32fast", 913 | "deflate", 914 | "miniz_oxide", 915 | ] 916 | 917 | [[package]] 918 | name = "proc-macro-crate" 919 | version = "1.1.3" 920 | source = "registry+https://github.com/rust-lang/crates.io-index" 921 | checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" 922 | dependencies = [ 923 | "thiserror", 924 | "toml", 925 | ] 926 | 927 | [[package]] 928 | name = "proc-macro2" 929 | version = "1.0.37" 930 | source = "registry+https://github.com/rust-lang/crates.io-index" 931 | checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" 932 | dependencies = [ 933 | "unicode-xid", 934 | ] 935 | 936 | [[package]] 937 | name = "quote" 938 | version = "1.0.18" 939 | source = "registry+https://github.com/rust-lang/crates.io-index" 940 | checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" 941 | dependencies = [ 942 | "proc-macro2", 943 | ] 944 | 945 | [[package]] 946 | name = "rand" 947 | version = "0.4.6" 948 | source = "registry+https://github.com/rust-lang/crates.io-index" 949 | checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" 950 | dependencies = [ 951 | "fuchsia-cprng", 952 | "libc", 953 | "rand_core 0.3.1", 954 | "rdrand", 955 | "winapi", 956 | ] 957 | 958 | [[package]] 959 | name = "rand" 960 | version = "0.6.5" 961 | source = "registry+https://github.com/rust-lang/crates.io-index" 962 | checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" 963 | dependencies = [ 964 | "autocfg 0.1.8", 965 | "libc", 966 | "rand_chacha", 967 | "rand_core 0.4.2", 968 | "rand_hc", 969 | "rand_isaac", 970 | "rand_jitter", 971 | "rand_os", 972 | "rand_pcg", 973 | "rand_xorshift", 974 | "winapi", 975 | ] 976 | 977 | [[package]] 978 | name = "rand_chacha" 979 | version = "0.1.1" 980 | source = "registry+https://github.com/rust-lang/crates.io-index" 981 | checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" 982 | dependencies = [ 983 | "autocfg 0.1.8", 984 | "rand_core 0.3.1", 985 | ] 986 | 987 | [[package]] 988 | name = "rand_core" 989 | version = "0.3.1" 990 | source = "registry+https://github.com/rust-lang/crates.io-index" 991 | checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" 992 | dependencies = [ 993 | "rand_core 0.4.2", 994 | ] 995 | 996 | [[package]] 997 | name = "rand_core" 998 | version = "0.4.2" 999 | source = "registry+https://github.com/rust-lang/crates.io-index" 1000 | checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" 1001 | 1002 | [[package]] 1003 | name = "rand_hc" 1004 | version = "0.1.0" 1005 | source = "registry+https://github.com/rust-lang/crates.io-index" 1006 | checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" 1007 | dependencies = [ 1008 | "rand_core 0.3.1", 1009 | ] 1010 | 1011 | [[package]] 1012 | name = "rand_isaac" 1013 | version = "0.1.1" 1014 | source = "registry+https://github.com/rust-lang/crates.io-index" 1015 | checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" 1016 | dependencies = [ 1017 | "rand_core 0.3.1", 1018 | ] 1019 | 1020 | [[package]] 1021 | name = "rand_jitter" 1022 | version = "0.1.4" 1023 | source = "registry+https://github.com/rust-lang/crates.io-index" 1024 | checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" 1025 | dependencies = [ 1026 | "libc", 1027 | "rand_core 0.4.2", 1028 | "winapi", 1029 | ] 1030 | 1031 | [[package]] 1032 | name = "rand_os" 1033 | version = "0.1.3" 1034 | source = "registry+https://github.com/rust-lang/crates.io-index" 1035 | checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" 1036 | dependencies = [ 1037 | "cloudabi", 1038 | "fuchsia-cprng", 1039 | "libc", 1040 | "rand_core 0.4.2", 1041 | "rdrand", 1042 | "winapi", 1043 | ] 1044 | 1045 | [[package]] 1046 | name = "rand_pcg" 1047 | version = "0.1.2" 1048 | source = "registry+https://github.com/rust-lang/crates.io-index" 1049 | checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" 1050 | dependencies = [ 1051 | "autocfg 0.1.8", 1052 | "rand_core 0.4.2", 1053 | ] 1054 | 1055 | [[package]] 1056 | name = "rand_xorshift" 1057 | version = "0.1.1" 1058 | source = "registry+https://github.com/rust-lang/crates.io-index" 1059 | checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" 1060 | dependencies = [ 1061 | "rand_core 0.3.1", 1062 | ] 1063 | 1064 | [[package]] 1065 | name = "raw-window-handle" 1066 | version = "0.4.3" 1067 | source = "registry+https://github.com/rust-lang/crates.io-index" 1068 | checksum = "b800beb9b6e7d2df1fe337c9e3d04e3af22a124460fb4c30fcc22c9117cefb41" 1069 | dependencies = [ 1070 | "cty", 1071 | ] 1072 | 1073 | [[package]] 1074 | name = "rdrand" 1075 | version = "0.4.0" 1076 | source = "registry+https://github.com/rust-lang/crates.io-index" 1077 | checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" 1078 | dependencies = [ 1079 | "rand_core 0.3.1", 1080 | ] 1081 | 1082 | [[package]] 1083 | name = "redox_syscall" 1084 | version = "0.2.13" 1085 | source = "registry+https://github.com/rust-lang/crates.io-index" 1086 | checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" 1087 | dependencies = [ 1088 | "bitflags", 1089 | ] 1090 | 1091 | [[package]] 1092 | name = "rustc-serialize" 1093 | version = "0.3.24" 1094 | source = "registry+https://github.com/rust-lang/crates.io-index" 1095 | checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" 1096 | 1097 | [[package]] 1098 | name = "ryu" 1099 | version = "1.0.9" 1100 | source = "registry+https://github.com/rust-lang/crates.io-index" 1101 | checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" 1102 | 1103 | [[package]] 1104 | name = "scoped-tls" 1105 | version = "1.0.0" 1106 | source = "registry+https://github.com/rust-lang/crates.io-index" 1107 | checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" 1108 | 1109 | [[package]] 1110 | name = "scopeguard" 1111 | version = "1.1.0" 1112 | source = "registry+https://github.com/rust-lang/crates.io-index" 1113 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 1114 | 1115 | [[package]] 1116 | name = "serde" 1117 | version = "1.0.136" 1118 | source = "registry+https://github.com/rust-lang/crates.io-index" 1119 | checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" 1120 | dependencies = [ 1121 | "serde_derive", 1122 | ] 1123 | 1124 | [[package]] 1125 | name = "serde_derive" 1126 | version = "1.0.136" 1127 | source = "registry+https://github.com/rust-lang/crates.io-index" 1128 | checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" 1129 | dependencies = [ 1130 | "proc-macro2", 1131 | "quote", 1132 | "syn", 1133 | ] 1134 | 1135 | [[package]] 1136 | name = "serde_json" 1137 | version = "1.0.79" 1138 | source = "registry+https://github.com/rust-lang/crates.io-index" 1139 | checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" 1140 | dependencies = [ 1141 | "itoa", 1142 | "ryu", 1143 | "serde", 1144 | ] 1145 | 1146 | [[package]] 1147 | name = "shared_library" 1148 | version = "0.1.9" 1149 | source = "registry+https://github.com/rust-lang/crates.io-index" 1150 | checksum = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11" 1151 | dependencies = [ 1152 | "lazy_static", 1153 | "libc", 1154 | ] 1155 | 1156 | [[package]] 1157 | name = "siphasher" 1158 | version = "0.2.3" 1159 | source = "registry+https://github.com/rust-lang/crates.io-index" 1160 | checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" 1161 | 1162 | [[package]] 1163 | name = "slotmap" 1164 | version = "1.0.6" 1165 | source = "registry+https://github.com/rust-lang/crates.io-index" 1166 | checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" 1167 | dependencies = [ 1168 | "version_check", 1169 | ] 1170 | 1171 | [[package]] 1172 | name = "smallvec" 1173 | version = "1.8.0" 1174 | source = "registry+https://github.com/rust-lang/crates.io-index" 1175 | checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" 1176 | 1177 | [[package]] 1178 | name = "smithay-client-toolkit" 1179 | version = "0.15.4" 1180 | source = "registry+https://github.com/rust-lang/crates.io-index" 1181 | checksum = "8a28f16a97fa0e8ce563b2774d1e732dd5d4025d2772c5dba0a41a0f90a29da3" 1182 | dependencies = [ 1183 | "bitflags", 1184 | "calloop", 1185 | "dlib", 1186 | "lazy_static", 1187 | "log", 1188 | "memmap2", 1189 | "nix", 1190 | "pkg-config", 1191 | "wayland-client", 1192 | "wayland-cursor", 1193 | "wayland-protocols", 1194 | ] 1195 | 1196 | [[package]] 1197 | name = "strsim" 1198 | version = "0.10.0" 1199 | source = "registry+https://github.com/rust-lang/crates.io-index" 1200 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 1201 | 1202 | [[package]] 1203 | name = "syn" 1204 | version = "1.0.91" 1205 | source = "registry+https://github.com/rust-lang/crates.io-index" 1206 | checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" 1207 | dependencies = [ 1208 | "proc-macro2", 1209 | "quote", 1210 | "unicode-xid", 1211 | ] 1212 | 1213 | [[package]] 1214 | name = "thiserror" 1215 | version = "1.0.30" 1216 | source = "registry+https://github.com/rust-lang/crates.io-index" 1217 | checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" 1218 | dependencies = [ 1219 | "thiserror-impl", 1220 | ] 1221 | 1222 | [[package]] 1223 | name = "thiserror-impl" 1224 | version = "1.0.30" 1225 | source = "registry+https://github.com/rust-lang/crates.io-index" 1226 | checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" 1227 | dependencies = [ 1228 | "proc-macro2", 1229 | "quote", 1230 | "syn", 1231 | ] 1232 | 1233 | [[package]] 1234 | name = "toml" 1235 | version = "0.5.9" 1236 | source = "registry+https://github.com/rust-lang/crates.io-index" 1237 | checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" 1238 | dependencies = [ 1239 | "serde", 1240 | ] 1241 | 1242 | [[package]] 1243 | name = "unicode-xid" 1244 | version = "0.2.2" 1245 | source = "registry+https://github.com/rust-lang/crates.io-index" 1246 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 1247 | 1248 | [[package]] 1249 | name = "version_check" 1250 | version = "0.9.4" 1251 | source = "registry+https://github.com/rust-lang/crates.io-index" 1252 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 1253 | 1254 | [[package]] 1255 | name = "wasi" 1256 | version = "0.11.0+wasi-snapshot-preview1" 1257 | source = "registry+https://github.com/rust-lang/crates.io-index" 1258 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1259 | 1260 | [[package]] 1261 | name = "wasm-bindgen" 1262 | version = "0.2.80" 1263 | source = "registry+https://github.com/rust-lang/crates.io-index" 1264 | checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" 1265 | dependencies = [ 1266 | "cfg-if 1.0.0", 1267 | "wasm-bindgen-macro", 1268 | ] 1269 | 1270 | [[package]] 1271 | name = "wasm-bindgen-backend" 1272 | version = "0.2.80" 1273 | source = "registry+https://github.com/rust-lang/crates.io-index" 1274 | checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" 1275 | dependencies = [ 1276 | "bumpalo", 1277 | "lazy_static", 1278 | "log", 1279 | "proc-macro2", 1280 | "quote", 1281 | "syn", 1282 | "wasm-bindgen-shared", 1283 | ] 1284 | 1285 | [[package]] 1286 | name = "wasm-bindgen-macro" 1287 | version = "0.2.80" 1288 | source = "registry+https://github.com/rust-lang/crates.io-index" 1289 | checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" 1290 | dependencies = [ 1291 | "quote", 1292 | "wasm-bindgen-macro-support", 1293 | ] 1294 | 1295 | [[package]] 1296 | name = "wasm-bindgen-macro-support" 1297 | version = "0.2.80" 1298 | source = "registry+https://github.com/rust-lang/crates.io-index" 1299 | checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" 1300 | dependencies = [ 1301 | "proc-macro2", 1302 | "quote", 1303 | "syn", 1304 | "wasm-bindgen-backend", 1305 | "wasm-bindgen-shared", 1306 | ] 1307 | 1308 | [[package]] 1309 | name = "wasm-bindgen-shared" 1310 | version = "0.2.80" 1311 | source = "registry+https://github.com/rust-lang/crates.io-index" 1312 | checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" 1313 | 1314 | [[package]] 1315 | name = "wayland-client" 1316 | version = "0.29.4" 1317 | source = "registry+https://github.com/rust-lang/crates.io-index" 1318 | checksum = "91223460e73257f697d9e23d401279123d36039a3f7a449e983f123292d4458f" 1319 | dependencies = [ 1320 | "bitflags", 1321 | "downcast-rs", 1322 | "libc", 1323 | "nix", 1324 | "scoped-tls", 1325 | "wayland-commons", 1326 | "wayland-scanner", 1327 | "wayland-sys", 1328 | ] 1329 | 1330 | [[package]] 1331 | name = "wayland-commons" 1332 | version = "0.29.4" 1333 | source = "registry+https://github.com/rust-lang/crates.io-index" 1334 | checksum = "94f6e5e340d7c13490eca867898c4cec5af56c27a5ffe5c80c6fc4708e22d33e" 1335 | dependencies = [ 1336 | "nix", 1337 | "once_cell", 1338 | "smallvec", 1339 | "wayland-sys", 1340 | ] 1341 | 1342 | [[package]] 1343 | name = "wayland-cursor" 1344 | version = "0.29.4" 1345 | source = "registry+https://github.com/rust-lang/crates.io-index" 1346 | checksum = "c52758f13d5e7861fc83d942d3d99bf270c83269575e52ac29e5b73cb956a6bd" 1347 | dependencies = [ 1348 | "nix", 1349 | "wayland-client", 1350 | "xcursor", 1351 | ] 1352 | 1353 | [[package]] 1354 | name = "wayland-egl" 1355 | version = "0.29.4" 1356 | source = "registry+https://github.com/rust-lang/crates.io-index" 1357 | checksum = "83281d69ee162b59031c666385e93bde4039ec553b90c4191cdb128ceea29a3a" 1358 | dependencies = [ 1359 | "wayland-client", 1360 | "wayland-sys", 1361 | ] 1362 | 1363 | [[package]] 1364 | name = "wayland-protocols" 1365 | version = "0.29.4" 1366 | source = "registry+https://github.com/rust-lang/crates.io-index" 1367 | checksum = "60147ae23303402e41fe034f74fb2c35ad0780ee88a1c40ac09a3be1e7465741" 1368 | dependencies = [ 1369 | "bitflags", 1370 | "wayland-client", 1371 | "wayland-commons", 1372 | "wayland-scanner", 1373 | ] 1374 | 1375 | [[package]] 1376 | name = "wayland-scanner" 1377 | version = "0.29.4" 1378 | source = "registry+https://github.com/rust-lang/crates.io-index" 1379 | checksum = "39a1ed3143f7a143187156a2ab52742e89dac33245ba505c17224df48939f9e0" 1380 | dependencies = [ 1381 | "proc-macro2", 1382 | "quote", 1383 | "xml-rs", 1384 | ] 1385 | 1386 | [[package]] 1387 | name = "wayland-sys" 1388 | version = "0.29.4" 1389 | source = "registry+https://github.com/rust-lang/crates.io-index" 1390 | checksum = "d9341df79a8975679188e37dab3889bfa57c44ac2cb6da166f519a81cbe452d4" 1391 | dependencies = [ 1392 | "dlib", 1393 | "lazy_static", 1394 | "pkg-config", 1395 | ] 1396 | 1397 | [[package]] 1398 | name = "web-sys" 1399 | version = "0.3.57" 1400 | source = "registry+https://github.com/rust-lang/crates.io-index" 1401 | checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283" 1402 | dependencies = [ 1403 | "js-sys", 1404 | "wasm-bindgen", 1405 | ] 1406 | 1407 | [[package]] 1408 | name = "winapi" 1409 | version = "0.3.9" 1410 | source = "registry+https://github.com/rust-lang/crates.io-index" 1411 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1412 | dependencies = [ 1413 | "winapi-i686-pc-windows-gnu", 1414 | "winapi-x86_64-pc-windows-gnu", 1415 | ] 1416 | 1417 | [[package]] 1418 | name = "winapi-i686-pc-windows-gnu" 1419 | version = "0.4.0" 1420 | source = "registry+https://github.com/rust-lang/crates.io-index" 1421 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1422 | 1423 | [[package]] 1424 | name = "winapi-x86_64-pc-windows-gnu" 1425 | version = "0.4.0" 1426 | source = "registry+https://github.com/rust-lang/crates.io-index" 1427 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1428 | 1429 | [[package]] 1430 | name = "winit" 1431 | version = "0.26.1" 1432 | source = "registry+https://github.com/rust-lang/crates.io-index" 1433 | checksum = "9b43cc931d58b99461188607efd7acb2a093e65fc621f54cad78517a6063e73a" 1434 | dependencies = [ 1435 | "bitflags", 1436 | "cocoa", 1437 | "core-foundation 0.9.3", 1438 | "core-graphics 0.22.3", 1439 | "core-video-sys", 1440 | "dispatch", 1441 | "instant", 1442 | "lazy_static", 1443 | "libc", 1444 | "log", 1445 | "mio", 1446 | "ndk", 1447 | "ndk-glue", 1448 | "ndk-sys", 1449 | "objc", 1450 | "parking_lot", 1451 | "percent-encoding", 1452 | "raw-window-handle", 1453 | "smithay-client-toolkit", 1454 | "wasm-bindgen", 1455 | "wayland-client", 1456 | "wayland-protocols", 1457 | "web-sys", 1458 | "winapi", 1459 | "x11-dl", 1460 | ] 1461 | 1462 | [[package]] 1463 | name = "wizrad" 1464 | version = "0.1.0" 1465 | dependencies = [ 1466 | "assert_hex", 1467 | "glow", 1468 | "glutin", 1469 | "itertools", 1470 | "ordered-float", 1471 | "palette", 1472 | "png", 1473 | "serde", 1474 | "serde_json", 1475 | "winit", 1476 | ] 1477 | 1478 | [[package]] 1479 | name = "x11-dl" 1480 | version = "2.19.1" 1481 | source = "registry+https://github.com/rust-lang/crates.io-index" 1482 | checksum = "ea26926b4ce81a6f5d9d0f3a0bc401e5a37c6ae14a1bfaa8ff6099ca80038c59" 1483 | dependencies = [ 1484 | "lazy_static", 1485 | "libc", 1486 | "pkg-config", 1487 | ] 1488 | 1489 | [[package]] 1490 | name = "xcursor" 1491 | version = "0.3.4" 1492 | source = "registry+https://github.com/rust-lang/crates.io-index" 1493 | checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7" 1494 | dependencies = [ 1495 | "nom", 1496 | ] 1497 | 1498 | [[package]] 1499 | name = "xml-rs" 1500 | version = "0.8.4" 1501 | source = "registry+https://github.com/rust-lang/crates.io-index" 1502 | checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" 1503 | --------------------------------------------------------------------------------