mirror of
https://github.com/italicsjenga/agb.git
synced 2025-01-11 09:31:34 +11:00
commit
70f6e25a7c
3
.github/workflows/rust.yml
vendored
3
.github/workflows/rust.yml
vendored
|
@ -46,6 +46,9 @@ jobs:
|
|||
- name: Run Clippy on agb
|
||||
working-directory: agb
|
||||
run: cargo clippy --verbose
|
||||
- name: Run Clippy on agb image converter
|
||||
working-directory: agb-image-converter
|
||||
run: cargo clippy --verbose
|
||||
- name: Run Tests for agb
|
||||
working-directory: agb
|
||||
run: cargo test --verbose
|
||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,3 +1,3 @@
|
|||
*/target
|
||||
target
|
||||
/out
|
||||
/.vscode
|
||||
|
|
332
agb-image-converter/Cargo.lock
generated
Normal file
332
agb-image-converter/Cargo.lock
generated
Normal file
|
@ -0,0 +1,332 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "adler32"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
|
||||
|
||||
[[package]]
|
||||
name = "agb_image_converter"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"image",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bed57e2090563b83ba8f83366628ce535a7584c9afa4c9fc0612a03925c6df58"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "color_quant"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2584f639eb95fea8c798496315b297cf81b9b58b6d30ab066a75455333cf4b12"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"lazy_static",
|
||||
"memoffset",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deflate"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174"
|
||||
dependencies = [
|
||||
"adler32",
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||
|
||||
[[package]]
|
||||
name = "gif"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a668f699973d0f573d15749b7002a9ac9e1f9c6b220e7b165601334c173d8de"
|
||||
dependencies = [
|
||||
"color_quant",
|
||||
"weezl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.23.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"byteorder",
|
||||
"color_quant",
|
||||
"gif",
|
||||
"jpeg-decoder",
|
||||
"num-iter",
|
||||
"num-rational",
|
||||
"num-traits",
|
||||
"png",
|
||||
"scoped_threadpool",
|
||||
"tiff",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jpeg-decoder"
|
||||
version = "0.1.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2"
|
||||
dependencies = [
|
||||
"rayon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f83fb6581e8ed1f85fd45c116db8405483899489e38406156c25eb743554361d"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435"
|
||||
dependencies = [
|
||||
"adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
|
||||
dependencies = [
|
||||
"adler",
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-iter"
|
||||
version = "0.1.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.16.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"crc32fast",
|
||||
"deflate",
|
||||
"miniz_oxide 0.3.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"crossbeam-deque",
|
||||
"either",
|
||||
"rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
"lazy_static",
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scoped_threadpool"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "tiff"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a53f4706d65497df0c4349241deddf35f84cee19c87ed86ea8ca590f4464437"
|
||||
dependencies = [
|
||||
"jpeg-decoder",
|
||||
"miniz_oxide 0.4.4",
|
||||
"weezl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "weezl"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8b77fdfd5a253be4ab714e4ffa3c49caf146b4de743e97510c0656cf90f1e8e"
|
8
agb-image-converter/Cargo.toml
Normal file
8
agb-image-converter/Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "agb_image_converter"
|
||||
version = "0.1.0"
|
||||
authors = ["Gwilym Kuiper <gw@ilym.me>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
image = "0.23.14"
|
16
agb-image-converter/src/bin/convert.rs
Normal file
16
agb-image-converter/src/bin/convert.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
use std::env;
|
||||
|
||||
use agb_image_converter::{convert_image, ImageConverterConfig, TileSize};
|
||||
|
||||
fn main() {
|
||||
let args: Vec<_> = env::args().collect();
|
||||
|
||||
let file_path = &args[1];
|
||||
let output_path = &args[2];
|
||||
convert_image(&ImageConverterConfig {
|
||||
transparent_colour: None,
|
||||
tile_size: TileSize::Tile8,
|
||||
input_image: file_path.into(),
|
||||
output_file: output_path.into(),
|
||||
});
|
||||
}
|
17
agb-image-converter/src/colour.rs
Normal file
17
agb-image-converter/src/colour.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct Colour {
|
||||
pub r: u8,
|
||||
pub g: u8,
|
||||
pub b: u8,
|
||||
}
|
||||
|
||||
impl Colour {
|
||||
pub fn from_rgb(r: u8, g: u8, b: u8) -> Self {
|
||||
Colour { r, g, b }
|
||||
}
|
||||
|
||||
pub fn to_rgb15(self) -> u16 {
|
||||
let (r, g, b) = (self.r as u16, self.g as u16, self.b as u16);
|
||||
((r >> 3) & 31) | (((g >> 3) & 31) << 5) | (((b >> 3) & 31) << 10)
|
||||
}
|
||||
}
|
37
agb-image-converter/src/image_loader.rs
Normal file
37
agb-image-converter/src/image_loader.rs
Normal file
|
@ -0,0 +1,37 @@
|
|||
use std::path;
|
||||
|
||||
use image::GenericImageView;
|
||||
|
||||
use crate::colour::Colour;
|
||||
|
||||
pub(crate) struct Image {
|
||||
pub width: usize,
|
||||
pub height: usize,
|
||||
colour_data: Vec<Colour>,
|
||||
}
|
||||
|
||||
impl Image {
|
||||
pub fn load_from_file(image_path: &path::Path) -> Self {
|
||||
let img = image::open(image_path).expect("Expected image to exist");
|
||||
let (width, height) = img.dimensions();
|
||||
|
||||
let width = width as usize;
|
||||
let height = height as usize;
|
||||
|
||||
let mut colour_data = Vec::with_capacity(width * height);
|
||||
|
||||
for (_, _, pixel) in img.pixels() {
|
||||
colour_data.push(Colour::from_rgb(pixel[0], pixel[1], pixel[2]));
|
||||
}
|
||||
|
||||
Image {
|
||||
width,
|
||||
height,
|
||||
colour_data,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn colour(&self, x: usize, y: usize) -> Colour {
|
||||
self.colour_data[x + y * self.width]
|
||||
}
|
||||
}
|
82
agb-image-converter/src/lib.rs
Normal file
82
agb-image-converter/src/lib.rs
Normal file
|
@ -0,0 +1,82 @@
|
|||
use std::fs::File;
|
||||
use std::io::BufWriter;
|
||||
use std::path::PathBuf;
|
||||
|
||||
mod colour;
|
||||
mod image_loader;
|
||||
mod palette16;
|
||||
mod rust_generator;
|
||||
|
||||
use image_loader::Image;
|
||||
|
||||
pub use colour::Colour;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum TileSize {
|
||||
Tile8,
|
||||
Tile16,
|
||||
}
|
||||
|
||||
impl TileSize {
|
||||
fn to_size(self) -> usize {
|
||||
match self {
|
||||
TileSize::Tile8 => 8,
|
||||
TileSize::Tile16 => 16,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ImageConverterConfig {
|
||||
pub transparent_colour: Option<Colour>,
|
||||
pub tile_size: TileSize,
|
||||
pub input_image: PathBuf,
|
||||
pub output_file: PathBuf,
|
||||
}
|
||||
|
||||
pub fn convert_image(settings: &ImageConverterConfig) {
|
||||
let image = Image::load_from_file(&settings.input_image);
|
||||
|
||||
let tile_size = settings.tile_size.to_size();
|
||||
if image.width % tile_size != 0 || image.height % tile_size != 0 {
|
||||
panic!("Image size not a multiple of tile size");
|
||||
}
|
||||
|
||||
let optimiser = optimiser_for_image(&image, tile_size);
|
||||
let optimisation_results = optimiser.optimise_palettes(settings.transparent_colour);
|
||||
|
||||
let output_file = File::create(&settings.output_file).expect("Failed to create file");
|
||||
let mut writer = BufWriter::new(output_file);
|
||||
|
||||
rust_generator::generate_code(
|
||||
&mut writer,
|
||||
&optimisation_results,
|
||||
&image,
|
||||
settings.tile_size,
|
||||
)
|
||||
.expect("Failed to write data");
|
||||
}
|
||||
|
||||
fn optimiser_for_image(image: &Image, tile_size: usize) -> palette16::Palette16Optimiser {
|
||||
let tiles_x = image.width / tile_size;
|
||||
let tiles_y = image.height / tile_size;
|
||||
|
||||
let mut palette_optimiser = palette16::Palette16Optimiser::new();
|
||||
|
||||
for y in 0..tiles_y {
|
||||
for x in 0..tiles_x {
|
||||
let mut palette = palette16::Palette16::new();
|
||||
|
||||
for j in 0..tile_size {
|
||||
for i in 0..tile_size {
|
||||
let colour = image.colour(x * tile_size + i, y * tile_size + j);
|
||||
|
||||
palette.add_colour(colour);
|
||||
}
|
||||
}
|
||||
|
||||
palette_optimiser.add_palette(palette);
|
||||
}
|
||||
}
|
||||
|
||||
palette_optimiser
|
||||
}
|
189
agb-image-converter/src/palette16.rs
Normal file
189
agb-image-converter/src/palette16.rs
Normal file
|
@ -0,0 +1,189 @@
|
|||
use crate::colour::Colour;
|
||||
use std::collections::HashSet;
|
||||
|
||||
const MAX_COLOURS: usize = 256;
|
||||
const MAX_COLOURS_PER_PALETTE: usize = 16;
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
pub(crate) struct Palette16 {
|
||||
colours: Vec<Colour>,
|
||||
}
|
||||
|
||||
impl Palette16 {
|
||||
pub fn new() -> Self {
|
||||
Palette16 {
|
||||
colours: Vec::with_capacity(MAX_COLOURS_PER_PALETTE),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_colour(&mut self, colour: Colour) -> bool {
|
||||
if self.colours.contains(&colour) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if self.colours.len() == MAX_COLOURS_PER_PALETTE {
|
||||
panic!("Can have at most 16 colours in a single palette");
|
||||
}
|
||||
self.colours.push(colour);
|
||||
true
|
||||
}
|
||||
pub fn colour_index(&self, colour: Colour) -> u8 {
|
||||
self.colours
|
||||
.iter()
|
||||
.position(|c| *c == colour)
|
||||
.expect("Can't get a colour index without it existing") as u8
|
||||
}
|
||||
|
||||
fn union_length(&self, other: &Palette16) -> usize {
|
||||
self.colours
|
||||
.iter()
|
||||
.chain(&other.colours)
|
||||
.collect::<HashSet<_>>()
|
||||
.len()
|
||||
}
|
||||
|
||||
fn is_satisfied_by(&self, other: &Palette16) -> bool {
|
||||
self.colours
|
||||
.iter()
|
||||
.collect::<HashSet<_>>()
|
||||
.is_subset(&other.colours.iter().collect::<HashSet<_>>())
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for Palette16 {
|
||||
type Item = Colour;
|
||||
type IntoIter = std::vec::IntoIter<Self::Item>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.colours.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Palette16Optimiser {
|
||||
palettes: Vec<Palette16>,
|
||||
colours: Vec<Colour>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Palette16OptimisationResults {
|
||||
pub optimised_palettes: Vec<Palette16>,
|
||||
pub assignments: Vec<usize>,
|
||||
}
|
||||
|
||||
impl Palette16Optimiser {
|
||||
pub fn new() -> Self {
|
||||
Palette16Optimiser {
|
||||
palettes: vec![],
|
||||
colours: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_palette(&mut self, palette: Palette16) {
|
||||
self.palettes.push(palette.clone());
|
||||
|
||||
for colour in palette.colours {
|
||||
if self.colours.contains(&colour) {
|
||||
continue;
|
||||
}
|
||||
|
||||
self.colours.push(colour);
|
||||
}
|
||||
|
||||
if self.colours.len() > MAX_COLOURS {
|
||||
panic!("Cannot have over 256 colours");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn optimise_palettes(
|
||||
&self,
|
||||
transparent_colour: Option<Colour>,
|
||||
) -> Palette16OptimisationResults {
|
||||
let mut assignments = vec![0; self.palettes.len()];
|
||||
let mut optimised_palettes = vec![];
|
||||
|
||||
let mut unsatisfied_palettes = self
|
||||
.palettes
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect::<HashSet<Palette16>>();
|
||||
|
||||
while !unsatisfied_palettes.is_empty() {
|
||||
let palette = self.find_maximal_palette_for(&unsatisfied_palettes, transparent_colour);
|
||||
|
||||
for test_palette in unsatisfied_palettes.clone() {
|
||||
if test_palette.is_satisfied_by(&palette) {
|
||||
unsatisfied_palettes.remove(&test_palette);
|
||||
}
|
||||
}
|
||||
|
||||
for (i, overall_palette) in self.palettes.iter().enumerate() {
|
||||
if overall_palette.is_satisfied_by(&palette) {
|
||||
assignments[i] = optimised_palettes.len();
|
||||
}
|
||||
}
|
||||
|
||||
optimised_palettes.push(palette);
|
||||
|
||||
if optimised_palettes.len() == MAX_COLOURS / MAX_COLOURS_PER_PALETTE {
|
||||
panic!("Failed to find covering palettes");
|
||||
}
|
||||
}
|
||||
|
||||
Palette16OptimisationResults {
|
||||
optimised_palettes,
|
||||
assignments,
|
||||
}
|
||||
}
|
||||
|
||||
fn find_maximal_palette_for(
|
||||
&self,
|
||||
unsatisfied_palettes: &HashSet<Palette16>,
|
||||
transparent_colour: Option<Colour>,
|
||||
) -> Palette16 {
|
||||
let mut palette = Palette16::new();
|
||||
|
||||
if let Some(transparent_colour) = transparent_colour {
|
||||
palette.add_colour(transparent_colour);
|
||||
}
|
||||
|
||||
loop {
|
||||
let mut colour_usage = vec![0; MAX_COLOURS];
|
||||
let mut a_colour_is_used = false;
|
||||
|
||||
for current_palette in unsatisfied_palettes {
|
||||
if palette.union_length(¤t_palette) > MAX_COLOURS_PER_PALETTE {
|
||||
continue;
|
||||
}
|
||||
|
||||
for colour in ¤t_palette.colours {
|
||||
if palette.colours.contains(&colour) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(colour_index) = self.colours.iter().position(|c| c == colour) {
|
||||
colour_usage[colour_index] += 1;
|
||||
a_colour_is_used = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !a_colour_is_used {
|
||||
return palette;
|
||||
}
|
||||
|
||||
let best_index = colour_usage
|
||||
.iter()
|
||||
.enumerate()
|
||||
.max_by(|(_, usage1), (_, usage2)| usage1.cmp(usage2))
|
||||
.unwrap()
|
||||
.0;
|
||||
|
||||
let best_colour = self.colours[best_index];
|
||||
|
||||
palette.add_colour(best_colour);
|
||||
if palette.colours.len() == MAX_COLOURS_PER_PALETTE {
|
||||
return palette;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
91
agb-image-converter/src/rust_generator.rs
Normal file
91
agb-image-converter/src/rust_generator.rs
Normal file
|
@ -0,0 +1,91 @@
|
|||
use std::io;
|
||||
use std::io::Write;
|
||||
|
||||
use crate::image_loader::Image;
|
||||
use crate::palette16::Palette16OptimisationResults;
|
||||
use crate::TileSize;
|
||||
|
||||
pub(crate) fn generate_code(
|
||||
output: &mut dyn Write,
|
||||
results: &Palette16OptimisationResults,
|
||||
image: &Image,
|
||||
tile_size: TileSize,
|
||||
) -> io::Result<()> {
|
||||
writeln!(
|
||||
output,
|
||||
"pub const PALETTE_DATA: &[crate::display::palette16::Palette16] = &[",
|
||||
)?;
|
||||
|
||||
for palette in &results.optimised_palettes {
|
||||
write!(output, " crate::display::palette16::Palette16::new([")?;
|
||||
|
||||
for colour in palette.clone() {
|
||||
write!(output, "0x{:08x}, ", colour.to_rgb15())?;
|
||||
}
|
||||
|
||||
for _ in palette.clone().into_iter().len()..16 {
|
||||
write!(output, "0x00000000, ")?;
|
||||
}
|
||||
|
||||
writeln!(output, "]),")?;
|
||||
}
|
||||
|
||||
writeln!(output, "];")?;
|
||||
writeln!(output)?;
|
||||
|
||||
writeln!(output, "pub const TILE_DATA: &[u32] = &[",)?;
|
||||
|
||||
let tile_size = tile_size.to_size();
|
||||
|
||||
let tiles_x = image.width / tile_size;
|
||||
let tiles_y = image.height / tile_size;
|
||||
|
||||
for y in 0..tiles_y {
|
||||
for x in 0..tiles_x {
|
||||
let palette_index = results.assignments[y * tiles_x + x];
|
||||
let palette = &results.optimised_palettes[palette_index];
|
||||
writeln!(
|
||||
output,
|
||||
" /* {}, {} (palette index {}) */",
|
||||
x, y, palette_index
|
||||
)?;
|
||||
|
||||
for inner_y in 0..tile_size / 8 {
|
||||
write!(output, " ")?;
|
||||
|
||||
for inner_x in 0..tile_size / 8 {
|
||||
for j in inner_y * 8..inner_y * 8 + 8 {
|
||||
write!(output, "0x")?;
|
||||
|
||||
for i in (inner_x * 8..inner_x * 8 + 8).rev() {
|
||||
let colour = image.colour(x * tile_size + i, y * tile_size + j);
|
||||
let colour_index = palette.colour_index(colour);
|
||||
|
||||
write!(output, "{:x}", colour_index)?;
|
||||
}
|
||||
|
||||
write!(output, ", ")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writeln!(output)?;
|
||||
}
|
||||
}
|
||||
|
||||
writeln!(output, "];")?;
|
||||
writeln!(output)?;
|
||||
|
||||
write!(output, "pub const PALETTE_ASSIGNMENT: &[u8] = &[")?;
|
||||
|
||||
for (i, assignment) in results.assignments.iter().enumerate() {
|
||||
if i % 16 == 0 {
|
||||
write!(output, "\n ")?;
|
||||
}
|
||||
write!(output, "{}, ", assignment)?;
|
||||
}
|
||||
|
||||
writeln!(output, "\n];")?;
|
||||
|
||||
Ok(())
|
||||
}
|
324
agb/Cargo.lock
generated
324
agb/Cargo.lock
generated
|
@ -2,15 +2,339 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "adler32"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
|
||||
|
||||
[[package]]
|
||||
name = "agb"
|
||||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"agb_image_converter",
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "agb_image_converter"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"image",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bed57e2090563b83ba8f83366628ce535a7584c9afa4c9fc0612a03925c6df58"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "color_quant"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2584f639eb95fea8c798496315b297cf81b9b58b6d30ab066a75455333cf4b12"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"lazy_static",
|
||||
"memoffset",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deflate"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174"
|
||||
dependencies = [
|
||||
"adler32",
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||
|
||||
[[package]]
|
||||
name = "gif"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a668f699973d0f573d15749b7002a9ac9e1f9c6b220e7b165601334c173d8de"
|
||||
dependencies = [
|
||||
"color_quant",
|
||||
"weezl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.23.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"byteorder",
|
||||
"color_quant",
|
||||
"gif",
|
||||
"jpeg-decoder",
|
||||
"num-iter",
|
||||
"num-rational",
|
||||
"num-traits",
|
||||
"png",
|
||||
"scoped_threadpool",
|
||||
"tiff",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jpeg-decoder"
|
||||
version = "0.1.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2"
|
||||
dependencies = [
|
||||
"rayon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f83fb6581e8ed1f85fd45c116db8405483899489e38406156c25eb743554361d"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435"
|
||||
dependencies = [
|
||||
"adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
|
||||
dependencies = [
|
||||
"adler",
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-iter"
|
||||
version = "0.1.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.16.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"crc32fast",
|
||||
"deflate",
|
||||
"miniz_oxide 0.3.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"crossbeam-deque",
|
||||
"either",
|
||||
"rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
"lazy_static",
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scoped_threadpool"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "tiff"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a53f4706d65497df0c4349241deddf35f84cee19c87ed86ea8ca590f4464437"
|
||||
dependencies = [
|
||||
"jpeg-decoder",
|
||||
"miniz_oxide 0.4.4",
|
||||
"weezl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "weezl"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8b77fdfd5a253be4ab714e4ffa3c49caf146b4de743e97510c0656cf90f1e8e"
|
||||
|
|
|
@ -18,3 +18,6 @@ lto = true
|
|||
|
||||
[dependencies]
|
||||
bitflags = "1.0"
|
||||
|
||||
[build-dependencies]
|
||||
agb_image_converter = { path = "../agb-image-converter" }
|
10
agb/build.rs
10
agb/build.rs
|
@ -1,6 +1,9 @@
|
|||
use agb_image_converter::{convert_image, Colour, ImageConverterConfig, TileSize};
|
||||
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=crt0.s");
|
||||
println!("cargo:rerun-if-changed=interrupt_simple.s");
|
||||
println!("cargo:rerun-if-changed=gfx/test_logo.png");
|
||||
|
||||
let out_file_name = "crt0.o";
|
||||
let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR environment variable must be specified");
|
||||
|
@ -19,4 +22,11 @@ fn main() {
|
|||
}
|
||||
|
||||
println!("cargo:rustc-link-search={}", out_dir);
|
||||
|
||||
convert_image(&ImageConverterConfig {
|
||||
transparent_colour: Some(Colour::from_rgb(1, 1, 1)),
|
||||
tile_size: TileSize::Tile8,
|
||||
input_image: "gfx/test_logo.png".into(),
|
||||
output_file: format!("{}/test_logo.rs", out_dir).into(),
|
||||
});
|
||||
}
|
||||
|
|
41
agb/examples/test_logo.rs
Normal file
41
agb/examples/test_logo.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
#![no_std]
|
||||
#![feature(start)]
|
||||
|
||||
extern crate agb;
|
||||
|
||||
use agb::display::{example_logo, tiled0};
|
||||
|
||||
#[start]
|
||||
fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
||||
let mut gba = agb::Gba::new();
|
||||
let mut gfx = gba.display.video.tiled0();
|
||||
|
||||
gfx.set_background_palettes(example_logo::PALETTE_DATA);
|
||||
gfx.set_background_tilemap(example_logo::TILE_DATA);
|
||||
|
||||
gfx.background_0.enable();
|
||||
gfx.background_0
|
||||
.set_background_size(tiled0::BackgroundSize::S32x32);
|
||||
gfx.background_0
|
||||
.set_colour_mode(tiled0::ColourMode::FourBitPerPixel);
|
||||
|
||||
gfx.background_0.set_screen_base_block(20);
|
||||
|
||||
let mut entries: [u16; 32 * 20] = [0; 32 * 20];
|
||||
for i in 0..(32 * 20) {
|
||||
let x = i % 32;
|
||||
let y = i / 32;
|
||||
|
||||
if x >= 30 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let tile_id = (x + y * 30) as u16;
|
||||
let palette_entry = example_logo::PALETTE_ASSIGNMENT[tile_id as usize] as u16;
|
||||
entries[i] = tile_id | (palette_entry << 12);
|
||||
}
|
||||
|
||||
gfx.copy_to_map(20, &entries);
|
||||
|
||||
loop {}
|
||||
}
|
BIN
agb/gfx/test_logo.png
Normal file
BIN
agb/gfx/test_logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
1
agb/src/display/example_logo.rs
Normal file
1
agb/src/display/example_logo.rs
Normal file
|
@ -0,0 +1 @@
|
|||
include!(concat!(env!("OUT_DIR"), "/test_logo.rs"));
|
|
@ -6,7 +6,9 @@ use video::Video;
|
|||
|
||||
pub mod bitmap3;
|
||||
pub mod bitmap4;
|
||||
pub mod example_logo;
|
||||
pub mod object;
|
||||
pub mod palette16;
|
||||
pub mod tiled0;
|
||||
pub mod vblank;
|
||||
pub mod video;
|
||||
|
|
9
agb/src/display/palette16.rs
Normal file
9
agb/src/display/palette16.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
pub struct Palette16 {
|
||||
pub(crate) colours: [u16; 16],
|
||||
}
|
||||
|
||||
impl Palette16 {
|
||||
pub const fn new(colours: [u16; 16]) -> Self {
|
||||
Palette16 { colours }
|
||||
}
|
||||
}
|
|
@ -3,8 +3,8 @@ use core::convert::TryInto;
|
|||
use crate::memory_mapped::MemoryMapped1DArray;
|
||||
|
||||
use super::{
|
||||
object::ObjectControl, set_graphics_mode, set_graphics_settings, DisplayMode, GraphicsSettings,
|
||||
DISPLAY_CONTROL,
|
||||
object::ObjectControl, palette16, set_graphics_mode, set_graphics_settings, DisplayMode,
|
||||
GraphicsSettings, DISPLAY_CONTROL,
|
||||
};
|
||||
|
||||
const PALETTE_BACKGROUND: MemoryMapped1DArray<u16, 256> =
|
||||
|
@ -12,7 +12,7 @@ const PALETTE_BACKGROUND: MemoryMapped1DArray<u16, 256> =
|
|||
const PALETTE_SPRITE: MemoryMapped1DArray<u16, 256> =
|
||||
unsafe { MemoryMapped1DArray::new(0x0500_0200) };
|
||||
|
||||
const TILE_BACKGROUND: MemoryMapped1DArray<u32, { 512 * 8 }> =
|
||||
const TILE_BACKGROUND: MemoryMapped1DArray<u32, { 2048 * 8 }> =
|
||||
unsafe { MemoryMapped1DArray::new(0x06000000) };
|
||||
const TILE_SPRITE: MemoryMapped1DArray<u32, { 512 * 8 }> =
|
||||
unsafe { MemoryMapped1DArray::new(0x06010000) };
|
||||
|
@ -144,6 +144,17 @@ impl Tiled0 {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn set_background_palettes(&mut self, palettes: &[palette16::Palette16]) {
|
||||
for (palette_index, entry) in palettes.iter().enumerate() {
|
||||
for (colour_index, &colour) in entry.colours.iter().enumerate() {
|
||||
self.set_background_palette_entry(
|
||||
(palette_index * 16 + colour_index) as u8,
|
||||
colour,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_sprite_tilemap(&mut self, tiles: &[u32]) {
|
||||
for (index, &tile) in tiles.iter().enumerate() {
|
||||
self.set_sprite_tilemap_entry(index as u32, tile)
|
||||
|
|
Loading…
Reference in a new issue