Skip to content

Commit

Permalink
Refactor tile to a trait
Browse files Browse the repository at this point in the history
  • Loading branch information
twvd committed Nov 10, 2023
1 parent c6f5be8 commit a4233cf
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 67 deletions.
54 changes: 26 additions & 28 deletions src/snes/ppu/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod bus;
pub mod render;
pub mod sprites;
pub mod tile;

#[cfg(test)]
pub mod tests;
Expand All @@ -14,6 +15,8 @@ use num_traits::{FromPrimitive, ToPrimitive};
use crate::frontend::Renderer;
use crate::tickable::{Tickable, Ticks};

use tile::Tile;

pub const SCREEN_WIDTH: usize = 8 * 32;
pub const SCREEN_HEIGHT: usize = 8 * 28;

Expand Down Expand Up @@ -70,7 +73,7 @@ impl TilemapEntry {
}
}

#[derive(Debug, ToPrimitive)]
#[derive(Clone, Copy, Debug, ToPrimitive)]
pub enum BPP {
// BPP == number of bitplanes
Two = 2, // 4 colors
Expand Down Expand Up @@ -126,35 +129,29 @@ pub struct PPU<TRenderer: Renderer> {
inidisp: u8,
}

#[derive(Debug)]
pub struct Tile<'a> {
pub struct BgTile<'a> {
data: &'a [u16],
map: &'a TilemapEntry,
bpp: BPP,
}
impl<'a> Tile<'a> {
pub fn get_coloridx(&self, x: usize, y: usize) -> u8 {
let mut result: u8 = 0;
let bitp_w = self.bpp.num_bitplanes() / VRAM_WORDSIZE;
let y = if self.map.flip_y() { 7 - y } else { y };

let (x_a, x_b) = if self.map.flip_x() {
(1 << x, 1 << 8 + x)
} else {
(1 << 7 - x, 1 << 15 - x)
};

for i in 0..bitp_w {
let offset = y + (8 * i);

if self.data[offset] & x_a != 0 {
result |= 1 << (i * VRAM_WORDSIZE);
}
if self.data[offset] & x_b != 0 {
result |= 1 << ((i * VRAM_WORDSIZE) + 1);
}
}
result
impl<'a, 'tdata> Tile<'tdata> for BgTile<'a>
where
'a: 'tdata,
{
fn get_tile_data(&self) -> &'tdata [VramWord] {
self.data
}
fn get_tile_flip_x(&self) -> bool {
self.map.flip_x()
}
fn get_tile_flip_y(&self) -> bool {
self.map.flip_y()
}
fn get_tile_bpp(&self) -> BPP {
self.bpp
}
fn get_tile_palette(&self) -> u8 {
self.map.palettenr()
}
}

Expand Down Expand Up @@ -320,11 +317,12 @@ where
}
}

