Skip to content

Commit

Permalink
Implement 16x16 bg tiles
Browse files Browse the repository at this point in the history
  • Loading branch information
twvd committed Nov 12, 2023
1 parent 4bd53a8 commit 0246e15
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 52 deletions.
102 changes: 61 additions & 41 deletions src/snes/ppu/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use num_traits::{FromPrimitive, ToPrimitive};
use crate::frontend::Renderer;
use crate::tickable::{Tickable, Ticks};

use tile::Tile;
use tile::{Tile, TILE_HEIGHT, TILE_WIDTH};

pub const SCREEN_WIDTH: usize = 8 * 32;
pub const SCREEN_HEIGHT: usize = 8 * 28;
Expand Down Expand Up @@ -259,46 +259,42 @@ where
fn get_tilemap_entry_xy(&self, bg: usize, x: usize, y: usize) -> TilemapEntry {
let bghofs = self.bgxhofs[bg] as usize;
let bgvofs = self.bgxvofs[bg] as usize;
let tilesize = 8;
let tilesize = self.get_bg_tile_size(bg);

match self.get_screen_mode() {
0 | 1 | 3 => {
if !self.is_layer_16x16(bg) {
// AA BB CC DD, size = 0x800 per sub-map
// 00 32x32 AA
// AA
// 01 64x32 AB
// AB
// 10 32x64 AA
// BB
// 11 64x64 AB
// CD
let (expand_x, expand_y) = match self.get_tilemap_dimensions(bg) {
TilemapDimensions::D32x32 => (false, false),
TilemapDimensions::D32x64 => (false, true),
TilemapDimensions::D64x32 => (true, false),
TilemapDimensions::D64x64 => (true, true),
};
let tm_x = (bghofs + x) / tilesize;
let tm_y = (bgvofs + y) / tilesize;

// 32 tiles per row in the sub-map, 0-31
let mut idx = ((tm_y & 0x1F) << 5) + (tm_x & 0x1F);
if expand_y {
if expand_x {
idx += (tm_y & 0x20) << 6;
} else {
idx += (tm_y & 0x20) << 5;
}
}
// AA BB CC DD, size = 0x800 per sub-map
// 00 32x32 AA
// AA
// 01 64x32 AB
// AB
// 10 32x64 AA
// BB
// 11 64x64 AB
// CD
let (expand_x, expand_y) = match self.get_tilemap_dimensions(bg) {
TilemapDimensions::D32x32 => (false, false),
TilemapDimensions::D32x64 => (false, true),
TilemapDimensions::D64x32 => (true, false),
TilemapDimensions::D64x64 => (true, true),
};
let tm_x = (bghofs + x) / tilesize;
let tm_y = (bgvofs + y) / tilesize;

// 32 tiles per row in the sub-map, 0-31
let mut idx = ((tm_y & 0x1F) << 5) + (tm_x & 0x1F);
if expand_y {
if expand_x {
idx += (tm_x & 0x20) << 5;
idx += (tm_y & 0x20) << 6;
} else {
idx += (tm_y & 0x20) << 5;
}

self.get_tilemap_entry(bg, idx)
} else {
todo!()
}
if expand_x {
idx += (tm_x & 0x20) << 5;
}

self.get_tilemap_entry(bg, idx)
}
_ => todo!(),
}
Expand All @@ -323,20 +319,44 @@ where
}

/// Retrieve a pixel data reference to a specific bg layer tile.
fn get_bg_tile<'a>(&'a self, bg: usize, tile: &'a TilemapEntry) -> BgTile {
fn get_bg_tile<'a>(
&'a self,
bg: usize,
entry: &'a TilemapEntry,
px_x: usize,
px_y: usize,
) -> BgTile {
let bpp = self.get_layer_bpp(bg);
let len = 8 * bpp.num_bitplanes() / VRAM_WORDSIZE;
let idx = (self.bgxnba[bg] as usize * 4096) + (tile.charnr() as usize * len);
let len = TILE_HEIGHT * bpp.num_bitplanes() / VRAM_WORDSIZE;

// Determine tile/character table index
// For 8x8, always what is indicated by the map.
// For 16x16:
// T+00 T+01
// T+16 T+17
let mut tilenr = entry.charnr() as usize;
if self.get_bg_tile_size(bg) == 16 && px_x > TILE_WIDTH {
tilenr += 1;
}
if self.get_bg_tile_size(bg) == 16 && px_y > TILE_HEIGHT {
tilenr += 16;
}

let idx = (self.bgxnba[bg] as usize * 4096) + (tilenr * len);
BgTile {
data: &self.vram[idx..(idx + len)],
bpp,
map: tile,
map: entry,
}
}

fn is_layer_16x16(&self, bg: usize) -> bool {
pub fn get_bg_tile_size(&self, bg: usize) -> usize {
debug_assert!((0..4).contains(&bg));
self.bgmode & (1 << (4 + bg)) != 0
if self.bgmode & (1 << (4 + bg)) != 0 {
16
} else {
8
}
}

pub fn get_current_scanline(&self) -> usize {
Expand Down
23 changes: 14 additions & 9 deletions src/snes/ppu/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,24 +63,28 @@ where

let bghofs = self.bgxhofs[bg] as usize;
let bgvofs = self.bgxvofs[bg] as usize;
let tilesize = 8;
let tilesize = self.get_bg_tile_size(bg);

for x in 0..SCREEN_WIDTH {
let entry = self.get_tilemap_entry_xy(bg, x, scanline);
if entry.bgprio() != priority {
continue;
}

let chr = self.get_bg_tile(bg, &entry);
let tx = (x + bghofs) % tilesize;
let ty = (scanline + bgvofs) % tilesize;
// Determine coordinates within the tile. This is
// a full tile (so either 8x8 or 16x16).
let px_x = (x + bghofs) % tilesize;
let px_y = (scanline + bgvofs) % tilesize;
// get_bg_tile will select the sub-tile (for 16x16).
let tile = self.get_bg_tile(bg, &entry, px_x, px_y);

let c = chr.get_coloridx(tx, ty);
// Wrap coordinates back here to the (sub)-tile size
let c = tile.get_coloridx(px_x % TILE_WIDTH, px_y % TILE_HEIGHT);
if c == 0 || line_idx[x] != 0 {
continue;
}
line_idx[x] = c;
line_paletted[x] = self.cindex_to_color(bg, &chr, c);
line_paletted[x] = self.cindex_to_color(bg, &tile, c);
}
}

Expand Down Expand Up @@ -108,11 +112,12 @@ where
break;
}

let t_x = (x - e.x) / 8;
let t_y = (scanline - e.y) / 8;
let t_x = (x - e.x) / TILE_WIDTH;
let t_y = (scanline - e.y) / TILE_HEIGHT;
let sprite = self.get_sprite_tile(&e, t_x, t_y);

let coloridx = sprite.get_coloridx((x - e.x) % 8, (scanline - e.y) % 8);
let coloridx =
sprite.get_coloridx((x - e.x) % TILE_WIDTH, (scanline - e.y) % TILE_HEIGHT);
if coloridx == 0 || line_idx[x] != 0 {
continue;
}
Expand Down
2 changes: 0 additions & 2 deletions src/snes/ppu/sprites.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use super::*;

pub const OAM_ENTRIES: usize = 128;
pub const TILE_WIDTH: usize = 8;
pub const TILE_HEIGHT: usize = 8;

#[derive(Debug)]
pub struct OAMEntry {
Expand Down
3 changes: 3 additions & 0 deletions src/snes/ppu/tile.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use super::*;

pub const TILE_WIDTH: usize = 8;
pub const TILE_HEIGHT: usize = 8;

/// A tile is a single 8 x 8 pixel segment of a background layer
/// or a sprite.
pub trait Tile<'tdata> {
Expand Down

0 comments on commit 0246e15

Please sign in to comment.