started refactor of map editor
This commit is contained in:
parent
f77b66ecc9
commit
f0ad2726f8
|
@ -1,5 +1,6 @@
|
||||||
# 0.3.0
|
# 0.3.0
|
||||||
- added size to backgrounds
|
- added size to backgrounds
|
||||||
|
- added rotation to backgrounds
|
||||||
- refactored api, background functions are now methods to background rather than gsa
|
- refactored api, background functions are now methods to background rather than gsa
|
||||||
|
|
||||||
# 0.2.1 - 2023-07-27
|
# 0.2.1 - 2023-07-27
|
||||||
|
|
|
@ -25,6 +25,7 @@ path-slash = "0.2.1"
|
||||||
serde = {version = "1.0.181", features = ["derive"]}
|
serde = {version = "1.0.181", features = ["derive"]}
|
||||||
postcard = {version = "1.0.6", features = ["alloc"]}
|
postcard = {version = "1.0.6", features = ["alloc"]}
|
||||||
rayon = "1.7.0"
|
rayon = "1.7.0"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
|
||||||
[profile.release-dani]
|
[profile.release-dani]
|
||||||
inherits = "release"
|
inherits = "release"
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
@ -1,5 +1,5 @@
|
||||||
use glam::IVec2;
|
use glam::IVec2;
|
||||||
use gsa::{run, Gsa, FACE_DOWN, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_MIDDLE, FACE_LEFT, FACE_RIGHT};
|
use gsa::{run, Gsa, FACE_DOWN, FACE_LEFT, FACE_RIGHT, SCREEN_HEIGHT, SCREEN_MIDDLE, SCREEN_WIDTH};
|
||||||
|
|
||||||
struct Game {}
|
struct Game {}
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -30,7 +30,7 @@ impl Default for Background {
|
||||||
active: true,
|
active: true,
|
||||||
size: IVec2 { x: 19, y: 11 },
|
size: IVec2 { x: 19, y: 11 },
|
||||||
origin: IVec2::ZERO,
|
origin: IVec2::ZERO,
|
||||||
rot: 0
|
rot: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,7 @@ use crate::rgb::Rgb;
|
||||||
use crate::sprite::Sprite;
|
use crate::sprite::Sprite;
|
||||||
use crate::tilemap::Tilemap;
|
use crate::tilemap::Tilemap;
|
||||||
use crate::{
|
use crate::{
|
||||||
Buttons, BACKGROUND_MAX_SIZE, DPAD_DOWN, DPAD_LEFT, DPAD_RIGHT, DPAD_UP, EMPTY_TILE,
|
Buttons, DPAD_DOWN, DPAD_LEFT, DPAD_RIGHT, DPAD_UP, EMPTY_TILE, MAX_BACKGROUNDS, MAX_SPRITES,
|
||||||
MAX_BACKGROUNDS, MAX_SPRITES,
|
|
||||||
};
|
};
|
||||||
use ascii::{AsciiChar, AsciiStr};
|
use ascii::{AsciiChar, AsciiStr};
|
||||||
use glam::IVec2;
|
use glam::IVec2;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use std::{usize, f32::consts::PI};
|
use std::{f32::consts::PI, usize};
|
||||||
use rayon::prelude::*;
|
//use rayon::prelude::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Background, Gsa, Rgb, EMPTY_TILE, HALF_TILE_SIZE, MAX_BACKGROUNDS, TILESET_SIZE, TILE_SIZE,
|
Background, Gsa, Rgb, EMPTY_TILE, HALF_TILE_SIZE, MAX_BACKGROUNDS, TILESET_SIZE, TILE_SIZE,
|
||||||
|
@ -33,46 +33,46 @@ fn draw_tile(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_bg(target: &mut [u8], map: &Background, tileset: &[u8], screen_size: IVec2) {
|
// fn render_bg(target: &mut [u8], map: &Background, tileset: &[u8], screen_size: IVec2) {
|
||||||
let tcmult = if map.half_tile { 2 } else { 1 };
|
// let tcmult = if map.half_tile { 2 } else { 1 };
|
||||||
let tilesize = if map.half_tile {
|
// let tilesize = if map.half_tile {
|
||||||
HALF_TILE_SIZE
|
// HALF_TILE_SIZE
|
||||||
} else {
|
// } else {
|
||||||
TILE_SIZE
|
// TILE_SIZE
|
||||||
} as i32;
|
// } as i32;
|
||||||
let mut startx = map.scroll.x / tilesize;
|
// let mut startx = map.scroll.x / tilesize;
|
||||||
let mut starty = map.scroll.y / tilesize;
|
// let mut starty = map.scroll.y / tilesize;
|
||||||
let endx = map
|
// let endx = map
|
||||||
.size
|
// .size
|
||||||
.x
|
// .x
|
||||||
.min(startx + (screen_size.x / TILE_SIZE as i32 + 1) * tcmult);
|
// .min(startx + (screen_size.x / TILE_SIZE as i32 + 1) * tcmult);
|
||||||
let endy = map
|
// let endy = map
|
||||||
.size
|
// .size
|
||||||
.y
|
// .y
|
||||||
.min(starty + (screen_size.y / TILE_SIZE as i32 + 1) * tcmult);
|
// .min(starty + (screen_size.y / TILE_SIZE as i32 + 1) * tcmult);
|
||||||
startx = 0.max(startx);
|
// startx = 0.max(startx);
|
||||||
starty = 0.max(starty);
|
// starty = 0.max(starty);
|
||||||
for x in startx..endx {
|
// for x in startx..endx {
|
||||||
for y in starty..endy {
|
// for y in starty..endy {
|
||||||
let tile = map.tiles[x as usize][y as usize];
|
// let tile = map.tiles[x as usize][y as usize];
|
||||||
if tile != EMPTY_TILE {
|
// if tile != EMPTY_TILE {
|
||||||
draw_tile(
|
// draw_tile(
|
||||||
target,
|
// target,
|
||||||
IVec2 {
|
// IVec2 {
|
||||||
x: x * tilesize - map.scroll.x,
|
// x: x * tilesize - map.scroll.x,
|
||||||
y: y * tilesize - map.scroll.y,
|
// y: y * tilesize - map.scroll.y,
|
||||||
},
|
// },
|
||||||
tile,
|
// tile,
|
||||||
tileset,
|
// tileset,
|
||||||
map.half_tile,
|
// map.half_tile,
|
||||||
screen_size,
|
// screen_size,
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
fn render_bg2(target: &mut [u8], map: &Background, tileset: &[u8], screen_size: IVec2) {
|
fn render_bg(target: &mut [u8], map: &Background, tileset: &[u8], screen_size: IVec2) {
|
||||||
let tilesize = if map.half_tile {
|
let tilesize = if map.half_tile {
|
||||||
HALF_TILE_SIZE
|
HALF_TILE_SIZE
|
||||||
} else {
|
} else {
|
||||||
|
@ -81,7 +81,6 @@ fn render_bg2(target: &mut [u8], map: &Background, tileset: &[u8], screen_size:
|
||||||
|
|
||||||
let a = map.rot as f32 / 256.0 * PI * 2.0;
|
let a = map.rot as f32 / 256.0 * PI * 2.0;
|
||||||
|
|
||||||
|
|
||||||
let du = glam::Vec2::new(a.cos(), a.sin());
|
let du = glam::Vec2::new(a.cos(), a.sin());
|
||||||
let dv = glam::Vec2::new(-a.sin(), a.cos());
|
let dv = glam::Vec2::new(-a.sin(), a.cos());
|
||||||
let duv = Mat2::from_cols(du, dv);
|
let duv = Mat2::from_cols(du, dv);
|
||||||
|
@ -93,7 +92,11 @@ fn render_bg2(target: &mut [u8], map: &Background, tileset: &[u8], screen_size:
|
||||||
.for_each({
|
.for_each({
|
||||||
|(screeny, row)| {
|
|(screeny, row)| {
|
||||||
for screenx in 0..screen_size.x {
|
for screenx in 0..screen_size.x {
|
||||||
let screen = duv * Vec2::new(screenx as f32 - map.origin.x as f32, screeny as f32 - map.origin.y as f32);
|
let screen = duv
|
||||||
|
* Vec2::new(
|
||||||
|
screenx as f32 - map.origin.x as f32,
|
||||||
|
screeny as f32 - map.origin.y as f32,
|
||||||
|
);
|
||||||
let x = screen.x.floor() as i32 + map.scroll.x;
|
let x = screen.x.floor() as i32 + map.scroll.x;
|
||||||
let y = screen.y.floor() as i32 + map.scroll.y;
|
let y = screen.y.floor() as i32 + map.scroll.y;
|
||||||
let tilex = x.div_euclid(tilesize);
|
let tilex = x.div_euclid(tilesize);
|
||||||
|
@ -102,8 +105,8 @@ fn render_bg2(target: &mut [u8], map: &Background, tileset: &[u8], screen_size:
|
||||||
//assert!(tilex >= 0);
|
//assert!(tilex >= 0);
|
||||||
// the addition is there because otherwise x might be below 0
|
// the addition is there because otherwise x might be below 0
|
||||||
// which messes with the modulo
|
// which messes with the modulo
|
||||||
let pixx = (x+tilesize) % tilesize;
|
let pixx = (x + tilesize) % tilesize;
|
||||||
let pixy = (y+tilesize) % tilesize;
|
let pixy = (y + tilesize) % tilesize;
|
||||||
let tile =
|
let tile =
|
||||||
if tilex >= 0 && tiley >= 0 && tilex < map.size.x && tiley < map.size.y {
|
if tilex >= 0 && tiley >= 0 && tilex < map.size.x && tiley < map.size.y {
|
||||||
map.tiles[tilex as usize][tiley as usize]
|
map.tiles[tilex as usize][tiley as usize]
|
||||||
|
@ -113,7 +116,8 @@ fn render_bg2(target: &mut [u8], map: &Background, tileset: &[u8], screen_size:
|
||||||
if tile != EMPTY_TILE {
|
if tile != EMPTY_TILE {
|
||||||
let tilesetx = tile as i32 % 0x100 * tilesize + pixx;
|
let tilesetx = tile as i32 % 0x100 * tilesize + pixx;
|
||||||
let tilesety = tile as i32 / 0x100 * tilesize + pixy;
|
let tilesety = tile as i32 / 0x100 * tilesize + pixy;
|
||||||
let p = tileset[tilesetx as usize + tilesety as usize * (TILESET_SIZE * TILE_SIZE)];
|
let p = tileset
|
||||||
|
[tilesetx as usize + tilesety as usize * (TILESET_SIZE * TILE_SIZE)];
|
||||||
if p != TRANSPARENT {
|
if p != TRANSPARENT {
|
||||||
row[screenx as usize] = p;
|
row[screenx as usize] = p;
|
||||||
}
|
}
|
||||||
|
@ -126,7 +130,7 @@ fn render_bg2(target: &mut [u8], map: &Background, tileset: &[u8], screen_size:
|
||||||
pub(crate) fn render_to_screen(target: &mut [u8], gsa: &Gsa, tileset: &[u8], screen_size: IVec2) {
|
pub(crate) fn render_to_screen(target: &mut [u8], gsa: &Gsa, tileset: &[u8], screen_size: IVec2) {
|
||||||
for i in 0..MAX_BACKGROUNDS {
|
for i in 0..MAX_BACKGROUNDS {
|
||||||
if gsa.bg[i].active {
|
if gsa.bg[i].active {
|
||||||
render_bg2(target, &gsa.bg[i], tileset, screen_size);
|
render_bg(target, &gsa.bg[i], tileset, screen_size);
|
||||||
}
|
}
|
||||||
for sprite in &gsa.sprite {
|
for sprite in &gsa.sprite {
|
||||||
if sprite.tile != EMPTY_TILE && sprite.priority == i as u8 {
|
if sprite.tile != EMPTY_TILE && sprite.priority == i as u8 {
|
||||||
|
|
10
src/lib.rs
10
src/lib.rs
|
@ -69,10 +69,16 @@ pub const SCREEN_WIDTH: usize = 304;
|
||||||
pub const SCREEN_HEIGHT: usize = 176;
|
pub const SCREEN_HEIGHT: usize = 176;
|
||||||
|
|
||||||
/// Screen size as vector (SCREEN_WIDTH,SCREEN_HEIGHT)
|
/// Screen size as vector (SCREEN_WIDTH,SCREEN_HEIGHT)
|
||||||
pub const SCREEN_SIZE: IVec2 = IVec2{x: SCREEN_WIDTH as i32, y: SCREEN_HEIGHT as i32};
|
pub const SCREEN_SIZE: IVec2 = IVec2 {
|
||||||
|
x: SCREEN_WIDTH as i32,
|
||||||
|
y: SCREEN_HEIGHT as i32,
|
||||||
|
};
|
||||||
|
|
||||||
/// Center of screen as vector
|
/// Center of screen as vector
|
||||||
pub const SCREEN_MIDDLE: IVec2 = IVec2{x: SCREEN_WIDTH as i32 / 2, y: SCREEN_HEIGHT as i32 / 2};
|
pub const SCREEN_MIDDLE: IVec2 = IVec2 {
|
||||||
|
x: SCREEN_WIDTH as i32 / 2,
|
||||||
|
y: SCREEN_HEIGHT as i32 / 2,
|
||||||
|
};
|
||||||
|
|
||||||
/// X and y dimensions of maps in [Gsa::bgs]
|
/// X and y dimensions of maps in [Gsa::bgs]
|
||||||
pub const BACKGROUND_MAX_SIZE: usize = 1024;
|
pub const BACKGROUND_MAX_SIZE: usize = 1024;
|
||||||
|
|
730
src/mapedit.rs
730
src/mapedit.rs
|
@ -1,730 +0,0 @@
|
||||||
use std::fs;
|
|
||||||
use std::num::NonZeroU32;
|
|
||||||
|
|
||||||
use crate::gsa::Gsa;
|
|
||||||
use crate::gsa_render_to_screen::render_to_screen;
|
|
||||||
use crate::gsa_render_to_screen::render_to_window;
|
|
||||||
use crate::maps::Maps;
|
|
||||||
use crate::sprite::Sprite;
|
|
||||||
use crate::tilemap::Tilemap;
|
|
||||||
use crate::tileset::*;
|
|
||||||
use crate::*;
|
|
||||||
use clap::crate_version;
|
|
||||||
use glam::IVec2;
|
|
||||||
use winit::event::ElementState;
|
|
||||||
use winit::{
|
|
||||||
dpi::LogicalSize,
|
|
||||||
event::{Event, VirtualKeyCode, WindowEvent},
|
|
||||||
event_loop::{ControlFlow, EventLoop},
|
|
||||||
window::WindowBuilder,
|
|
||||||
};
|
|
||||||
|
|
||||||
const SPR_CURSOR: usize = 0x01;
|
|
||||||
const TILE_CURSOR: u16 = 0x7110;
|
|
||||||
const TILE_MARKER: u16 = 0x7210;
|
|
||||||
const TILE_FRT: u16 = 0x7018;
|
|
||||||
const TILE_FRB: u16 = 0x7118;
|
|
||||||
const TILE_FRL: u16 = 0x7218;
|
|
||||||
const TILE_FRR: u16 = 0x7219;
|
|
||||||
const TILE_FRTL: u16 = 0x7019;
|
|
||||||
const TILE_FRTR: u16 = 0x701A;
|
|
||||||
const TILE_FRBL: u16 = 0x7119;
|
|
||||||
const TILE_FRBR: u16 = 0x711A;
|
|
||||||
const TILE_FRBG: u16 = 0x721A;
|
|
||||||
const TILE_INPUT: u16 = 0x7318;
|
|
||||||
|
|
||||||
const TILE_BUT_YES: u16 = 0x7311;
|
|
||||||
const TILE_BUT_NO: u16 = 0x7312;
|
|
||||||
const TILE_BUT_CREATE: u16 = 0x7213;
|
|
||||||
|
|
||||||
const BUT_SAVE: usize = 0;
|
|
||||||
const BUT_CREATE: usize = 1;
|
|
||||||
const BUT_LAYER1: usize = 3;
|
|
||||||
const BUT_LAYER2: usize = 4;
|
|
||||||
const BUT_LAYER3: usize = 5;
|
|
||||||
const BUT_LAYERS: usize = 6;
|
|
||||||
const BUT_EXIT: usize = 8;
|
|
||||||
|
|
||||||
struct Surface<'a> {
|
|
||||||
pub data: &'a mut [u8],
|
|
||||||
pub size: IVec2,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Surface<'a> {
|
|
||||||
fn draw_vline(&mut self, pos: IVec2, len: i32, color: u8) {
|
|
||||||
for i in 0..len {
|
|
||||||
self.data[(pos.x + (pos.y + i) * self.size.x) as usize] = color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw_hline(&mut self, pos: IVec2, len: i32, color: u8) {
|
|
||||||
for i in 0..len {
|
|
||||||
self.data[(pos.x + i + pos.y * self.size.x) as usize] = color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
enum State {
|
|
||||||
Edit,
|
|
||||||
SelectTile,
|
|
||||||
NewMapDialog,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn key_to_num(key: VirtualKeyCode) -> u16 {
|
|
||||||
match key {
|
|
||||||
VirtualKeyCode::Key0 => 0x0,
|
|
||||||
VirtualKeyCode::Key1 => 0x1,
|
|
||||||
VirtualKeyCode::Key2 => 0x2,
|
|
||||||
VirtualKeyCode::Key3 => 0x3,
|
|
||||||
VirtualKeyCode::Key4 => 0x4,
|
|
||||||
VirtualKeyCode::Key5 => 0x5,
|
|
||||||
VirtualKeyCode::Key6 => 0x6,
|
|
||||||
VirtualKeyCode::Key7 => 0x7,
|
|
||||||
VirtualKeyCode::Key8 => 0x8,
|
|
||||||
VirtualKeyCode::Key9 => 0x9,
|
|
||||||
VirtualKeyCode::A => 0xa,
|
|
||||||
VirtualKeyCode::B => 0xb,
|
|
||||||
VirtualKeyCode::C => 0xc,
|
|
||||||
VirtualKeyCode::D => 0xd,
|
|
||||||
VirtualKeyCode::E => 0xe,
|
|
||||||
VirtualKeyCode::F => 0xf,
|
|
||||||
_ => 0x0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Background {
|
|
||||||
fn draw_frame(&mut self, pos: IVec2, size: IVec2) {
|
|
||||||
let px1 = pos.x as usize;
|
|
||||||
let py1 = pos.y as usize;
|
|
||||||
let sx = size.x as usize;
|
|
||||||
let sy = size.y as usize;
|
|
||||||
let px2 = px1 + sx - 1;
|
|
||||||
let py2 = py1 + sy - 1;
|
|
||||||
|
|
||||||
self.tiles[px1][py1] = TILE_FRTL;
|
|
||||||
self.tiles[px1][py2] = TILE_FRBL;
|
|
||||||
self.tiles[px2][py1] = TILE_FRTR;
|
|
||||||
self.tiles[px2][py2] = TILE_FRBR;
|
|
||||||
|
|
||||||
for x in (px1 + 1)..px2 {
|
|
||||||
self.tiles[x][py1] = TILE_FRT;
|
|
||||||
self.tiles[x][py2] = TILE_FRB;
|
|
||||||
}
|
|
||||||
|
|
||||||
for y in (py1 + 1)..py2 {
|
|
||||||
self.tiles[px1][y] = TILE_FRL;
|
|
||||||
self.tiles[px2][y] = TILE_FRR;
|
|
||||||
}
|
|
||||||
for x in (px1 + 1)..px2 {
|
|
||||||
for y in (py1 + 1)..py2 {
|
|
||||||
self.tiles[x][y] = TILE_FRBG;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw_input_window(gsa: &mut Gsa, pos: IVec2, caption: &str) {
|
|
||||||
gsa.bg[2].draw_frame(pos, IVec2 { x: 7, y: 5 });
|
|
||||||
gsa.bg[2].tiles[pos.x as usize + 3][pos.y as usize + 1] = TILE_INPUT;
|
|
||||||
gsa.bg[2].tiles[pos.x as usize + 4][pos.y as usize + 1] = TILE_INPUT;
|
|
||||||
gsa.bg[2].tiles[pos.x as usize + 1][pos.y as usize + 3] = TILE_BUT_YES;
|
|
||||||
gsa.bg[2].tiles[pos.x as usize + 5][pos.y as usize + 3] = TILE_BUT_NO;
|
|
||||||
gsa.write_string(
|
|
||||||
IVec2 {
|
|
||||||
x: pos.x * 2 + 2,
|
|
||||||
y: pos.y * 2 + 1,
|
|
||||||
},
|
|
||||||
caption,
|
|
||||||
);
|
|
||||||
gsa.write_string(
|
|
||||||
IVec2 {
|
|
||||||
x: pos.x * 2 + 3,
|
|
||||||
y: pos.y * 2 + 3,
|
|
||||||
},
|
|
||||||
"ID:0000",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_input_window(gsa: &mut Gsa, pos: IVec2, val: u16) {
|
|
||||||
gsa.write_string(
|
|
||||||
IVec2 {
|
|
||||||
x: pos.x * 2 + 6,
|
|
||||||
y: pos.y * 2 + 3,
|
|
||||||
},
|
|
||||||
&format!("{:04x}", val),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_state(
|
|
||||||
state: State,
|
|
||||||
gsa1: &mut Gsa,
|
|
||||||
gsa2: &mut Gsa,
|
|
||||||
current_layer: usize,
|
|
||||||
all_layers: bool,
|
|
||||||
current_map: u16,
|
|
||||||
) {
|
|
||||||
match state {
|
|
||||||
State::Edit => {
|
|
||||||
//update editing layers
|
|
||||||
if all_layers {
|
|
||||||
gsa1.bg[0].active = true;
|
|
||||||
gsa1.bg[1].active = true;
|
|
||||||
gsa1.bg[2].active = true;
|
|
||||||
} else {
|
|
||||||
gsa1.bg[0].active = current_layer == 0;
|
|
||||||
gsa1.bg[1].active = current_layer == 1;
|
|
||||||
gsa1.bg[2].active = current_layer == 2;
|
|
||||||
}
|
|
||||||
gsa2.bg[2].clear();
|
|
||||||
gsa2.bg[2].clear();
|
|
||||||
draw_toolbar(gsa1, gsa2, current_layer, all_layers, current_map);
|
|
||||||
|
|
||||||
gsa2.bg[0].active = false;
|
|
||||||
gsa2.bg[1].active = false;
|
|
||||||
gsa1.sprite[SPR_CURSOR].priority = 3;
|
|
||||||
gsa1.sprite[SPR_CURSOR].tile = TILE_CURSOR;
|
|
||||||
gsa2.sprite[SPR_CURSOR].tile = EMPTY_TILE;
|
|
||||||
}
|
|
||||||
State::SelectTile => {
|
|
||||||
draw_toolbar(gsa1, gsa2, current_layer, all_layers, current_map);
|
|
||||||
gsa1.bg[0].active = false;
|
|
||||||
gsa1.bg[1].active = false;
|
|
||||||
gsa1.bg[2].active = false;
|
|
||||||
gsa2.bg[0].active = true;
|
|
||||||
gsa2.bg[1].active = true;
|
|
||||||
gsa1.sprite[SPR_CURSOR].tile = EMPTY_TILE;
|
|
||||||
gsa2.sprite[SPR_CURSOR].tile = TILE_CURSOR;
|
|
||||||
}
|
|
||||||
State::NewMapDialog => {
|
|
||||||
gsa1.bg[0].active = false;
|
|
||||||
gsa1.bg[1].active = false;
|
|
||||||
gsa1.bg[2].active = false;
|
|
||||||
gsa2.bg[0].active = false;
|
|
||||||
gsa2.bg[1].active = false;
|
|
||||||
gsa1.sprite[SPR_CURSOR].tile = EMPTY_TILE;
|
|
||||||
gsa2.sprite[SPR_CURSOR].tile = EMPTY_TILE;
|
|
||||||
draw_input_window(gsa2, IVec2 { x: 15, y: 9 }, "Create Map");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw_toolbar(
|
|
||||||
gsa1: &mut Gsa,
|
|
||||||
gsa2: &mut Gsa,
|
|
||||||
current_layer: usize,
|
|
||||||
all_layers: bool,
|
|
||||||
current_map: u16,
|
|
||||||
) {
|
|
||||||
for y in 0..BACKGROUND_MAX_SIZE {
|
|
||||||
gsa2.bg[2].tiles[0][y] = 0x7010;
|
|
||||||
}
|
|
||||||
gsa2.bg[2].tiles[0][BUT_SAVE] = 0x7211;
|
|
||||||
gsa2.bg[2].tiles[0][BUT_CREATE] = TILE_BUT_CREATE;
|
|
||||||
gsa2.bg[2].tiles[0][BUT_EXIT] = 0x7212;
|
|
||||||
|
|
||||||
//layer buttons
|
|
||||||
gsa2.bg[2].tiles[0][BUT_LAYER1] = if current_layer == 0 { 0x7111 } else { 0x7011 };
|
|
||||||
gsa2.bg[2].tiles[0][BUT_LAYER2] = if current_layer == 1 { 0x7112 } else { 0x7012 };
|
|
||||||
gsa2.bg[2].tiles[0][BUT_LAYER3] = if current_layer == 2 { 0x7113 } else { 0x7013 };
|
|
||||||
gsa2.bg[2].tiles[0][BUT_LAYERS] = if all_layers { 0x7114 } else { 0x7014 };
|
|
||||||
|
|
||||||
gsa2.bg[2].size = IVec2 { x: 120, y: 68 }; //enough to cover 4k monitors? <_<
|
|
||||||
gsa2.bg[3].size = IVec2 { x: 240, y: 136 };
|
|
||||||
|
|
||||||
gsa2.write_string_vertical(
|
|
||||||
IVec2 {
|
|
||||||
x: 0,
|
|
||||||
y: BUT_EXIT as i32 * 2 + 3,
|
|
||||||
},
|
|
||||||
&format!("MAP-{:04X}", current_map),
|
|
||||||
);
|
|
||||||
|
|
||||||
gsa2.write_string_vertical(
|
|
||||||
IVec2 {
|
|
||||||
x: 0,
|
|
||||||
y: BUT_EXIT as i32 * 2 + 12,
|
|
||||||
},
|
|
||||||
&format!("W-{}", gsa1.bg[0].size.x),
|
|
||||||
);
|
|
||||||
|
|
||||||
gsa2.write_string_vertical(
|
|
||||||
IVec2 {
|
|
||||||
x: 1,
|
|
||||||
y: BUT_EXIT as i32 * 2 + 12,
|
|
||||||
},
|
|
||||||
&format!("H-{}", gsa1.bg[0].size.y),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn run_mapedit() {
|
|
||||||
println!("running map edit");
|
|
||||||
|
|
||||||
let tileset_path = "examples/basic/gfx.gif";
|
|
||||||
let (tileset, palette) = load_tileset(&fs::read(tileset_path).unwrap());
|
|
||||||
|
|
||||||
let maps_path = "examples/basic/maps.dat";
|
|
||||||
let maps = if Path::new(maps_path).exists() {
|
|
||||||
postcard::from_bytes(&fs::read(maps_path).unwrap()).unwrap()
|
|
||||||
} else {
|
|
||||||
Maps::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut gsa1 = Gsa {
|
|
||||||
sprite: [Sprite::default(); MAX_SPRITES],
|
|
||||||
palette,
|
|
||||||
bg: Default::default(),
|
|
||||||
font: FONT_BOLD,
|
|
||||||
pressed: 0,
|
|
||||||
released: 0,
|
|
||||||
down: 0,
|
|
||||||
maps,
|
|
||||||
str_bg: 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
gsa1.reset_bgs();
|
|
||||||
gsa1.reset_sprites();
|
|
||||||
|
|
||||||
if gsa1.map_exists(0) {
|
|
||||||
gsa1.load_map(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
for i in 0..3 {
|
|
||||||
gsa1.bg[i].scroll = IVec2 {
|
|
||||||
x: -16 - 32,
|
|
||||||
y: -32,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut gsa2 = Gsa {
|
|
||||||
sprite: [Sprite::default(); MAX_SPRITES],
|
|
||||||
palette,
|
|
||||||
bg: Default::default(),
|
|
||||||
font: FONT_BOLD,
|
|
||||||
pressed: 0,
|
|
||||||
released: 0,
|
|
||||||
down: 0,
|
|
||||||
maps: Maps::default(),
|
|
||||||
str_bg: 3,
|
|
||||||
};
|
|
||||||
gsa2.reset_bgs();
|
|
||||||
gsa2.reset_sprites();
|
|
||||||
for i in 0..2 {
|
|
||||||
gsa2.bg[i].scroll = IVec2 {
|
|
||||||
x: -16 - 32,
|
|
||||||
y: -32,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
for y in 0..TILESET_SIZE {
|
|
||||||
for x in 0..TILESET_SIZE {
|
|
||||||
gsa2.bg[0].tiles[x][y] = (x + (y << 8)) as u16;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//draw_input_window(&mut gsa2, IVec2 { x: 5, y: 3 }, "Create Map");
|
|
||||||
|
|
||||||
let event_loop = EventLoop::new();
|
|
||||||
let size = LogicalSize::new(1280, 720);
|
|
||||||
let window = WindowBuilder::new()
|
|
||||||
.with_title(format!(
|
|
||||||
"Game Skunk Advance Map Editor v{}",
|
|
||||||
crate_version!()
|
|
||||||
))
|
|
||||||
.with_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();
|
|
||||||
window.request_redraw();
|
|
||||||
let mut mouse_pos = IVec2::ZERO;
|
|
||||||
let mut tile_pos = IVec2::ZERO;
|
|
||||||
let mut tile_pos2 = IVec2::ZERO;
|
|
||||||
let mut left_down = false;
|
|
||||||
let mut middle_down = false;
|
|
||||||
let mut right_down = false;
|
|
||||||
let mut selected_tile = IVec2::ZERO;
|
|
||||||
gsa2.bg[1].tiles[0][0] = TILE_MARKER;
|
|
||||||
let mut current_layer = 0usize;
|
|
||||||
let mut all_layers = true;
|
|
||||||
let mut state = State::Edit;
|
|
||||||
let mut input_buf = 0u16;
|
|
||||||
let mut current_map = 0;
|
|
||||||
set_state(
|
|
||||||
State::Edit,
|
|
||||||
&mut gsa1,
|
|
||||||
&mut gsa2,
|
|
||||||
current_layer,
|
|
||||||
all_layers,
|
|
||||||
current_map,
|
|
||||||
);
|
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| {
|
|
||||||
let mouse_pos = &mut mouse_pos;
|
|
||||||
let tile_pos = &mut tile_pos;
|
|
||||||
let tile_pos2 = &mut tile_pos2;
|
|
||||||
let left_down = &mut left_down;
|
|
||||||
let middle_down = &mut middle_down;
|
|
||||||
let right_down = &mut right_down;
|
|
||||||
let selected_tile = &mut selected_tile;
|
|
||||||
let state = &mut state;
|
|
||||||
let current_layer = &mut current_layer;
|
|
||||||
let all_layers = &mut all_layers;
|
|
||||||
let input_buf = &mut input_buf;
|
|
||||||
let current_map = &mut current_map;
|
|
||||||
|
|
||||||
match event {
|
|
||||||
Event::WindowEvent { event, .. } => match event {
|
|
||||||
WindowEvent::KeyboardInput { input, .. } => {
|
|
||||||
let vk = input.virtual_keycode.unwrap_or(VirtualKeyCode::F24);
|
|
||||||
match vk {
|
|
||||||
VirtualKeyCode::Escape => {
|
|
||||||
//*control_flow = ControlFlow::Exit;
|
|
||||||
}
|
|
||||||
VirtualKeyCode::LShift => {
|
|
||||||
if input.state == ElementState::Pressed {
|
|
||||||
*state = State::SelectTile;
|
|
||||||
set_state(
|
|
||||||
*state,
|
|
||||||
&mut gsa1,
|
|
||||||
&mut gsa2,
|
|
||||||
*current_layer,
|
|
||||||
*all_layers,
|
|
||||||
*current_map,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
*state = State::Edit;
|
|
||||||
set_state(
|
|
||||||
*state,
|
|
||||||
&mut gsa1,
|
|
||||||
&mut gsa2,
|
|
||||||
*current_layer,
|
|
||||||
*all_layers,
|
|
||||||
*current_map,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
VirtualKeyCode::Key0
|
|
||||||
| VirtualKeyCode::Key1
|
|
||||||
| VirtualKeyCode::Key2
|
|
||||||
| VirtualKeyCode::Key3
|
|
||||||
| VirtualKeyCode::Key4
|
|
||||||
| VirtualKeyCode::Key5
|
|
||||||
| VirtualKeyCode::Key6
|
|
||||||
| VirtualKeyCode::Key7
|
|
||||||
| VirtualKeyCode::Key8
|
|
||||||
| VirtualKeyCode::Key9
|
|
||||||
| VirtualKeyCode::A
|
|
||||||
| VirtualKeyCode::B
|
|
||||||
| VirtualKeyCode::C
|
|
||||||
| VirtualKeyCode::D
|
|
||||||
| VirtualKeyCode::E
|
|
||||||
| VirtualKeyCode::F => {
|
|
||||||
if input.state == ElementState::Pressed {
|
|
||||||
*input_buf = ((*input_buf & 0xFFF) << 4) | key_to_num(vk);
|
|
||||||
update_input_window(&mut gsa2, IVec2 { x: 15, y: 9 }, *input_buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
WindowEvent::MouseInput {
|
|
||||||
state: but_state,
|
|
||||||
button,
|
|
||||||
..
|
|
||||||
} => match (but_state, button) {
|
|
||||||
(winit::event::ElementState::Pressed, winit::event::MouseButton::Left) => {
|
|
||||||
if mouse_pos.x < 16 {
|
|
||||||
match (mouse_pos.y / 16) as usize {
|
|
||||||
BUT_SAVE => {
|
|
||||||
println!("saving");
|
|
||||||
gsa1.store_map(*current_map);
|
|
||||||
fs::write(
|
|
||||||
maps_path,
|
|
||||||
postcard::to_allocvec(&gsa1.maps).unwrap(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
BUT_CREATE => {
|
|
||||||
*state = State::NewMapDialog;
|
|
||||||
*input_buf = *current_map;
|
|
||||||
set_state(
|
|
||||||
*state,
|
|
||||||
&mut gsa1,
|
|
||||||
&mut gsa2,
|
|
||||||
*current_layer,
|
|
||||||
*all_layers,
|
|
||||||
*current_map,
|
|
||||||
);
|
|
||||||
update_input_window(
|
|
||||||
&mut gsa2,
|
|
||||||
IVec2 { x: 15, y: 9 },
|
|
||||||
*input_buf,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
BUT_LAYER1 => {
|
|
||||||
*current_layer = 0;
|
|
||||||
set_state(
|
|
||||||
*state,
|
|
||||||
&mut gsa1,
|
|
||||||
&mut gsa2,
|
|
||||||
*current_layer,
|
|
||||||
*all_layers,
|
|
||||||
*current_map,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
BUT_LAYER2 => {
|
|
||||||
*current_layer = 1;
|
|
||||||
set_state(
|
|
||||||
*state,
|
|
||||||
&mut gsa1,
|
|
||||||
&mut gsa2,
|
|
||||||
*current_layer,
|
|
||||||
*all_layers,
|
|
||||||
*current_map,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
BUT_LAYER3 => {
|
|
||||||
*current_layer = 2;
|
|
||||||
set_state(
|
|
||||||
*state,
|
|
||||||
&mut gsa1,
|
|
||||||
&mut gsa2,
|
|
||||||
*current_layer,
|
|
||||||
*all_layers,
|
|
||||||
*current_map,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
BUT_LAYERS => {
|
|
||||||
*all_layers = !*all_layers;
|
|
||||||
set_state(
|
|
||||||
*state,
|
|
||||||
&mut gsa1,
|
|
||||||
&mut gsa2,
|
|
||||||
*current_layer,
|
|
||||||
*all_layers,
|
|
||||||
*current_map,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
BUT_EXIT => {
|
|
||||||
println!("exit");
|
|
||||||
*control_flow = ControlFlow::Exit;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
match *state {
|
|
||||||
State::NewMapDialog => {
|
|
||||||
//todo: not hardcode?
|
|
||||||
if mouse_pos.y / 16 == 12 {
|
|
||||||
if mouse_pos.x / 16 == 16 {
|
|
||||||
println!("yes");
|
|
||||||
gsa1.store_map(*current_map);
|
|
||||||
*current_map = *input_buf;
|
|
||||||
if gsa1.map_exists(*current_map) {
|
|
||||||
gsa1.load_map(*current_map);
|
|
||||||
} else {
|
|
||||||
//todo: not reset scrolling
|
|
||||||
gsa1.reset_bgs();
|
|
||||||
}
|
|
||||||
*state = State::Edit;
|
|
||||||
set_state(
|
|
||||||
*state,
|
|
||||||
&mut gsa1,
|
|
||||||
&mut gsa2,
|
|
||||||
*current_layer,
|
|
||||||
*all_layers,
|
|
||||||
*current_map,
|
|
||||||
);
|
|
||||||
} else if mouse_pos.x / 16 == 20 {
|
|
||||||
println!("no");
|
|
||||||
*state = State::Edit;
|
|
||||||
set_state(
|
|
||||||
*state,
|
|
||||||
&mut gsa1,
|
|
||||||
&mut gsa2,
|
|
||||||
*current_layer,
|
|
||||||
*all_layers,
|
|
||||||
*current_map,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
*left_down = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(winit::event::ElementState::Released, winit::event::MouseButton::Left) => {
|
|
||||||
*left_down = false;
|
|
||||||
}
|
|
||||||
(winit::event::ElementState::Pressed, winit::event::MouseButton::Middle) => {
|
|
||||||
*middle_down = true;
|
|
||||||
}
|
|
||||||
(winit::event::ElementState::Released, winit::event::MouseButton::Middle) => {
|
|
||||||
*middle_down = false;
|
|
||||||
}
|
|
||||||
(winit::event::ElementState::Pressed, winit::event::MouseButton::Right) => {
|
|
||||||
*right_down = true;
|
|
||||||
}
|
|
||||||
(winit::event::ElementState::Released, winit::event::MouseButton::Right) => {
|
|
||||||
*right_down = false;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
},
|
|
||||||
WindowEvent::CursorMoved { position, .. } => {
|
|
||||||
let new_pos = IVec2 {
|
|
||||||
x: position.x as i32 / 2,
|
|
||||||
y: position.y as i32 / 2,
|
|
||||||
};
|
|
||||||
let delta = new_pos - *mouse_pos;
|
|
||||||
if *middle_down {
|
|
||||||
match *state {
|
|
||||||
State::Edit => {
|
|
||||||
// normal mode
|
|
||||||
gsa1.bg[0].scroll -= delta;
|
|
||||||
gsa1.bg[1].scroll -= delta;
|
|
||||||
gsa1.bg[2].scroll -= delta;
|
|
||||||
}
|
|
||||||
State::SelectTile => {
|
|
||||||
// tile select mode
|
|
||||||
gsa2.bg[0].scroll -= delta;
|
|
||||||
gsa2.bg[1].scroll -= delta;
|
|
||||||
//gsa2.bgs[2].scroll -= delta;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*mouse_pos = new_pos;
|
|
||||||
*tile_pos = IVec2 {
|
|
||||||
x: (new_pos.x + gsa1.bg[0].scroll.x).div_euclid(TILE_SIZE as i32),
|
|
||||||
y: (new_pos.y + gsa1.bg[0].scroll.y).div_euclid(TILE_SIZE as i32),
|
|
||||||
};
|
|
||||||
*tile_pos2 = IVec2 {
|
|
||||||
x: (new_pos.x + gsa2.bg[0].scroll.x).div_euclid(TILE_SIZE as i32),
|
|
||||||
y: (new_pos.y + gsa2.bg[0].scroll.y).div_euclid(TILE_SIZE as i32),
|
|
||||||
};
|
|
||||||
let cursor_pos = *tile_pos * TILE_SIZE as i32 - gsa1.bg[0].scroll;
|
|
||||||
let cursor_pos2 = *tile_pos2 * TILE_SIZE as i32 - gsa2.bg[0].scroll;
|
|
||||||
gsa1.sprite[SPR_CURSOR].pos = cursor_pos;
|
|
||||||
gsa2.sprite[SPR_CURSOR].pos = cursor_pos2;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
},
|
|
||||||
|
|
||||||
Event::MainEventsCleared => {
|
|
||||||
match *state {
|
|
||||||
State::Edit => {
|
|
||||||
if *left_down {
|
|
||||||
if tile_pos.x >= 0
|
|
||||||
&& tile_pos.y >= 0
|
|
||||||
&& tile_pos.x < BACKGROUND_MAX_SIZE as i32
|
|
||||||
&& tile_pos.y < BACKGROUND_MAX_SIZE as i32
|
|
||||||
{
|
|
||||||
let tile = (selected_tile.x + (selected_tile.y << 8)) as u16;
|
|
||||||
gsa1.bg[*current_layer].tiles[tile_pos.x as usize]
|
|
||||||
[tile_pos.y as usize] = tile;
|
|
||||||
}
|
|
||||||
} else if *right_down {
|
|
||||||
if tile_pos.x >= 0
|
|
||||||
&& tile_pos.y >= 0
|
|
||||||
&& tile_pos.x < BACKGROUND_MAX_SIZE as i32
|
|
||||||
&& tile_pos.y < BACKGROUND_MAX_SIZE as i32
|
|
||||||
{
|
|
||||||
gsa1.bg[*current_layer].tiles[tile_pos.x as usize]
|
|
||||||
[tile_pos.y as usize] = EMPTY_TILE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
State::SelectTile => {
|
|
||||||
if *left_down {
|
|
||||||
if tile_pos2.x >= 0
|
|
||||||
&& tile_pos2.y >= 0
|
|
||||||
&& tile_pos2.x < BACKGROUND_MAX_SIZE as i32
|
|
||||||
&& tile_pos2.y < BACKGROUND_MAX_SIZE as i32
|
|
||||||
{
|
|
||||||
gsa2.bg[1].tiles[selected_tile.x as usize]
|
|
||||||
[selected_tile.y as usize] = EMPTY_TILE;
|
|
||||||
*selected_tile = *tile_pos2;
|
|
||||||
gsa2.bg[1].tiles[selected_tile.x as usize]
|
|
||||||
[selected_tile.y as usize] = TILE_MARKER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
|
|
||||||
// render
|
|
||||||
let size = window.inner_size();
|
|
||||||
surface
|
|
||||||
.resize(
|
|
||||||
NonZeroU32::new(size.width).unwrap(),
|
|
||||||
NonZeroU32::new(size.height).unwrap(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let mut screen_buffer =
|
|
||||||
vec![TRANSPARENT; size.width as usize * size.height as usize / 4];
|
|
||||||
let mut window_buffer = surface.buffer_mut().unwrap();
|
|
||||||
let screen_size = IVec2 {
|
|
||||||
x: size.width as i32 / 2,
|
|
||||||
y: size.height as i32 / 2,
|
|
||||||
};
|
|
||||||
render_to_screen(&mut screen_buffer, &gsa1, &tileset, screen_size);
|
|
||||||
render_to_screen(&mut screen_buffer, &gsa2, &tileset, screen_size);
|
|
||||||
let mut screen = Surface {
|
|
||||||
data: &mut screen_buffer,
|
|
||||||
size: screen_size,
|
|
||||||
};
|
|
||||||
match *state {
|
|
||||||
State::Edit => {
|
|
||||||
let xs = -gsa1.bg[0].scroll.x - 1;
|
|
||||||
let ys = -gsa1.bg[0].scroll.y - 1;
|
|
||||||
let xe = xs + gsa1.bg[0].size.x * TILE_SIZE as i32 + 1;
|
|
||||||
let ye = ys + gsa1.bg[0].size.y * TILE_SIZE as i32 + 1;
|
|
||||||
if xs >= 16 && xs < screen_size.x {
|
|
||||||
let starty = (ys + 1).max(0);
|
|
||||||
let len = ye.min(screen_size.y) - starty;
|
|
||||||
screen.draw_vline(IVec2 { x: xs, y: starty }, len, 0xfc);
|
|
||||||
}
|
|
||||||
if xe >= 16 && xe < screen_size.x {
|
|
||||||
let starty = (ys + 1).max(0);
|
|
||||||
let len = ye.min(screen_size.y) - starty;
|
|
||||||
screen.draw_vline(IVec2 { x: xe, y: starty }, len, 0xfc);
|
|
||||||
}
|
|
||||||
if ys >= 0 && ys < screen_size.y {
|
|
||||||
let startx = (xs + 1).max(16);
|
|
||||||
let len = xe.min(screen_size.x) - startx;
|
|
||||||
screen.draw_hline(IVec2 { x: startx, y: ys }, len, 0xfc);
|
|
||||||
}
|
|
||||||
if ye >= 0 && ye < screen_size.y {
|
|
||||||
let startx = (xs + 1).max(16);
|
|
||||||
let len = xe.min(screen_size.x) - startx;
|
|
||||||
screen.draw_hline(IVec2 { x: startx, y: ye }, len, 0xfc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
render_to_window(
|
|
||||||
&mut window_buffer,
|
|
||||||
&mut screen_buffer,
|
|
||||||
&palette,
|
|
||||||
IVec2 {
|
|
||||||
x: size.width as i32,
|
|
||||||
y: size.height as i32,
|
|
||||||
},
|
|
||||||
IVec2 {
|
|
||||||
x: size.width as i32 / 2,
|
|
||||||
y: size.height as i32 / 2,
|
|
||||||
},
|
|
||||||
2,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
window_buffer.present().unwrap();
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
use crate::mapedit::*;
|
||||||
|
use crate::Background;
|
||||||
|
|
||||||
|
impl Background {
|
||||||
|
pub(crate) fn draw_frame(&mut self, pos: IVec2, size: IVec2) {
|
||||||
|
let px1 = pos.x as usize;
|
||||||
|
let py1 = pos.y as usize;
|
||||||
|
let sx = size.x as usize;
|
||||||
|
let sy = size.y as usize;
|
||||||
|
let px2 = px1 + sx - 1;
|
||||||
|
let py2 = py1 + sy - 1;
|
||||||
|
|
||||||
|
self.tiles[px1][py1] = TILE_FRTL;
|
||||||
|
self.tiles[px1][py2] = TILE_FRBL;
|
||||||
|
self.tiles[px2][py1] = TILE_FRTR;
|
||||||
|
self.tiles[px2][py2] = TILE_FRBR;
|
||||||
|
|
||||||
|
for x in (px1 + 1)..px2 {
|
||||||
|
self.tiles[x][py1] = TILE_FRT;
|
||||||
|
self.tiles[x][py2] = TILE_FRB;
|
||||||
|
}
|
||||||
|
|
||||||
|
for y in (py1 + 1)..py2 {
|
||||||
|
self.tiles[px1][y] = TILE_FRL;
|
||||||
|
self.tiles[px2][y] = TILE_FRR;
|
||||||
|
}
|
||||||
|
for x in (px1 + 1)..px2 {
|
||||||
|
for y in (py1 + 1)..py2 {
|
||||||
|
self.tiles[x][y] = TILE_FRBG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
pub const SPR_CURSOR: usize = 0x01;
|
||||||
|
pub const TILE_CURSOR: u16 = 0x7110;
|
||||||
|
pub const TILE_MARKER: u16 = 0x7210;
|
||||||
|
pub const TILE_FRT: u16 = 0x7018;
|
||||||
|
pub const TILE_FRB: u16 = 0x7118;
|
||||||
|
pub const TILE_FRL: u16 = 0x7218;
|
||||||
|
pub const TILE_FRR: u16 = 0x7219;
|
||||||
|
pub const TILE_FRTL: u16 = 0x7019;
|
||||||
|
pub const TILE_FRTR: u16 = 0x701A;
|
||||||
|
pub const TILE_FRBL: u16 = 0x7119;
|
||||||
|
pub const TILE_FRBR: u16 = 0x711A;
|
||||||
|
pub const TILE_FRBG: u16 = 0x721A;
|
||||||
|
pub const TILE_INPUT: u16 = 0x7318;
|
||||||
|
|
||||||
|
pub const TILE_BUT_YES: u16 = 0x7311;
|
||||||
|
pub const TILE_BUT_NO: u16 = 0x7312;
|
||||||
|
pub const TILE_BUT_CREATE: u16 = 0x7213;
|
||||||
|
|
||||||
|
pub const BUT_SAVE: usize = 0;
|
||||||
|
pub const BUT_CREATE: usize = 1;
|
||||||
|
pub const BUT_LAYER1: usize = 3;
|
||||||
|
pub const BUT_LAYER2: usize = 4;
|
||||||
|
pub const BUT_LAYER3: usize = 5;
|
||||||
|
pub const BUT_LAYERS: usize = 6;
|
||||||
|
pub const BUT_EXIT: usize = 8;
|
|
@ -0,0 +1,449 @@
|
||||||
|
mod background;
|
||||||
|
mod state;
|
||||||
|
use state::State;
|
||||||
|
mod stuff;
|
||||||
|
use stuff::Stuff;
|
||||||
|
mod constants;
|
||||||
|
use constants::*;
|
||||||
|
mod surface;
|
||||||
|
use surface::Surface;
|
||||||
|
mod util;
|
||||||
|
use util::*;
|
||||||
|
|
||||||
|
use std::fs;
|
||||||
|
use std::num::NonZeroU32;
|
||||||
|
|
||||||
|
use crate::gsa::Gsa;
|
||||||
|
use crate::gsa_render_to_screen::render_to_screen;
|
||||||
|
use crate::gsa_render_to_screen::render_to_window;
|
||||||
|
use crate::maps::Maps;
|
||||||
|
use crate::sprite::Sprite;
|
||||||
|
use crate::tileset::*;
|
||||||
|
use crate::*;
|
||||||
|
use clap::crate_version;
|
||||||
|
use glam::IVec2;
|
||||||
|
use winit::dpi::PhysicalSize;
|
||||||
|
use winit::event::ElementState;
|
||||||
|
use winit::{
|
||||||
|
dpi::LogicalSize,
|
||||||
|
event::{Event, VirtualKeyCode, WindowEvent},
|
||||||
|
event_loop::{ControlFlow, EventLoop},
|
||||||
|
window::WindowBuilder,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
pub(crate) fn run_mapedit() {
|
||||||
|
println!("running map edit");
|
||||||
|
|
||||||
|
let tileset_path = "examples/basic/gfx.gif";
|
||||||
|
let (tileset, palette) = load_tileset(&fs::read(tileset_path).unwrap());
|
||||||
|
|
||||||
|
let maps_path = "examples/basic/maps.dat";
|
||||||
|
let maps = if Path::new(maps_path).exists() {
|
||||||
|
postcard::from_bytes(&fs::read(maps_path).unwrap()).unwrap()
|
||||||
|
} else {
|
||||||
|
Maps::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut gsa1 = Gsa {
|
||||||
|
sprite: [Sprite::default(); MAX_SPRITES],
|
||||||
|
palette,
|
||||||
|
bg: Default::default(),
|
||||||
|
font: FONT_BOLD,
|
||||||
|
pressed: 0,
|
||||||
|
released: 0,
|
||||||
|
down: 0,
|
||||||
|
maps,
|
||||||
|
str_bg: 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
gsa1.reset_bgs();
|
||||||
|
gsa1.reset_sprites();
|
||||||
|
|
||||||
|
if gsa1.map_exists(0) {
|
||||||
|
gsa1.load_map(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..3 {
|
||||||
|
gsa1.bg[i].scroll = IVec2 {
|
||||||
|
x: -16 - 32,
|
||||||
|
y: -32,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut gsa2 = Gsa {
|
||||||
|
sprite: [Sprite::default(); MAX_SPRITES],
|
||||||
|
palette,
|
||||||
|
bg: Default::default(),
|
||||||
|
font: FONT_BOLD,
|
||||||
|
pressed: 0,
|
||||||
|
released: 0,
|
||||||
|
down: 0,
|
||||||
|
maps: Maps::default(),
|
||||||
|
str_bg: 3,
|
||||||
|
};
|
||||||
|
gsa2.reset_bgs();
|
||||||
|
gsa2.reset_sprites();
|
||||||
|
for i in 0..2 {
|
||||||
|
gsa2.bg[i].scroll = IVec2 {
|
||||||
|
x: -16 - 32,
|
||||||
|
y: -32,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
for y in 0..TILESET_SIZE {
|
||||||
|
for x in 0..TILESET_SIZE {
|
||||||
|
gsa2.bg[0].tiles[x][y] = (x + (y << 8)) as u16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//draw_input_window(&mut gsa2, IVec2 { x: 5, y: 3 }, "Create Map");
|
||||||
|
|
||||||
|
let mut stuff = Stuff {
|
||||||
|
gsa1,
|
||||||
|
gsa2,
|
||||||
|
mouse_pos: IVec2::ZERO,
|
||||||
|
tile_pos: IVec2::ZERO,
|
||||||
|
tile_pos2: IVec2::ZERO,
|
||||||
|
left_down: false,
|
||||||
|
middle_down: false,
|
||||||
|
right_down: false,
|
||||||
|
selected_tile: IVec2::ZERO,
|
||||||
|
current_layer: 0,
|
||||||
|
all_layers: true,
|
||||||
|
state: State::Edit,
|
||||||
|
input_buf: 0,
|
||||||
|
current_map: 0,
|
||||||
|
window_tile_size: IVec2::new(1280 / 32, 640 / 32),
|
||||||
|
};
|
||||||
|
|
||||||
|
let event_loop = EventLoop::new();
|
||||||
|
let size = LogicalSize::new(1280, 640);
|
||||||
|
let window = WindowBuilder::new()
|
||||||
|
.with_title(format!(
|
||||||
|
"Game Skunk Advance Map Editor v{}",
|
||||||
|
crate_version!()
|
||||||
|
))
|
||||||
|
.with_inner_size(size)
|
||||||
|
.with_resize_increments(LogicalSize::new(32, 32))
|
||||||
|
.build(&event_loop)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let context = unsafe { softbuffer::Context::new(&window) }.unwrap();
|
||||||
|
let mut surface = unsafe { softbuffer::Surface::new(&context, &window) }.unwrap();
|
||||||
|
window.request_redraw();
|
||||||
|
|
||||||
|
stuff.gsa2.bg[1].tiles[0][0] = TILE_MARKER;
|
||||||
|
stuff.set_state(State::Edit);
|
||||||
|
|
||||||
|
event_loop.run(move |event, _, control_flow| {
|
||||||
|
//let stuff = &mut stuff;
|
||||||
|
|
||||||
|
match event {
|
||||||
|
Event::WindowEvent { event, .. } => match event {
|
||||||
|
WindowEvent::Resized(size) => {
|
||||||
|
if size.width % 32 != 0 || size.height % 32 != 0 {
|
||||||
|
let tw = (size.width as f32 / 32.0).round();
|
||||||
|
let th = (size.height as f32 / 32.0).round();
|
||||||
|
let w = (tw * 32.0) as u32;
|
||||||
|
let h = (th * 32.0) as u32;
|
||||||
|
stuff.window_tile_size.x = tw as i32;
|
||||||
|
stuff.window_tile_size.y = th as i32;
|
||||||
|
stuff.draw_toolbar();
|
||||||
|
let pos = window.outer_position().unwrap();
|
||||||
|
window.set_inner_size(PhysicalSize::new(w, h));
|
||||||
|
window.set_outer_position(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WindowEvent::KeyboardInput { input, .. } => {
|
||||||
|
let vk = input.virtual_keycode.unwrap_or(VirtualKeyCode::F24);
|
||||||
|
match vk {
|
||||||
|
VirtualKeyCode::Escape => {
|
||||||
|
//*control_flow = ControlFlow::Exit;
|
||||||
|
}
|
||||||
|
VirtualKeyCode::LShift => {
|
||||||
|
if input.state == ElementState::Pressed {
|
||||||
|
stuff.set_state(State::SelectTile);
|
||||||
|
} else {
|
||||||
|
stuff.set_state(State::Edit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VirtualKeyCode::Key0
|
||||||
|
| VirtualKeyCode::Key1
|
||||||
|
| VirtualKeyCode::Key2
|
||||||
|
| VirtualKeyCode::Key3
|
||||||
|
| VirtualKeyCode::Key4
|
||||||
|
| VirtualKeyCode::Key5
|
||||||
|
| VirtualKeyCode::Key6
|
||||||
|
| VirtualKeyCode::Key7
|
||||||
|
| VirtualKeyCode::Key8
|
||||||
|
| VirtualKeyCode::Key9
|
||||||
|
| VirtualKeyCode::A
|
||||||
|
| VirtualKeyCode::B
|
||||||
|
| VirtualKeyCode::C
|
||||||
|
| VirtualKeyCode::D
|
||||||
|
| VirtualKeyCode::E
|
||||||
|
| VirtualKeyCode::F => {
|
||||||
|
if input.state == ElementState::Pressed {
|
||||||
|
stuff.input_buf = ((stuff.input_buf & 0xFFF) << 4) | key_to_num(vk);
|
||||||
|
stuff.update_input_window(IVec2 { x: 15, y: 9 }, stuff.input_buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WindowEvent::MouseInput {
|
||||||
|
state: but_state,
|
||||||
|
button,
|
||||||
|
..
|
||||||
|
} => match (but_state, button) {
|
||||||
|
(winit::event::ElementState::Pressed, winit::event::MouseButton::Left) => {
|
||||||
|
if stuff.mouse_pos.x < 16 {
|
||||||
|
match (stuff.mouse_pos.y / 16) as usize {
|
||||||
|
BUT_SAVE => {
|
||||||
|
println!("saving");
|
||||||
|
stuff.gsa1.store_map(stuff.current_map);
|
||||||
|
fs::write(
|
||||||
|
maps_path,
|
||||||
|
postcard::to_allocvec(&stuff.gsa1.maps).unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
BUT_CREATE => {
|
||||||
|
stuff.input_buf = stuff.current_map;
|
||||||
|
stuff.set_state(State::NewMapDialog);
|
||||||
|
stuff.update_input_window(
|
||||||
|
IVec2 { x: 15, y: 9 },
|
||||||
|
stuff.input_buf,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
BUT_LAYER1 => {
|
||||||
|
stuff.current_layer = 0;
|
||||||
|
stuff.set_state(stuff.state);
|
||||||
|
}
|
||||||
|
BUT_LAYER2 => {
|
||||||
|
stuff.current_layer = 1;
|
||||||
|
stuff.set_state(stuff.state);
|
||||||
|
}
|
||||||
|
BUT_LAYER3 => {
|
||||||
|
stuff.current_layer = 2;
|
||||||
|
stuff.set_state(stuff.state);
|
||||||
|
}
|
||||||
|
BUT_LAYERS => {
|
||||||
|
stuff.all_layers = !stuff.all_layers;
|
||||||
|
stuff.set_state(stuff.state);
|
||||||
|
}
|
||||||
|
BUT_EXIT => {
|
||||||
|
println!("exit");
|
||||||
|
*control_flow = ControlFlow::Exit;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match stuff.state {
|
||||||
|
State::NewMapDialog => {
|
||||||
|
//todo: not hardcode?
|
||||||
|
if stuff.mouse_pos.y / 16 == 12 {
|
||||||
|
if stuff.mouse_pos.x / 16 == 16 {
|
||||||
|
println!("yes");
|
||||||
|
stuff.gsa1.store_map(stuff.current_map);
|
||||||
|
stuff.current_map = stuff.input_buf;
|
||||||
|
if stuff.gsa1.map_exists(stuff.current_map) {
|
||||||
|
stuff.gsa1.load_map(stuff.current_map);
|
||||||
|
} else {
|
||||||
|
//todo: not reset scrolling
|
||||||
|
stuff.gsa1.reset_bgs();
|
||||||
|
}
|
||||||
|
stuff.set_state(State::Edit);
|
||||||
|
} else if stuff.mouse_pos.x / 16 == 20 {
|
||||||
|
println!("no");
|
||||||
|
stuff.set_state(State::Edit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
stuff.left_down = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(winit::event::ElementState::Released, winit::event::MouseButton::Left) => {
|
||||||
|
stuff.left_down = false;
|
||||||
|
}
|
||||||
|
(winit::event::ElementState::Pressed, winit::event::MouseButton::Middle) => {
|
||||||
|
stuff.middle_down = true;
|
||||||
|
}
|
||||||
|
(winit::event::ElementState::Released, winit::event::MouseButton::Middle) => {
|
||||||
|
stuff.middle_down = false;
|
||||||
|
}
|
||||||
|
(winit::event::ElementState::Pressed, winit::event::MouseButton::Right) => {
|
||||||
|
stuff.right_down = true;
|
||||||
|
}
|
||||||
|
(winit::event::ElementState::Released, winit::event::MouseButton::Right) => {
|
||||||
|
stuff.right_down = false;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
WindowEvent::CursorMoved { position, .. } => {
|
||||||
|
let new_pos = IVec2 {
|
||||||
|
x: position.x as i32 / 2,
|
||||||
|
y: position.y as i32 / 2,
|
||||||
|
};
|
||||||
|
let delta = new_pos - stuff.mouse_pos;
|
||||||
|
if stuff.middle_down {
|
||||||
|
match stuff.state {
|
||||||
|
State::Edit => {
|
||||||
|
// normal mode
|
||||||
|
stuff.gsa1.bg[0].scroll -= delta;
|
||||||
|
stuff.gsa1.bg[1].scroll -= delta;
|
||||||
|
stuff.gsa1.bg[2].scroll -= delta;
|
||||||
|
}
|
||||||
|
State::SelectTile => {
|
||||||
|
// tile select mode
|
||||||
|
stuff.gsa2.bg[0].scroll -= delta;
|
||||||
|
stuff.gsa2.bg[1].scroll -= delta;
|
||||||
|
//gsa2.bgs[2].scroll -= delta;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stuff.mouse_pos = new_pos;
|
||||||
|
let new_tile_pos =
|
||||||
|
IVec2 {
|
||||||
|
x: (new_pos.x + stuff.gsa1.bg[0].scroll.x).div_euclid(TILE_SIZE as i32),
|
||||||
|
y: (new_pos.y + stuff.gsa1.bg[0].scroll.y).div_euclid(TILE_SIZE as i32),
|
||||||
|
};
|
||||||
|
let tile_pos_changed = stuff.tile_pos != new_tile_pos;
|
||||||
|
stuff.tile_pos = new_tile_pos;
|
||||||
|
stuff.tile_pos2 = IVec2 {
|
||||||
|
x: (new_pos.x + stuff.gsa2.bg[0].scroll.x).div_euclid(TILE_SIZE as i32),
|
||||||
|
y: (new_pos.y + stuff.gsa2.bg[0].scroll.y).div_euclid(TILE_SIZE as i32),
|
||||||
|
};
|
||||||
|
let cursor_pos = stuff.tile_pos * TILE_SIZE as i32 - stuff.gsa1.bg[0].scroll;
|
||||||
|
let cursor_pos2 = stuff.tile_pos2 * TILE_SIZE as i32 - stuff.gsa2.bg[0].scroll;
|
||||||
|
stuff.gsa1.sprite[SPR_CURSOR].pos = cursor_pos;
|
||||||
|
stuff.gsa2.sprite[SPR_CURSOR].pos = cursor_pos2;
|
||||||
|
if tile_pos_changed {
|
||||||
|
stuff.update_status_bar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
|
||||||
|
Event::MainEventsCleared => {
|
||||||
|
match stuff.state {
|
||||||
|
State::Edit => {
|
||||||
|
if stuff.left_down {
|
||||||
|
if stuff.tile_pos.x >= 0
|
||||||
|
&& stuff.tile_pos.y >= 0
|
||||||
|
&& stuff.tile_pos.x < BACKGROUND_MAX_SIZE as i32
|
||||||
|
&& stuff.tile_pos.y < BACKGROUND_MAX_SIZE as i32
|
||||||
|
{
|
||||||
|
let tile =
|
||||||
|
(stuff.selected_tile.x + (stuff.selected_tile.y << 8)) as u16;
|
||||||
|
stuff.gsa1.bg[stuff.current_layer].tiles
|
||||||
|
[stuff.tile_pos.x as usize]
|
||||||
|
[stuff.tile_pos.y as usize] = tile;
|
||||||
|
}
|
||||||
|
} else if stuff.right_down {
|
||||||
|
if stuff.tile_pos.x >= 0
|
||||||
|
&& stuff.tile_pos.y >= 0
|
||||||
|
&& stuff.tile_pos.x < BACKGROUND_MAX_SIZE as i32
|
||||||
|
&& stuff.tile_pos.y < BACKGROUND_MAX_SIZE as i32
|
||||||
|
{
|
||||||
|
stuff.gsa1.bg[stuff.current_layer].tiles
|
||||||
|
[stuff.tile_pos.x as usize]
|
||||||
|
[stuff.tile_pos.y as usize] = EMPTY_TILE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
State::SelectTile => {
|
||||||
|
if stuff.left_down {
|
||||||
|
if stuff.tile_pos2.x >= 0
|
||||||
|
&& stuff.tile_pos2.y >= 0
|
||||||
|
&& stuff.tile_pos2.x < BACKGROUND_MAX_SIZE as i32
|
||||||
|
&& stuff.tile_pos2.y < BACKGROUND_MAX_SIZE as i32
|
||||||
|
{
|
||||||
|
stuff.gsa2.bg[1].tiles[stuff.selected_tile.x as usize]
|
||||||
|
[stuff.selected_tile.y as usize] = EMPTY_TILE;
|
||||||
|
stuff.selected_tile = stuff.tile_pos2;
|
||||||
|
stuff.gsa2.bg[1].tiles[stuff.selected_tile.x as usize]
|
||||||
|
[stuff.selected_tile.y as usize] = TILE_MARKER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// render
|
||||||
|
let size = window.inner_size();
|
||||||
|
surface
|
||||||
|
.resize(
|
||||||
|
NonZeroU32::new(size.width).unwrap(),
|
||||||
|
NonZeroU32::new(size.height).unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let mut screen_buffer =
|
||||||
|
vec![TRANSPARENT; size.width as usize * size.height as usize / 4];
|
||||||
|
let mut window_buffer = surface.buffer_mut().unwrap();
|
||||||
|
let screen_size = IVec2 {
|
||||||
|
x: size.width as i32 / 2,
|
||||||
|
y: size.height as i32 / 2,
|
||||||
|
};
|
||||||
|
render_to_screen(&mut screen_buffer, &stuff.gsa1, &tileset, screen_size);
|
||||||
|
render_to_screen(&mut screen_buffer, &stuff.gsa2, &tileset, screen_size);
|
||||||
|
let mut screen = Surface {
|
||||||
|
data: &mut screen_buffer,
|
||||||
|
size: screen_size,
|
||||||
|
};
|
||||||
|
match stuff.state {
|
||||||
|
State::Edit => {
|
||||||
|
let xs = -stuff.gsa1.bg[0].scroll.x - 1;
|
||||||
|
let ys = -stuff.gsa1.bg[0].scroll.y - 1;
|
||||||
|
let xe = xs + stuff.gsa1.bg[0].size.x * TILE_SIZE as i32 + 1;
|
||||||
|
let ye = ys + stuff.gsa1.bg[0].size.y * TILE_SIZE as i32 + 1;
|
||||||
|
if xs >= 16 && xs < screen_size.x {
|
||||||
|
let starty = (ys + 1).max(0);
|
||||||
|
let len = ye.min(screen_size.y) - starty;
|
||||||
|
screen.draw_vline(IVec2 { x: xs, y: starty }, len, 0xfc);
|
||||||
|
}
|
||||||
|
if xe >= 16 && xe < screen_size.x {
|
||||||
|
let starty = (ys + 1).max(0);
|
||||||
|
let len = ye.min(screen_size.y) - starty;
|
||||||
|
screen.draw_vline(IVec2 { x: xe, y: starty }, len, 0xfc);
|
||||||
|
}
|
||||||
|
if ys >= 0 && ys < screen_size.y {
|
||||||
|
let startx = (xs + 1).max(16);
|
||||||
|
let len = xe.min(screen_size.x) - startx;
|
||||||
|
screen.draw_hline(IVec2 { x: startx, y: ys }, len, 0xfc);
|
||||||
|
}
|
||||||
|
if ye >= 0 && ye < screen_size.y {
|
||||||
|
let startx = (xs + 1).max(16);
|
||||||
|
let len = xe.min(screen_size.x) - startx;
|
||||||
|
screen.draw_hline(IVec2 { x: startx, y: ye }, len, 0xfc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
render_to_window(
|
||||||
|
&mut window_buffer,
|
||||||
|
&mut screen_buffer,
|
||||||
|
&palette,
|
||||||
|
IVec2 {
|
||||||
|
x: size.width as i32,
|
||||||
|
y: size.height as i32,
|
||||||
|
},
|
||||||
|
IVec2 {
|
||||||
|
x: size.width as i32 / 2,
|
||||||
|
y: size.height as i32 / 2,
|
||||||
|
},
|
||||||
|
2,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
window_buffer.present().unwrap();
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
use super::stuff::Stuff;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub enum State {
|
||||||
|
Edit,
|
||||||
|
SelectTile,
|
||||||
|
NewMapDialog,
|
||||||
|
}
|
|
@ -0,0 +1,180 @@
|
||||||
|
use super::constants::*;
|
||||||
|
use super::state::State;
|
||||||
|
use crate::gsa::Gsa;
|
||||||
|
use crate::*;
|
||||||
|
use glam::IVec2;
|
||||||
|
|
||||||
|
pub struct Stuff {
|
||||||
|
pub gsa1: Gsa,
|
||||||
|
pub gsa2: Gsa,
|
||||||
|
pub mouse_pos: IVec2,
|
||||||
|
pub tile_pos: IVec2,
|
||||||
|
pub tile_pos2: IVec2,
|
||||||
|
pub left_down: bool,
|
||||||
|
pub middle_down: bool,
|
||||||
|
pub right_down: bool,
|
||||||
|
pub selected_tile: IVec2,
|
||||||
|
pub current_layer: usize,
|
||||||
|
pub all_layers: bool,
|
||||||
|
pub state: State,
|
||||||
|
pub input_buf: u16,
|
||||||
|
pub current_map: u16,
|
||||||
|
pub window_tile_size: IVec2,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Stuff {
|
||||||
|
pub fn draw_input_window(&mut self, pos: IVec2, caption: &str) {
|
||||||
|
self.gsa2.bg[2].draw_frame(pos, IVec2 { x: 7, y: 5 });
|
||||||
|
self.gsa2.bg[2].tiles[pos.x as usize + 3][pos.y as usize + 1] = TILE_INPUT;
|
||||||
|
self.gsa2.bg[2].tiles[pos.x as usize + 4][pos.y as usize + 1] = TILE_INPUT;
|
||||||
|
self.gsa2.bg[2].tiles[pos.x as usize + 1][pos.y as usize + 3] = TILE_BUT_YES;
|
||||||
|
self.gsa2.bg[2].tiles[pos.x as usize + 5][pos.y as usize + 3] = TILE_BUT_NO;
|
||||||
|
self.gsa2.write_string(
|
||||||
|
IVec2 {
|
||||||
|
x: pos.x * 2 + 2,
|
||||||
|
y: pos.y * 2 + 1,
|
||||||
|
},
|
||||||
|
caption,
|
||||||
|
);
|
||||||
|
self.gsa2.write_string(
|
||||||
|
IVec2 {
|
||||||
|
x: pos.x * 2 + 3,
|
||||||
|
y: pos.y * 2 + 3,
|
||||||
|
},
|
||||||
|
"ID:0000",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw_toolbar(&mut self) {
|
||||||
|
self.gsa2.bg[2].clear();
|
||||||
|
self.gsa2.bg[3].clear();
|
||||||
|
|
||||||
|
//vertical
|
||||||
|
for y in 0..(self.window_tile_size.y - 1) {
|
||||||
|
self.gsa2.bg[2].tiles[0][y as usize] = 0x7010;
|
||||||
|
}
|
||||||
|
self.gsa2.bg[2].tiles[0][BUT_SAVE] = 0x7211;
|
||||||
|
self.gsa2.bg[2].tiles[0][BUT_CREATE] = TILE_BUT_CREATE;
|
||||||
|
self.gsa2.bg[2].tiles[0][BUT_EXIT] = 0x7212;
|
||||||
|
|
||||||
|
//layer buttons
|
||||||
|
self.gsa2.bg[2].tiles[0][BUT_LAYER1] = if self.current_layer == 0 {
|
||||||
|
0x7111
|
||||||
|
} else {
|
||||||
|
0x7011
|
||||||
|
};
|
||||||
|
self.gsa2.bg[2].tiles[0][BUT_LAYER2] = if self.current_layer == 1 {
|
||||||
|
0x7112
|
||||||
|
} else {
|
||||||
|
0x7012
|
||||||
|
};
|
||||||
|
self.gsa2.bg[2].tiles[0][BUT_LAYER3] = if self.current_layer == 2 {
|
||||||
|
0x7113
|
||||||
|
} else {
|
||||||
|
0x7013
|
||||||
|
};
|
||||||
|
self.gsa2.bg[2].tiles[0][BUT_LAYERS] = if self.all_layers { 0x7114 } else { 0x7014 };
|
||||||
|
|
||||||
|
self.gsa2.bg[2].size = IVec2 { x: 120, y: 68 }; //enough to cover 4k monitors? <_<
|
||||||
|
self.gsa2.bg[3].size = IVec2 { x: 240, y: 136 };
|
||||||
|
|
||||||
|
//horizontal
|
||||||
|
let bottom = self.window_tile_size.y as usize - 1;
|
||||||
|
self.gsa2.bg[2].tiles[0][bottom] = 0x7410;
|
||||||
|
for x in 1..self.window_tile_size.x {
|
||||||
|
self.gsa2.bg[2].tiles[x as usize][bottom] = 0x7310;
|
||||||
|
}
|
||||||
|
self.update_status_bar();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_state(&mut self, state: State) {
|
||||||
|
self.state = state;
|
||||||
|
match state {
|
||||||
|
State::Edit => {
|
||||||
|
//update editing layers
|
||||||
|
if self.all_layers {
|
||||||
|
self.gsa1.bg[0].active = true;
|
||||||
|
self.gsa1.bg[1].active = true;
|
||||||
|
self.gsa1.bg[2].active = true;
|
||||||
|
} else {
|
||||||
|
self.gsa1.bg[0].active = self.current_layer == 0;
|
||||||
|
self.gsa1.bg[1].active = self.current_layer == 1;
|
||||||
|
self.gsa1.bg[2].active = self.current_layer == 2;
|
||||||
|
}
|
||||||
|
self.draw_toolbar();
|
||||||
|
|
||||||
|
self.gsa2.bg[0].active = false;
|
||||||
|
self.gsa2.bg[1].active = false;
|
||||||
|
self.gsa1.sprite[SPR_CURSOR].priority = 3;
|
||||||
|
self.gsa1.sprite[SPR_CURSOR].tile = TILE_CURSOR;
|
||||||
|
self.gsa2.sprite[SPR_CURSOR].tile = EMPTY_TILE;
|
||||||
|
}
|
||||||
|
State::SelectTile => {
|
||||||
|
self.draw_toolbar();
|
||||||
|
self.gsa1.bg[0].active = false;
|
||||||
|
self.gsa1.bg[1].active = false;
|
||||||
|
self.gsa1.bg[2].active = false;
|
||||||
|
self.gsa2.bg[0].active = true;
|
||||||
|
self.gsa2.bg[1].active = true;
|
||||||
|
self.gsa1.sprite[SPR_CURSOR].tile = EMPTY_TILE;
|
||||||
|
self.gsa2.sprite[SPR_CURSOR].tile = TILE_CURSOR;
|
||||||
|
}
|
||||||
|
State::NewMapDialog => {
|
||||||
|
self.gsa1.bg[0].active = false;
|
||||||
|
self.gsa1.bg[1].active = false;
|
||||||
|
self.gsa1.bg[2].active = false;
|
||||||
|
self.gsa2.bg[0].active = false;
|
||||||
|
self.gsa2.bg[1].active = false;
|
||||||
|
self.gsa1.sprite[SPR_CURSOR].tile = EMPTY_TILE;
|
||||||
|
self.gsa2.sprite[SPR_CURSOR].tile = EMPTY_TILE;
|
||||||
|
self.draw_input_window(IVec2 { x: 15, y: 9 }, "Create Map");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_input_window(&mut self, pos: IVec2, val: u16) {
|
||||||
|
self.gsa2.write_string(
|
||||||
|
IVec2 {
|
||||||
|
x: pos.x * 2 + 6,
|
||||||
|
y: pos.y * 2 + 3,
|
||||||
|
},
|
||||||
|
&format!("{:04x}", val),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_status_bar(&mut self) {
|
||||||
|
let bottom = self.window_tile_size.y as usize - 1;
|
||||||
|
let text_bottom = (bottom * 2 + 1) as i32;
|
||||||
|
|
||||||
|
self.gsa2.write_string(
|
||||||
|
IVec2 {
|
||||||
|
x: 0,
|
||||||
|
y: text_bottom,
|
||||||
|
},
|
||||||
|
&" ".repeat(self.window_tile_size.x as usize * 2),
|
||||||
|
);
|
||||||
|
self.gsa2.write_string(
|
||||||
|
IVec2 {
|
||||||
|
x: 1,
|
||||||
|
y: text_bottom,
|
||||||
|
},
|
||||||
|
&format!("Map:{:04X}", self.current_map),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.gsa2.write_string(
|
||||||
|
IVec2 {
|
||||||
|
x: 17,
|
||||||
|
y: text_bottom,
|
||||||
|
},
|
||||||
|
&format!("Size:{}*{}", self.gsa1.bg[0].size.x, self.gsa1.bg[0].size.y),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.gsa2.write_string(
|
||||||
|
IVec2 {
|
||||||
|
x: 33,
|
||||||
|
y: text_bottom,
|
||||||
|
},
|
||||||
|
&format!("Cursor:{}*{}", self.tile_pos.x, self.tile_pos.y),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
use glam::IVec2;
|
||||||
|
|
||||||
|
pub struct Surface<'a> {
|
||||||
|
pub data: &'a mut [u8],
|
||||||
|
pub size: IVec2,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Surface<'a> {
|
||||||
|
pub fn draw_vline(&mut self, pos: IVec2, len: i32, color: u8) {
|
||||||
|
for i in 0..len {
|
||||||
|
self.data[(pos.x + (pos.y + i) * self.size.x) as usize] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw_hline(&mut self, pos: IVec2, len: i32, color: u8) {
|
||||||
|
for i in 0..len {
|
||||||
|
self.data[(pos.x + i + pos.y * self.size.x) as usize] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
use winit::event::VirtualKeyCode;
|
||||||
|
|
||||||
|
pub fn key_to_num(key: VirtualKeyCode) -> u16 {
|
||||||
|
match key {
|
||||||
|
VirtualKeyCode::Key0 => 0x0,
|
||||||
|
VirtualKeyCode::Key1 => 0x1,
|
||||||
|
VirtualKeyCode::Key2 => 0x2,
|
||||||
|
VirtualKeyCode::Key3 => 0x3,
|
||||||
|
VirtualKeyCode::Key4 => 0x4,
|
||||||
|
VirtualKeyCode::Key5 => 0x5,
|
||||||
|
VirtualKeyCode::Key6 => 0x6,
|
||||||
|
VirtualKeyCode::Key7 => 0x7,
|
||||||
|
VirtualKeyCode::Key8 => 0x8,
|
||||||
|
VirtualKeyCode::Key9 => 0x9,
|
||||||
|
VirtualKeyCode::A => 0xa,
|
||||||
|
VirtualKeyCode::B => 0xb,
|
||||||
|
VirtualKeyCode::C => 0xc,
|
||||||
|
VirtualKeyCode::D => 0xd,
|
||||||
|
VirtualKeyCode::E => 0xe,
|
||||||
|
VirtualKeyCode::F => 0xf,
|
||||||
|
_ => 0x0,
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::buttons::{button_from_gilrs, button_from_scancode};
|
use crate::buttons::{button_from_gilrs, button_from_scancode};
|
||||||
use crate::gsa_render_to_screen::{render_to_screen, render_to_window};
|
use crate::gsa_render_to_screen::{render_to_screen, render_to_window};
|
||||||
use crate::maps::Maps;
|
|
||||||
use crate::tileset::load_tileset;
|
use crate::tileset::load_tileset;
|
||||||
use crate::{
|
use crate::{
|
||||||
Buttons, Gsa, Sprite, FONT_BOLD, MAX_SPRITES, SCREEN_HEIGHT, SCREEN_WIDTH, TRANSPARENT,
|
Buttons, Gsa, Sprite, FONT_BOLD, MAX_SPRITES, SCREEN_HEIGHT, SCREEN_WIDTH, TRANSPARENT,
|
||||||
|
|
Loading…
Reference in New Issue