mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-24 00:31:34 +11:00
Merge pull request #65 from corwinkuiper/optimisation-of-backgrounds
Optimisation of backgrounds
This commit is contained in:
commit
8e50dc8bd8
|
@ -55,7 +55,7 @@ pub fn main() -> ! {
|
||||||
gfx.set_background_tilemap(0, &MAP_TILES);
|
gfx.set_background_tilemap(0, &MAP_TILES);
|
||||||
|
|
||||||
let mut background = gfx.get_background().unwrap();
|
let mut background = gfx.get_background().unwrap();
|
||||||
background.set_map(&MAP_MAP, 32, 32);
|
background.draw_full_map(&MAP_MAP, (32, 32).into());
|
||||||
background.show();
|
background.show();
|
||||||
|
|
||||||
let mut object = gba.display.object.get();
|
let mut object = gba.display.object.get();
|
||||||
|
|
|
@ -21,8 +21,7 @@ pub fn main() -> ! {
|
||||||
entries[tile_id as usize] = tile_id | (palette_entry << 12);
|
entries[tile_id as usize] = tile_id | (palette_entry << 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
back.set_map(&entries, 30, 20);
|
back.draw_full_map(&entries, (30, 20).into());
|
||||||
back.set_position(0, 0);
|
|
||||||
back.show();
|
back.show();
|
||||||
|
|
||||||
loop {}
|
loop {}
|
||||||
|
|
BIN
agb/iwillnotletyouletmedown.gba
Executable file
BIN
agb/iwillnotletyouletmedown.gba
Executable file
Binary file not shown.
|
@ -15,8 +15,7 @@ fn logo_display(gba: &mut crate::Gba) {
|
||||||
entries[tile_id as usize] = tile_id | (palette_entry << 12);
|
entries[tile_id as usize] = tile_id | (palette_entry << 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
back.set_map(&entries, 30, 20);
|
back.draw_full_map(&entries, (30, 20).into());
|
||||||
back.set_position(0, 0);
|
|
||||||
back.show();
|
back.show();
|
||||||
|
|
||||||
crate::assert_image_output("gfx/test_logo.png");
|
crate::assert_image_output("gfx/test_logo.png");
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
use core::{borrow::Borrow, cell::RefCell, convert::TryInto};
|
use core::{convert::TryInto, ops::Deref};
|
||||||
|
|
||||||
use crate::memory_mapped::MemoryMapped1DArray;
|
use crate::{
|
||||||
|
memory_mapped::MemoryMapped1DArray,
|
||||||
|
number::{Rect, Vector2D},
|
||||||
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
object::ObjectControl, palette16, set_graphics_mode, set_graphics_settings, DisplayMode,
|
palette16, set_graphics_mode, set_graphics_settings, DisplayMode, GraphicsSettings,
|
||||||
GraphicsSettings, DISPLAY_CONTROL,
|
DISPLAY_CONTROL,
|
||||||
};
|
};
|
||||||
|
|
||||||
const PALETTE_BACKGROUND: MemoryMapped1DArray<u16, 256> =
|
const PALETTE_BACKGROUND: MemoryMapped1DArray<u16, 256> =
|
||||||
|
@ -42,29 +45,18 @@ pub enum BackgroundSize {
|
||||||
/// The map background is the method of drawing game maps to the screen. It
|
/// The map background is the method of drawing game maps to the screen. It
|
||||||
/// automatically handles copying the correct portion of a provided map to the
|
/// automatically handles copying the correct portion of a provided map to the
|
||||||
/// assigned block depending on given coordinates.
|
/// assigned block depending on given coordinates.
|
||||||
pub struct Background<'a> {
|
pub struct Background {
|
||||||
background: u8,
|
background: u8,
|
||||||
block: u8,
|
block: u8,
|
||||||
map: Option<MapStorage<'a>>,
|
|
||||||
map_dim_x: u32,
|
|
||||||
map_dim_y: u32,
|
|
||||||
pos_x: i32,
|
pos_x: i32,
|
||||||
pos_y: i32,
|
pos_y: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum MapStorage<'a> {
|
impl Background {
|
||||||
R(&'a RefCell<[u16]>),
|
unsafe fn new(layer: u8, block: u8) -> Background {
|
||||||
S(&'a [u16]),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Background<'a> {
|
|
||||||
unsafe fn new(layer: u8, block: u8) -> Background<'a> {
|
|
||||||
let mut background = Background {
|
let mut background = Background {
|
||||||
background: layer,
|
background: layer,
|
||||||
block,
|
block,
|
||||||
map: None,
|
|
||||||
map_dim_x: 0,
|
|
||||||
map_dim_y: 0,
|
|
||||||
pos_x: 0,
|
pos_x: 0,
|
||||||
pos_y: 0,
|
pos_y: 0,
|
||||||
};
|
};
|
||||||
|
@ -73,34 +65,12 @@ impl<'a> Background<'a> {
|
||||||
background.set_block(block);
|
background.set_block(block);
|
||||||
background
|
background
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the internal map to the provided map. Dimensions should be the
|
|
||||||
/// dimensions of the map. The mapping between coordinate and index is given
|
|
||||||
/// by `y * dim_x + x`. The length of the map slice should be `dim_x *
|
|
||||||
/// dim_y`, or panics may occur.
|
|
||||||
///
|
|
||||||
/// The portion of this map that is in view is copied to the map block
|
|
||||||
/// assigned to this background.
|
|
||||||
pub fn set_map(&mut self, map: &'a [u16], dim_x: u32, dim_y: u32) {
|
|
||||||
self.map = Some(MapStorage::S(map));
|
|
||||||
self.map_dim_x = dim_x;
|
|
||||||
self.map_dim_y = dim_y;
|
|
||||||
self.draw_full_map();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_map_refcell(&mut self, map: &'a RefCell<[u16]>, dim_x: u32, dim_y: u32) {
|
|
||||||
self.map = Some(MapStorage::R(map));
|
|
||||||
self.map_dim_x = dim_x;
|
|
||||||
self.map_dim_y = dim_y;
|
|
||||||
self.draw_full_map();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Background<'_> {
|
impl Background {
|
||||||
/// Sets the background to be shown on screen. Requires the background to
|
/// Sets the background to be shown on screen. Requires the background to
|
||||||
/// have a map enabled otherwise a panic is caused.
|
/// have a map enabled otherwise a panic is caused.
|
||||||
pub fn show(&mut self) {
|
pub fn show(&mut self) {
|
||||||
assert!(self.map.is_some(), "map should be set before showing");
|
|
||||||
let mode = DISPLAY_CONTROL.get();
|
let mode = DISPLAY_CONTROL.get();
|
||||||
let new_mode = mode | (1 << (self.background + 0x08));
|
let new_mode = mode | (1 << (self.background + 0x08));
|
||||||
DISPLAY_CONTROL.set(new_mode);
|
DISPLAY_CONTROL.set(new_mode);
|
||||||
|
@ -143,30 +113,21 @@ impl Background<'_> {
|
||||||
unsafe { self.set_bits(0x0E, 2, size as u16) }
|
unsafe { self.set_bits(0x0E, 2, size as u16) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map_get(&self, x: i32, y: i32, default: u16) -> u16 {
|
fn map_get<T>(&self, map: &T, dim_x: u32, dim_y: u32, x: i32, y: i32, default: u16) -> u16
|
||||||
match self.map.as_ref().unwrap() {
|
where
|
||||||
MapStorage::R(map) => {
|
T: Deref<Target = [u16]>,
|
||||||
let map = (*map).borrow();
|
{
|
||||||
if x >= self.map_dim_x as i32 || x < 0 || y >= self.map_dim_y as i32 || y < 0 {
|
if x >= dim_x as i32 || x < 0 || y >= dim_y as i32 || y < 0 {
|
||||||
default
|
default
|
||||||
} else {
|
} else {
|
||||||
map[(self.map_dim_x as i32 * y + x) as usize]
|
map[(dim_x as i32 * y + x) as usize]
|
||||||
}
|
|
||||||
}
|
|
||||||
MapStorage::S(map) => {
|
|
||||||
if x >= self.map_dim_x as i32 || x < 0 || y >= self.map_dim_y as i32 || y < 0 {
|
|
||||||
default
|
|
||||||
} else {
|
|
||||||
map[(self.map_dim_x as i32 * y + x) as usize]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_x(&mut self, x: u16) {
|
fn set_x(&self, x: u16) {
|
||||||
unsafe { *((0x0400_0010 + 4 * self.background as usize) as *mut u16) = x }
|
unsafe { *((0x0400_0010 + 4 * self.background as usize) as *mut u16) = x }
|
||||||
}
|
}
|
||||||
fn set_y(&mut self, y: u16) {
|
fn set_y(&self, y: u16) {
|
||||||
unsafe { *((0x0400_0012 + 4 * self.background as usize) as *mut u16) = y }
|
unsafe { *((0x0400_0012 + 4 * self.background as usize) as *mut u16) = y }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,20 +135,60 @@ impl Background<'_> {
|
||||||
/// block assigned to this background. This is currently unnecesary to call.
|
/// block assigned to this background. This is currently unnecesary to call.
|
||||||
/// Setting position already updates the drawn map, and changing map forces
|
/// Setting position already updates the drawn map, and changing map forces
|
||||||
/// an update.
|
/// an update.
|
||||||
pub fn draw_full_map(&mut self) {
|
pub fn draw_full_map(&mut self, map: &[u16], dimensions: Vector2D<u32>) {
|
||||||
|
let area: Rect<i32> = Rect {
|
||||||
|
position: Vector2D::new(-1, -1),
|
||||||
|
size: Vector2D::new(32, 22),
|
||||||
|
};
|
||||||
|
self.draw_area(map, dimensions, area);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Forces a specific area of the screen to be drawn, taking into account any positonal offsets.
|
||||||
|
pub fn draw_area(&self, map: &[u16], dimensions: Vector2D<u32>, area: Rect<i32>) {
|
||||||
|
self.draw_area_mapped(
|
||||||
|
&map,
|
||||||
|
dimensions.x,
|
||||||
|
dimensions.y,
|
||||||
|
area.position.x,
|
||||||
|
area.position.y,
|
||||||
|
area.size.x,
|
||||||
|
area.size.y,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
fn draw_area_mapped<T>(
|
||||||
|
&self,
|
||||||
|
map: &T,
|
||||||
|
dim_x: u32,
|
||||||
|
dim_y: u32,
|
||||||
|
left: i32,
|
||||||
|
top: i32,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
) where
|
||||||
|
T: Deref<Target = [u16]>,
|
||||||
|
{
|
||||||
let x_map_space = self.pos_x / 8;
|
let x_map_space = self.pos_x / 8;
|
||||||
let y_map_space = self.pos_y / 8;
|
let y_map_space = self.pos_y / 8;
|
||||||
|
|
||||||
let x_block_space = x_map_space % 32;
|
let x_block_space = x_map_space % 32;
|
||||||
let y_block_space = y_map_space % 32;
|
let y_block_space = y_map_space % 32;
|
||||||
|
|
||||||
for x in -1..31 {
|
for x in left..(left + width) {
|
||||||
for y in -1..21 {
|
for y in top..(top + height) {
|
||||||
unsafe {
|
unsafe {
|
||||||
(&mut (*MAP)[self.block as usize][(y_block_space + y).rem_euclid(32) as usize]
|
(&mut (*MAP)[self.block as usize][(y_block_space + y).rem_euclid(32) as usize]
|
||||||
[(x_block_space + x).rem_euclid(32) as usize]
|
[(x_block_space + x).rem_euclid(32) as usize]
|
||||||
as *mut u16)
|
as *mut u16)
|
||||||
.write_volatile(self.map_get(x_map_space + x, y_map_space + y, 0))
|
.write_volatile(self.map_get(
|
||||||
|
map,
|
||||||
|
dim_x,
|
||||||
|
dim_y,
|
||||||
|
x_map_space + x,
|
||||||
|
y_map_space + y,
|
||||||
|
0,
|
||||||
|
))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -196,7 +197,21 @@ impl Background<'_> {
|
||||||
/// Sets the position of the map to be shown on screen. This automatically
|
/// Sets the position of the map to be shown on screen. This automatically
|
||||||
/// manages copying the correct portion to the map block and moving the map
|
/// manages copying the correct portion to the map block and moving the map
|
||||||
/// registers.
|
/// registers.
|
||||||
pub fn set_position(&mut self, x: i32, y: i32) {
|
pub fn set_position(
|
||||||
|
&mut self,
|
||||||
|
map: &[u16],
|
||||||
|
dimensions: Vector2D<u32>,
|
||||||
|
position: Vector2D<i32>,
|
||||||
|
) {
|
||||||
|
self.set_position_mapped(&map, dimensions.x, dimensions.y, position.x, position.y);
|
||||||
|
self.pos_x = position.x;
|
||||||
|
self.pos_y = position.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_position_mapped<T>(&self, map: &T, dim_x: u32, dim_y: u32, x: i32, y: i32)
|
||||||
|
where
|
||||||
|
T: Deref<Target = [u16]>,
|
||||||
|
{
|
||||||
let x_map_space = x / 8;
|
let x_map_space = x / 8;
|
||||||
let y_map_space = y / 8;
|
let y_map_space = y / 8;
|
||||||
|
|
||||||
|
@ -209,12 +224,9 @@ impl Background<'_> {
|
||||||
let x_block_space = x_map_space % 32;
|
let x_block_space = x_map_space % 32;
|
||||||
let y_block_space = y_map_space % 32;
|
let y_block_space = y_map_space % 32;
|
||||||
|
|
||||||
self.pos_x = x;
|
|
||||||
self.pos_y = y;
|
|
||||||
|
|
||||||
// don't fancily handle if we've moved more than one tile, just copy the whole new map
|
// don't fancily handle if we've moved more than one tile, just copy the whole new map
|
||||||
if x_difference.abs() > 1 || y_difference.abs() > 1 {
|
if x_difference.abs() > 1 || y_difference.abs() > 1 {
|
||||||
self.draw_full_map();
|
self.draw_area_mapped(map, dim_x, dim_y, -1, 32, -1, 22);
|
||||||
} else {
|
} else {
|
||||||
if x_difference != 0 {
|
if x_difference != 0 {
|
||||||
let x_offset = match x_difference {
|
let x_offset = match x_difference {
|
||||||
|
@ -229,6 +241,9 @@ impl Background<'_> {
|
||||||
[(x_block_space + x_offset).rem_euclid(32) as usize]
|
[(x_block_space + x_offset).rem_euclid(32) as usize]
|
||||||
as *mut u16)
|
as *mut u16)
|
||||||
.write_volatile(self.map_get(
|
.write_volatile(self.map_get(
|
||||||
|
map,
|
||||||
|
dim_x,
|
||||||
|
dim_y,
|
||||||
x_map_space + x_offset,
|
x_map_space + x_offset,
|
||||||
y_map_space + y,
|
y_map_space + y,
|
||||||
0,
|
0,
|
||||||
|
@ -249,6 +264,9 @@ impl Background<'_> {
|
||||||
[(x_block_space + x).rem_euclid(32) as usize]
|
[(x_block_space + x).rem_euclid(32) as usize]
|
||||||
as *mut u16)
|
as *mut u16)
|
||||||
.write_volatile(self.map_get(
|
.write_volatile(self.map_get(
|
||||||
|
map,
|
||||||
|
dim_x,
|
||||||
|
dim_y,
|
||||||
x_map_space + x,
|
x_map_space + x,
|
||||||
y_map_space + y_offset,
|
y_map_space + y_offset,
|
||||||
0,
|
0,
|
||||||
|
|
|
@ -7,6 +7,24 @@ use core::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub trait Number:
|
||||||
|
Sized
|
||||||
|
+ Copy
|
||||||
|
+ PartialOrd
|
||||||
|
+ Ord
|
||||||
|
+ PartialEq
|
||||||
|
+ Eq
|
||||||
|
+ Add<Output = Self>
|
||||||
|
+ Sub<Output = Self>
|
||||||
|
+ Rem<Output = Self>
|
||||||
|
+ Div<Output = Self>
|
||||||
|
+ Mul<Output = Self>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: FixedWidthUnsignedInteger, const N: usize> Number for Num<I, N> {}
|
||||||
|
impl<I: FixedWidthUnsignedInteger> Number for I {}
|
||||||
|
|
||||||
pub trait FixedWidthUnsignedInteger:
|
pub trait FixedWidthUnsignedInteger:
|
||||||
Sized
|
Sized
|
||||||
+ Copy
|
+ Copy
|
||||||
|
@ -73,22 +91,8 @@ fixed_width_signed_integer_impl!(i32);
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Num<I: FixedWidthUnsignedInteger, const N: usize>(I);
|
pub struct Num<I: FixedWidthUnsignedInteger, const N: usize>(I);
|
||||||
|
|
||||||
pub type Number<const N: usize> = Num<i32, N>;
|
pub type FixedNum<const N: usize> = Num<i32, N>;
|
||||||
|
pub type Integer = Num<i32, 0>;
|
||||||
pub fn change_base<
|
|
||||||
I: FixedWidthUnsignedInteger,
|
|
||||||
J: FixedWidthUnsignedInteger + Into<I>,
|
|
||||||
const N: usize,
|
|
||||||
const M: usize,
|
|
||||||
>(
|
|
||||||
num: Num<J, N>,
|
|
||||||
) -> Num<I, M> {
|
|
||||||
if N < M {
|
|
||||||
Num(num.0.into() << (M - N))
|
|
||||||
} else {
|
|
||||||
Num(num.0.into() >> (N - M))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: FixedWidthUnsignedInteger, const N: usize> From<I> for Num<I, N> {
|
impl<I: FixedWidthUnsignedInteger, const N: usize> From<I> for Num<I, N> {
|
||||||
fn from(value: I) -> Self {
|
fn from(value: I) -> Self {
|
||||||
|
@ -213,6 +217,15 @@ impl<I: FixedWidthSignedInteger, const N: usize> Neg for Num<I, N> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: FixedWidthUnsignedInteger, const N: usize> Num<I, N> {
|
impl<I: FixedWidthUnsignedInteger, const N: usize> Num<I, N> {
|
||||||
|
pub fn change_base<J: FixedWidthUnsignedInteger + From<I>, const M: usize>(self) -> Num<J, M> {
|
||||||
|
let n: J = self.0.into();
|
||||||
|
if N < M {
|
||||||
|
Num(n << (M - N))
|
||||||
|
} else {
|
||||||
|
Num(n >> (N - M))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn from_raw(n: I) -> Self {
|
pub fn from_raw(n: I) -> Self {
|
||||||
Num(n)
|
Num(n)
|
||||||
}
|
}
|
||||||
|
@ -276,7 +289,7 @@ impl<I: FixedWidthSignedInteger, const N: usize> Num<I, N> {
|
||||||
pub fn sin(self) -> Self {
|
pub fn sin(self) -> Self {
|
||||||
let one: Self = I::one().into();
|
let one: Self = I::one().into();
|
||||||
let four: I = 4.into();
|
let four: I = 4.into();
|
||||||
(self - one / four).cos()
|
(self + one / four).cos()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,8 +352,8 @@ fn test_change_base(_gba: &mut super::Gba) {
|
||||||
let two: Num<i32, 9> = 2.into();
|
let two: Num<i32, 9> = 2.into();
|
||||||
let three: Num<i32, 4> = 3.into();
|
let three: Num<i32, 4> = 3.into();
|
||||||
|
|
||||||
assert_eq!(two + change_base(three), 5.into());
|
assert_eq!(two + three.change_base(), 5.into());
|
||||||
assert_eq!(three + change_base(two), 5.into());
|
assert_eq!(three + two.change_base(), 5.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test_case]
|
#[test_case]
|
||||||
|
@ -432,3 +445,145 @@ impl<I: FixedWidthUnsignedInteger, const N: usize> Debug for Num<I, N> {
|
||||||
write!(f, "Num<{}, {}>({})", type_name::<I>(), N, self)
|
write!(f, "Num<{}, {}>({})", type_name::<I>(), N, self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
|
pub struct Vector2D<T: Number> {
|
||||||
|
pub x: T,
|
||||||
|
pub y: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Number> Add<Vector2D<T>> for Vector2D<T> {
|
||||||
|
type Output = Vector2D<T>;
|
||||||
|
fn add(self, rhs: Vector2D<T>) -> Self::Output {
|
||||||
|
Vector2D {
|
||||||
|
x: self.x + rhs.x,
|
||||||
|
y: self.y + rhs.y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Number, U: Number + Into<T>> Mul<U> for Vector2D<T> {
|
||||||
|
type Output = Vector2D<T>;
|
||||||
|
fn mul(self, rhs: U) -> Self::Output {
|
||||||
|
Vector2D {
|
||||||
|
x: self.x * rhs.into(),
|
||||||
|
y: self.y * rhs.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Number, U: Number + Into<T>> Div<U> for Vector2D<T> {
|
||||||
|
type Output = Vector2D<T>;
|
||||||
|
fn div(self, rhs: U) -> Self::Output {
|
||||||
|
Vector2D {
|
||||||
|
x: self.x / rhs.into(),
|
||||||
|
y: self.y / rhs.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test_case]
|
||||||
|
fn test_vector_multiplication_and_division(_gba: &mut super::Gba) {
|
||||||
|
let a: Vector2D<i32> = (1, 2).into();
|
||||||
|
let b = a * 5;
|
||||||
|
let c = b / 5;
|
||||||
|
assert_eq!(b, (5, 10).into());
|
||||||
|
assert_eq!(a, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Number> AddAssign<Self> for Vector2D<T> {
|
||||||
|
fn add_assign(&mut self, rhs: Self) {
|
||||||
|
*self = *self + rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Number> Sub<Vector2D<T>> for Vector2D<T> {
|
||||||
|
type Output = Vector2D<T>;
|
||||||
|
fn sub(self, rhs: Vector2D<T>) -> Self::Output {
|
||||||
|
Vector2D {
|
||||||
|
x: self.x - rhs.x,
|
||||||
|
y: self.y - rhs.y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Number> SubAssign<Self> for Vector2D<T> {
|
||||||
|
fn sub_assign(&mut self, rhs: Self) {
|
||||||
|
*self = *self - rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: FixedWidthUnsignedInteger, const N: usize> Vector2D<Num<I, N>> {
|
||||||
|
pub fn trunc(self) -> Vector2D<I> {
|
||||||
|
Vector2D {
|
||||||
|
x: self.x.trunc(),
|
||||||
|
y: self.y.trunc(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn floor(self) -> Vector2D<I> {
|
||||||
|
Vector2D {
|
||||||
|
x: self.x.floor(),
|
||||||
|
y: self.y.floor(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Number> From<(T, T)> for Vector2D<T> {
|
||||||
|
fn from(f: (T, T)) -> Self {
|
||||||
|
Vector2D::new(f.0, f.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Number> Vector2D<T> {
|
||||||
|
pub fn change_base<U: Number + From<T>>(self) -> Vector2D<U> {
|
||||||
|
(self.x.into(), self.y.into()).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: FixedWidthSignedInteger, const N: usize> Vector2D<Num<I, N>> {
|
||||||
|
pub fn new_from_angle(angle: Num<I, N>) -> Self {
|
||||||
|
Vector2D {
|
||||||
|
x: angle.cos(),
|
||||||
|
y: angle.sin(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: FixedWidthUnsignedInteger, const N: usize> From<Vector2D<I>> for Vector2D<Num<I, N>> {
|
||||||
|
fn from(n: Vector2D<I>) -> Self {
|
||||||
|
Vector2D {
|
||||||
|
x: n.x.into(),
|
||||||
|
y: n.y.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Rect<T: Number> {
|
||||||
|
pub position: Vector2D<T>,
|
||||||
|
pub size: Vector2D<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Number> Rect<T> {
|
||||||
|
pub fn new(position: Vector2D<T>, size: Vector2D<T>) -> Self {
|
||||||
|
Rect { position, size }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Number> Vector2D<T> {
|
||||||
|
pub fn new(x: T, y: T) -> Self {
|
||||||
|
Vector2D { x, y }
|
||||||
|
}
|
||||||
|
pub fn get(self) -> (T, T) {
|
||||||
|
(self.x, self.y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test_case]
|
||||||
|
fn test_vector_changing(_gba: &mut super::Gba) {
|
||||||
|
let v1: Vector2D<FixedNum<8>> = Vector2D::new(1.into(), 2.into());
|
||||||
|
|
||||||
|
let v2 = v1.trunc();
|
||||||
|
assert_eq!(v2.get(), (1, 2));
|
||||||
|
|
||||||
|
assert_eq!(v1 + v1, (v2 + v2).into());
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue