mirror of
https://github.com/italicsjenga/agb.git
synced 2025-01-11 17:41:33 +11:00
objects now exist and work
This commit is contained in:
parent
a1b67e107f
commit
2a7b350f57
28
agb/Cargo.lock
generated
28
agb/Cargo.lock
generated
|
@ -25,6 +25,7 @@ dependencies = [
|
||||||
"bare-metal",
|
"bare-metal",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
|
"modular-bitfield",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -192,6 +193,27 @@ dependencies = [
|
||||||
"adler",
|
"adler",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "modular-bitfield"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a53d79ba8304ac1c4f9eb3b9d281f21f7be9d4626f72ce7df4ad8fbde4f38a74"
|
||||||
|
dependencies = [
|
||||||
|
"modular-bitfield-impl",
|
||||||
|
"static_assertions",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "modular-bitfield-impl"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a7d5f7076603ebc68de2dc6a650ec331a062a13abaa346975be747bbfa4b789"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-integer"
|
name = "num-integer"
|
||||||
version = "0.1.44"
|
version = "0.1.44"
|
||||||
|
@ -289,6 +311,12 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "static_assertions"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.86"
|
version = "1.0.86"
|
||||||
|
|
|
@ -27,6 +27,7 @@ agb_macros = { version = "0.1.0", path = "../agb-macros" }
|
||||||
agb_fixnum = { version = "0.1.0", path = "../agb-fixnum" }
|
agb_fixnum = { version = "0.1.0", path = "../agb-fixnum" }
|
||||||
bare-metal = "1.0"
|
bare-metal = "1.0"
|
||||||
hashbrown = "0.12.0"
|
hashbrown = "0.12.0"
|
||||||
|
modular-bitfield = "0.11.2"
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
default-target = "thumbv6m-none-eabi"
|
default-target = "thumbv6m-none-eabi"
|
||||||
|
|
|
@ -2,7 +2,12 @@
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
use agb::{
|
use agb::{
|
||||||
display::{background::Map, object::ObjectStandard, HEIGHT, WIDTH},
|
display::{
|
||||||
|
background::Map,
|
||||||
|
object::{Object, ObjectController, Size, Sprite},
|
||||||
|
palette16::Palette16,
|
||||||
|
HEIGHT, WIDTH,
|
||||||
|
},
|
||||||
input::Button,
|
input::Button,
|
||||||
};
|
};
|
||||||
use core::convert::TryInto;
|
use core::convert::TryInto;
|
||||||
|
@ -15,7 +20,7 @@ enum State {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Character<'a> {
|
struct Character<'a> {
|
||||||
object: ObjectStandard<'a>,
|
object: Object<'a, 'a>,
|
||||||
position: Vector2D,
|
position: Vector2D,
|
||||||
velocity: Vector2D,
|
velocity: Vector2D,
|
||||||
}
|
}
|
||||||
|
@ -30,8 +35,8 @@ fn tile_is_collidable(tile: u16) -> bool {
|
||||||
masked == 0 || masked == 4
|
masked == 0 || masked == 4
|
||||||
}
|
}
|
||||||
|
|
||||||
fn frame_ranger(count: u32, start: u32, end: u32, delay: u32) -> u16 {
|
fn frame_ranger(count: u32, start: u32, end: u32, delay: u32) -> usize {
|
||||||
(((count / delay) % (end + 1 - start)) + start) as u16
|
(((count / delay) % (end + 1 - start)) + start) as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
#[agb::entry]
|
#[agb::entry]
|
||||||
|
@ -54,14 +59,11 @@ fn main(mut gba: agb::Gba) -> ! {
|
||||||
background.show();
|
background.show();
|
||||||
background.commit();
|
background.commit();
|
||||||
|
|
||||||
let mut object = gba.display.object.get();
|
let object = gba.display.object.get();
|
||||||
|
|
||||||
object.set_sprite_palette_raw(&CHICKEN_PALETTE);
|
let sprite = object.get_sprite(&ChickenSprites[0]).unwrap();
|
||||||
object.set_sprite_tilemap(&CHICKEN_TILES);
|
|
||||||
|
|
||||||
object.enable();
|
|
||||||
let mut chicken = Character {
|
let mut chicken = Character {
|
||||||
object: object.get_object_standard(),
|
object: object.get_object(sprite).unwrap(),
|
||||||
position: Vector2D {
|
position: Vector2D {
|
||||||
x: (6 * 8) << 8,
|
x: (6 * 8) << 8,
|
||||||
y: ((7 * 8) - 4) << 8,
|
y: ((7 * 8) - 4) << 8,
|
||||||
|
@ -69,7 +71,6 @@ fn main(mut gba: agb::Gba) -> ! {
|
||||||
velocity: Vector2D { x: 0, y: 0 },
|
velocity: Vector2D { x: 0, y: 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
chicken.object.set_tile_id(0);
|
|
||||||
chicken
|
chicken
|
||||||
.object
|
.object
|
||||||
.set_x((chicken.position.x >> 8).try_into().unwrap());
|
.set_x((chicken.position.x >> 8).try_into().unwrap());
|
||||||
|
@ -120,14 +121,19 @@ fn main(mut gba: agb::Gba) -> ! {
|
||||||
}
|
}
|
||||||
|
|
||||||
restrict_to_screen(&mut chicken);
|
restrict_to_screen(&mut chicken);
|
||||||
update_chicken_object(&mut chicken, state, frame_count);
|
update_chicken_object(&mut chicken, &object, state, frame_count);
|
||||||
|
|
||||||
// Commit the chicken to vram
|
// Commit the chicken to vram
|
||||||
chicken.object.commit();
|
chicken.object.commit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_chicken_object(chicken: &mut Character, state: State, frame_count: u32) {
|
fn update_chicken_object<'a>(
|
||||||
|
chicken: &'_ mut Character<'a>,
|
||||||
|
object: &'a ObjectController,
|
||||||
|
state: State,
|
||||||
|
frame_count: u32,
|
||||||
|
) {
|
||||||
if chicken.velocity.x > 1 {
|
if chicken.velocity.x > 1 {
|
||||||
chicken.object.set_hflip(false);
|
chicken.object.set_hflip(false);
|
||||||
} else if chicken.velocity.x < -1 {
|
} else if chicken.velocity.x < -1 {
|
||||||
|
@ -136,18 +142,24 @@ fn update_chicken_object(chicken: &mut Character, state: State, frame_count: u32
|
||||||
match state {
|
match state {
|
||||||
State::Ground => {
|
State::Ground => {
|
||||||
if chicken.velocity.x.abs() > 1 << 4 {
|
if chicken.velocity.x.abs() > 1 << 4 {
|
||||||
|
chicken.object.set_sprite(
|
||||||
|
object
|
||||||
|
.get_sprite(&ChickenSprites[frame_ranger(frame_count, 1, 3, 10)])
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
chicken
|
chicken
|
||||||
.object
|
.object
|
||||||
.set_tile_id(frame_ranger(frame_count, 1, 3, 10));
|
.set_sprite(object.get_sprite(&ChickenSprites[0]).unwrap());
|
||||||
} else {
|
|
||||||
chicken.object.set_tile_id(0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
State::Upwards => {}
|
State::Upwards => {}
|
||||||
State::Flapping => {
|
State::Flapping => {
|
||||||
chicken
|
chicken.object.set_sprite(
|
||||||
.object
|
object
|
||||||
.set_tile_id(frame_ranger(frame_count, 4, 5, 5));
|
.get_sprite(&ChickenSprites[frame_ranger(frame_count, 4, 5, 5)])
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,16 +244,65 @@ fn handle_collision(
|
||||||
|
|
||||||
// Below is the data for the sprites
|
// Below is the data for the sprites
|
||||||
|
|
||||||
static CHICKEN_TILES: [u32; 8 * 6] = [
|
static ChickenPalette: Palette16 =
|
||||||
0x01100000, 0x11100000, 0x01100010, 0x01111110, 0x01111110, 0x00001000, 0x00001000, 0x00011000,
|
Palette16::new([0x7C1E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
|
||||||
0x01100000, 0x11100000, 0x01100010, 0x01111110, 0x01111110, 0x00010100, 0x00100100, 0x00000010,
|
|
||||||
0x01100000, 0x11100000, 0x01100010, 0x01111110, 0x01111110, 0x00011000, 0x00100110, 0x00100000,
|
|
||||||
0x01100000, 0x11100000, 0x01100010, 0x01111110, 0x01111110, 0x00011000, 0x00011100, 0x00001000,
|
|
||||||
0x01100000, 0x11111100, 0x01111010, 0x01111110, 0x01111110, 0x00011000, 0x00010000, 0x00000000,
|
|
||||||
0x01100000, 0x11100000, 0x01111110, 0x01111110, 0x01111110, 0x00011000, 0x00010000, 0x00000000,
|
|
||||||
];
|
|
||||||
|
|
||||||
static CHICKEN_PALETTE: [u16; 1] = [0x7C1E];
|
static ChickenSprites: &[Sprite] = &[
|
||||||
|
Sprite {
|
||||||
|
palette: &ChickenPalette,
|
||||||
|
data: &[
|
||||||
|
0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x10, 0x11, 0x10, 0x00, 0x10, 0x01, 0x10, 0x11,
|
||||||
|
0x11, 0x01, 0x10, 0x11, 0x11, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
|
||||||
|
0x00, 0x10, 0x01, 0x00,
|
||||||
|
],
|
||||||
|
size: Size::S8x8,
|
||||||
|
},
|
||||||
|
Sprite {
|
||||||
|
palette: &ChickenPalette,
|
||||||
|
data: &[
|
||||||
|
0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x10, 0x11, 0x10, 0x00, 0x10, 0x01, 0x10, 0x11,
|
||||||
|
0x11, 0x01, 0x10, 0x11, 0x11, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x10, 0x00,
|
||||||
|
0x10, 0x00, 0x00, 0x00,
|
||||||
|
],
|
||||||
|
size: Size::S8x8,
|
||||||
|
},
|
||||||
|
Sprite {
|
||||||
|
palette: &ChickenPalette,
|
||||||
|
data: &[
|
||||||
|
0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x10, 0x11, 0x10, 0x00, 0x10, 0x01, 0x10, 0x11,
|
||||||
|
0x11, 0x01, 0x10, 0x11, 0x11, 0x01, 0x00, 0x10, 0x01, 0x00, 0x10, 0x01, 0x10, 0x00,
|
||||||
|
0x00, 0x00, 0x10, 0x00,
|
||||||
|
],
|
||||||
|
size: Size::S8x8,
|
||||||
|
},
|
||||||
|
Sprite {
|
||||||
|
palette: &ChickenPalette,
|
||||||
|
data: &[
|
||||||
|
0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x10, 0x11, 0x10, 0x00, 0x10, 0x01, 0x10, 0x11,
|
||||||
|
0x11, 0x01, 0x10, 0x11, 0x11, 0x01, 0x00, 0x10, 0x01, 0x00, 0x00, 0x11, 0x01, 0x00,
|
||||||
|
0x00, 0x10, 0x00, 0x00,
|
||||||
|
],
|
||||||
|
size: Size::S8x8,
|
||||||
|
},
|
||||||
|
Sprite {
|
||||||
|
palette: &ChickenPalette,
|
||||||
|
data: &[
|
||||||
|
0x00, 0x00, 0x10, 0x01, 0x00, 0x11, 0x11, 0x11, 0x10, 0x10, 0x11, 0x01, 0x10, 0x11,
|
||||||
|
0x11, 0x01, 0x10, 0x11, 0x11, 0x01, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
],
|
||||||
|
size: Size::S8x8,
|
||||||
|
},
|
||||||
|
Sprite {
|
||||||
|
palette: &ChickenPalette,
|
||||||
|
data: &[
|
||||||
|
0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x10, 0x11, 0x10, 0x11, 0x11, 0x01, 0x10, 0x11,
|
||||||
|
0x11, 0x01, 0x10, 0x11, 0x11, 0x01, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
],
|
||||||
|
size: Size::S8x8,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
static MAP_TILES: [u32; 8 * 17] = [
|
static MAP_TILES: [u32; 8 * 17] = [
|
||||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
use crate::memory_mapped::MemoryMapped;
|
use crate::memory_mapped::MemoryMapped;
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
|
|
||||||
|
use modular_bitfield::BitfieldSpecifier;
|
||||||
use video::Video;
|
use video::Video;
|
||||||
|
|
||||||
use self::object::ObjectControl;
|
use self::object::ObjectController;
|
||||||
|
|
||||||
/// Graphics mode 0. Four regular backgrounds.
|
/// Graphics mode 0. Four regular backgrounds.
|
||||||
pub mod background;
|
pub mod background;
|
||||||
|
@ -69,8 +70,8 @@ pub struct Display {
|
||||||
pub struct ObjectDistribution {}
|
pub struct ObjectDistribution {}
|
||||||
|
|
||||||
impl ObjectDistribution {
|
impl ObjectDistribution {
|
||||||
pub fn get(&mut self) -> ObjectControl {
|
pub fn get(&mut self) -> ObjectController {
|
||||||
ObjectControl::new()
|
ObjectController::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,6 +110,7 @@ pub fn busy_wait_for_vblank() {
|
||||||
while VCOUNT.get() < 160 {}
|
while VCOUNT.get() < 160 {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(BitfieldSpecifier)]
|
||||||
pub enum Priority {
|
pub enum Priority {
|
||||||
P0 = 0,
|
P0 = 0,
|
||||||
P1 = 1,
|
P1 = 1,
|
||||||
|
|
|
@ -2,6 +2,8 @@ use alloc::vec::Vec;
|
||||||
use core::alloc::Layout;
|
use core::alloc::Layout;
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
use core::ptr::NonNull;
|
use core::ptr::NonNull;
|
||||||
|
use modular_bitfield::prelude::{B10, B2, B3, B4, B5, B8, B9};
|
||||||
|
use modular_bitfield::{bitfield, BitfieldSpecifier};
|
||||||
|
|
||||||
use hashbrown::{hash_map::Entry, HashMap};
|
use hashbrown::{hash_map::Entry, HashMap};
|
||||||
|
|
||||||
|
@ -13,6 +15,8 @@ use crate::agb_alloc::block_allocator::BlockAllocator;
|
||||||
use crate::agb_alloc::bump_allocator::StartEnd;
|
use crate::agb_alloc::bump_allocator::StartEnd;
|
||||||
use crate::fixnum::Vector2D;
|
use crate::fixnum::Vector2D;
|
||||||
|
|
||||||
|
use attributes::*;
|
||||||
|
|
||||||
static SPRITE_ALLOCATOR: BlockAllocator = unsafe {
|
static SPRITE_ALLOCATOR: BlockAllocator = unsafe {
|
||||||
BlockAllocator::new(StartEnd {
|
BlockAllocator::new(StartEnd {
|
||||||
start: || TILE_SPRITE,
|
start: || TILE_SPRITE,
|
||||||
|
@ -73,6 +77,9 @@ impl Size {
|
||||||
Size::S32x64 => 32,
|
Size::S32x64 => 32,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const fn shape_size(self) -> (u8, u8) {
|
||||||
|
(self as u8 >> 2, self as u8 & 0b11)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SpriteBorrow<'a> {
|
pub struct SpriteBorrow<'a> {
|
||||||
|
@ -104,11 +111,33 @@ impl Storage {
|
||||||
fn as_palette_ptr(&self) -> *mut u8 {
|
fn as_palette_ptr(&self) -> *mut u8 {
|
||||||
(self.location as usize * Palette16::layout().size() + PALETTE_SPRITE) as *mut u8
|
(self.location as usize * Palette16::layout().size() + PALETTE_SPRITE) as *mut u8
|
||||||
}
|
}
|
||||||
|
fn as_sprite_ptr(&self) -> *mut u8 {
|
||||||
|
(self.location as usize * BYTES_PER_TILE_4BPP + TILE_SPRITE) as *mut u8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Attributes {
|
||||||
|
a0: ObjectAttribute0,
|
||||||
|
a1s: ObjectAttribute1Standard,
|
||||||
|
a1a: ObjectAttribute1Affine,
|
||||||
|
a2: ObjectAttribute2,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Attributes {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
a0: ObjectAttribute0::new(),
|
||||||
|
a1s: ObjectAttribute1Standard::new(),
|
||||||
|
a1a: ObjectAttribute1Affine::new(),
|
||||||
|
a2: ObjectAttribute2::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Object<'a, 'b> {
|
pub struct Object<'a, 'b> {
|
||||||
sprite: SpriteBorrow<'a>,
|
sprite: SpriteBorrow<'a>,
|
||||||
loan: Loan<'b>,
|
loan: Loan<'b>,
|
||||||
|
attrs: Attributes,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SpriteControllerInner {
|
struct SpriteControllerInner {
|
||||||
|
@ -140,6 +169,17 @@ pub struct ObjectController {
|
||||||
|
|
||||||
impl ObjectController {
|
impl ObjectController {
|
||||||
pub(crate) fn new() -> Self {
|
pub(crate) fn new() -> Self {
|
||||||
|
DISPLAY_CONTROL.set_bits(1, 1, 0x6);
|
||||||
|
DISPLAY_CONTROL.set_bits(1, 1, 0xC);
|
||||||
|
|
||||||
|
for i in 0..128 {
|
||||||
|
unsafe {
|
||||||
|
(OBJECT_ATTRIBUTE_MEMORY as *mut u16)
|
||||||
|
.add(i * 4)
|
||||||
|
.write_volatile(0b10 << 8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
free_objects: RefCell::new((0..128).collect()),
|
free_objects: RefCell::new((0..128).collect()),
|
||||||
free_affine_matricies: RefCell::new((0..32).collect()),
|
free_affine_matricies: RefCell::new((0..32).collect()),
|
||||||
|
@ -153,7 +193,11 @@ impl ObjectController {
|
||||||
index: inner.pop()?,
|
index: inner.pop()?,
|
||||||
free_list: &self.free_objects,
|
free_list: &self.free_objects,
|
||||||
};
|
};
|
||||||
Some(Object { sprite, loan })
|
Some(Object {
|
||||||
|
sprite,
|
||||||
|
loan,
|
||||||
|
attrs: Attributes::new(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_sprite(&self, sprite: &'static Sprite) -> Option<SpriteBorrow> {
|
pub fn get_sprite(&self, sprite: &'static Sprite) -> Option<SpriteBorrow> {
|
||||||
|
@ -161,10 +205,80 @@ impl ObjectController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Drop for Object<'_, '_> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.attrs.a0.set_object_mode(ObjectMode::Disabled);
|
||||||
|
self.commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, 'b> Object<'a, 'b> {
|
impl<'a, 'b> Object<'a, 'b> {
|
||||||
pub fn set_sprite(&'a mut self, sprite: SpriteBorrow<'a>) {
|
pub fn set_sprite(&'_ mut self, sprite: SpriteBorrow<'a>) {
|
||||||
|
self.attrs.a2.set_tile_index(sprite.sprite_location);
|
||||||
|
let shape_size = sprite.id.get_sprite().size.shape_size();
|
||||||
|
self.attrs.a0.set_shape(shape_size.0);
|
||||||
|
self.attrs.a1a.set_size(shape_size.1);
|
||||||
|
self.attrs.a1s.set_size(shape_size.1);
|
||||||
self.sprite = sprite;
|
self.sprite = sprite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn show(&mut self) -> &mut Self {
|
||||||
|
self.attrs.a0.set_object_mode(ObjectMode::Normal);
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_hflip(&mut self, flip: bool) -> &mut Self {
|
||||||
|
self.attrs.a1s.set_horizontal_flip(flip);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_vflip(&mut self, flip: bool) -> &mut Self {
|
||||||
|
self.attrs.a1s.set_vertical_flip(flip);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_x(&mut self, x: u16) -> &mut Self {
|
||||||
|
self.attrs.a1a.set_x(x as u16);
|
||||||
|
self.attrs.a1s.set_x(x as u16);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_y(&mut self, y: u16) -> &mut Self {
|
||||||
|
self.attrs.a0.set_y(y as u8);
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_position(&mut self, position: Vector2D<i32>) -> &mut Self {
|
||||||
|
self.attrs.a0.set_y(position.y as u8);
|
||||||
|
self.attrs.a1a.set_x(position.x as u16);
|
||||||
|
self.attrs.a1s.set_x(position.x as u16);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn commit(&self) {
|
||||||
|
let mode = self.attrs.a0.object_mode();
|
||||||
|
let attrs: [[u8; 2]; 3] = match mode {
|
||||||
|
ObjectMode::Normal => [
|
||||||
|
self.attrs.a0.into_bytes(),
|
||||||
|
self.attrs.a1s.into_bytes(),
|
||||||
|
self.attrs.a2.into_bytes(),
|
||||||
|
],
|
||||||
|
_ => [
|
||||||
|
self.attrs.a0.into_bytes(),
|
||||||
|
self.attrs.a1a.into_bytes(),
|
||||||
|
self.attrs.a2.into_bytes(),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let attrs: [u8; 6] = core::mem::transmute(attrs);
|
||||||
|
(OBJECT_ATTRIBUTE_MEMORY as *mut u8)
|
||||||
|
.add(self.loan.index as usize * (4 * 2))
|
||||||
|
.copy_from(attrs.as_ptr(), attrs.len())
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The Sprite Id is a thin wrapper around the pointer to the sprite in
|
/// The Sprite Id is a thin wrapper around the pointer to the sprite in
|
||||||
|
@ -288,6 +402,26 @@ impl SpriteControllerInner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn return_sprite(&mut self, sprite: &'static Sprite) {
|
||||||
|
let entry = self
|
||||||
|
.sprite
|
||||||
|
.entry(sprite.get_id())
|
||||||
|
.and_replace_entry_with(|_, mut storage| {
|
||||||
|
storage.count -= 1;
|
||||||
|
if storage.count == 0 {
|
||||||
|
unsafe { SPRITE_ALLOCATOR.dealloc(storage.as_sprite_ptr(), sprite.layout()) }
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(storage)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
match entry {
|
||||||
|
Entry::Occupied(_) => {}
|
||||||
|
Entry::Vacant(_) => self.return_palette(sprite.palette),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn return_palette(&mut self, palette: &'static Palette16) {
|
fn return_palette(&mut self, palette: &'static Palette16) {
|
||||||
let id = palette.get_id();
|
let id = palette.get_id();
|
||||||
self.palette
|
self.palette
|
||||||
|
@ -309,21 +443,70 @@ impl SpriteControllerInner {
|
||||||
impl<'a> Drop for SpriteBorrow<'a> {
|
impl<'a> Drop for SpriteBorrow<'a> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let mut inner = self.controller.borrow_mut();
|
let mut inner = self.controller.borrow_mut();
|
||||||
let entry = inner
|
inner.return_sprite(self.id.get_sprite())
|
||||||
.sprite
|
}
|
||||||
.entry(self.id)
|
}
|
||||||
.and_replace_entry_with(|_, mut storage| {
|
|
||||||
storage.count -= 1;
|
#[derive(BitfieldSpecifier, Clone, Copy)]
|
||||||
if storage.count == 0 {
|
enum ObjectMode {
|
||||||
None
|
Normal,
|
||||||
} else {
|
Affine,
|
||||||
Some(storage)
|
Disabled,
|
||||||
}
|
AffineDouble,
|
||||||
});
|
}
|
||||||
|
|
||||||
match entry {
|
#[derive(BitfieldSpecifier, Clone, Copy)]
|
||||||
Entry::Occupied(_) => {}
|
#[bits = 2]
|
||||||
Entry::Vacant(_) => inner.return_palette(self.id.get_sprite().palette),
|
enum GraphicsMode {
|
||||||
}
|
Normal,
|
||||||
|
AlphaBlending,
|
||||||
|
Window,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(BitfieldSpecifier, Clone, Copy)]
|
||||||
|
enum ColourMode {
|
||||||
|
Four,
|
||||||
|
Eight,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
mod attributes {
|
||||||
|
use super::*;
|
||||||
|
#[bitfield]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub(super) struct ObjectAttribute0 {
|
||||||
|
pub y: B8,
|
||||||
|
pub object_mode: ObjectMode,
|
||||||
|
pub graphics_mode: GraphicsMode,
|
||||||
|
pub mosaic: bool,
|
||||||
|
pub colour_mode: ColourMode,
|
||||||
|
pub shape: B2,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitfield]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub(super) struct ObjectAttribute1Standard {
|
||||||
|
pub x: B9,
|
||||||
|
#[skip]
|
||||||
|
__: B3,
|
||||||
|
pub horizontal_flip: bool,
|
||||||
|
pub vertical_flip: bool,
|
||||||
|
pub size: B2,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitfield]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub(super) struct ObjectAttribute1Affine {
|
||||||
|
pub x: B9,
|
||||||
|
pub affine_index: B5,
|
||||||
|
pub size: B2,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitfield]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub(super) struct ObjectAttribute2 {
|
||||||
|
pub tile_index: B10,
|
||||||
|
pub priority: Priority,
|
||||||
|
pub palete_bank: B4,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use core::arch::asm;
|
use core::arch::asm;
|
||||||
|
|
||||||
use crate::display::object::AffineMatrixAttributes;
|
// use crate::display::object::AffineMatrixAttributes;
|
||||||
use crate::fixnum::Num;
|
use crate::fixnum::Num;
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
|
@ -113,55 +113,55 @@ pub fn arc_tan2(x: i16, y: i32) -> i16 {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn affine_matrix(
|
// pub fn affine_matrix(
|
||||||
x_scale: Num<i16, 8>,
|
// x_scale: Num<i16, 8>,
|
||||||
y_scale: Num<i16, 8>,
|
// y_scale: Num<i16, 8>,
|
||||||
rotation: u8,
|
// rotation: u8,
|
||||||
) -> AffineMatrixAttributes {
|
// ) -> AffineMatrixAttributes {
|
||||||
let mut result = AffineMatrixAttributes {
|
// let mut result = AffineMatrixAttributes {
|
||||||
p_a: 0,
|
// p_a: 0,
|
||||||
p_b: 0,
|
// p_b: 0,
|
||||||
p_c: 0,
|
// p_c: 0,
|
||||||
p_d: 0,
|
// p_d: 0,
|
||||||
};
|
// };
|
||||||
|
|
||||||
#[allow(dead_code)]
|
// #[allow(dead_code)]
|
||||||
#[repr(C, packed)]
|
// #[repr(C, packed)]
|
||||||
struct Input {
|
// struct Input {
|
||||||
x_scale: i16,
|
// x_scale: i16,
|
||||||
y_scale: i16,
|
// y_scale: i16,
|
||||||
rotation: u16,
|
// rotation: u16,
|
||||||
}
|
// }
|
||||||
|
|
||||||
let input = Input {
|
// let input = Input {
|
||||||
y_scale: x_scale.to_raw(),
|
// y_scale: x_scale.to_raw(),
|
||||||
x_scale: y_scale.to_raw(),
|
// x_scale: y_scale.to_raw(),
|
||||||
rotation: rotation as u16,
|
// rotation: rotation as u16,
|
||||||
};
|
// };
|
||||||
|
|
||||||
unsafe {
|
// unsafe {
|
||||||
asm!("swi 0x0F",
|
// asm!("swi 0x0F",
|
||||||
in("r0") &input as *const Input as usize,
|
// in("r0") &input as *const Input as usize,
|
||||||
in("r1") &mut result as *mut AffineMatrixAttributes as usize,
|
// in("r1") &mut result as *mut AffineMatrixAttributes as usize,
|
||||||
in("r2") 1,
|
// in("r2") 1,
|
||||||
in("r3") 2,
|
// in("r3") 2,
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
|
|
||||||
result
|
// result
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[cfg(test)]
|
// #[cfg(test)]
|
||||||
mod tests {
|
// mod tests {
|
||||||
use super::*;
|
// use super::*;
|
||||||
|
|
||||||
#[test_case]
|
// #[test_case]
|
||||||
fn affine(_gba: &mut crate::Gba) {
|
// fn affine(_gba: &mut crate::Gba) {
|
||||||
// expect identity matrix
|
// // expect identity matrix
|
||||||
let one: Num<i16, 8> = 1.into();
|
// let one: Num<i16, 8> = 1.into();
|
||||||
|
|
||||||
let aff = affine_matrix(one, one, 0);
|
// let aff = affine_matrix(one, one, 0);
|
||||||
assert_eq!(aff.p_a, one.to_raw());
|
// assert_eq!(aff.p_a, one.to_raw());
|
||||||
assert_eq!(aff.p_d, one.to_raw());
|
// assert_eq!(aff.p_d, one.to_raw());
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
Loading…
Reference in a new issue