Skip to content

Commit

Permalink
Merge pull request #26 from yeastplume/tilemap_rotation
Browse files Browse the repository at this point in the history
Tilemap V and H Flips
  • Loading branch information
yeastplume authored Jun 15, 2020
2 parents d574fdb + bd8a7b2 commit e8dd6a9
Show file tree
Hide file tree
Showing 20 changed files with 161 additions and 42 deletions.
20 changes: 10 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "aloevera"
version = "0.2.3"
version = "0.2.4"
authors = ["Revcore Technologies Ltd."]
description = "Graphics Asset Pipeline for the Commander X16"
license = "Apache-2.0"
Expand All @@ -25,6 +25,6 @@ log = "0.4"
failure = "0.1"
failure_derive = "0.1"

aloevera_util = { path = "./util", version = "0.2.3" }
aloevera_proj = { path = "./proj", version = "0.2.3" }
aloevera_vera = { path = "./vera", version = "0.2.3" }
aloevera_util = { path = "./util", version = "0.2.4" }
aloevera_proj = { path = "./proj", version = "0.2.4" }
aloevera_vera = { path = "./vera", version = "0.2.4" }
14 changes: 12 additions & 2 deletions docs/ex_004.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,18 @@ And here's the result of assembling and poking all this data via the [tile_wall

The end result in both the BASIC and Assembly versions are the same. The assembly version is nice and fast. The BASIC version reminds me of a Next Generation episode where Picard experienced an entire lifetime in about 15 minutes elapsed time. You should have time to go and do something similar while you wait for the BASIC version to finish doing its thing.

## Horizontal and Vertical Flip

The more astute among you may have noticed the poorly-drawn set of symbols in the Tilemap:

![tile_wall tiles](images/04-tile_wall-006.png)

However if you look at the Imageset, only the first symbol is present:

![tile_wall tiles](images/04-tile_wall-007.png)

Non-text VERA display modes allow a vertical-flip and horizontal-flip flag to be set for each tile in a Tilemap, and the four tiles in our Aloevera Tilemap .png contain the unflipped original tile, the vertically-flipped version, the horizontally-flipped, and both flipped frames respectively. Aloevera is clever enough to recognise when an input Tile is the flipped version of a frame in the Imageset, and if it encouters a flipped tile it will output the original index as well as the correct v and h flip fields at assembly time.

## More on Palette Alignment

For a bit of futher clarity of the alignment rules above, let's consider a brief example from one of Aloevera's automated tests. This is a 2 Frame Imageset targeted at 2BPP (4 Colour Mode). Thus, each tile in the Imageset consists of indices from a range of 4 colours, and each range must start on a multiple of 16:
Expand Down Expand Up @@ -83,6 +95,4 @@ There's still plenty of work and future possibilities for Aloevera's Tilemap sup

* The ability to 'append' maps together to create larger maps to be used in scrolling applications.
* A better method of specifying the foreground and background colours for each tile in Text_16 mode.
* 'Conflating' Tilemaps, essentially blowing Tilemap data to be the size of the target VERA map size.
* Support for Tile rotation
* Output assembly code that does the Tilemap loading
Binary file modified docs/images/04-tile_wall-001.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/04-tile_wall-002.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/04-tile_wall-003.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/04-tile_wall-006.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/04-tile_wall-007.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions proj/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "aloevera_proj"
version = "0.2.3"
version = "0.2.4"
authors = ["Revcore Technologies Ltd."]
description = "Aloevera project file definitions"
license = "Apache-2.0"
Expand All @@ -19,5 +19,5 @@ failure = "0.1"
failure_derive = "0.1"
bincode = "1.2"

aloevera_util = { path = "../util", version = "0.2.3" }
aloevera_vera = { path = "../vera", version = "0.2.3" }
aloevera_util = { path = "../util", version = "0.2.4" }
aloevera_vera = { path = "../vera", version = "0.2.4" }
Binary file modified samples/tile_wall/tile_wall-imageset-4bpp.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified samples/tile_wall/tile_wall-map.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion samples/tile_wall/tile_wall.bas
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
420 REM POKE IMAGESET DATA INTO TILE BASE
430 PRINT "POKING TILESET"
500 POKE $9F20,0:POKE $9F21,$A8:POKE $9F22,$11
600 FOR I = 0 TO 2175
600 FOR I = 0 TO 2303
700 READ A:POKE $9F23,A:NEXT I

704 REM CLEAR TILEMAP MEMORY
Expand Down
2 changes: 1 addition & 1 deletion samples/tile_wall/tile_wall.s
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jmp start
v_address_set $1A800, 1
set_const_16 $00, imageset

TARGET = 2176 ;loop until size reached
TARGET = 2304 ;loop until size reached

loop:
lda ($00),y
Expand Down
2 changes: 1 addition & 1 deletion util/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "aloevera_util"
version = "0.2.3"
version = "0.2.4"
authors = ["Revcore Technologies Ltd."]
description = "Aloevera utils crate."
license = "Apache-2.0"
Expand Down
4 changes: 2 additions & 2 deletions vera/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "aloevera_vera"
version = "0.2.3"
version = "0.2.4"
authors = ["Revcore Technologies Ltd."]
description = "Aloevera VERA operations"
license = "Apache-2.0"
Expand All @@ -17,4 +17,4 @@ serde = "1"
serde_derive = "1"
png = "0.15"
permutate = "0.3"
aloevera_util = { path = "../util", version = "0.2.3" }
aloevera_util = { path = "../util", version = "0.2.4" }
53 changes: 52 additions & 1 deletion vera/src/imageset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ pub struct VeraImage {
pub foreground: u8,
/// Background colour on 1BPP mode
pub background: u8,
/// Also store hashes of each rotation
/// h_flipped, v_flipped, h_flipped and v_flipped
pub flip_hashes: [u64; 3],
}

impl Hash for VeraImage {
Expand Down Expand Up @@ -191,10 +194,11 @@ impl VeraImage {
depth: VeraPixelDepth::BPP8,
foreground: 0,
background: 0,
flip_hashes: [0; 3],
}
}

/// push an pixel value
/// push a pixel value
pub fn push_pixel(&mut self, r: u8, g: u8, b: u8, pal_index: Option<u8>) {
self.data.push(VeraPixel {
r,
Expand Down Expand Up @@ -234,6 +238,44 @@ impl VeraImage {
self.hash(&mut hasher);
hasher.finish()
}

/// Return a new image from this one, horizontally flipped
pub fn h_flip(&self) -> VeraImage {
let mut ret = self.clone();
ret.data = vec![];
let width = self.width as usize;
let height = self.height as usize;
for j in 0..height {
for i in (0..width).rev() {
ret.data.push(self.data[j * width + i].clone());
}
}
ret
}

/// Return a new image from this one, vertically flipped
pub fn v_flip(&self) -> VeraImage {
let mut ret = self.clone();
ret.data = vec![];
let width = self.width as usize;
let height = self.height as usize;
for j in (0..height).rev() {
for i in 0..width {
ret.data.push(self.data[j * width + i].clone());
}
}
ret
}

/// Store flip hashes
pub fn store_flip_hashes(&mut self) {
let h_flipped = self.h_flip();
self.flip_hashes[0] = h_flipped.calc_hash();
let v_flipped = self.v_flip();
self.flip_hashes[1] = v_flipped.calc_hash();
let both = h_flipped.v_flip();
self.flip_hashes[2] = both.calc_hash();
}
}

#[derive(Clone, Copy, Debug)]
Expand Down Expand Up @@ -381,6 +423,14 @@ impl VeraImageSet {
Ok(())
}

/// Calc/Store all the hashes of vflipped or hflipped
/// versions of the frame
pub fn store_flip_hashes(&mut self) {
for f in self.frame_data.iter_mut() {
f.store_flip_hashes();
}
}

/// Format the stored indices with a given palette and colour depth
/// Should fail if any frame in the set contains a range of colours
/// that can't be found within a single 2^BPP length range in the
Expand Down Expand Up @@ -472,6 +522,7 @@ impl VeraImageSet {
}
}
self.depth = Some(depth);
self.store_flip_hashes();
self.formatted = true;
Ok(())
}
Expand Down
33 changes: 26 additions & 7 deletions vera/src/tilemap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,9 @@ impl fmt::Display for VeraTileMapEntry {
let out = match self {
VeraTileMapEntry::Text0(i, _, _) => format!("{}", i),
VeraTileMapEntry::Text1(i, _) => format!("{}", i),
VeraTileMapEntry::Tile234(i, _, _, _) => format!("{}", i),
VeraTileMapEntry::Tile234(i, o, h, v) => {
format!("Index: {}, offset: {}, h_flip: {}, v_flip: {}", i, o, h, v)
}
};
write!(f, "{}", out)
}
Expand Down Expand Up @@ -115,11 +117,17 @@ impl Assemblable for VeraTileMapEntry {
(*index, byte_1)
}
VeraTileMapEntry::Text1(index, foreground) => (*index, *foreground),
VeraTileMapEntry::Tile234(index, pal_offset, _, _) => {
VeraTileMapEntry::Tile234(index, pal_offset, h_flip, v_flip) => {
let byte0 = (index & 0x00ff) as u8;
let mut byte1 = pal_offset / 16 << 4;
let high_index = (index >> 8) as u8 & 3;
byte1 |= high_index as u8;
if *h_flip == 1 {
byte1 |= 0x04;
}
if *v_flip == 1 {
byte1 |= 0x08;
}
(byte0, byte1)
}
};
Expand Down Expand Up @@ -253,9 +261,9 @@ pub struct VeraTileMap {
/// Map data itself
tiles: Vec<VeraTileMapEntry>,

/// Also going to keep a map of tile hashes to indices/pal offset when initialized
/// Also going to keep a map of tile hashes to indices/pal offset/hflip/vflip when initialized
/// from an imageset
imageset_entries: BTreeMap<u64, (usize, u8)>,
imageset_entries: BTreeMap<u64, (usize, u8, u8, u8)>,
}