fn get_tile<'a>(&'a self, bg: usize, tile: &'a TilemapEntry) -> Tile {
/// Retrieve a pixel data reference to a specific bg layer tile.
fn get_bg_tile<'a>(&'a self, bg: usize, tile: &'a TilemapEntry) -> 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);
Tile {
BgTile {
data: &self.vram[idx..(idx + len)],
bpp,
map: tile,
Expand Down
13 changes: 7 additions & 6 deletions src/snes/ppu/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ where
(r, g, b)
}

fn cindex_to_color(&self, bg: usize, tile: &Tile, idx: u8) -> Color {
let palette = match tile.bpp {
BPP::Two if self.get_screen_mode() == 0 => bg as u8 * 32 + tile.map.palettenr() * 4,
BPP::Two => tile.map.palettenr() * 4,
BPP::Four => tile.map.palettenr() * 16,
fn cindex_to_color<'a>(&self, bg: usize, tile: &impl Tile<'a>, idx: u8) -> Color {
let paletteidx = tile.get_tile_palette();
let palette = match tile.get_tile_bpp() {
BPP::Two if self.get_screen_mode() == 0 => bg as u8 * 32 + paletteidx * 4,
BPP::Two => paletteidx * 4,
BPP::Four => paletteidx * 16,
BPP::Eight => 0,
};
self.cgram_to_color(palette + idx)
Expand Down Expand Up @@ -70,7 +71,7 @@ where
continue;
}

let chr = self.get_tile(bg, &entry);
let chr = self.get_bg_tile(bg, &entry);
let tx = (x + bghofs) % tilesize;
let ty = (scanline + bgvofs) % tilesize;

Expand Down
65 changes: 32 additions & 33 deletions src/snes/ppu/sprites.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,50 +47,49 @@ impl OAMEntry {
}
}

#[derive(Debug)]
/// A sprite tile is a single 8 x 8 pixel segment of a sprite.
pub struct SpriteTile<'a> {
pub data: &'a [VramWord],
pub oam: &'a OAMEntry,
}
impl<'a> SpriteTile<'a> {
pub fn get_coloridx(&self, x: usize, y: usize) -> u8 {
let mut result: u8 = 0;
let bitp_w = BPP::Four.num_bitplanes() / VRAM_WORDSIZE;
let y = if self.oam.flip_y() {
TILE_HEIGHT - 1 - y
} else {
y
};

let (x_a, x_b) = if self.oam.flip_x() {
(1 << x, 1 << 8 + x)
} else {
(1 << 7 - x, 1 << 15 - x)
};

for i in 0..bitp_w {
let offset = y + (TILE_WIDTH * i);

if self.data[offset] & x_a != 0 {
result |= 1 << (i * VRAM_WORDSIZE);
}
if self.data[offset] & x_b != 0 {
result |= 1 << ((i * VRAM_WORDSIZE) + 1);
}
}
result
impl<'a, 'tdata> Tile<'tdata> for SpriteTile<'a>
where
'a: 'tdata,
{
fn get_tile_data(&self) -> &'tdata [VramWord] {
self.data
}
fn get_tile_flip_x(&self) -> bool {
self.oam.flip_x()
}
fn get_tile_flip_y(&self) -> bool {
self.oam.flip_y()
}
fn get_tile_bpp(&self) -> BPP {
// Sprites are alwaye 4BPP
BPP::Four
}
fn get_tile_palette(&self) -> u8 {
self.oam.palette()
}
}

impl<TRenderer> PPU<TRenderer>
where
TRenderer: Renderer,
{
/// Retrieve a sprite entry from OAM
pub fn get_oam_entry(&self, idx: usize) -> OAMEntry {
// Base OAM table entry
let e = &self.oam[(idx * 4)..((idx + 1) * 4)];

// The two bits left in the 32-byte extended table
// at the end of OAM.
let extoffset_byte = 512 + (idx / 4);
let extoffset_sh = (idx % 4) * 2;
let ext = (self.oam[extoffset_byte] >> extoffset_sh) & 0x03;

// Determine size (in pixels)
let large = ext & 0x02 != 0;
let (width, height) = match ((self.obsel >> 5) & 0x07, large) {
// Small sprites
Expand Down Expand Up @@ -120,26 +119,26 @@ where
}
}

/// Retrieve a pixel data reference to a specific sprite tile.
/// One tile is an 8x8 pixel segment of a sprite.
pub fn get_sprite_tile<'a>(
&'a self,
oam: &'a OAMEntry,
tile_x: usize,
tile_y: usize,
) -> SpriteTile {
let base_addr = (self.obsel as usize & 0x07) * 8192;
let len = 32 * BPP::Four.num_bitplanes() / VRAM_WORDSIZE;

let len = TILE_HEIGHT * BPP::Four.num_bitplanes() / VRAM_WORDSIZE;
let idx = base_addr + (oam.get_tileidx(tile_x, tile_y) << 4);
let idx = if oam.tileidx >= 0x100 {
// Add the configured gap between 0x100..0x101
idx + ((self.obsel as usize >> 3) & 3) * 4096
} else {
idx
};
let idx = idx & VRAM_ADDRMASK;
let end_idx = (idx + len) & VRAM_ADDRMASK;

SpriteTile {
data: &self.vram[idx..end_idx],
data: &self.vram[idx..(idx + len)],
oam,
}
}
Expand Down
37 changes: 37 additions & 0 deletions src/snes/ppu/tile.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use super::*;

/// A tile is a single 8 x 8 pixel segment of a background layer
/// or a sprite.
pub trait Tile<'tdata> {
fn get_tile_data(&self) -> &'tdata [VramWord];
fn get_tile_flip_x(&self) -> bool;
fn get_tile_flip_y(&self) -> bool;
fn get_tile_bpp(&self) -> BPP;
fn get_tile_palette(&self) -> u8;

/// Get a single pixel (color index) of a tile.
fn get_coloridx(&self, x: usize, y: usize) -> u8 {
let mut result: u8 = 0;
let bitp_w = self.get_tile_bpp().num_bitplanes() / VRAM_WORDSIZE;
let y = if self.get_tile_flip_y() { 7 - y } else { y };

let (x_a, x_b) = if self.get_tile_flip_x() {
(1 << x, 1 << 8 + x)
} else {
(1 << 7 - x, 1 << 15 - x)
};

let data = self.get_tile_data();
for i in 0..bitp_w {
let offset = y + (8 * i);

if data[offset] & x_a != 0 {
result |= 1 << (i * VRAM_WORDSIZE);
}
if data[offset] & x_b != 0 {
result |= 1 << ((i * VRAM_WORDSIZE) + 1);
}
}
result
}
}

0 comments on commit a4233cf

Please sign in to comment.