mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-23 16:21:33 +11:00
start on writing docs. A long way to go...
This commit is contained in:
parent
c84e81299b
commit
c608458247
|
@ -16,7 +16,6 @@ pub mod bitmap3;
|
||||||
pub mod bitmap4;
|
pub mod bitmap4;
|
||||||
/// Test logo of agb.
|
/// Test logo of agb.
|
||||||
pub mod example_logo;
|
pub mod example_logo;
|
||||||
/// Implements sprites.
|
|
||||||
pub mod object;
|
pub mod object;
|
||||||
/// Palette type.
|
/// Palette type.
|
||||||
pub mod palette16;
|
pub mod palette16;
|
||||||
|
|
|
@ -1,10 +1,21 @@
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
//! # Sprites and objects
|
||||||
|
//!
|
||||||
|
//! There are two implementations of objects depending on how you want to make
|
||||||
|
//! your game. There is the *Managed* and *Unmanaged* systems, given by
|
||||||
|
//! [OamManaged] and [OamUnmanaged] respectively. The managed Oam is easier to
|
||||||
|
//! use and has built in support for setting the `z` coordinate. The unmanaged
|
||||||
|
//! Oam is simpler and more efficient with the tradeoff that it is slightly
|
||||||
|
//! harder to integrate into your games depending on how they are architectured.
|
||||||
|
|
||||||
mod affine;
|
mod affine;
|
||||||
mod managed;
|
mod managed;
|
||||||
mod sprites;
|
mod sprites;
|
||||||
mod unmanaged;
|
mod unmanaged;
|
||||||
|
|
||||||
pub use sprites::{
|
pub use sprites::{
|
||||||
include_aseprite, DynamicSprite, Graphics, Size, Sprite, SpriteLoader, SpriteVram, Tag, TagMap,
|
include_aseprite, DynamicSprite, Graphics, PaletteVram, Size, Sprite, SpriteLoader, SpriteVram,
|
||||||
|
Tag, TagMap,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use affine::AffineMatrixInstance;
|
pub use affine::AffineMatrixInstance;
|
||||||
|
|
|
@ -14,6 +14,11 @@ struct AffineMatrixData {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) struct AffineMatrixVram(Rc<AffineMatrixData>);
|
pub(crate) struct AffineMatrixVram(Rc<AffineMatrixData>);
|
||||||
|
|
||||||
|
/// An affine matrix that can be used on objects. It is just in time copied to
|
||||||
|
/// vram, so you can have as many as you like of these but you can only use up
|
||||||
|
/// to 16 in one frame. They are reference counted (Cloning is cheap) and
|
||||||
|
/// immutable, if you want to change a matrix you must make a new one and set it
|
||||||
|
/// on all your objects.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct AffineMatrixInstance {
|
pub struct AffineMatrixInstance {
|
||||||
location: AffineMatrixVram,
|
location: AffineMatrixVram,
|
||||||
|
@ -21,6 +26,9 @@ pub struct AffineMatrixInstance {
|
||||||
|
|
||||||
impl AffineMatrixInstance {
|
impl AffineMatrixInstance {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
/// Creates an instance of an affine matrix from its object form. Check out
|
||||||
|
/// the docs for [AffineMatrix][crate::display::affine::AffineMatrix] to see
|
||||||
|
/// how you can use them to create effects.
|
||||||
pub fn new(affine_matrix: AffineMatrixObject) -> AffineMatrixInstance {
|
pub fn new(affine_matrix: AffineMatrixObject) -> AffineMatrixInstance {
|
||||||
AffineMatrixInstance {
|
AffineMatrixInstance {
|
||||||
location: AffineMatrixVram(Rc::new(AffineMatrixData {
|
location: AffineMatrixVram(Rc::new(AffineMatrixData {
|
||||||
|
|
|
@ -4,4 +4,4 @@ mod sprite_allocator;
|
||||||
const BYTES_PER_TILE_4BPP: usize = 32;
|
const BYTES_PER_TILE_4BPP: usize = 32;
|
||||||
|
|
||||||
pub use sprite::{include_aseprite, Graphics, Size, Sprite, Tag, TagMap};
|
pub use sprite::{include_aseprite, Graphics, Size, Sprite, Tag, TagMap};
|
||||||
pub use sprite_allocator::{DynamicSprite, SpriteLoader, SpriteVram};
|
pub use sprite_allocator::{DynamicSprite, PaletteVram, SpriteLoader, SpriteVram};
|
||||||
|
|
|
@ -28,6 +28,7 @@ impl Sprite {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
/// Gives the size of the sprite
|
||||||
pub fn size(&self) -> Size {
|
pub fn size(&self) -> Size {
|
||||||
self.size
|
self.size
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,14 +87,17 @@ impl Drop for PaletteVramData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
/// A palette in vram, this is reference counted so it is cheap to Clone.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct PaletteVram {
|
pub struct PaletteVram {
|
||||||
data: Rc<PaletteVramData>,
|
data: Rc<PaletteVramData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PaletteVram {
|
impl PaletteVram {
|
||||||
fn new(palette: &Palette16) -> Option<PaletteVram> {
|
/// Attempts to allocate a new palette in sprite vram
|
||||||
let allocated = unsafe { PALETTE_ALLOCATOR.alloc(Palette16::layout()) }?;
|
pub fn new(palette: &Palette16) -> Result<PaletteVram, LoaderError> {
|
||||||
|
let allocated = unsafe { PALETTE_ALLOCATOR.alloc(Palette16::layout()) }
|
||||||
|
.ok_or(LoaderError::PaletteFull)?;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
allocated
|
allocated
|
||||||
|
@ -103,7 +106,7 @@ impl PaletteVram {
|
||||||
.copy_from_nonoverlapping(palette.colours.as_ptr(), palette.colours.len());
|
.copy_from_nonoverlapping(palette.colours.as_ptr(), palette.colours.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(PaletteVram {
|
Ok(PaletteVram {
|
||||||
data: Rc::new(PaletteVramData {
|
data: Rc::new(PaletteVramData {
|
||||||
location: Location::from_palette_ptr(allocated),
|
location: Location::from_palette_ptr(allocated),
|
||||||
}),
|
}),
|
||||||
|
@ -124,20 +127,37 @@ impl Drop for SpriteVramData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[non_exhaustive]
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
|
pub enum LoaderError {
|
||||||
|
SpriteFull,
|
||||||
|
PaletteFull,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A sprite that is currently loaded into vram.
|
||||||
|
///
|
||||||
|
/// This is referenced counted such that clones of this are cheap and can be
|
||||||
|
/// reused between objects. When nothing references the sprite it gets
|
||||||
|
/// deallocated from vram.
|
||||||
|
///
|
||||||
|
/// You can create one of these either via the [DynamicSprite] interface, which
|
||||||
|
/// allows you to generate sprites at run time, or via a [SpriteLoader] (or
|
||||||
|
/// [OamManaged][super::super::OamManaged]).
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct SpriteVram {
|
pub struct SpriteVram {
|
||||||
data: Rc<SpriteVramData>,
|
data: Rc<SpriteVramData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpriteVram {
|
impl SpriteVram {
|
||||||
fn new(data: &[u8], size: Size, palette: PaletteVram) -> Option<SpriteVram> {
|
fn new(data: &[u8], size: Size, palette: PaletteVram) -> Result<SpriteVram, LoaderError> {
|
||||||
let allocated = unsafe { SPRITE_ALLOCATOR.alloc(size.layout()) }?;
|
let allocated =
|
||||||
|
unsafe { SPRITE_ALLOCATOR.alloc(size.layout()) }.ok_or(LoaderError::SpriteFull)?;
|
||||||
unsafe {
|
unsafe {
|
||||||
allocated
|
allocated
|
||||||
.as_ptr()
|
.as_ptr()
|
||||||
.copy_from_nonoverlapping(data.as_ptr(), data.len());
|
.copy_from_nonoverlapping(data.as_ptr(), data.len());
|
||||||
}
|
}
|
||||||
Some(SpriteVram {
|
Ok(SpriteVram {
|
||||||
data: Rc::new(SpriteVramData {
|
data: Rc::new(SpriteVramData {
|
||||||
location: Location::from_sprite_ptr(allocated),
|
location: Location::from_sprite_ptr(allocated),
|
||||||
size,
|
size,
|
||||||
|
@ -163,19 +183,19 @@ impl SpriteLoader {
|
||||||
fn create_sprite_no_insert(
|
fn create_sprite_no_insert(
|
||||||
palette_map: &mut HashMap<PaletteId, Weak<PaletteVramData>>,
|
palette_map: &mut HashMap<PaletteId, Weak<PaletteVramData>>,
|
||||||
sprite: &'static Sprite,
|
sprite: &'static Sprite,
|
||||||
) -> Option<(Weak<SpriteVramData>, SpriteVram)> {
|
) -> Result<(Weak<SpriteVramData>, SpriteVram), LoaderError> {
|
||||||
let palette = Self::try_get_vram_palette_asoc(palette_map, sprite.palette)?;
|
let palette = Self::try_get_vram_palette_asoc(palette_map, sprite.palette)?;
|
||||||
|
|
||||||
let sprite = SpriteVram::new(sprite.data, sprite.size, palette)?;
|
let sprite = SpriteVram::new(sprite.data, sprite.size, palette)?;
|
||||||
Some((Rc::downgrade(&sprite.data), sprite))
|
Ok((Rc::downgrade(&sprite.data), sprite))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_get_vram_palette_asoc(
|
fn try_get_vram_palette_asoc(
|
||||||
palette_map: &mut HashMap<PaletteId, Weak<PaletteVramData>>,
|
palette_map: &mut HashMap<PaletteId, Weak<PaletteVramData>>,
|
||||||
palette: &'static Palette16,
|
palette: &'static Palette16,
|
||||||
) -> Option<PaletteVram> {
|
) -> Result<PaletteVram, LoaderError> {
|
||||||
let id = PaletteId::from_static_palette(palette);
|
let id = PaletteId::from_static_palette(palette);
|
||||||
Some(match palette_map.entry(id) {
|
Ok(match palette_map.entry(id) {
|
||||||
crate::hash_map::Entry::Occupied(mut entry) => match entry.get().upgrade() {
|
crate::hash_map::Entry::Occupied(mut entry) => match entry.get().upgrade() {
|
||||||
Some(data) => PaletteVram { data },
|
Some(data) => PaletteVram { data },
|
||||||
None => {
|
None => {
|
||||||
|
@ -192,12 +212,16 @@ impl SpriteLoader {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_get_vram_sprite(&mut self, sprite: &'static Sprite) -> Option<SpriteVram> {
|
/// Attempts to get a sprite
|
||||||
|
pub fn try_get_vram_sprite(
|
||||||
|
&mut self,
|
||||||
|
sprite: &'static Sprite,
|
||||||
|
) -> Result<SpriteVram, LoaderError> {
|
||||||
// check if we already have the sprite in vram
|
// check if we already have the sprite in vram
|
||||||
|
|
||||||
let id = SpriteId::from_static_sprite(sprite);
|
let id = SpriteId::from_static_sprite(sprite);
|
||||||
|
|
||||||
Some(match self.static_sprite_map.entry(id) {
|
Ok(match self.static_sprite_map.entry(id) {
|
||||||
crate::hash_map::Entry::Occupied(mut entry) => match entry.get().upgrade() {
|
crate::hash_map::Entry::Occupied(mut entry) => match entry.get().upgrade() {
|
||||||
Some(data) => SpriteVram { data },
|
Some(data) => SpriteVram { data },
|
||||||
None => {
|
None => {
|
||||||
|
@ -216,18 +240,24 @@ impl SpriteLoader {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_get_vram_palette(&mut self, palette: &'static Palette16) -> Option<PaletteVram> {
|
/// Attempts to allocate a static palette
|
||||||
|
pub fn try_get_vram_palette(
|
||||||
|
&mut self,
|
||||||
|
palette: &'static Palette16,
|
||||||
|
) -> Result<PaletteVram, LoaderError> {
|
||||||
Self::try_get_vram_palette_asoc(&mut self.static_palette_map, palette)
|
Self::try_get_vram_palette_asoc(&mut self.static_palette_map, palette)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Allocates a sprite to vram, panics if it cannot fit.
|
||||||
pub fn get_vram_sprite(&mut self, sprite: &'static Sprite) -> SpriteVram {
|
pub fn get_vram_sprite(&mut self, sprite: &'static Sprite) -> SpriteVram {
|
||||||
self.try_get_vram_sprite(sprite)
|
self.try_get_vram_sprite(sprite)
|
||||||
.expect("no free sprite slots")
|
.expect("cannot create sprite")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Allocates a palette to vram, panics if it cannot fit.
|
||||||
pub fn get_vram_palette(&mut self, palette: &'static Palette16) -> PaletteVram {
|
pub fn get_vram_palette(&mut self, palette: &'static Palette16) -> PaletteVram {
|
||||||
self.try_get_vram_palette(palette)
|
self.try_get_vram_palette(palette)
|
||||||
.expect("no free palette slots")
|
.expect("cannot create sprite")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn new() -> Self {
|
pub(crate) fn new() -> Self {
|
||||||
|
@ -237,6 +267,9 @@ impl SpriteLoader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove internal references to sprites that no longer exist in vram. If
|
||||||
|
/// you neglect calling this, memory will leak over time in relation to the
|
||||||
|
/// total number of different sprites used. It will not leak vram.
|
||||||
pub fn garbage_collect(&mut self) {
|
pub fn garbage_collect(&mut self) {
|
||||||
self.static_sprite_map
|
self.static_sprite_map
|
||||||
.retain(|_, v| Weak::strong_count(v) != 0);
|
.retain(|_, v| Weak::strong_count(v) != 0);
|
||||||
|
@ -277,18 +310,15 @@ impl DynamicSprite<'_> {
|
||||||
DynamicSprite { data, size }
|
DynamicSprite { data, size }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
/// Tries to copy the sprite to vram to be used to set object sprites.
|
/// Tries to copy the sprite to vram to be used to set object sprites.
|
||||||
/// Returns None if there is no room in sprite vram.
|
pub fn try_vram(&self, palette: PaletteVram) -> Result<SpriteVram, LoaderError> {
|
||||||
pub fn try_vram(&self, palette: PaletteVram) -> Option<SpriteVram> {
|
|
||||||
SpriteVram::new(self.data, self.size, palette)
|
SpriteVram::new(self.data, self.size, palette)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
/// Tries to copy the sprite to vram to be used to set object sprites.
|
/// Tries to copy the sprite to vram to be used to set object sprites.
|
||||||
/// Panics if there is no room in sprite vram.
|
/// Panics if it cannot be allocated.
|
||||||
pub fn to_vram(&self, palette: PaletteVram) -> SpriteVram {
|
pub fn to_vram(&self, palette: PaletteVram) -> SpriteVram {
|
||||||
self.try_vram(palette)
|
self.try_vram(palette).expect("cannot create sprite")
|
||||||
.expect("No slot for sprite available")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,11 @@ impl Default for Attributes {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||||
|
/// The affine mode
|
||||||
pub enum AffineMode {
|
pub enum AffineMode {
|
||||||
|
/// Normal affine, this is where the area of the affine is equal to the sprite size
|
||||||
Affine = 1,
|
Affine = 1,
|
||||||
|
/// Double affine, this is where the area of the affine is double that of the sprite
|
||||||
AffineDouble = 3,
|
AffineDouble = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@ impl Palette16 {
|
||||||
|
|
||||||
// Clippy bug: claims that index is only used in recursion. I can't reproduce in
|
// Clippy bug: claims that index is only used in recursion. I can't reproduce in
|
||||||
// other examples, even just copy pasting this struct and impl into a blank project :/
|
// other examples, even just copy pasting this struct and impl into a blank project :/
|
||||||
#[allow(clippy::only_used_in_recursion)]
|
|
||||||
pub fn update_colour(&mut self, index: usize, colour: u16) {
|
pub fn update_colour(&mut self, index: usize, colour: u16) {
|
||||||
self.colours[index] = colour;
|
self.colours[index] = colour;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue