mirror of
https://github.com/italicsjenga/agb.git
synced 2025-01-11 01:21:34 +11:00
Merge pull request #34 from corwinkuiper/object
Further Object Implementations
This commit is contained in:
commit
e6affbd0a9
|
@ -31,8 +31,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) -> u32 {
|
fn frame_ranger(count: u32, start: u32, end: u32, delay: u32) -> u16 {
|
||||||
((count / delay) % (end + 1 - start)) + start
|
(((count / delay) % (end + 1 - start)) + start) as u16
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -61,9 +61,8 @@ pub fn main() -> ! {
|
||||||
let mut object = gfx.object;
|
let mut object = gfx.object;
|
||||||
|
|
||||||
object.enable();
|
object.enable();
|
||||||
unsafe { object.clear_objects() };
|
|
||||||
let mut chicken = Character {
|
let mut chicken = Character {
|
||||||
object: unsafe { object.get_object(0) },
|
object: object.get_object_standard(),
|
||||||
position: Vector2D {
|
position: Vector2D {
|
||||||
x: (6 * 8) << 8,
|
x: (6 * 8) << 8,
|
||||||
y: ((7 * 8) - 4) << 8,
|
y: ((7 * 8) - 4) << 8,
|
||||||
|
|
|
@ -1,23 +1,43 @@
|
||||||
use super::DISPLAY_CONTROL;
|
use super::DISPLAY_CONTROL;
|
||||||
use crate::memory_mapped::MemoryMapped1DArray;
|
use crate::memory_mapped::MemoryMapped1DArray;
|
||||||
|
|
||||||
const OBJECT_MEMORY_STANDARD: MemoryMapped1DArray<u32, 256> =
|
const OBJECT_ATTRIBUTE_MEMORY: MemoryMapped1DArray<u16, 512> =
|
||||||
unsafe { MemoryMapped1DArray::new(0x0700_0000) };
|
unsafe { MemoryMapped1DArray::new(0x0700_0000) };
|
||||||
|
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct ObjectControl {}
|
pub struct ObjectControl {
|
||||||
|
object_count: u8,
|
||||||
|
affine_count: u8,
|
||||||
|
}
|
||||||
|
|
||||||
#[non_exhaustive]
|
|
||||||
pub struct ObjectStandard {
|
pub struct ObjectStandard {
|
||||||
attributes: ObjectAttributeStandard,
|
attributes: ObjectAttribute,
|
||||||
id: usize,
|
id: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ObjectAffine {
|
||||||
|
attributes: ObjectAttribute,
|
||||||
|
id: u8,
|
||||||
|
aff_id: Option<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AffineMatrix {
|
||||||
|
pub attributes: AffineMatrixAttributes,
|
||||||
|
id: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AffineMatrixAttributes {
|
||||||
|
pub p_a: i16,
|
||||||
|
pub p_b: i16,
|
||||||
|
pub p_c: i16,
|
||||||
|
pub p_d: i16,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Mode {
|
pub enum Mode {
|
||||||
Normal = 0,
|
Normal = 0,
|
||||||
Affline = 1,
|
Affine = 1,
|
||||||
Hidden = 2,
|
Hidden = 2,
|
||||||
AfflineDouble = 3,
|
AffineDouble = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjectStandard {
|
impl ObjectStandard {
|
||||||
|
@ -31,85 +51,124 @@ impl ObjectStandard {
|
||||||
pub fn set_y(&mut self, y: u8) {
|
pub fn set_y(&mut self, y: u8) {
|
||||||
self.attributes.set_y(y)
|
self.attributes.set_y(y)
|
||||||
}
|
}
|
||||||
pub fn set_tile_id(&mut self, id: u32) {
|
pub fn set_tile_id(&mut self, id: u16) {
|
||||||
self.attributes.set_tile_id(id)
|
self.attributes.set_tile_id(id)
|
||||||
}
|
}
|
||||||
pub fn set_hflip(&mut self, hflip: bool) {
|
pub fn set_hflip(&mut self, hflip: bool) {
|
||||||
self.attributes.set_hflip(hflip)
|
self.attributes.set_hflip(hflip)
|
||||||
}
|
}
|
||||||
}
|
pub fn show(&mut self) {
|
||||||
|
self.attributes.set_mode(Mode::Normal)
|
||||||
pub struct ObjectAttributeStandard {
|
|
||||||
low: u32,
|
|
||||||
high: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ObjectAttributeStandard {
|
|
||||||
unsafe fn commit(&self, index: usize) {
|
|
||||||
OBJECT_MEMORY_STANDARD.set(index * 2, self.low);
|
|
||||||
OBJECT_MEMORY_STANDARD.set(index * 2 + 1, self.high);
|
|
||||||
}
|
}
|
||||||
|
pub fn hide(&mut self) {
|
||||||
|
self.attributes.set_mode(Mode::Hidden)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_hflip(&mut self, hflip: bool) {
|
impl ObjectAffine {
|
||||||
let mask = (1 << 0xC) << 16;
|
pub fn commit(&self) {
|
||||||
let attr = self.low;
|
unsafe { self.attributes.commit(self.id) }
|
||||||
let attr = attr & !mask;
|
|
||||||
if hflip {
|
|
||||||
self.low = attr | mask
|
|
||||||
} else {
|
|
||||||
self.low = attr
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_x(&mut self, x: u8) {
|
pub fn set_x(&mut self, x: u8) {
|
||||||
let mask = ((1 << 8) - 1) << 16;
|
self.attributes.set_x(x)
|
||||||
let attr1 = self.low;
|
|
||||||
let attr_without_x = attr1 & !mask;
|
|
||||||
let attr_with_new_x = attr_without_x | ((x as u32) << 16);
|
|
||||||
self.low = attr_with_new_x;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_y(&mut self, y: u8) {
|
pub fn set_y(&mut self, y: u8) {
|
||||||
let mask = (1 << 8) - 1;
|
self.attributes.set_y(y)
|
||||||
let attr0 = self.low;
|
}
|
||||||
let attr_without_y = attr0 & !mask;
|
pub fn set_tile_id(&mut self, id: u16) {
|
||||||
let attr_with_new_y = attr_without_y | y as u32;
|
self.attributes.set_tile_id(id)
|
||||||
self.low = attr_with_new_y;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_tile_id(&mut self, id: u32) {
|
pub fn show(&mut self) {
|
||||||
let mask = (1 << 9) - 1;
|
if self.aff_id.is_none() {
|
||||||
assert!(id <= mask, "tile id is greater than 9 bits");
|
panic!("affine matrix should be set")
|
||||||
let attr = self.high;
|
}
|
||||||
let attr = attr & !mask;
|
self.attributes.set_mode(Mode::Affine)
|
||||||
let attr = attr | id;
|
|
||||||
self.high = attr;
|
|
||||||
}
|
}
|
||||||
|
pub fn hide(&mut self) {
|
||||||
pub fn set_mode(&mut self, mode: Mode) {
|
self.attributes.set_mode(Mode::Hidden)
|
||||||
let mask = 0b11 << 0x8;
|
}
|
||||||
self.low = (self.low & !mask) | ((mode as u32) << 0x8);
|
pub fn set_affine_mat(&mut self, aff: &AffineMatrix) {
|
||||||
|
self.attributes.set_affine(aff.id);
|
||||||
|
self.aff_id = Some(aff.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjectAttributeStandard {
|
fn set_bits(current: u16, value: u16, length: u16, shift: u16) -> u16 {
|
||||||
|
let mask: u16 = (1 << length) - 1;
|
||||||
|
(current & !(mask << shift)) | ((value & mask) << shift)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ObjectAttribute {
|
||||||
|
a0: u16,
|
||||||
|
a1: u16,
|
||||||
|
a2: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectAttribute {
|
||||||
|
unsafe fn commit(&self, index: u8) {
|
||||||
|
OBJECT_ATTRIBUTE_MEMORY.set(index as usize * 4, self.a0);
|
||||||
|
OBJECT_ATTRIBUTE_MEMORY.set(index as usize * 4 + 1, self.a1);
|
||||||
|
OBJECT_ATTRIBUTE_MEMORY.set(index as usize * 4 + 2, self.a2);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_hflip(&mut self, hflip: bool) {
|
||||||
|
self.a1 = set_bits(self.a1, hflip as u16, 1, 0xC);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_x(&mut self, x: u8) {
|
||||||
|
self.a1 = set_bits(self.a1, x as u16, 8, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_y(&mut self, y: u8) {
|
||||||
|
self.a0 = set_bits(self.a0, y as u16, 8, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_tile_id(&mut self, id: u16) {
|
||||||
|
self.a2 = set_bits(self.a2, id, 9, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_mode(&mut self, mode: Mode) {
|
||||||
|
self.a0 = set_bits(self.a0, mode as u16, 2, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_affine(&mut self, aff_id: u8) {
|
||||||
|
self.a1 = set_bits(self.a1, aff_id as u16, 5, 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AffineMatrix {
|
||||||
|
#[allow(clippy::identity_op)]
|
||||||
|
pub fn commit(&self) {
|
||||||
|
let id = self.id as usize;
|
||||||
|
OBJECT_ATTRIBUTE_MEMORY.set((id + 0) * 4 + 3, self.attributes.p_a as u16);
|
||||||
|
OBJECT_ATTRIBUTE_MEMORY.set((id + 1) * 4 + 3, self.attributes.p_b as u16);
|
||||||
|
OBJECT_ATTRIBUTE_MEMORY.set((id + 2) * 4 + 3, self.attributes.p_c as u16);
|
||||||
|
OBJECT_ATTRIBUTE_MEMORY.set((id + 3) * 4 + 3, self.attributes.p_d as u16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectAttribute {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
ObjectAttributeStandard { low: 0, high: 0 }
|
ObjectAttribute {
|
||||||
|
a0: 0,
|
||||||
|
a1: 0,
|
||||||
|
a2: 0,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjectControl {
|
impl ObjectControl {
|
||||||
pub(crate) fn new() -> Self {
|
pub(crate) fn new() -> Self {
|
||||||
ObjectControl {}
|
let mut o = ObjectAttribute::new();
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
/// Temporary, do not call if you currently hold an object
|
|
||||||
pub unsafe fn clear_objects(&mut self) {
|
|
||||||
let mut o = ObjectAttributeStandard::new();
|
|
||||||
o.set_mode(Mode::Hidden);
|
o.set_mode(Mode::Hidden);
|
||||||
for index in 0..128 {
|
for index in 0..128 {
|
||||||
o.commit(index);
|
unsafe { o.commit(index) };
|
||||||
|
}
|
||||||
|
ObjectControl {
|
||||||
|
object_count: 0,
|
||||||
|
affine_count: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,12 +184,38 @@ impl ObjectControl {
|
||||||
DISPLAY_CONTROL.set(disp);
|
DISPLAY_CONTROL.set(disp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Safety
|
pub fn get_object_standard(&mut self) -> ObjectStandard {
|
||||||
/// Temporary function, you must not get multiple objects with the same id
|
let id = self.object_count;
|
||||||
pub unsafe fn get_object(&self, id: usize) -> ObjectStandard {
|
self.object_count += 1;
|
||||||
assert!(id < 128, "object id must be less than 128");
|
assert!(id < 128, "object id must be less than 128");
|
||||||
ObjectStandard {
|
ObjectStandard {
|
||||||
attributes: ObjectAttributeStandard::new(),
|
attributes: ObjectAttribute::new(),
|
||||||
|
id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_object_affine(&mut self) -> ObjectAffine {
|
||||||
|
let id = self.object_count;
|
||||||
|
self.object_count += 1;
|
||||||
|
assert!(id < 128, "object id must be less than 128");
|
||||||
|
ObjectAffine {
|
||||||
|
attributes: ObjectAttribute::new(),
|
||||||
|
id,
|
||||||
|
aff_id: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_affine(&mut self) -> AffineMatrix {
|
||||||
|
let id = self.affine_count;
|
||||||
|
self.affine_count += 1;
|
||||||
|
assert!(id < 32, "affine id must be less than 32");
|
||||||
|
AffineMatrix {
|
||||||
|
attributes: AffineMatrixAttributes {
|
||||||
|
p_a: 0,
|
||||||
|
p_b: 0,
|
||||||
|
p_c: 0,
|
||||||
|
p_d: 0,
|
||||||
|
},
|
||||||
id,
|
id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use crate::display::object::AffineMatrixAttributes;
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
|
|
||||||
pub fn halt() {
|
pub fn halt() {
|
||||||
|
@ -102,3 +104,44 @@ pub fn arc_tan2(x: i16, y: i32) -> i16 {
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn affine_matrix(x_scale: i16, y_scale: i16, rotation: u16) -> AffineMatrixAttributes {
|
||||||
|
let mut result = AffineMatrixAttributes {
|
||||||
|
p_a: 0,
|
||||||
|
p_b: 0,
|
||||||
|
p_c: 0,
|
||||||
|
p_d: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
struct Input {
|
||||||
|
x_scale: i16,
|
||||||
|
y_scale: i16,
|
||||||
|
rotation: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
let input = Input {
|
||||||
|
x_scale,
|
||||||
|
y_scale,
|
||||||
|
rotation,
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
asm!("swi 0x0F",
|
||||||
|
in("r0") &input as *const Input as usize,
|
||||||
|
in("r1") &mut result as *mut AffineMatrixAttributes as usize,
|
||||||
|
in("r2") 1,
|
||||||
|
in("r3") 2,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test_case]
|
||||||
|
fn affine(_gba: &mut crate::Gba) {
|
||||||
|
// expect identity matrix
|
||||||
|
let aff = affine_matrix(1 << 8, 1 << 8, 0);
|
||||||
|
assert_eq!(aff.p_a, 1 << 8);
|
||||||
|
assert_eq!(aff.p_d, 1 << 8);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue