use crate::{
color,
physics::{Position, Velocity},
};
use anyhow::Result;
use specs_blit::{
blit::{BlitBuffer, Color},
specs::*,
Sprite, SpriteRef,
};
use sprite_gen::{
MaskValue::{self, *},
Options,
};
type Vec2 = vek::Vec2<f64>;
#[derive(Component, Debug, Default)]
#[storage(NullStorage)]
pub struct RotationFollowsVelocity;
pub struct SpriteRotationSystem;
impl<'a> System<'a> for SpriteRotationSystem {
type SystemData = (
ReadStorage<'a, Velocity>,
ReadStorage<'a, RotationFollowsVelocity>,
WriteStorage<'a, Sprite>,
);
fn run(&mut self, (vel, marker, mut sprite): Self::SystemData) {
for (vel, _, sprite) in (&vel, &marker, &mut sprite).join() {
let rot = Vec2::new(-1.0, 0.0).angle_between(vel.0).to_degrees();
sprite.set_rot(rot as i16);
}
}
}
pub struct SpritePositionSystem;
impl<'a> System<'a> for SpritePositionSystem {
type SystemData = (ReadStorage<'a, Position>, WriteStorage<'a, Sprite>);
fn run(&mut self, (pos, mut sprite): Self::SystemData) {
for (pos, sprite) in (&pos, &mut sprite).join() {
sprite.set_pos(pos.x as i32, pos.y as i32);
}
}
}
pub fn buffer(width: usize, options: Options, mask: &[MaskValue]) -> BlitBuffer {
let buffer_width = if options.mirror_x { width * 2 } else { width };
BlitBuffer::from_buffer(
&sprite_gen::gen_sprite(&mask, width, options)
.into_iter()
.map(|p| p ^ 0xFF_FF_FF_FF)
.collect::<Vec<_>>(),
buffer_width as i32,
Color::from_u32(0),
)
}
pub fn generate(width: usize, options: Options, mask: &[MaskValue]) -> Result<SpriteRef> {
specs_blit::load(buffer(width, options, mask))
}
pub fn single_pixel(color: Color) -> Result<SpriteRef> {
let buf = BlitBuffer::from_buffer(&[color.u32()], 1, Color::from_u32(0));
specs_blit::load(buf)
}
pub fn generate_planet() -> Result<SpriteRef> {
let (width, height, options) = (
6,
crate::HEIGHT / 2,
Options {
mirror_x: false,
mirror_y: true,
colored: true,
edge_brightness: 0.0,
color_variations: 0.8547504,
brightness_noise: 0.9012264,
saturation: 0.0,
seed: quad_rand::rand() as u64,
},
);
let mut data = vec![Empty; width * height];
for x in 0..2 {
for y in 0..height {
data[x + y * width] = Body2;
}
}
for y in height / 2..height {
data[y * width + 1] = Body1;
}
for y in height / 3..height {
data[y * width + 2] = Body2;
}
generate(width, options, &data)
}
pub struct Sprites {
pub red_particle: SpriteRef,
pub white_particle: SpriteRef,
pub big_projectile: SpriteRef,
pub big_projectile_width: f64,
pub big_projectile_height: f64,
pub small_projectile: SpriteRef,
pub small_projectile_width: f64,
pub small_projectile_height: f64,
pub planet: SpriteRef,
}
impl Sprites {
pub fn generate() -> Result<Self> {
let white_particle = single_pixel(Color::from_u32(color::FOREGROUND))?;
let red_particle = single_pixel(Color::from_u32(color::RED))?;
let (big_projectile, big_projectile_width, big_projectile_height) =
Sprites::generate_big_projectile()?;
let (small_projectile, small_projectile_width, small_projectile_height) =
Sprites::generate_small_projectile()?;
let planet = generate_planet()?;
Ok(Self {
red_particle,
white_particle,
big_projectile,
big_projectile_width,
big_projectile_height,
small_projectile,
small_projectile_width,
small_projectile_height,
planet,
})
}
pub fn big_projectile(&self) -> (SpriteRef, f64, f64) {
(
self.big_projectile.clone(),
self.big_projectile_width,
self.big_projectile_height,
)
}
pub fn small_projectile(&self) -> (SpriteRef, f64, f64) {
(
self.small_projectile.clone(),
self.small_projectile_width,
self.small_projectile_height,
)
}
fn generate_big_projectile() -> Result<(SpriteRef, f64, f64)> {
let (width, height, options) = (
4,
4,
Options {
mirror_x: true,
mirror_y: true,
colored: true,
edge_brightness: 0.0,
color_variations: 0.8547504,
brightness_noise: 0.9012264,
saturation: 1.0,
seed: quad_rand::rand() as u64,
},
);
let data = [
Empty, Empty, Empty, Body1, Empty, Body1, Body2, Body2, Empty, Body2, Body2, Body2,
Body1, Body2, Body2, Body2,
];
Ok((
generate(width, options, &data)?,
width as f64 * 2.0,
height as f64 * 2.0,
))
}
fn generate_small_projectile() -> Result<(SpriteRef, f64, f64)> {
let (width, height, options) = (
3,
3,
Options {
mirror_x: true,
mirror_y: true,
colored: true,
edge_brightness: 0.0,
color_variations: 0.8547504,
brightness_noise: 0.9012264,
saturation: 1.0,
seed: quad_rand::rand() as u64,
},
);
let data = [
Empty, Empty, Empty, Empty, Body1, Body2, Empty, Body2, Body2,
];
Ok((
generate(width, options, &data)?,
width as f64 * 2.0,
height as f64 * 2.0,
))
}
}