impl fmt::Display for VeraTileMap {
Expand Down Expand Up @@ -317,7 +325,14 @@ impl VeraTileMap {
// Tile Indices init here
for (i, f) in imageset.frame_data.iter().enumerate() {
res.imageset_entries
.insert(f.calc_hash(), (i, f.pal_offset));
.insert(f.calc_hash(), (i, f.pal_offset, 0, 0));
// And possible h/v flip iterations as well
res.imageset_entries
.insert(f.flip_hashes[0], (i, f.pal_offset, 1, 0));
res.imageset_entries
.insert(f.flip_hashes[1], (i, f.pal_offset, 0, 1));
res.imageset_entries
.insert(f.flip_hashes[2], (i, f.pal_offset, 1, 1));
}
Ok(res)
}
Expand Down Expand Up @@ -354,10 +369,12 @@ impl VeraTileMap {
pal_offset: u8,
foreground: u8,
background: u8,
h_flip: u8,
v_flip: u8,
) -> Result<VeraTileMapEntry, Error> {
match self.mode {
VeraTileMapMode::Tile2BPP | VeraTileMapMode::Tile4BPP | VeraTileMapMode::Tile8BPP => {
Ok(VeraTileMapEntry::Tile234(index, pal_offset, 0, 0))
Ok(VeraTileMapEntry::Tile234(index, pal_offset, h_flip, v_flip))
}
VeraTileMapMode::TextBPP1_16 => {
Ok(VeraTileMapEntry::Text0(index as u8, foreground, background))
Expand Down Expand Up @@ -463,12 +480,14 @@ impl VeraTileMap {
}
let hash = f.calc_hash();
match self.imageset_entries.get(&hash) {
Some((index, pal_offset)) => {
Some((index, pal_offset, h_flip, v_flip)) => {
self.tiles.push(self.entry_from_image(
*index as u16,
*pal_offset,
f.foreground,
f.background,
*h_flip,
*v_flip,
)?);
}
None => {
Expand Down
Binary file modified vera/tests/data/tilemap/tile_wall-map.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
38 changes: 28 additions & 10 deletions vera/tests/imageset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,25 +344,43 @@ fn imageset_pal_64_4bpp() -> Result<(), Error> {
Ok(())
}

/*#[test]
fn imageset_crash() -> Result<(), Error> {
let test_png = include_bytes!("data/imageset/crash-test-pal.png");
#[test]
fn image_flip() -> Result<(), Error> {
let test_png = include_bytes!("data/imageset/indexed-4bpp-pal-64.png");
let pal_config = VeraPaletteLoadConfig {
direct_load: true,
include_defaults: false,
sort: false,
..VeraPaletteLoadConfig::default()
};
let palette = VeraPalette::derive_from_png("pal", test_png.to_vec(), &pal_config)?;
println!("{}", palette);

let imageset_png = include_bytes!("data/imageset/crash-test-imageset.png");
let mut set = VeraImageSet::new("imageset_1", 16, 16);
let mut set = VeraImageSet::new("imageset_1", 8, 8);
let config = VeraImageSetLoadConfig::default();
set.load_from_png(imageset_png.to_vec(), &config)?;

set.load_from_png(test_png.to_vec(), &config)?;
set.format_indices(&palette, VeraPixelDepth::BPP4)?;
println!("{}", set);

Ok(())
let orig = set.frame_data[2].clone();
println!("{:?}", orig.flip_hashes);
println!("{}", orig);
let h_flipped = orig.h_flip();
println!("{}", h_flipped);
assert_eq!(orig.flip_hashes[0], h_flipped.calc_hash());
assert_eq!(h_flipped.data[7].pal_index, Some(7));
let v_flipped = h_flipped.v_flip();
println!("{}", v_flipped);
assert_eq!(v_flipped.data[63].pal_index, Some(7));
assert_eq!(orig.flip_hashes[2], v_flipped.calc_hash());

let orig = set.frame_data[3].clone();
println!("{}", orig);
let h_flipped = orig.h_flip();
println!("{}", h_flipped);
assert_eq!(h_flipped.data[7].pal_index, Some(2));
let v_flipped = h_flipped.v_flip();
println!("{}", v_flipped);
assert_eq!(v_flipped.data[63].pal_index, Some(2));

}*/
Ok(())
}
Loading

0 comments on commit e8dd6a9

Please sign in to comment.