Compare commits
3 Commits
8dd14c7719
...
1cc839c911
| Author | SHA1 | Date | |
|---|---|---|---|
| 1cc839c911 | |||
| fbfe751d75 | |||
| c880766ae4 |
@ -1,6 +1,11 @@
|
|||||||
extern crate libc;
|
extern crate libc;
|
||||||
extern crate sdl2;
|
extern crate sdl2;
|
||||||
|
|
||||||
|
mod palette;
|
||||||
|
mod structs;
|
||||||
|
use palette::{CgbPalette, DmgPalette};
|
||||||
|
use structs::*;
|
||||||
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
// Internal ram size
|
// Internal ram size
|
||||||
@ -46,109 +51,6 @@ const SPRITE_X_FLIP: u8 = 1 << 5;
|
|||||||
//const SPRITE_PALETTE_NO: u8 = 1 << 4; // NonCGB only
|
//const SPRITE_PALETTE_NO: u8 = 1 << 4; // NonCGB only
|
||||||
const SPRITE_TILE_VRAM_BANK: u8 = 1 << 3; // CGB only
|
const SPRITE_TILE_VRAM_BANK: u8 = 1 << 3; // CGB only
|
||||||
|
|
||||||
// Display color
|
|
||||||
/*
|
|
||||||
const MONOCHROME_PALETTE: &'static [[f64; 3]; 4] = &[
|
|
||||||
[0.605, 0.734, 0.059],
|
|
||||||
[0.543, 0.672, 0.059],
|
|
||||||
[0.188, 0.383, 0.188],
|
|
||||||
[0.059, 0.219, 0.059],
|
|
||||||
];
|
|
||||||
const MONOCHROME_PALETTE: &'static [[u8; 3]; 4] = &[
|
|
||||||
[255, 255, 255],
|
|
||||||
[200, 200, 200],
|
|
||||||
[125, 125, 12],
|
|
||||||
[50, 50, 50],
|
|
||||||
];
|
|
||||||
*/
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default)]
|
|
||||||
struct DmgPalette(u8);
|
|
||||||
impl DmgPalette {
|
|
||||||
fn get_color(self, n: usize) -> sdl2::pixels::Color {
|
|
||||||
const MONOCHROME_PALETTE: &'static [[u8; 3]; 4] = &[
|
|
||||||
[255, 255, 255],
|
|
||||||
[200, 200, 200],
|
|
||||||
[125, 125, 12],
|
|
||||||
[50, 50, 50],
|
|
||||||
];
|
|
||||||
assert!(n < 4);
|
|
||||||
let c = self.0 >> (2 * n);
|
|
||||||
let n = c & 3;
|
|
||||||
let c = MONOCHROME_PALETTE[n as usize];
|
|
||||||
sdl2::pixels::Color::RGB(c[0], c[1], c[2])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
struct CgbPalette([u8; 8]);
|
|
||||||
impl CgbPalette {
|
|
||||||
fn get_color(self, n: usize) -> sdl2::pixels::Color {
|
|
||||||
if n == 0 {
|
|
||||||
return sdl2::pixels::Color::RGB(255, 255, 255);
|
|
||||||
}
|
|
||||||
let v = ((self.0[2 * n + 1] as u16) << 8) | (self.0[2 * n] as u16);
|
|
||||||
let r = (v & 0b1_1111) as u8;
|
|
||||||
let g = ((v >> 5) & 0b1_1111) as u8;
|
|
||||||
let b = ((v >> 10) & 0b1_1111) as u8;
|
|
||||||
|
|
||||||
if false {
|
|
||||||
sdl2::pixels::Color::RGB(r << 3, g << 3, b << 3)
|
|
||||||
} else {
|
|
||||||
// According to some code:
|
|
||||||
// Real colors:
|
|
||||||
let r = r as u16;
|
|
||||||
let g = g as u16;
|
|
||||||
let b = b as u16;
|
|
||||||
let mapped_r = ((r * 13 + g * 2 + b) >> 1) as u8;
|
|
||||||
let mapped_g = ((g * 3 + b) << 1) as u8;
|
|
||||||
let mapped_b = ((r * 3 + g * 2 + b * 11) >> 1) as u8;
|
|
||||||
sdl2::pixels::Color::RGB(mapped_r, mapped_g, mapped_b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for CgbPalette {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "Palette: ")?;
|
|
||||||
for n in 0..4 {
|
|
||||||
let v = ((self.0[2 * n + 1] as u16) << 8) | (self.0[2 * n] as u16);
|
|
||||||
let r = (v & 0b1_1111) as u8;
|
|
||||||
let g = ((v >> 5) & 0b1_1111) as u8;
|
|
||||||
let b = ((v >> 10) & 0b1_1111) as u8;
|
|
||||||
write!(f, "{:02X}{:02X}{:02X} ", r, g, b)?;
|
|
||||||
}
|
|
||||||
write!(f, "")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct BgMapAttributes(u8);
|
|
||||||
impl BgMapAttributes {
|
|
||||||
fn palette_number(&self) -> usize {
|
|
||||||
(self.0 & 0b111) as usize
|
|
||||||
}
|
|
||||||
|
|
||||||
fn vram_bank_number(&self) -> usize {
|
|
||||||
((self.0 >> 3) & 1) as usize
|
|
||||||
}
|
|
||||||
|
|
||||||
fn horizontal_flip(&self) -> bool {
|
|
||||||
(self.0 >> 5) != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn vertical_flip(&self) -> bool {
|
|
||||||
(self.0 >> 6) != 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
enum PixelOrigin {
|
|
||||||
Empty,
|
|
||||||
Background(usize),
|
|
||||||
Window,
|
|
||||||
Sprite,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
struct Pixel {
|
struct Pixel {
|
||||||
origin: PixelOrigin,
|
origin: PixelOrigin,
|
||||||
@ -178,53 +80,6 @@ impl Default for DisplayMode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Sprite {
|
|
||||||
x: u8,
|
|
||||||
y: u8,
|
|
||||||
tile: u8,
|
|
||||||
flags: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Sprite {
|
|
||||||
fn is_hidden(&self) -> bool {
|
|
||||||
self.x == 0 || self.y == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_foreground(&self) -> bool {
|
|
||||||
(self.flags & SPRITE_OBJ_BG_PRIORITY) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_x_flipped(&self) -> bool {
|
|
||||||
(self.flags & SPRITE_X_FLIP) == SPRITE_X_FLIP
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_y_flipped(&self) -> bool {
|
|
||||||
(self.flags & SPRITE_Y_FLIP) == SPRITE_Y_FLIP
|
|
||||||
}
|
|
||||||
|
|
||||||
fn palette(&self) -> u8 {
|
|
||||||
// GB
|
|
||||||
/*
|
|
||||||
if (self.flags & SPRITE_PALETTE_NO) == 0 {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
1
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
// GBC
|
|
||||||
self.flags & 0b111
|
|
||||||
}
|
|
||||||
|
|
||||||
// GBC only
|
|
||||||
fn vram_bank(&self) -> u8 {
|
|
||||||
if (self.flags & SPRITE_TILE_VRAM_BANK) == 0 {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Display {
|
pub struct Display {
|
||||||
control: u8,
|
control: u8,
|
||||||
status: u8,
|
status: u8,
|
||||||
@ -655,7 +510,7 @@ impl Display {
|
|||||||
// Do not draw if the sprite should be drawn in the background
|
// Do not draw if the sprite should be drawn in the background
|
||||||
if !sprite.is_foreground() {
|
if !sprite.is_foreground() {
|
||||||
match pixel_origin {
|
match pixel_origin {
|
||||||
PixelOrigin::Background(0) => {},
|
PixelOrigin::Background(0) => {}
|
||||||
PixelOrigin::Window | PixelOrigin::Background(_) => continue,
|
PixelOrigin::Window | PixelOrigin::Background(_) => continue,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@ -737,12 +592,7 @@ impl Display {
|
|||||||
// Order sprites by priority
|
// Order sprites by priority
|
||||||
let mut queue: Vec<Sprite> = Vec::new();
|
let mut queue: Vec<Sprite> = Vec::new();
|
||||||
for i in 0..39 {
|
for i in 0..39 {
|
||||||
queue.push(Sprite {
|
queue.push(Sprite::load(&self.oam[i * 4..(i + 1) * 4]));
|
||||||
y: self.oam[i * 4 + 0],
|
|
||||||
x: self.oam[i * 4 + 1],
|
|
||||||
tile: self.oam[i * 4 + 2],
|
|
||||||
flags: self.oam[i * 4 + 3],
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is the non-CGB priority.
|
// This is the non-CGB priority.
|
||||||
@ -804,30 +654,9 @@ impl Display {
|
|||||||
|
|
||||||
// Lookup the color
|
// Lookup the color
|
||||||
let c = ((b2 as u8) * 2 + b1 as u8) as usize;
|
let c = ((b2 as u8) * 2 + b1 as u8) as usize;
|
||||||
let origin = PixelOrigin::Background(c);
|
// let color = self.background_palette.get_color(c);
|
||||||
let c = self.background_palette_cgb[bg_attribs.palette_number()].get_color(c);
|
let color = self.background_palette_cgb[bg_attribs.palette_number()].get_color(c);
|
||||||
self.set_pixel(render_x, render_y, c, origin);
|
self.set_pixel(render_x, render_y, color, PixelOrigin::Background(c));
|
||||||
/*
|
|
||||||
let c = (b1 as u8) * 2 + b2 as u8;
|
|
||||||
let lookup: [u8; 4] = [
|
|
||||||
self.background_palette & 3,
|
|
||||||
(self.background_palette >> 2) & 3,
|
|
||||||
(self.background_palette >> 4) & 3,
|
|
||||||
(self.background_palette >> 6) & 3,
|
|
||||||
];
|
|
||||||
let entry = MONOCHROME_PALETTE[lookup[c as usize] as usize];
|
|
||||||
|
|
||||||
let origin = match c {
|
|
||||||
0 => PixelOrigin::Empty, // Hack so that objects will be in front of it.
|
|
||||||
_ => PixelOrigin::Background,
|
|
||||||
};
|
|
||||||
self.set_pixel(
|
|
||||||
render_x,
|
|
||||||
render_y,
|
|
||||||
sdl2::pixels::Color::RGB(entry[0], entry[1], entry[2]),
|
|
||||||
origin,
|
|
||||||
);
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -894,37 +723,10 @@ impl Display {
|
|||||||
let b2: bool = (tile_line_2 & 1 << (7 - tile_offset_x)) > 0;
|
let b2: bool = (tile_line_2 & 1 << (7 - tile_offset_x)) > 0;
|
||||||
|
|
||||||
let c = (b2 as u8) * 2 + b1 as u8;
|
let c = (b2 as u8) * 2 + b1 as u8;
|
||||||
/*
|
// let c = self.background_palette.get_color(c);
|
||||||
let origin = match c {
|
|
||||||
0 => PixelOrigin::Empty, // Hack so that objects will be in front of it.
|
|
||||||
_ => PixelOrigin::Window,
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
let origin = PixelOrigin::Window;
|
|
||||||
let c = self.background_palette_cgb[bg_attribs.palette_number()]
|
let c = self.background_palette_cgb[bg_attribs.palette_number()]
|
||||||
.get_color(c as usize);
|
.get_color(c as usize);
|
||||||
self.set_pixel(render_x, render_y, c, origin);
|
self.set_pixel(render_x, render_y, c, PixelOrigin::Window);
|
||||||
/*
|
|
||||||
let lookup: [u8; 4] = [
|
|
||||||
self.background_palette & 3,
|
|
||||||
(self.background_palette >> 2) & 3,
|
|
||||||
(self.background_palette >> 4) & 3,
|
|
||||||
(self.background_palette >> 6) & 3,
|
|
||||||
];
|
|
||||||
let entry = MONOCHROME_PALETTE[lookup[c as usize] as usize];
|
|
||||||
|
|
||||||
// Draw stuff. We're currently only in monochrome mode
|
|
||||||
let origin = match c {
|
|
||||||
0 => PixelOrigin::Empty, // Hack so that objects will be in front of it.
|
|
||||||
_ => PixelOrigin::Window,
|
|
||||||
};
|
|
||||||
self.set_pixel(
|
|
||||||
render_x,
|
|
||||||
render_y,
|
|
||||||
sdl2::pixels::Color::RGB(entry[0], entry[1], entry[2]),
|
|
||||||
origin,
|
|
||||||
);
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
61
src/display/palette.rs
Normal file
61
src/display/palette.rs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
use super::sdl2;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Default)]
|
||||||
|
pub struct DmgPalette(pub u8);
|
||||||
|
impl DmgPalette {
|
||||||
|
pub fn get_color(self, n: usize) -> sdl2::pixels::Color {
|
||||||
|
const MONOCHROME_PALETTE: &[[u8; 3]; 4] = &[
|
||||||
|
[255, 255, 255],
|
||||||
|
[200, 200, 200],
|
||||||
|
[125, 125, 12],
|
||||||
|
[50, 50, 50],
|
||||||
|
];
|
||||||
|
assert!(n < 4);
|
||||||
|
let c = self.0 >> (2 * n);
|
||||||
|
let n = c & 3;
|
||||||
|
let c = MONOCHROME_PALETTE[n as usize];
|
||||||
|
sdl2::pixels::Color::RGB(c[0], c[1], c[2])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct CgbPalette(pub [u8; 8]);
|
||||||
|
impl CgbPalette {
|
||||||
|
pub fn get_color(self, n: usize) -> sdl2::pixels::Color {
|
||||||
|
if n == 0 {
|
||||||
|
return sdl2::pixels::Color::RGB(255, 255, 255);
|
||||||
|
}
|
||||||
|
let v = ((self.0[2 * n + 1] as u16) << 8) | (self.0[2 * n] as u16);
|
||||||
|
let r = (v & 0b1_1111) as u8;
|
||||||
|
let g = ((v >> 5) & 0b1_1111) as u8;
|
||||||
|
let b = ((v >> 10) & 0b1_1111) as u8;
|
||||||
|
|
||||||
|
if false {
|
||||||
|
sdl2::pixels::Color::RGB(r << 3, g << 3, b << 3)
|
||||||
|
} else {
|
||||||
|
// According to some code:
|
||||||
|
// Real colors:
|
||||||
|
let r = r as u16;
|
||||||
|
let g = g as u16;
|
||||||
|
let b = b as u16;
|
||||||
|
let mapped_r = ((r * 13 + g * 2 + b) >> 1) as u8;
|
||||||
|
let mapped_g = ((g * 3 + b) << 1) as u8;
|
||||||
|
let mapped_b = ((r * 3 + g * 2 + b * 11) >> 1) as u8;
|
||||||
|
sdl2::pixels::Color::RGB(mapped_r, mapped_g, mapped_b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for CgbPalette {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "Palette: ")?;
|
||||||
|
for n in 0..4 {
|
||||||
|
let v = ((self.0[2 * n + 1] as u16) << 8) | (self.0[2 * n] as u16);
|
||||||
|
let r = (v & 0b1_1111) as u8;
|
||||||
|
let g = ((v >> 5) & 0b1_1111) as u8;
|
||||||
|
let b = ((v >> 10) & 0b1_1111) as u8;
|
||||||
|
write!(f, "{:02X}{:02X}{:02X} ", r, g, b)?;
|
||||||
|
}
|
||||||
|
write!(f, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
85
src/display/structs.rs
Normal file
85
src/display/structs.rs
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
use super::*;
|
||||||
|
// Display color
|
||||||
|
pub struct BgMapAttributes(pub u8);
|
||||||
|
impl BgMapAttributes {
|
||||||
|
pub fn palette_number(&self) -> usize {
|
||||||
|
(self.0 & 0b111) as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn vram_bank_number(&self) -> usize {
|
||||||
|
((self.0 >> 3) & 1) as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn horizontal_flip(&self) -> bool {
|
||||||
|
(self.0 >> 5) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn vertical_flip(&self) -> bool {
|
||||||
|
(self.0 >> 6) != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub enum PixelOrigin {
|
||||||
|
Empty,
|
||||||
|
Background(usize),
|
||||||
|
Window,
|
||||||
|
Sprite,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Sprite {
|
||||||
|
pub x: u8,
|
||||||
|
pub y: u8,
|
||||||
|
pub tile: u8,
|
||||||
|
flags: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sprite {
|
||||||
|
pub fn load(buf: &[u8]) -> Self {
|
||||||
|
assert!(buf.len() > 4);
|
||||||
|
Self {
|
||||||
|
x: buf[0],
|
||||||
|
y: buf[1],
|
||||||
|
tile: buf[2],
|
||||||
|
flags: buf[3],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_hidden(&self) -> bool {
|
||||||
|
self.x == 0 || self.y == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_foreground(&self) -> bool {
|
||||||
|
(self.flags & SPRITE_OBJ_BG_PRIORITY) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_x_flipped(&self) -> bool {
|
||||||
|
(self.flags & SPRITE_X_FLIP) == SPRITE_X_FLIP
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_y_flipped(&self) -> bool {
|
||||||
|
(self.flags & SPRITE_Y_FLIP) == SPRITE_Y_FLIP
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn palette(&self) -> u8 {
|
||||||
|
// GB
|
||||||
|
/*
|
||||||
|
if (self.flags & SPRITE_PALETTE_NO) == 0 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
// GBC
|
||||||
|
self.flags & 0b111
|
||||||
|
}
|
||||||
|
|
||||||
|
// GBC only
|
||||||
|
pub fn vram_bank(&self) -> u8 {
|
||||||
|
if (self.flags & SPRITE_TILE_VRAM_BANK) == 0 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user