diff --git a/Cargo.lock b/Cargo.lock index 49ec0cb..60734d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -386,6 +386,12 @@ dependencies = [ "weezl", ] +[[package]] +name = "glam" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42218cb640844e3872cc3c153dc975229e080a6c4733b34709ef445610550226" + [[package]] name = "hashbrown" version = "0.14.0" @@ -1033,6 +1039,7 @@ name = "skunk2d" version = "0.1.0" dependencies = [ "gif", + "glam", "measure_time", "num", "rand", diff --git a/Cargo.toml b/Cargo.toml index 32a9a7c..1b387cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,4 +12,5 @@ rand = "0.8.5" num = "0.4.0" measure_time = "0.8.2" softbuffer = "0.3.0" -rayon = "1.7.0" \ No newline at end of file +rayon = "1.7.0" +glam = "0.24.0" \ No newline at end of file diff --git a/examples/test.rs b/examples/test.rs index 4b645f8..e6dd78c 100644 --- a/examples/test.rs +++ b/examples/test.rs @@ -1,3 +1,4 @@ +use glam::IVec2; use rand::Rng; use skunk2d::*; use std::rc::Rc; @@ -8,7 +9,7 @@ const HEIGHT: i32 = 1080 / 3; struct World { img: Rc, font: Rc, - pos: Vec2, + pos: IVec2, map: HexMap, } @@ -23,12 +24,15 @@ impl Game for World { window_state.scramble_palette(); Self { img: Image::load_data(include_bytes!("assets/test.gif")), - font: Tileset::load_data(include_bytes!("assets/ega-8x14.gif"), Vec2 { x: 16, y: 16 }), - pos: Vec2::zero(), + font: Tileset::load_data( + include_bytes!("assets/ega-8x14.gif"), + IVec2 { x: 16, y: 16 }, + ), + pos: IVec2::ZERO, map: HexMap::new( - Vec2 { x: 27, y: 13 }, - Tileset::load_data(include_bytes!("assets/hex2.gif"), Vec2 { x: 2, y: 1 }), - Vec2 { x: 23, y: 13 }, + IVec2 { x: 27, y: 13 }, + Tileset::load_data(include_bytes!("assets/hex2.gif"), IVec2 { x: 2, y: 1 }), + IVec2 { x: 23, y: 13 }, ), } } @@ -54,7 +58,7 @@ impl Game for World { fn draw(&self, target: &mut Image) { target.clear(); - target.draw_hexmap(Vec2 { x: 0, y: 0 }, &self.map); + target.draw_hexmap(IVec2 { x: 0, y: 0 }, &self.map); /*target.draw_image(Vec2 { x: 200, y: 100 }, &self.img); target.draw_image(self.pos, self.font.get(68)); diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..271800c --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" \ No newline at end of file diff --git a/src/console.rs b/src/console.rs index e00d2a6..89be93c 100644 --- a/src/console.rs +++ b/src/console.rs @@ -1,4 +1,5 @@ -use crate::{Image, Rect, Tileset, Vec2}; +use crate::{IRect, Image, Tileset}; +use glam::IVec2; use std::collections::VecDeque; pub(crate) struct Console { @@ -29,13 +30,13 @@ impl Console { } } - pub(crate) fn draw_to_image(&self, target: &mut Image, pos: Vec2, font: &Tileset) { + pub(crate) fn draw_to_image(&self, target: &mut Image, pos: IVec2, font: &Tileset) { let height = self.max_lines as i32 * font.tile_size().y; let width = self.max_line_length as i32 * font.tile_size().x; target.fill_rect( - Rect { + IRect { pos, - size: Vec2 { + size: IVec2 { x: width, y: height, }, @@ -44,8 +45,8 @@ impl Console { ); let y = height + pos.y; target.draw_line( - Vec2 { x: pos.x, y }, - Vec2 { + IVec2 { x: pos.x, y }, + IVec2 { x: pos.x + width, y, }, @@ -53,7 +54,7 @@ impl Console { ); for (i, str) in self.lines.iter().enumerate() { target.draw_string( - pos + Vec2 { + pos + IVec2 { x: 0, y: i as i32 * font.tile_size().y, }, diff --git a/src/hexmap.rs b/src/hexmap.rs index 5ae2550..3c7a501 100644 --- a/src/hexmap.rs +++ b/src/hexmap.rs @@ -1,4 +1,6 @@ -use crate::{Image, Tileset, Vec2}; +use crate::vec_util::IVec2Helper; +use crate::{Image, Tileset}; +use glam::IVec2; use rand::distributions::Standard; use rand::prelude::Distribution; use rand::Rng; @@ -6,10 +8,10 @@ use std::rc::Rc; //odd-q vertical layout https://www.redblobgames.com/grids/hexagons pub struct HexMap { - size: Vec2, + size: IVec2, data: Vec, tileset: Rc, - pix_tile_off: Vec2, + pix_tile_off: IVec2, } pub enum Direction { @@ -24,7 +26,7 @@ pub enum Direction { impl HexMap { //pub static //pix_tile_off: x offset per tile, up/down alternating y offset on x axis - pub fn new(size: Vec2, tileset: Rc, pix_tile_off: Vec2) -> Self { + pub fn new(size: IVec2, tileset: Rc, pix_tile_off: IVec2) -> Self { HexMap { size, data: vec![0; size.size()], @@ -33,15 +35,15 @@ impl HexMap { } } - pub fn get_neighbour(coord: Vec2, dir: Direction) -> Vec2 { + pub fn get_neighbour(coord: IVec2, dir: Direction) -> IVec2 { let yoff = coord.x % 2; (match dir { - Direction::North => Vec2 { x: 0, y: -1 }, - Direction::NorthEast => Vec2 { x: 1, y: -1 + yoff }, - Direction::SouthEast => Vec2 { x: 1, y: 0 + yoff }, - Direction::South => Vec2 { x: 0, y: 1 }, - Direction::SouthWest => Vec2 { x: -1, y: 0 + yoff }, - Direction::NorthWest => Vec2 { + Direction::North => IVec2 { x: 0, y: -1 }, + Direction::NorthEast => IVec2 { x: 1, y: -1 + yoff }, + Direction::SouthEast => IVec2 { x: 1, y: 0 + yoff }, + Direction::South => IVec2 { x: 0, y: 1 }, + Direction::SouthWest => IVec2 { x: -1, y: 0 + yoff }, + Direction::NorthWest => IVec2 { x: -1, y: -1 + yoff, }, @@ -49,7 +51,7 @@ impl HexMap { } //pub - pub fn get(&self, coord: Vec2) -> i32 { + pub fn get(&self, coord: IVec2) -> i32 { if !self.is_valid_coord(coord) { -1 } else { @@ -57,7 +59,7 @@ impl HexMap { } } - pub fn pixel_to_coord(&self, pixel: Vec2) -> Vec2 { + pub fn pixel_to_coord(&self, pixel: IVec2) -> IVec2 { let tilesize = self.tileset.tile_size(); let xrepeat = pixel.x % self.pix_tile_off.x; let mut x = pixel.x / self.pix_tile_off.x; @@ -68,7 +70,7 @@ impl HexMap { }; let yrepeat = py % tilesize.y; let mut y = py / tilesize.y; - let outside = self.tileset.get(0).get_pixel(Vec2 { + let outside = self.tileset.get(0).get_pixel(IVec2 { x: xrepeat, y: yrepeat, }) == 0; @@ -79,38 +81,38 @@ impl HexMap { } y -= x % 2; } - Vec2 { x, y } + IVec2 { x, y } } - fn coord_to_idx(&self, coord: Vec2) -> usize { + fn coord_to_idx(&self, coord: IVec2) -> usize { (coord.x + coord.y * self.size.x) as usize } - pub fn coord_to_pixel(&self, coord: Vec2) -> Vec2 { - Vec2 { + pub fn coord_to_pixel(&self, coord: IVec2) -> IVec2 { + IVec2 { x: coord.x * self.pix_tile_off.x, y: coord.y * self.tileset.tile_size().y + (coord.x % 2) * self.pix_tile_off.y, } } - pub fn coord_to_pixel_center(&self, coord: Vec2) -> Vec2 { + pub fn coord_to_pixel_center(&self, coord: IVec2) -> IVec2 { let tilesize = self.tileset.tile_size(); - self.coord_to_pixel(Vec2 { + self.coord_to_pixel(IVec2 { x: coord.x + tilesize.x / 2, y: coord.y + tilesize.y / 2, }) } - pub fn is_valid_coord(&self, coord: Vec2) -> bool { + pub fn is_valid_coord(&self, coord: IVec2) -> bool { coord.x >= 0 && coord.y >= 0 && coord.x < self.size.x && coord.y < self.size.y } - pub fn set(&mut self, coord: Vec2, val: i32) { + pub fn set(&mut self, coord: IVec2, val: i32) { let idx = self.coord_to_idx(coord); self.data[idx] = val; } - pub fn size(&self) -> Vec2 { + pub fn size(&self) -> IVec2 { self.size } @@ -119,12 +121,7 @@ impl HexMap { } //pubcrate - pub(crate) fn draw_tile_to_image( - &self, - target: &mut Image, - coord: Vec2, - offset: Vec2, - ) { + pub(crate) fn draw_tile_to_image(&self, target: &mut Image, coord: IVec2, offset: IVec2) { target.draw_image( self.coord_to_pixel(coord) + offset, self.tileset.get(self.data[self.coord_to_idx(coord)]), diff --git a/src/image.rs b/src/image.rs index f84aa7d..69cb55e 100644 --- a/src/image.rs +++ b/src/image.rs @@ -1,18 +1,19 @@ -use crate::vec2::Vec2; -use crate::{HexMap, Rect, Tileset}; +use crate::vec_util::IVec2Helper; +use crate::{HexMap, IRect, Tileset}; +use glam::IVec2; use std::fs; use std::rc::Rc; //todo: make dynamically different bitdepths pub struct Image { data: Vec, - size: Vec2, + size: IVec2, } impl Image { - pub fn new(size: Vec2) -> Self { + pub fn new(size: IVec2) -> Self { Image { - data: vec![0u8; size.size()], + data: vec![0u8; (size.x * size.y) as usize], size, } } @@ -34,7 +35,7 @@ impl Image { decoder.read_into_buffer(&mut data).unwrap(); Image { data, - size: Vec2 { + size: IVec2 { x: x as i32, y: y as i32, }, @@ -54,26 +55,26 @@ impl Image { self.data.as_slice() } - pub fn draw_hexmap(&mut self, pos: Vec2, hexmap: &HexMap) { + pub fn draw_hexmap(&mut self, pos: IVec2, hexmap: &HexMap) { for i in hexmap.size().to_rect().iter() { hexmap.draw_tile_to_image(self, i, pos); } } - pub fn draw_image(&mut self, pos: Vec2, image: &Image) { + pub fn draw_image(&mut self, pos: IVec2, image: &Image) { self.draw_image_partial( pos, image, - Rect { - pos: Vec2::zero(), + IRect { + pos: IVec2::ZERO, size: image.size, }, ); } - pub fn draw_image_partial(&mut self, pos: Vec2, image: &Image, src_rect: Rect) { + pub fn draw_image_partial(&mut self, pos: IVec2, image: &Image, src_rect: IRect) { //todo: write proper implementation later - for i in Vec2::zero().iter_to(src_rect.size) { + for i in IVec2::ZERO.iter_to(src_rect.size) { //todo: implement better(very stupid to do per pixel) if self.size.to_rect().contains(i + pos) { let p = image.get_pixel(i + src_rect.pos); @@ -84,7 +85,7 @@ impl Image { } } - pub fn draw_line(&mut self, pos1: Vec2, pos2: Vec2, color: u8) { + pub fn draw_line(&mut self, pos1: IVec2, pos2: IVec2, color: u8) { let (x1, y1, x2, y2) = (pos1.x, pos1.y, pos2.x, pos2.y); let mut x = x1 as f32; @@ -100,7 +101,7 @@ impl Image { let ys = ydiff / step; for _ in 1..=(step as i32) { self.set_pixel( - Vec2 { + IVec2 { x: x as i32, y: y as i32, }, @@ -111,13 +112,13 @@ impl Image { } } - pub fn draw_string(&mut self, pos: Vec2, str: &str, font: &Tileset) { + pub fn draw_string(&mut self, pos: IVec2, str: &str, font: &Tileset) { assert!(str.is_ascii()); let array = str.as_bytes(); //for i in 0..array.len() for (i, idx) in array.iter().enumerate() { self.draw_image( - Vec2 { + IVec2 { x: pos.x + font.tile_size().x * i as i32, y: pos.y, }, @@ -130,21 +131,21 @@ impl Image { self.data.fill(color); } - pub fn fill_rect(&mut self, rect: Rect, color: u8) { + pub fn fill_rect(&mut self, rect: IRect, color: u8) { for pos in rect.iter() { self.set_pixel(pos, color); } } - pub fn get_pixel(&self, pos: Vec2) -> u8 { + pub fn get_pixel(&self, pos: IVec2) -> u8 { self.data[(pos.x + self.size.x * pos.y) as usize] } - pub fn set_pixel(&mut self, pos: Vec2, color: u8) { + pub fn set_pixel(&mut self, pos: IVec2, color: u8) { self.data[(pos.x + self.size.x * pos.y) as usize] = color; } - pub fn size(&self) -> Vec2 { + pub fn size(&self) -> IVec2 { self.size } } diff --git a/src/lib.rs b/src/lib.rs index 4ace6ca..ccdf3b4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,12 +3,11 @@ mod hexmap; mod image; mod rect; mod tileset; -mod vec2; +mod vec_util; mod window; pub use hexmap::*; pub use image::*; pub use rect::*; pub use tileset::*; -pub use vec2::*; pub use window::*; diff --git a/src/rect.rs b/src/rect.rs index 28fb667..391357f 100644 --- a/src/rect.rs +++ b/src/rect.rs @@ -1,30 +1,30 @@ -use crate::vec2::Vec2; -use crate::Vec2Iter; +use crate::vec_util::{IVec2Helper, IVec2Iter}; +use glam::IVec2; use num::{Num, ToPrimitive}; #[derive(Copy, Clone)] -pub struct Rect { - pub pos: Vec2, - pub size: Vec2, +pub struct IRect { + pub pos: IVec2, + pub size: IVec2, } -impl Rect { - pub fn new(x: T, y: T, w: T, h: T) -> Rect { - Rect { - pos: Vec2 { x, y }, - size: Vec2 { x: w, y: h }, +impl IRect { + pub fn new(x: i32, y: i32, w: i32, h: i32) -> IRect { + IRect { + pos: IVec2 { x, y }, + size: IVec2 { x: w, y: h }, } } - pub fn pos2(&self) -> Vec2 { + pub fn pos2(&self) -> IVec2 { self.pos + self.size } - pub fn iter(&self) -> Vec2Iter { + pub fn iter(&self) -> IVec2Iter { self.pos.iter_to(self.size) } - pub fn contains(&self, point: Vec2) -> bool { + pub fn contains(&self, point: IVec2) -> bool { let p2 = self.pos2(); point.x >= self.pos.x && point.y >= self.pos.y && point.x < p2.x && point.y < p2.y } diff --git a/src/tileset.rs b/src/tileset.rs index ae8864e..77ce5c9 100644 --- a/src/tileset.rs +++ b/src/tileset.rs @@ -1,32 +1,34 @@ -use crate::{Image, Rect, Vec2}; +use crate::vec_util::IVec2Helper; +use crate::{IRect, Image}; +use glam::IVec2; use std::fs; use std::rc::Rc; pub struct Tileset { count: i32, - size: Vec2, + size: IVec2, images: Vec, } impl Tileset { - pub fn load(path: &str, tile_count: Vec2) -> Rc { + pub fn load(path: &str, tile_count: IVec2) -> Rc { Self::load_data(fs::read(path).unwrap().as_slice(), tile_count) } - pub fn load_data(data: &[u8], tile_count: Vec2) -> Rc { + pub fn load_data(data: &[u8], tile_count: IVec2) -> Rc { let img = Image::load_data(data); let mut images: Vec = vec![]; - let size = Vec2 { + let size = IVec2 { x: img.size().x / tile_count.x, y: img.size().y / tile_count.y, }; for tile in tile_count.to_rect().iter() { let mut image = Image::new(size); image.draw_image_partial( - Vec2::zero(), + IVec2::ZERO, &img, - Rect { - pos: Vec2 { + IRect { + pos: IVec2 { x: tile.x * size.x, y: tile.y * size.y, }, @@ -51,7 +53,7 @@ impl Tileset { self.count } - pub fn tile_size(&self) -> Vec2 { + pub fn tile_size(&self) -> IVec2 { self.size } } diff --git a/src/vec2.rs b/src/vec2.rs deleted file mode 100644 index c9c6a6c..0000000 --- a/src/vec2.rs +++ /dev/null @@ -1,116 +0,0 @@ -use crate::Rect; -use num::{Num, ToPrimitive}; -use std::cmp::Ordering; -use std::ops::{Add, AddAssign, Sub, SubAssign}; - -#[derive(Copy, Clone)] -pub struct Vec2 { - pub x: T, - pub y: T, -} - -pub struct Vec2Iter { - start: Vec2, - end: Vec2, - current: Vec2, -} - -impl Vec2 { - //pub static - pub fn zero() -> Self { - Vec2 { - x: T::zero(), - y: T::zero(), - } - } - - //pub - pub fn iter_to(self, other: Self) -> Vec2Iter { - Vec2Iter { - start: self, - end: other, - current: Vec2 { - x: self.x - T::one(), - y: self.y, - }, - } - } - - pub fn size(&self) -> usize { - (self.x * self.y).to_usize().unwrap() - } - - pub fn to_rect(self) -> Rect { - Rect { - pos: Self::zero(), - size: self, - } - } -} - -impl Default for Vec2 { - fn default() -> Self { - Vec2 { - x: T::default(), - y: T::default(), - } - } -} - -impl PartialEq for Vec2 { - fn eq(&self, other: &Self) -> bool { - self.x == other.x && self.y == other.y - } -} - -impl Iterator for Vec2Iter { - type Item = Vec2; - - fn next(&mut self) -> Option { - self.current.x = self.current.x + T::one(); - if self.current.x >= self.end.x { - self.current.y = self.current.y + T::one(); - self.current.x = self.start.x; - if self.current.y >= self.end.y { - return None; - } - } - Some(self.current) - } -} - -impl Add for Vec2 { - type Output = Self; - - fn add(self, rhs: Self) -> Self::Output { - Self { - x: self.x + rhs.x, - y: self.y + rhs.y, - } - } -} - -impl Sub for Vec2 { - type Output = Self; - - fn sub(self, rhs: Self) -> Self::Output { - Self { - x: self.x - rhs.x, - y: self.y - rhs.y, - } - } -} - -impl AddAssign for Vec2 { - fn add_assign(&mut self, rhs: Self) { - self.x += rhs.x; - self.y += rhs.y; - } -} - -impl SubAssign for Vec2 { - fn sub_assign(&mut self, rhs: Self) { - self.x -= rhs.x; - self.y -= rhs.y; - } -} diff --git a/src/vec_util.rs b/src/vec_util.rs new file mode 100644 index 0000000..01dd178 --- /dev/null +++ b/src/vec_util.rs @@ -0,0 +1,54 @@ +use crate::IRect; +use glam::IVec2; + +pub trait IVec2Helper { + fn iter_to(self, other: IVec2) -> IVec2Iter; + fn size(&self) -> usize; + fn to_rect(self) -> IRect; +} + +pub struct IVec2Iter { + start: IVec2, + end: IVec2, + current: IVec2, +} + +impl IVec2Helper for IVec2 { + fn iter_to(self, other: IVec2) -> IVec2Iter { + IVec2Iter { + start: self, + end: other, + current: IVec2 { + x: self.x - 1, + y: self.y, + }, + } + } + + fn size(&self) -> usize { + (self.x * self.y) as usize + } + + fn to_rect(self) -> IRect { + IRect { + pos: IVec2::ZERO, + size: self, + } + } +} + +impl Iterator for IVec2Iter { + type Item = IVec2; + + fn next(&mut self) -> Option { + self.current.x = self.current.x + 1; + if self.current.x >= self.end.x { + self.current.y = self.current.y + 1; + self.current.x = self.start.x; + if self.current.y >= self.end.y { + return None; + } + } + Some(self.current) + } +} diff --git a/src/window.rs b/src/window.rs index ae99b56..abb4fd8 100644 --- a/src/window.rs +++ b/src/window.rs @@ -1,7 +1,7 @@ use crate::console::Console; use crate::image::Image; -use crate::vec2::Vec2; use crate::Tileset; +use glam::IVec2; use rand::Rng; use rayon::prelude::*; use std::cmp::{max, min}; @@ -28,7 +28,7 @@ pub enum MouseButton { } pub enum Event { - MouseClick(MouseButton, Vec2), + MouseClick(MouseButton, IVec2), } pub trait Game { @@ -40,7 +40,7 @@ pub trait Game { pub struct WindowState { palette: [u32; 256], - mouse_pos: Vec2, + mouse_pos: IVec2, console: Console, } @@ -51,13 +51,14 @@ impl WindowState { } impl WindowState { - fn new(console_size: Vec2) -> Self { + fn new(console_size: IVec2) -> Self { WindowState { palette: [0u32; 256], - mouse_pos: Vec2::zero(), + mouse_pos: IVec2::ZERO, console: Console::new(console_size.y, console_size.x), } } + pub fn set_palette(&mut self, index: u8, r: u8, g: u8, b: u8) { self.palette[index as usize] = (r as u32) | ((g as u32) << 8) | ((b as u32) << 16) | 0xff000000; @@ -70,7 +71,7 @@ impl WindowState { } } - pub fn mouse_pos(&self) -> Vec2 { + pub fn mouse_pos(&self) -> IVec2 { self.mouse_pos } } @@ -92,12 +93,12 @@ pub fn run(width: i32, height: i32, target_fps: u32) { //todo: replace Pixels with custom thingie (startup time slow because wgpu?) let context = unsafe { softbuffer::Context::new(&window) }.unwrap(); let mut surface = unsafe { softbuffer::Surface::new(&context, &window) }.unwrap(); - let mut screen = Image::new(Vec2 { + let mut screen = Image::new(IVec2 { x: width, y: height, }); - let internal_font = Tileset::load_data(include_bytes!("ega-8x14.gif"), Vec2 { x: 16, y: 16 }); - let mut window_state = WindowState::new(Vec2 { + let internal_font = Tileset::load_data(include_bytes!("ega-8x14.gif"), IVec2 { x: 16, y: 16 }); + let mut window_state = WindowState::new(IVec2 { x: width / internal_font.tile_size().x, y: height / internal_font.tile_size().y / 3, }); @@ -157,7 +158,7 @@ pub fn run(width: i32, height: i32, target_fps: u32) { WindowEvent::CursorMoved { position, .. } => { let x = (position.x as i32 - *off_x as i32) / *scale as i32; let y = (position.y as i32 - *off_y as i32) / *scale as i32; - window_state.mouse_pos = Vec2 { + window_state.mouse_pos = IVec2 { x: min(width - 1, max(0, x)), y: min(height - 1, max(0, y)), } @@ -205,7 +206,7 @@ pub fn run(width: i32, height: i32, target_fps: u32) { if display_console { window_state.console.draw_to_image( &mut screen, - Vec2::zero(), + IVec2::ZERO, &internal_font, ); } @@ -248,34 +249,9 @@ pub fn run(width: i32, height: i32, target_fps: u32) { } } } - /* - for (chunk_i, data) in chunk.iter_mut().enumerate() { - let i = chunk_i + chunk_idx * chunk_size; - let sx = i % window_width; - let sy = i / window_width; - let bx = sx / scale; - let by = sy / scale; - let p = - window_state.palette[screen_data[bx + by * width] as usize]; - *data = p; - } - - */ }); } - /*(0..height as usize).for_each(|y| { - for x in 0..width as usize { - let p = window_state.palette - [screen.data()[x + y * width as usize] as usize]; - for iy in 0..*scale { - for ix in 0..*scale { - let tx = x * *scale + ix + *off_x; - let ty = y * *scale + iy + *off_y; - buf[tx + ty * size.width as usize] = p; - } - } - } - });*/ + buf.present().unwrap(); frames_since_last_second += 1; last_frame += target_frame_duration;