Crates.io | png2wasm4src |
lib.rs | png2wasm4src |
version | 0.1.0 |
source | src |
created_at | 2021-10-18 21:41:44.31957 |
updated_at | 2021-10-18 21:41:44.31957 |
description | Convert indexed PNG images to Rust source code for WASM-4 engine |
homepage | |
repository | https://gitlab.com/claudiomattera/png2wasm4src |
max_upload_size | |
id | 467025 |
size | 61,790 |
Convert indexed PNG images to Rust source code for WASM-4 engine.
https://gitlab.com/claudiomattera/png2wasm4src
WASM-4 is an old-style fantasy game console implemented in WebAssembly.
Games can be developed in Rust (and in other languages), and the runtime has support for drawing sprites.
Sprites must either have a bit depth of one bit per pixel, or two bits per pixel, and must be properly encoded in variables, which can be done using the WASM-4 w4
command-line application.
This crate allows to perform the conversion from within Rust code, which allows to dynamically create variables from PNG images using a build.rs
build script.
This crate can be used to automatically generate Rust variables from PNG images on cargo build
.
This way the Rust variables always reflect the current PNG image, and there is no risk of forgetting to update them.
Assume the following crate structure.
Directory assets
contains a subdirectory sprites
, which contains all the sprites.
Sprites are organized in subdirectories: sprite letters.png
is inside directory fonts
, and sprite tiles.png
is inside directory tiles
.
.
├── assets
│ └── sprites
│ ├── fonts
│ │ └── letters.png
│ └── tiles
│ └── tiles.png
├── build.rs
├── Cargo.lock
├── Cargo.toml
└── src
└── lib.rs
Now it is possible to generate the Rust code from the sprites PNG image inside a build.rs
build script.
use std::env::var;
use std::fs::{File, OpenOptions};
use std::io::Write;
use std::path::PathBuf;
use anyhow::Result;
use png2wasm4src::build_sprite_modules_tree;
fn main() -> Result<()> {
let module = build_sprite_modules_tree("assets/sprites")?;
// Instruct cargo to re-run the build script if any source PNGs are changed
// cargo:rerun-if-changed=assets/sprites/player.png
// cargo:rerun-if-changed=assets/sprites/monsters/slime.png
// cargo:rerun-if-changed=assets/sprites/monsters/bandit.png
let mut cargo_instructions = String::default();
module.generate_cargo_build_instructions(&mut cargo_instructions)?;
println!("{}", cargo_instructions);
let mut output_file = open_output_file()?;
let module = module.parse()?;
writeln!(output_file, "{}", module)?;
Ok(())
}
fn open_output_file() -> Result<File> {
let output_directory = PathBuf::from(var("OUT_DIR")?);
let output_path = output_directory.join("sprites.rs");
let output_file = OpenOptions::new()
.write(true)
.create(true)
.open(output_path)?;
Ok(output_file)
}
The build script generates the following code, and writes it into the file ${OUT_DIR}/sprites.rs
.
pub mod sprites {
pub mod fonts {
pub const LETTERS_WIDTH: u32 = 320;
pub const LETTERS_HEIGHT: u32 = 32;
pub const LETTERS_FLAGS: u32 = 1; // BLIT_2BPP
pub const LETTERS: [u8; 200] = [0x12, 0x34, 0x56...];
}
pub mod tiles {
pub const TILES_WIDTH: u32 = 32;
pub const TILES_HEIGHT: u32 = 32;
pub const TILES_FLAGS: u32 = 0; // BLIT_1BPP
pub const TILES: [u8; 30] = [0x12, 0x34, 0x56...];
}
}
From any of the crate modules (for instance in lib.rs
) it is possible to include that file, and use all entities defined there.
use wasm::*;
// Include the generated file in the current module.
//
// Note: this is done at top level, not inside any function (but it could be
// inside a module).
include!(concat!(env!("OUT_DIR"), "/sprites.rs"));
fn draw_sprite() {
blit(
sprites::tiles::TILES,
10,
10,
sprites::tiles::TILES_WIDTH,
sprites::tiles::TILES_HEIGHT,
sprites::tiles::TILES_FLAGS,
);
blit(
sprites::fonts::LETTERS,
10,
10,
sprites::fonts::LETTERS_WIDTH,
sprites::fonts::LETTERS_HEIGHT,
sprites::fonts::LETTERS_FLAGS,
);
}
Copyright Claudio Mattera 2021
You are free to copy, modify, and distribute this application with attribution under the terms of the MIT license. See the License.txt
file for details.