switched from own vector to glam

This commit is contained in:
dani 2023-07-10 14:32:33 +00:00
parent 0d209125f0
commit ecc5209772
13 changed files with 169 additions and 241 deletions

7
Cargo.lock generated
View File

@ -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",

View File

@ -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"
rayon = "1.7.0"
glam = "0.24.0"

View File

@ -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<Image>,
font: Rc<Tileset>,
pos: Vec2<i32>,
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));

2
rust-toolchain.toml Normal file
View File

@ -0,0 +1,2 @@
[toolchain]
channel = "nightly"

View File

@ -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<i32>, 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,
},

View File

@ -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<i32>,
size: IVec2,
data: Vec<i32>,
tileset: Rc<Tileset>,
pix_tile_off: Vec2<i32>,
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<i32>, tileset: Rc<Tileset>, pix_tile_off: Vec2<i32>) -> Self {
pub fn new(size: IVec2, tileset: Rc<Tileset>, pix_tile_off: IVec2) -> Self {
HexMap {
size,
data: vec![0; size.size()],
@ -33,15 +35,15 @@ impl HexMap {
}
}
pub fn get_neighbour(coord: Vec2<i32>, dir: Direction) -> Vec2<i32> {
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>) -> 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<i32>) -> Vec2<i32> {
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<i32>) -> 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<i32>) -> Vec2<i32> {
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<i32>) -> Vec2<i32> {
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<i32>) -> 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<i32>, 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<i32> {
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<i32>,
offset: Vec2<i32>,
) {
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)]),

View File

@ -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<u8>,
size: Vec2<i32>,
size: IVec2,
}
impl Image {
pub fn new(size: Vec2<i32>) -> 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<i32>, 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<i32>, 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<i32>, image: &Image, src_rect: Rect<i32>) {
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<i32>, pos2: Vec2<i32>, 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<i32>, 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<i32>, 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<i32>) -> 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<i32>, 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<i32> {
pub fn size(&self) -> IVec2 {
self.size
}
}

View File

@ -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::*;

View File

@ -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<T: Num + Copy + ToPrimitive + PartialOrd> {
pub pos: Vec2<T>,
pub size: Vec2<T>,
pub struct IRect {
pub pos: IVec2,
pub size: IVec2,
}
impl<T: Num + Copy + ToPrimitive + PartialOrd> Rect<T> {
pub fn new(x: T, y: T, w: T, h: T) -> Rect<T> {
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<T> {
pub fn pos2(&self) -> IVec2 {
self.pos + self.size
}
pub fn iter(&self) -> Vec2Iter<T> {
pub fn iter(&self) -> IVec2Iter {
self.pos.iter_to(self.size)
}
pub fn contains(&self, point: Vec2<T>) -> 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
}

View File

@ -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<i32>,
size: IVec2,
images: Vec<Image>,
}
impl Tileset {
pub fn load(path: &str, tile_count: Vec2<i32>) -> Rc<Self> {
pub fn load(path: &str, tile_count: IVec2) -> Rc<Self> {
Self::load_data(fs::read(path).unwrap().as_slice(), tile_count)
}
pub fn load_data(data: &[u8], tile_count: Vec2<i32>) -> Rc<Self> {
pub fn load_data(data: &[u8], tile_count: IVec2) -> Rc<Self> {
let img = Image::load_data(data);
let mut images: Vec<Image> = 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<i32> {
pub fn tile_size(&self) -> IVec2 {
self.size
}
}

View File

@ -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<T: Num + Copy + ToPrimitive + PartialOrd> {
pub x: T,
pub y: T,
}
pub struct Vec2Iter<T: Num + Copy + ToPrimitive + PartialOrd> {
start: Vec2<T>,
end: Vec2<T>,
current: Vec2<T>,
}
impl<T: Num + Copy + ToPrimitive + PartialOrd> Vec2<T> {
//pub static
pub fn zero() -> Self {
Vec2 {
x: T::zero(),
y: T::zero(),
}
}
//pub
pub fn iter_to(self, other: Self) -> Vec2Iter<T> {
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<T> {
Rect {
pos: Self::zero(),
size: self,
}
}
}
impl<T: Num + Copy + ToPrimitive + PartialOrd + Default> Default for Vec2<T> {
fn default() -> Self {
Vec2 {
x: T::default(),
y: T::default(),
}
}
}
impl<T: Num + Copy + ToPrimitive + PartialOrd> PartialEq for Vec2<T> {
fn eq(&self, other: &Self) -> bool {
self.x == other.x && self.y == other.y
}
}
impl<T: Num + Copy + ToPrimitive + PartialOrd> Iterator for Vec2Iter<T> {
type Item = Vec2<T>;
fn next(&mut self) -> Option<Self::Item> {
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<T: Num + Copy + ToPrimitive + PartialOrd> Add for Vec2<T> {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
impl<T: Num + Copy + ToPrimitive + PartialOrd> Sub for Vec2<T> {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self {
x: self.x - rhs.x,
y: self.y - rhs.y,
}
}
}
impl<T: Num + Copy + ToPrimitive + PartialOrd + AddAssign> AddAssign for Vec2<T> {
fn add_assign(&mut self, rhs: Self) {
self.x += rhs.x;
self.y += rhs.y;
}
}
impl<T: Num + Copy + ToPrimitive + PartialOrd + SubAssign> SubAssign for Vec2<T> {
fn sub_assign(&mut self, rhs: Self) {
self.x -= rhs.x;
self.y -= rhs.y;
}
}

54
src/vec_util.rs Normal file
View File

@ -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::Item> {
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)
}
}

View File

@ -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<i32>),
MouseClick(MouseButton, IVec2),
}
pub trait Game {
@ -40,7 +40,7 @@ pub trait Game {
pub struct WindowState {
palette: [u32; 256],
mouse_pos: Vec2<i32>,
mouse_pos: IVec2,
console: Console,
}
@ -51,13 +51,14 @@ impl WindowState {
}
impl WindowState {
fn new(console_size: Vec2<i32>) -> 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<i32> {
pub fn mouse_pos(&self) -> IVec2 {
self.mouse_pos
}
}
@ -92,12 +93,12 @@ pub fn run<T: Game + 'static>(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<T: Game + 'static>(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<T: Game + 'static>(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<T: Game + 'static>(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;