basic drawing window stuffs
This commit is contained in:
parent
d75c8f483e
commit
40d4ba4574
|
@ -12,9 +12,9 @@ glam = "0.24.0"
|
|||
ascii = "1.1.0"
|
||||
gilrs = "0.10.2"
|
||||
cpal = "0.15.2"
|
||||
|
||||
[dependencies.skunk2d]
|
||||
path = "../skunk2d"
|
||||
winit = "0.28.6"
|
||||
softbuffer = "0.3.0"
|
||||
gif = "0.12.0"
|
||||
|
||||
[profile.release-dani]
|
||||
inherits = "release"
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
use crate::{Gsa, MAX_SPRITES, TILE_SIZE};
|
||||
use glam::IVec2;
|
||||
use softbuffer::Buffer;
|
||||
|
||||
pub(crate) fn render_to_window(target: &mut Buffer, gsa: &Gsa, window_size: IVec2) {
|
||||
for (y, row) in target.chunks_exact_mut(window_size.x as usize).enumerate() {
|
||||
let y = y as i32;
|
||||
for x in 0..window_size.x {
|
||||
let mut p = 0;
|
||||
for sprite in &gsa.sprites {
|
||||
if sprite.tile > 0
|
||||
&& x >= sprite.pos.x
|
||||
&& y >= sprite.pos.y
|
||||
&& x < sprite.pos.x + TILE_SIZE as i32
|
||||
&& y < sprite.pos.y + TILE_SIZE as i32
|
||||
{
|
||||
p = 1;
|
||||
}
|
||||
}
|
||||
row[x as usize] = gsa.palette[p].to_u32();
|
||||
}
|
||||
}
|
||||
}
|
17
src/lib.rs
17
src/lib.rs
|
@ -22,12 +22,14 @@
|
|||
|
||||
mod buttons;
|
||||
mod gsa;
|
||||
mod gsa_render_to_screen;
|
||||
mod input;
|
||||
mod rgb;
|
||||
mod run;
|
||||
mod sprite;
|
||||
mod state;
|
||||
mod tilemap;
|
||||
mod tileset;
|
||||
|
||||
pub use crate::buttons::Buttons;
|
||||
pub use crate::gsa::Gsa;
|
||||
|
@ -40,8 +42,23 @@ pub use crate::tilemap::Tilemap;
|
|||
/// Amount of sprites in [Gsa::sprites]
|
||||
pub const MAX_SPRITES: usize = 0xff;
|
||||
|
||||
/// Screen Width in pixels
|
||||
pub const SCREEN_WIDTH: usize = 304;
|
||||
|
||||
/// Screen Height in pixels
|
||||
pub const SCREEN_HEIGHT: usize = 176;
|
||||
|
||||
/// X and y dimensions of maps in [Gsa::maps]
|
||||
pub const TILEMAP_MAX_SIZE: usize = 1024;
|
||||
|
||||
/// Width and height (in tiles) of tileset
|
||||
pub const TILESET_SIZE: usize = 0x100;
|
||||
|
||||
/// Width and height of a tile
|
||||
pub const TILE_SIZE: usize = 16;
|
||||
|
||||
/// Width and height of a tile in half-tile mode
|
||||
pub const HALF_TILE_SIZE: usize = 8;
|
||||
|
||||
/// Amount of tile maps in [Gsa::maps]
|
||||
pub const MAX_TILEMAPS: usize = 4;
|
||||
|
|
|
@ -8,3 +8,9 @@ pub struct Rgb {
|
|||
/// Blue component 0-255
|
||||
pub b: u8,
|
||||
}
|
||||
|
||||
impl Rgb {
|
||||
pub(crate) fn to_u32(self) -> u32 {
|
||||
(self.r as u32) | ((self.g as u32) << 8) | ((self.b as u32) << 16)
|
||||
}
|
||||
}
|
||||
|
|
109
src/run.rs
109
src/run.rs
|
@ -1,7 +1,16 @@
|
|||
use crate::gsa_render_to_screen::render_to_window;
|
||||
use crate::state::State;
|
||||
use crate::{Gsa, Rgb, Sprite, MAX_SPRITES};
|
||||
use crate::tileset::load_tileset;
|
||||
use crate::{Gsa, Rgb, Sprite, MAX_SPRITES, SCREEN_HEIGHT, SCREEN_WIDTH};
|
||||
use gilrs::Gilrs;
|
||||
use skunk2d::Image8;
|
||||
use glam::IVec2;
|
||||
use std::cmp::min;
|
||||
use std::num::NonZeroU32;
|
||||
use std::time::{Duration, Instant};
|
||||
use winit::dpi::LogicalSize;
|
||||
use winit::event::{Event, VirtualKeyCode, WindowEvent};
|
||||
use winit::event_loop::{ControlFlow, EventLoop};
|
||||
use winit::window::WindowBuilder;
|
||||
|
||||
/// Creates main function, includes gfx.gif, and calls run
|
||||
///
|
||||
|
@ -25,17 +34,7 @@ pub fn run<TGame: 'static>(
|
|||
update_fn: fn(game: &mut TGame, gsa: &mut Gsa),
|
||||
image_data: &[u8],
|
||||
) {
|
||||
let tileset = Image8::load_data(image_data);
|
||||
let pal = Image8::load_data_palette(image_data);
|
||||
let mut palette = [Rgb { r: 0, g: 0, b: 0 }; 256];
|
||||
|
||||
for i in 0..pal.len() / 3 {
|
||||
palette[i] = Rgb {
|
||||
r: pal[i * 3 + 2],
|
||||
g: pal[i * 3 + 1],
|
||||
b: pal[i * 3],
|
||||
};
|
||||
}
|
||||
let (tileset, palette) = load_tileset(image_data);
|
||||
|
||||
let mut gsa = Gsa {
|
||||
sprites: [Sprite::default(); MAX_SPRITES],
|
||||
|
@ -44,8 +43,8 @@ pub fn run<TGame: 'static>(
|
|||
font: 0x1010,
|
||||
input: Default::default(),
|
||||
};
|
||||
let game = init_fn(&mut gsa);
|
||||
let state = State::<TGame> {
|
||||
let mut game = init_fn(&mut gsa);
|
||||
/*let state = State::<TGame> {
|
||||
gsa,
|
||||
game,
|
||||
tileset,
|
||||
|
@ -53,5 +52,83 @@ pub fn run<TGame: 'static>(
|
|||
first: true,
|
||||
gilrs: Gilrs::new().unwrap(),
|
||||
};
|
||||
skunk2d::run_with::<Image8, State<TGame>>(304, 176, 60, state);
|
||||
|
||||
*/
|
||||
|
||||
let event_loop = EventLoop::new();
|
||||
let size = LogicalSize::new(SCREEN_WIDTH as u32, SCREEN_HEIGHT as u32);
|
||||
let window = WindowBuilder::new()
|
||||
.with_title("Game Skunk Advance v0.1")
|
||||
.with_inner_size(size)
|
||||
.with_min_inner_size(size)
|
||||
.build(&event_loop)
|
||||
.unwrap();
|
||||
|
||||
let context = unsafe { softbuffer::Context::new(&window) }.unwrap();
|
||||
let mut surface = unsafe { softbuffer::Surface::new(&context, &window) }.unwrap();
|
||||
|
||||
let mut frames_since_last_second = 0;
|
||||
let mut last_second = Instant::now();
|
||||
|
||||
let mut last_frame = last_second;
|
||||
let target_frame_duration = Duration::from_secs(1).div_f64(6000.0);
|
||||
|
||||
let mut scale = 1usize;
|
||||
let mut off_x = 0usize;
|
||||
let mut off_y = 0usize;
|
||||
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
let scale = &mut scale;
|
||||
let off_x = &mut off_x;
|
||||
let off_y = &mut off_y;
|
||||
if Instant::now() - last_second > Duration::from_secs(1) {
|
||||
println!("fps: {}", frames_since_last_second);
|
||||
frames_since_last_second = 0;
|
||||
last_second += Duration::from_secs(1);
|
||||
}
|
||||
match event {
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::KeyboardInput { input, .. },
|
||||
..
|
||||
} => match input.virtual_keycode {
|
||||
Some(VirtualKeyCode::Escape) => {
|
||||
*control_flow = ControlFlow::Exit;
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
Event::MainEventsCleared {} => {
|
||||
if Instant::now() - last_frame >= target_frame_duration {
|
||||
update_fn(&mut game, &mut gsa);
|
||||
let size = window.inner_size();
|
||||
surface
|
||||
.resize(
|
||||
NonZeroU32::new(size.width).unwrap(),
|
||||
NonZeroU32::new(size.height).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
*scale = min(
|
||||
size.width / SCREEN_WIDTH as u32,
|
||||
size.height / SCREEN_HEIGHT as u32,
|
||||
) as usize;
|
||||
*off_x = (size.width as usize - SCREEN_WIDTH * *scale) / 2;
|
||||
*off_y = (size.height as usize - SCREEN_HEIGHT * *scale) / 2;
|
||||
|
||||
let mut buf = surface.buffer_mut().unwrap();
|
||||
render_to_window(
|
||||
&mut buf,
|
||||
&gsa,
|
||||
IVec2 {
|
||||
x: size.width as i32,
|
||||
y: size.height as i32,
|
||||
},
|
||||
);
|
||||
buf.present().unwrap();
|
||||
frames_since_last_second += 1;
|
||||
last_frame += target_frame_duration;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
25
src/state.rs
25
src/state.rs
|
@ -2,24 +2,19 @@ use crate::buttons::Buttons;
|
|||
use crate::{Gsa, TILEMAP_MAX_SIZE};
|
||||
use gilrs::{Button, EventType, Gilrs};
|
||||
use glam::IVec2;
|
||||
use skunk2d::{Event, IRect, Image8, WindowState};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct State<TGame> {
|
||||
pub(crate) gsa: Gsa,
|
||||
pub(crate) game: TGame,
|
||||
pub(crate) update_fn: fn(game: &mut TGame, gsa: &mut Gsa),
|
||||
pub(crate) tileset: Rc<Image8>,
|
||||
pub(crate) tileset: Vec<u8>,
|
||||
pub(crate) first: bool,
|
||||
pub(crate) gilrs: Gilrs,
|
||||
}
|
||||
|
||||
impl<TGame> skunk2d::Game<Image8> for State<TGame> {
|
||||
fn update(&mut self, window_state: &mut WindowState) {
|
||||
if self.first {
|
||||
window_state.toggle_fullscreen();
|
||||
self.first = false;
|
||||
}
|
||||
impl<TGame> State<TGame> {
|
||||
fn update(&mut self) {
|
||||
let mut new_buttons = self.gsa.input.down;
|
||||
while let Some(event) = self.gilrs.next_event() {
|
||||
match event {
|
||||
|
@ -72,6 +67,7 @@ impl<TGame> skunk2d::Game<Image8> for State<TGame> {
|
|||
};
|
||||
|
||||
//todo: don't if not updated... how check? <_<
|
||||
/*
|
||||
for i in 0..=255 {
|
||||
window_state.set_palette(
|
||||
i,
|
||||
|
@ -80,13 +76,12 @@ impl<TGame> skunk2d::Game<Image8> for State<TGame> {
|
|||
self.gsa.palette[i as usize].b,
|
||||
);
|
||||
}
|
||||
*/
|
||||
(self.update_fn)(&mut self.game, &mut self.gsa);
|
||||
}
|
||||
|
||||
fn on_event(&mut self, _window_state: &mut WindowState, _event: Event) {}
|
||||
|
||||
fn draw(&self, target: &mut Image8) {
|
||||
target.clear();
|
||||
fn draw(&self) {
|
||||
//target.clear();
|
||||
|
||||
for map in &self.gsa.maps {
|
||||
let tcmult = if map.half_tile { 2 } else { 1 };
|
||||
|
@ -103,6 +98,7 @@ impl<TGame> skunk2d::Game<Image8> for State<TGame> {
|
|||
if tile > 0 {
|
||||
let ty = tile / 0x100;
|
||||
let tx = tile % 0x100;
|
||||
/*
|
||||
target.draw_image_partial(
|
||||
IVec2 {
|
||||
x: x * tilesize - map.scroll.x,
|
||||
|
@ -120,6 +116,8 @@ impl<TGame> skunk2d::Game<Image8> for State<TGame> {
|
|||
},
|
||||
},
|
||||
)
|
||||
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -129,6 +127,7 @@ impl<TGame> skunk2d::Game<Image8> for State<TGame> {
|
|||
if sprite.tile > 0 {
|
||||
let ty = sprite.tile / 0x100;
|
||||
let tx = sprite.tile % 0x100;
|
||||
/*
|
||||
target.draw_image_partial(
|
||||
sprite.pos,
|
||||
&self.tileset,
|
||||
|
@ -140,6 +139,8 @@ impl<TGame> skunk2d::Game<Image8> for State<TGame> {
|
|||
size: IVec2 { x: 16, y: 16 },
|
||||
},
|
||||
);
|
||||
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use glam::IVec2;
|
|||
/// Tilemap which will be rendered on screen
|
||||
pub struct Tilemap {
|
||||
/// Tiles in idx, accessible via \[x\]\[y\], x and y 0..[TILEMAP_MAX_SIZE]
|
||||
pub tiles: Box<[[u16; TILEMAP_MAX_SIZE]; TILEMAP_MAX_SIZE]>,
|
||||
pub tiles: Vec<Vec<u16>>,
|
||||
/// Camera scroll (negative draw offset) for rendering
|
||||
pub scroll: IVec2,
|
||||
/// Are tiles indices half-tile indices?
|
||||
|
@ -13,8 +13,10 @@ pub struct Tilemap {
|
|||
|
||||
impl Default for Tilemap {
|
||||
fn default() -> Self {
|
||||
let row = vec![0u16; TILEMAP_MAX_SIZE];
|
||||
let tiles = vec![row; TILEMAP_MAX_SIZE];
|
||||
Self {
|
||||
tiles: [[0u16; TILEMAP_MAX_SIZE]; TILEMAP_MAX_SIZE].into(),
|
||||
tiles,
|
||||
scroll: IVec2::ZERO,
|
||||
half_tile: false,
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
use crate::{Rgb, TILESET_SIZE, TILE_SIZE};
|
||||
|
||||
pub(crate) fn load_tileset(data: &[u8]) -> (Vec<u8>, [Rgb; 256]) {
|
||||
let mut options = gif::DecodeOptions::new();
|
||||
options.set_color_output(gif::ColorOutput::Indexed);
|
||||
let mut decoder = options.read_info(data).unwrap();
|
||||
|
||||
assert_eq!(decoder.width(), (TILESET_SIZE * TILE_SIZE) as u16);
|
||||
assert_eq!(decoder.height(), (TILESET_SIZE * TILE_SIZE) as u16);
|
||||
|
||||
decoder.next_frame_info().unwrap();
|
||||
let mut tileset = Vec::new();
|
||||
tileset.resize(TILESET_SIZE * TILE_SIZE * TILESET_SIZE * TILE_SIZE, 0);
|
||||
decoder.read_into_buffer(tileset.as_mut_slice()).unwrap();
|
||||
let pal = decoder.palette().unwrap();
|
||||
let mut palette = [Rgb { r: 0, g: 0, b: 0 }; 256];
|
||||
for i in 0..pal.len() / 3 {
|
||||
palette[i] = Rgb {
|
||||
r: pal[i * 3 + 2],
|
||||
g: pal[i * 3 + 1],
|
||||
b: pal[i * 3],
|
||||
};
|
||||
}
|
||||
(tileset, palette)
|
||||
}
|
Loading…
Reference in New Issue