summaryrefslogtreecommitdiff
path: root/pixel-client/tools
diff options
context:
space:
mode:
Diffstat (limited to 'pixel-client/tools')
-rw-r--r--pixel-client/tools/Cargo.toml12
-rw-r--r--pixel-client/tools/src/bin/bunnymark.rs104
-rw-r--r--pixel-client/tools/src/bin/tex_compose.rs135
-rw-r--r--pixel-client/tools/src/bin/tex_export.rs75
-rw-r--r--pixel-client/tools/src/bin/tex_import.rs75
-rw-r--r--pixel-client/tools/src/bin/tex_pack.rs95
-rw-r--r--pixel-client/tools/src/lib.rs0
7 files changed, 496 insertions, 0 deletions
diff --git a/pixel-client/tools/Cargo.toml b/pixel-client/tools/Cargo.toml
new file mode 100644
index 00000000..f3075594
--- /dev/null
+++ b/pixel-client/tools/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "tools"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+image = "0.25.1"
+anyhow = "1.0.86"
+log = "0.4.22"
+env_logger = "0.11.3"
+clap = { version = "4.5.9", features = ["derive"] }
+sdl2 = "0.37.0"
diff --git a/pixel-client/tools/src/bin/bunnymark.rs b/pixel-client/tools/src/bin/bunnymark.rs
new file mode 100644
index 00000000..f59fecff
--- /dev/null
+++ b/pixel-client/tools/src/bin/bunnymark.rs
@@ -0,0 +1,104 @@
+/*
+ Hurry Curry! - a game about cooking
+ Copyright 2024 metamuffin
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, version 3 of the License only.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+*/
+use sdl2::{
+ event::Event,
+ image::{InitFlag, LoadTexture},
+ keyboard::Keycode,
+ pixels::Color,
+ rect::Rect,
+};
+use std::time::Instant;
+
+const WIDTH: i32 = 1920;
+const HEIGHT: i32 = 1080;
+
+pub fn main() {
+ let amount = std::env::args().skip(1).next().unwrap().parse().unwrap();
+
+ let sdl_context = sdl2::init().unwrap();
+ let video_subsystem = sdl_context.video().unwrap();
+ let _image_context = sdl2::image::init(InitFlag::WEBP | InitFlag::PNG).unwrap();
+ let window = video_subsystem
+ .window("Hurry Curry! Bunnymark", WIDTH as u32, HEIGHT as u32)
+ .position_centered()
+ .build()
+ .map_err(|e| e.to_string())
+ .unwrap();
+
+ let mut canvas = window
+ .into_canvas()
+ .accelerated()
+ .build()
+ .map_err(|e| e.to_string())
+ .unwrap();
+ let texture_creator = canvas.texture_creator();
+ let texture = texture_creator.load_texture("client/icon.png").unwrap();
+
+ let mut bunnies = vec![((0, 0), (0, 0)); amount];
+
+ for (i, (pos, vel)) in bunnies.iter_mut().enumerate() {
+ let mut r = xorshift(i as i32);
+ pos.0 = r % WIDTH;
+ r = xorshift(r);
+ pos.1 = r % HEIGHT;
+ r = xorshift(r);
+ vel.0 = r % 7 - 3;
+ r = xorshift(r);
+ vel.1 = r % 7 - 3;
+ }
+
+ let mut last = Instant::now();
+ 'mainloop: loop {
+ canvas.set_draw_color(Color::BLACK);
+ canvas.clear();
+ for (pos, vel) in &mut bunnies {
+ pos.0 += vel.0;
+ pos.1 += vel.1;
+ if pos.0 < 0 || pos.0 > WIDTH {
+ vel.0 *= -1
+ }
+ if pos.1 < 0 || pos.1 > HEIGHT {
+ vel.1 *= -1
+ }
+ canvas
+ .copy(&texture, None, Some(Rect::new(pos.0, pos.1, 30, 30)))
+ .unwrap();
+ }
+ canvas.present();
+
+ for event in sdl_context.event_pump().unwrap().poll_iter() {
+ match event {
+ Event::Quit { .. }
+ | Event::KeyDown {
+ keycode: Option::Some(Keycode::Escape),
+ ..
+ } => break 'mainloop,
+ _ => {}
+ }
+ }
+ println!("frame time: {:?}", last.elapsed());
+ last = Instant::now();
+ }
+}
+
+fn xorshift(mut x: i32) -> i32 {
+ x ^= x << 13;
+ x ^= x >> 17;
+ x ^= x << 5;
+ x
+}
diff --git a/pixel-client/tools/src/bin/tex_compose.rs b/pixel-client/tools/src/bin/tex_compose.rs
new file mode 100644
index 00000000..19c9ed7c
--- /dev/null
+++ b/pixel-client/tools/src/bin/tex_compose.rs
@@ -0,0 +1,135 @@
+/*
+ Hurry Curry! - a game about cooking
+ Copyright 2024 metamuffin
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, version 3 of the License only.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+*/
+use clap::Parser;
+use std::{
+ collections::HashMap,
+ fs::{read_to_string, File},
+ io::{BufRead, BufReader, BufWriter, Write},
+ path::PathBuf,
+};
+
+#[derive(Parser)]
+struct Args {
+ catalogue: PathBuf,
+ texture_dir: PathBuf,
+ output_dir: PathBuf,
+}
+
+fn main() {
+ let Args {
+ catalogue,
+ texture_dir,
+ output_dir,
+ } = Args::parse();
+
+ for line in read_to_string(catalogue).unwrap().lines() {
+ let (line, _) = line.split_once(";").unwrap_or((line, ""));
+ let line = line.trim();
+ if line.is_empty() {
+ continue;
+ }
+
+ let (name, rest) = line.split_once("=").unwrap();
+ let (connects, rest) = rest.split_once(":").unwrap_or(("a", rest));
+ eprintln!(" compose {name:?} ({connects})");
+
+ let mut texels = HashMap::new();
+
+ for part in rest.split(",") {
+ let mut mods = part.split("~");
+ let texname = mods.next().unwrap();
+
+ let mut hflip = false;
+ let mut vflip = true;
+ let mut xoff = 0;
+ let mut yoff = 0;
+
+ for m in mods {
+ if m == "hflip" {
+ hflip = !hflip
+ }
+ if m == "vflip" {
+ vflip = !vflip
+ }
+ if let Some(m) = m.strip_prefix("x") {
+ xoff += m.parse::<i32>().unwrap();
+ }
+ if let Some(m) = m.strip_prefix("y") {
+ yoff += m.parse::<i32>().unwrap();
+ }
+ }
+
+ let texpath = texture_dir.join(texname).with_extension("ta");
+ eprintln!(" + {texpath:?}");
+ let file = BufReader::new(File::open(&texpath).unwrap());
+ let tex = file.lines().map(Result::unwrap).collect::<Vec<String>>();
+ let (width, height) = (tex[0].chars().count(), tex.len());
+
+ for (mut y, line) in tex.iter().enumerate() {
+ if line.is_empty() {
+ continue;
+ }
+ if vflip {
+ y = height - y - 1
+ }
+ for (mut x, char) in line.chars().enumerate() {
+ if hflip {
+ x = width - x - 1
+ }
+ let e = texels
+ .entry((x as i32 + xoff, y as i32 + yoff))
+ .or_insert(' ');
+ if char != ' ' {
+ *e = char
+ }
+ }
+ }
+ }
+
+ let mut min_x = 0;
+ let mut min_y = 0;
+ let mut max_x = 0;
+ let mut max_y = 0;
+ for (x, y) in texels.keys() {
+ min_x = min_x.min(*x);
+ min_y = min_y.min(*y);
+ max_x = max_x.max(*x + 1);
+ max_y = max_y.max(*y + 1);
+ }
+
+ let width = max_x - min_x;
+ let height = max_y - min_y;
+
+ let outpath = output_dir
+ .join(format!("{name}+{connects}"))
+ .with_extension("ta");
+ let mut output = BufWriter::new(File::create(outpath).unwrap());
+
+ for y in 0..height {
+ for x in 0..width {
+ write!(
+ output,
+ "{}",
+ texels.get(&(x + min_x, max_y - y - 1)).unwrap_or(&' ')
+ )
+ .unwrap();
+ }
+ writeln!(output).unwrap();
+ }
+ }
+}
diff --git a/pixel-client/tools/src/bin/tex_export.rs b/pixel-client/tools/src/bin/tex_export.rs
new file mode 100644
index 00000000..248990e6
--- /dev/null
+++ b/pixel-client/tools/src/bin/tex_export.rs
@@ -0,0 +1,75 @@
+/*
+ Hurry Curry! - a game about cooking
+ Copyright 2024 metamuffin
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, version 3 of the License only.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+*/
+use clap::Parser;
+use image::Rgba;
+use std::{
+ collections::HashMap,
+ fs::File,
+ io::{BufRead, BufReader},
+ path::PathBuf,
+};
+
+#[derive(Parser)]
+struct Args {
+ input: PathBuf,
+ output: PathBuf,
+}
+
+fn main() {
+ let Args {
+ input,
+ output: out_path,
+ } = Args::parse();
+
+ let palette = include_str!("../../../assets/palette.csv")
+ .split('\n')
+ .filter(|l| !l.is_empty())
+ .map(|s| {
+ let (c, s) = s.split_once(",").unwrap();
+ let (r, s) = s.split_once(",").unwrap();
+ let (g, s) = s.split_once(",").unwrap();
+ let (b, a) = s.split_once(",").unwrap();
+ (
+ c.chars().next().unwrap(),
+ [
+ r.parse().unwrap(),
+ g.parse().unwrap(),
+ b.parse().unwrap(),
+ a.parse().unwrap(),
+ ],
+ )
+ })
+ .collect::<HashMap<_, _>>();
+
+ let file = BufReader::new(File::open(&input).unwrap());
+ let tex = file.lines().map(Result::unwrap).collect::<Vec<String>>();
+ let (width, height) = (tex[0].chars().count(), tex.len());
+
+ let mut output = image::ImageBuffer::<Rgba<u8>, Vec<_>>::new(width as u32, height as u32);
+
+ for (y, line) in tex.iter().enumerate() {
+ if line.is_empty() {
+ continue;
+ }
+ for (x, char) in line.chars().enumerate() {
+ output.put_pixel(x as u32, y as u32, Rgba(*palette.get(&char).unwrap()));
+ }
+ }
+
+ output.save(out_path).unwrap();
+}
diff --git a/pixel-client/tools/src/bin/tex_import.rs b/pixel-client/tools/src/bin/tex_import.rs
new file mode 100644
index 00000000..a5dad499
--- /dev/null
+++ b/pixel-client/tools/src/bin/tex_import.rs
@@ -0,0 +1,75 @@
+/*
+ Hurry Curry! - a game about cooking
+ Copyright 2024 metamuffin
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, version 3 of the License only.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+*/
+use clap::Parser;
+use std::{
+ collections::HashMap,
+ fs::File,
+ io::{BufWriter, Write},
+ path::PathBuf,
+ process::exit,
+};
+
+#[derive(Parser)]
+struct Args {
+ input: PathBuf,
+ output: PathBuf,
+}
+
+fn main() {
+ let Args { input, output } = Args::parse();
+
+ let palette = include_str!("../../../assets/palette.csv")
+ .split('\n')
+ .filter(|l| !l.is_empty())
+ .map(|s| {
+ let (c, s) = s.split_once(",").unwrap();
+ let (r, s) = s.split_once(",").unwrap();
+ let (g, s) = s.split_once(",").unwrap();
+ let (b, a) = s.split_once(",").unwrap();
+ (
+ [
+ r.parse().unwrap(),
+ g.parse().unwrap(),
+ b.parse().unwrap(),
+ a.parse().unwrap(),
+ ],
+ c.chars().next().unwrap(),
+ )
+ })
+ .collect::<HashMap<_, _>>();
+
+ let input = image::open(input).unwrap().to_rgba8();
+ let mut output = BufWriter::new(File::create(output).unwrap());
+
+ for y in 0..input.height() {
+ for x in 0..input.width() {
+ let mut c = input.get_pixel(x, y).0;
+ if c[3] == 0 {
+ c = [0, 0, 0, 0];
+ }
+ let Some(char) = palette.get(&c) else {
+ eprintln!("color at {x},{y} not in palette: {c:?}");
+ exit(1);
+ };
+ write!(output, "{char}").unwrap();
+ }
+ writeln!(output).unwrap();
+ }
+ output.flush().unwrap();
+ output.into_inner().unwrap().flush().unwrap()
+}
diff --git a/pixel-client/tools/src/bin/tex_pack.rs b/pixel-client/tools/src/bin/tex_pack.rs
new file mode 100644
index 00000000..5022d561
--- /dev/null
+++ b/pixel-client/tools/src/bin/tex_pack.rs
@@ -0,0 +1,95 @@
+/*
+ Hurry Curry! - a game about cooking
+ Copyright 2024 metamuffin
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, version 3 of the License only.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+*/
+use clap::Parser;
+use std::{
+ fs::File,
+ io::{BufRead, BufReader, BufWriter, Write},
+ path::PathBuf,
+};
+
+#[derive(Parser)]
+struct Args {
+ atlas_out: PathBuf,
+ atlas_meta_out: PathBuf,
+ inputs: Vec<PathBuf>,
+}
+
+fn main() {
+ let Args {
+ inputs,
+ atlas_meta_out,
+ atlas_out,
+ } = Args::parse();
+
+ let atlas_size = 1024;
+
+ let mut cursor_x = 0;
+ let mut cursor_y = 0;
+ let mut row_height = 0;
+
+ let mut texels = vec![vec![' '; atlas_size]; atlas_size];
+ let mut metadata = Vec::new();
+
+ println!(" savepack {atlas_out:?}");
+ for path in inputs {
+ let file = BufReader::new(File::open(&path).unwrap());
+ let tex = file.lines().map(Result::unwrap).collect::<Vec<String>>();
+ let name = path.file_stem().unwrap().to_str().unwrap().to_string();
+ let (width, height) = (tex[0].chars().count(), tex.len());
+
+ println!(" + {width}x{height} {name}");
+
+ if cursor_x + width > atlas_size {
+ cursor_y += row_height;
+ row_height = 0;
+ cursor_x = 0;
+ }
+ if cursor_y + height > atlas_size {
+ panic!("texture too big or atlas full");
+ }
+ row_height = row_height.max(height);
+ let texcoord = [cursor_x, cursor_y, width, height];
+
+ for (y, line) in tex.iter().enumerate() {
+ if line.is_empty() {
+ continue;
+ }
+ for (x, char) in line.chars().enumerate() {
+ texels[cursor_y + y][cursor_x + x] = char;
+ }
+ }
+
+ metadata.push((texcoord, name));
+
+ cursor_x += width;
+ }
+
+ let mut atlas_out = BufWriter::new(File::create(atlas_out).unwrap());
+ let mut atlas_meta_out = BufWriter::new(File::create(atlas_meta_out).unwrap());
+
+ for line in texels {
+ for char in line {
+ write!(atlas_out, "{char}").unwrap()
+ }
+ writeln!(atlas_out).unwrap();
+ }
+
+ for ([x, y, w, h], name) in metadata {
+ writeln!(atlas_meta_out, "{x},{y},{w},{h},{name}").unwrap();
+ }
+}
diff --git a/pixel-client/tools/src/lib.rs b/pixel-client/tools/src/lib.rs
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/pixel-client/tools/src/lib.rs