mirror of
https://github.com/italicsjenga/gba.git
synced 2025-01-11 11:31:31 +11:00
object attribute stuff
This commit is contained in:
parent
423a2f584b
commit
6b631474fa
|
@ -32,3 +32,21 @@ without trading away too much in terms of quality.
|
|||
To top it all off, we'll make a simple "memory game" sort of thing. There's some
|
||||
face down cards in a grid, you pick one to check, then you pick the other to
|
||||
check, and then if they match the pair disappears.
|
||||
|
||||
## Drawing Priority
|
||||
|
||||
Both backgrounds and objects can have "priority" values associated with them.
|
||||
TONC and GBATEK have _opposite_ ideas of what it means to have the "highest"
|
||||
priority. TONC goes by highest numerical value, and GBATEK goes by what's on the
|
||||
z-layer closest to the user. Let's list out the rules as clearly as we can:
|
||||
|
||||
* Priority is always two bits, so 0 through 3.
|
||||
* Priority conceptually proceeds in drawing passes that count _down_, so any
|
||||
priority 3 things can get covered up by priority 2 things. In truth there's
|
||||
probably depth testing and buffering stuff going on so it's all one single
|
||||
pass, but conceptually we will imagine it happening as all of the 3 elements,
|
||||
then all of 2, and so on.
|
||||
* Objects always draw over top of backgrounds of equal priority.
|
||||
* Within things of the same type and priority, the lower numbered element "wins"
|
||||
and gets its pixel drawn (bg0 is favored over bg1, obj0 is favored over obj1,
|
||||
etc).
|
||||
|
|
BIN
book/src/ch03/obj_memory_2d1d.jpg
Normal file
BIN
book/src/ch03/obj_memory_2d1d.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 147 KiB |
|
@ -122,10 +122,10 @@ GBA's CPU _can't do any of that_. On the GBA, there's a genuine speed difference
|
|||
between looping over indexes and then indexing each loop (slow) compared to
|
||||
using an iterator that just stores an internal pointer and does +1 offset per
|
||||
loop until it reaches the end (fast). The repeated indexing itself can by itself
|
||||
be an expensive step. If you've got a slice of data to process, be sure to go
|
||||
over it with `.iter()` and `.iter_mut()` if you can, instead of looping by
|
||||
index. This is Rust and all, so probably you were gonna do that anyway, but just
|
||||
a heads up.
|
||||
be an expensive step. If it's like a 3 element array it's no big deal, but if
|
||||
you've got a big slice of data to process, be sure to go over it with `.iter()`
|
||||
and `.iter_mut()` if you can, instead of looping by index. This is Rust and all,
|
||||
so probably you were gonna do that anyway, but just a heads up.
|
||||
|
||||
## Get your Tilemap ready
|
||||
|
||||
|
@ -241,9 +241,7 @@ separate groups of related registers.
|
|||
Each of these are a read/write `u16` location. This is where we get to all of
|
||||
the important details that we've been putting off.
|
||||
|
||||
* 2 bits for the priority of each background (0 being highest). If two
|
||||
backgrounds are set to the same priority the the lower numbered background
|
||||
layer takes prescience.
|
||||
* 2 bits for the priority.
|
||||
* 2 bits for "character base block", the charblock that all of the tile indexes
|
||||
for this background are offset from.
|
||||
* 1 bit for mosaic effect being enabled (we'll get to that below).
|
||||
|
|
|
@ -4,12 +4,387 @@ As with backgrounds, objects can be used in both an affine and non-affine way.
|
|||
For this section we'll focus on the non-affine elements, and then we'll do all
|
||||
the affine stuff in a later chapter.
|
||||
|
||||
TODO: tio afero ke mi diris
|
||||
|
||||
## Objects vs Sprites
|
||||
|
||||
As [TONC](https://www.coranac.com/tonc/text/regobj.htm) helpfully reminds us
|
||||
(and then proceeds to not follow its own advice), we should always try to think
|
||||
in terms of _objects_, not _sprites_. A sprite is a logical / software concern,
|
||||
perhaps a player concern, whereas an object is a hardware concern.
|
||||
|
||||
What's more, a given sprite that the player sees might need more than one object
|
||||
to display. Objects must be either square or rectangular (so sprite bits that
|
||||
stick out probably call for a second object), and can only be from 8x8 to 64x64
|
||||
(so anything bigger has to be two objects lined up to appear as one).
|
||||
|
||||
## General Object Info
|
||||
|
||||
Unlike with backgrounds, you can enable the object layer in any video mode.
|
||||
There's space for 128 object definitions in OAM.
|
||||
|
||||
The display gets a number of cycles per scanline to process objects: 1210 by
|
||||
default, but only 954 if you enable the "HBlank interval free" setting in the
|
||||
display control register. The [cycle cost per
|
||||
object](http://problemkaputt.de/gbatek.htm#lcdobjoverview) depends on the
|
||||
object's size and if it's using affine or regular mode, so enabling the HBlank
|
||||
interval free setting doesn't cut the number of objects displayable by an exact
|
||||
number of objects. The objects are processed in order of their definitions and
|
||||
if you run out of cycles then the rest just don't get shown. If there's a
|
||||
concern that you might run out of cycles you can place important objects (such
|
||||
as the player) at the start of the list and then less important animation
|
||||
objects later on.
|
||||
|
||||
## Ready the Palette
|
||||
|
||||
Objects use the palette the same as the background does. The only difference is
|
||||
that the palette data for objects starts at `0x500_0200`.
|
||||
|
||||
```rust
|
||||
pub const PALRAM_OBJECT_BASE: VolatilePtr<u16> = VolatilePtr(0x500_0200 as *mut u16);
|
||||
|
||||
pub fn object_palette(slot: usize) -> u16 {
|
||||
assert!(slot < 256);
|
||||
unsafe { PALRAM_OBJECT_BASE.offset(slot as isize).read() }
|
||||
}
|
||||
|
||||
pub fn set_object_palette(slot: usize, color: u16) {
|
||||
assert!(slot < 256);
|
||||
unsafe { PALRAM_OBJECT_BASE.offset(slot as isize).write(color) }
|
||||
}
|
||||
```
|
||||
|
||||
## Ready the Tiles
|
||||
|
||||
Objects, as with backgrounds, are composed of 8x8 tiles, and if you want
|
||||
something bigger than 8x8 you have to use more than one tile put together.
|
||||
Object tiles go into the final two charblocks of VRAM (indexes 4 and 5). Because
|
||||
there's only two of them, they are sometimes called the lower block
|
||||
(`0x601_0000`) and the higher/upper block (`0x601_4000`).
|
||||
|
||||
Tile indexes for sprites always offset from the base of the lower block, and
|
||||
they always go 32 bytes at a time, regardless of if the object is set for 4bpp
|
||||
or 8bpp. From this we can determine that there's 512 tile slots in each of the
|
||||
two object charblocks. However, in video modes 3, 4, and 5 the space for the
|
||||
background cuts into the lower charblock, so you can only safely use the upper
|
||||
charblock.
|
||||
|
||||
With backgrounds you picked every single tile individually with a bunch of
|
||||
screen entry values. Objects don't do that at all. Instead you pick a base tile,
|
||||
size, and shape, then it figures out the rest from there. However, you may
|
||||
recall back with the display control register something about an "object memory
|
||||
1d" bit. This is where that comes into play.
|
||||
|
||||
* If object memory is set to be 2d (the default) then each charblock is treated
|
||||
as 32 tiles by 32 tiles square. Each object has a base tile and dimensions,
|
||||
and that just extracts directly from the charblock picture as if you were
|
||||
selecting an area. This mode probably makes for the easiest image editing.
|
||||
* If object memory is set to be 1d then the tiles are loaded sequentially from
|
||||
the starting point, enough to fill in the object's dimensions. This most
|
||||
probably makes it the easiest to program with about things, since programming
|
||||
languages are pretty good at 1d things.
|
||||
|
||||
I'm not sure I explained that well, here's a picture:
|
||||
|
||||
![2d1d-diagram](obj_memory_2d1d.jpg)
|
||||
|
||||
In 2d mode, a new row of tiles starts every 32 tile indexes.
|
||||
|
||||
Of course, the mode that you actually end up using is not particularly
|
||||
important, since it should be the job of your image conversion routine to get
|
||||
everything all lined up and into place anyway.
|
||||
|
||||
## Set the Object Attributes
|
||||
|
||||
The final step is to assign the correct attributes to an object. Each object has
|
||||
three `u16` values that make up its overall attributes.
|
||||
|
||||
Before we go into the details, I want to remind you that the hardware will
|
||||
attempt to process every single object every single frame, and also that all of
|
||||
the GBA's memory is cleared to 0 at startup. Why do these two things matter
|
||||
right now? As you'll see in a second an "all zero" set of object attributes
|
||||
causes an 8x8 object to appear at 0,0 using object tile index 0. This is usually
|
||||
_not_ what you want your unused objects to do. When your game first starts you
|
||||
should take a moment to mark any objects you won't be using as objects to not
|
||||
render.
|
||||
|
||||
### ObjectAttributes.attr0
|
||||
|
||||
* 8 bits for row coordinate (marks the top of the sprite)
|
||||
* 2 bits for object rendering: 0 = Normal, 1 = Affine, 2 = Disabled, 3 = Affine with double rendering area
|
||||
* 2 bits for object mode: 0 = Normal, 1 = Alpha Blending, 2 = Object Window, 3 = Forbidden
|
||||
* 1 bit for mosaic enabled
|
||||
* 1 bit 8bpp color enabled
|
||||
* 2 bits for shape: 0 = Square, 1 = Horizontal, 2 = Vertical, 3 = Forbidden
|
||||
|
||||
If an object is 128 pixels big at Y > 128 you'll get a strange looking result
|
||||
where it acts like Y > -128 and then displays partly off screen to the top.
|
||||
|
||||
### ObjectAttributes.attr1
|
||||
|
||||
* 9 bit for column coordinate (marks the left of the sprite)
|
||||
* Either:
|
||||
* 3 empty bits, 1 bit for horizontal flip, 1 bit for vertical flip (non-affine)
|
||||
* 5 bits for affine index (affine)
|
||||
* 2 bits for size.
|
||||
|
||||
| Size | Square | Horizontal | Vertical|
|
||||
|:----:|:------:|:----------:|:-------:|
|
||||
| 0 | 8x8 | 16x8 | 8x16 |
|
||||
| 1 | 16x16 | 32x8 | 8x32 |
|
||||
| 2 | 32x32 | 32x16 | 16x32 |
|
||||
| 3 | 64x64 | 64x32 | 32x64 |
|
||||
|
||||
### ObjectAttributes.attr2
|
||||
|
||||
* 10 bits for the base tile index
|
||||
* 2 bits for priority
|
||||
* 4 bits for the palbank index (4bpp mode only, ignored in 8bpp)
|
||||
|
||||
### ObjectAttributes summary
|
||||
|
||||
So I said in the GBA memory mapping section that C people would tell you that
|
||||
the object attributes should look like this:
|
||||
|
||||
```rust
|
||||
#[repr(C)]
|
||||
pub struct ObjectAttributes {
|
||||
attr0: u16,
|
||||
attr1: u16,
|
||||
attr2: u16,
|
||||
filler: i16,
|
||||
}
|
||||
```
|
||||
|
||||
Except that:
|
||||
|
||||
1) It's wasteful when we store object attributes on their own outside of OAM
|
||||
(which we definitely might want to do).
|
||||
2) In Rust we can't access just one field through a volatile pointer (our
|
||||
pointers aren't actually volatile to begin with, just the ops we do with them
|
||||
are). We have to read or write the whole pointer's value at a time.
|
||||
Similarly, we can't do things like `|=` and `&=` with volatile in Rust. So in
|
||||
rust we can't have a volatile pointer to an ObjectAttributes and then write
|
||||
to just the three "real" values and not touch the filler field. Having the
|
||||
filler value in there just means we have to dance around it more, not less.
|
||||
3) We want to newtype this whole thing to prevent accidental invalid states from
|
||||
being written into memory.
|
||||
|
||||
So we will not be using that representation. At the same time we want to have no
|
||||
overhead, so we will stick to three `u16` values. We could newtype each
|
||||
individual field to be its own type (`ObjectAttributesAttr0` or something silly
|
||||
like that), since there aren't actual dependencies between two different fields
|
||||
such that a change in one can throw another into a forbidden state. The worst
|
||||
that can happen is if we disable or enable affine mode (`attr0`) it can change
|
||||
the meaning of `attr1`. The changed meaning isn't actually in invalid state
|
||||
though, so we _could_ make each field its own type if we wanted.
|
||||
|
||||
However, when you think about it, I can't imagine a common situation where we do
|
||||
something like make an `attr0` value that we then want to save on its own and
|
||||
apply to several different `ObjectAttributes` that we make during a game. That
|
||||
just doesn't sound likely to me. So, we'll go the route where `ObjectAttributes`
|
||||
is just a big black box to the outside world and we don't need to think about
|
||||
the three fields internally as being separate.
|
||||
|
||||
First we make it so that we can get and set object attributes from memory:
|
||||
|
||||
```rust
|
||||
pub const OAM: usize = 0x700_0000;
|
||||
|
||||
pub fn object_attributes(slot: usize) -> ObjectAttributes {
|
||||
assert!(slot < 128);
|
||||
let ptr = VolatilePtr((OAM + slot * (size_of::<u16>() * 4)) as *mut u16);
|
||||
unsafe {
|
||||
ObjectAttributes {
|
||||
attr0: ptr.read(),
|
||||
attr1: ptr.offset(1).read(),
|
||||
attr2: ptr.offset(2).read(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_object_attributes(slot: usize, obj: ObjectAttributes) {
|
||||
assert!(slot < 128);
|
||||
let ptr = VolatilePtr((OAM + slot * (size_of::<u16>() * 4)) as *mut u16);
|
||||
unsafe {
|
||||
ptr.write(obj.attr0);
|
||||
ptr.offset(1).write(obj.attr1);
|
||||
ptr.offset(2).write(obj.attr2);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct ObjectAttributes {
|
||||
attr0: u16,
|
||||
attr1: u16,
|
||||
attr2: u16,
|
||||
}
|
||||
```
|
||||
|
||||
Then we add a billion methods to the `ObjectAttributes` type so that we can
|
||||
actually set all the different values that we want to set.
|
||||
|
||||
This code block is the last thing on this page so if you don't wanna scroll past
|
||||
the whole thing you can just go to the next page.
|
||||
|
||||
```rust
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ObjectRenderMode {
|
||||
Normal,
|
||||
Affine,
|
||||
Disabled,
|
||||
DoubleAreaAffine,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ObjectMode {
|
||||
Normal,
|
||||
AlphaBlending,
|
||||
ObjectWindow,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ObjectShape {
|
||||
Square,
|
||||
Horizontal,
|
||||
Vertical,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ObjectOrientation {
|
||||
Normal,
|
||||
HFlip,
|
||||
VFlip,
|
||||
BothFlip,
|
||||
Affine(u8),
|
||||
}
|
||||
|
||||
impl ObjectAttributes {
|
||||
pub fn row(&self) -> u16 {
|
||||
self.attr0 & 0b1111_1111
|
||||
}
|
||||
pub fn column(&self) -> u16 {
|
||||
self.attr1 & 0b1_1111_1111
|
||||
}
|
||||
pub fn rendering(&self) -> ObjectRenderMode {
|
||||
match (self.attr0 >> 8) & 0b11 {
|
||||
0 => ObjectRenderMode::Normal,
|
||||
1 => ObjectRenderMode::Affine,
|
||||
2 => ObjectRenderMode::Disabled,
|
||||
3 => ObjectRenderMode::DoubleAreaAffine,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
pub fn mode(&self) -> ObjectMode {
|
||||
match (self.attr0 >> 0xA) & 0b11 {
|
||||
0 => ObjectMode::Normal,
|
||||
1 => ObjectMode::AlphaBlending,
|
||||
2 => ObjectMode::ObjectWindow,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
pub fn mosaic(&self) -> bool {
|
||||
((self.attr0 << 3) as i16) < 0
|
||||
}
|
||||
pub fn two_fifty_six_colors(&self) -> bool {
|
||||
((self.attr0 << 2) as i16) < 0
|
||||
}
|
||||
pub fn shape(&self) -> ObjectShape {
|
||||
match (self.attr0 >> 0xE) & 0b11 {
|
||||
0 => ObjectShape::Square,
|
||||
1 => ObjectShape::Horizontal,
|
||||
2 => ObjectShape::Vertical,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
pub fn orientation(&self) -> ObjectOrientation {
|
||||
if (self.attr0 >> 8) & 1 > 0 {
|
||||
ObjectOrientation::Affine((self.attr1 >> 9) as u8 & 0b1_1111)
|
||||
} else {
|
||||
match (self.attr1 >> 0xC) & 0b11 {
|
||||
0 => ObjectOrientation::Normal,
|
||||
1 => ObjectOrientation::HFlip,
|
||||
2 => ObjectOrientation::VFlip,
|
||||
3 => ObjectOrientation::BothFlip,
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn size(&self) -> u16 {
|
||||
self.attr1 >> 0xE
|
||||
}
|
||||
pub fn tile_index(&self) -> u16 {
|
||||
self.attr2 & 0b11_1111_1111
|
||||
}
|
||||
pub fn priority(&self) -> u16 {
|
||||
self.attr2 >> 0xA
|
||||
}
|
||||
pub fn palbank(&self) -> u16 {
|
||||
self.attr2 >> 0xC
|
||||
}
|
||||
//
|
||||
pub fn set_row(&mut self, row: u16) {
|
||||
self.attr0 &= !0b1111_1111;
|
||||
self.attr0 |= row & 0b1111_1111;
|
||||
}
|
||||
pub fn set_column(&mut self, col: u16) {
|
||||
self.attr1 &= !0b1_1111_1111;
|
||||
self.attr2 |= col & 0b1_1111_1111;
|
||||
}
|
||||
pub fn set_rendering(&mut self, rendering: ObjectRenderMode) {
|
||||
const RENDERING_MASK: u16 = 0b11 << 8;
|
||||
self.attr0 &= !RENDERING_MASK;
|
||||
self.attr0 |= (rendering as u16) << 8;
|
||||
}
|
||||
pub fn set_mode(&mut self, mode: ObjectMode) {
|
||||
const MODE_MASK: u16 = 0b11 << 0xA;
|
||||
self.attr0 &= MODE_MASK;
|
||||
self.attr0 |= (mode as u16) << 0xA;
|
||||
}
|
||||
pub fn set_mosaic(&mut self, bit: bool) {
|
||||
const MOSAIC_BIT: u16 = 1 << 0xC;
|
||||
if bit {
|
||||
self.attr0 |= MOSAIC_BIT
|
||||
} else {
|
||||
self.attr0 &= !MOSAIC_BIT
|
||||
}
|
||||
}
|
||||
pub fn set_two_fifty_six_colors(&mut self, bit: bool) {
|
||||
const COLOR_MODE_BIT: u16 = 1 << 0xD;
|
||||
if bit {
|
||||
self.attr0 |= COLOR_MODE_BIT
|
||||
} else {
|
||||
self.attr0 &= !COLOR_MODE_BIT
|
||||
}
|
||||
}
|
||||
pub fn set_shape(&mut self, shape: ObjectShape) {
|
||||
self.attr0 &= 0b0011_1111_1111_1111;
|
||||
self.attr0 |= (shape as u16) << 0xE;
|
||||
}
|
||||
pub fn set_orientation(&mut self, orientation: ObjectOrientation) {
|
||||
const AFFINE_INDEX_MASK: u16 = 0b1_1111 << 9;
|
||||
self.attr1 &= !AFFINE_INDEX_MASK;
|
||||
let bits = match orientation {
|
||||
ObjectOrientation::Affine(index) => (index as u16) << 9,
|
||||
ObjectOrientation::Normal => 0,
|
||||
ObjectOrientation::HFlip => 1 << 0xC,
|
||||
ObjectOrientation::VFlip => 1 << 0xD,
|
||||
ObjectOrientation::BothFlip => 0b11 << 0xC,
|
||||
};
|
||||
self.attr1 |= bits;
|
||||
}
|
||||
pub fn set_size(&mut self, size: u16) {
|
||||
self.attr1 &= 0b0011_1111_1111_1111;
|
||||
self.attr1 |= size << 14;
|
||||
}
|
||||
pub fn set_tile_index(&mut self, index: u16) {
|
||||
self.attr2 &= !0b11_1111_1111;
|
||||
self.attr2 |= 0b11_1111_1111 & index;
|
||||
}
|
||||
pub fn set_priority(&mut self, priority: u16) {
|
||||
self.attr2 &= !0b0000_1100_0000_0000;
|
||||
self.attr2 |= (priority & 0b11) << 0xA;
|
||||
}
|
||||
pub fn set_palbank(&mut self, palbank: u16) {
|
||||
self.attr2 &= !0b1111_0000_0000_0000;
|
||||
self.attr2 |= (palbank & 0b1111) << 0xC;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html" class="active"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.4.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html" class="active"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/regular_objects.html"><strong aria-hidden="true">5.4.</strong> Regular Objects</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html" class="active"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.4.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html" class="active"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/regular_objects.html"><strong aria-hidden="true">5.4.</strong> Regular Objects</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html" class="active"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.4.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html" class="active"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/regular_objects.html"><strong aria-hidden="true">5.4.</strong> Regular Objects</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html" class="active"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.4.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html" class="active"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/regular_objects.html"><strong aria-hidden="true">5.4.</strong> Regular Objects</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html" class="active"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.4.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html" class="active"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/regular_objects.html"><strong aria-hidden="true">5.4.</strong> Regular Objects</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html" class="active"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.4.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html" class="active"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/regular_objects.html"><strong aria-hidden="true">5.4.</strong> Regular Objects</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html" class="active"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.4.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html" class="active"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/regular_objects.html"><strong aria-hidden="true">5.4.</strong> Regular Objects</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html" class="active"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.4.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html" class="active"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/regular_objects.html"><strong aria-hidden="true">5.4.</strong> Regular Objects</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html" class="active"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.4.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html" class="active"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/regular_objects.html"><strong aria-hidden="true">5.4.</strong> Regular Objects</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html" class="active"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.4.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html" class="active"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/regular_objects.html"><strong aria-hidden="true">5.4.</strong> Regular Objects</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html" class="active"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.4.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html" class="active"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/regular_objects.html"><strong aria-hidden="true">5.4.</strong> Regular Objects</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html" class="active"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.4.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html" class="active"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/regular_objects.html"><strong aria-hidden="true">5.4.</strong> Regular Objects</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html" class="active"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.4.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html" class="active"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/regular_objects.html"><strong aria-hidden="true">5.4.</strong> Regular Objects</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
@ -225,6 +225,20 @@ and then a <em>separate</em> setting outside of the graphical data determines wh
|
|||
palbank is to be used for that background or object (the screen entry data for
|
||||
backgrounds, and the object attributes for objects).</li>
|
||||
</ul>
|
||||
<a class="header" href="#transparency" id="transparency"><h3>Transparency</h3></a>
|
||||
<p>When a pixel within a background or object specifies index 0 as its palette
|
||||
entry it is treated as a transparent pixel. This means that in 8bpp mode there's
|
||||
only 255 actual color options (0 being transparent), and in 4bpp mode there's
|
||||
only 15 actual color options available within each palbank (the 0th entry of
|
||||
<em>each</em> palbank is transparent).</p>
|
||||
<p>Individual backgrounds, and individual objects, each determine if they're 4bpp
|
||||
or 8bpp separately, so a given overall palette slot might map to a used color in
|
||||
8bpp and an unused/transparent color in 4bpp. If you're a palette wizard.</p>
|
||||
<p>Palette slot 0 of the overall background palette is used to determine the
|
||||
"backdrop" color. That's the color you see if no background or object ends up
|
||||
being rendered within a given pixel.</p>
|
||||
<p>Since display mode 3 and display mode 5 don't use the palette, they cannot
|
||||
benefit from transparency.</p>
|
||||
<a class="header" href="#video-ram--vram" id="video-ram--vram"><h2>Video RAM / VRAM</h2></a>
|
||||
<ul>
|
||||
<li><code>0x6000000</code> to <code>0x6017FFF</code> (96k)</li>
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.4.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html" class="active"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/regular_objects.html"><strong aria-hidden="true">5.4.</strong> Regular Objects</a></li><li><a href="../ch03/gba_rng.html" class="active"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
@ -144,7 +144,7 @@
|
|||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
|
||||
<a rel="prev" href="../ch03/object_basics.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../ch03/regular_objects.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
|
@ -162,7 +162,7 @@
|
|||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
|
||||
<a href="../ch03/object_basics.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a href="../ch03/regular_objects.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html" class="active"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.4.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html" class="active"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/regular_objects.html"><strong aria-hidden="true">5.4.</strong> Regular Objects</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
@ -165,6 +165,23 @@ without trading away too much in terms of quality.</p>
|
|||
<p>To top it all off, we'll make a simple "memory game" sort of thing. There's some
|
||||
face down cards in a grid, you pick one to check, then you pick the other to
|
||||
check, and then if they match the pair disappears.</p>
|
||||
<a class="header" href="#drawing-priority" id="drawing-priority"><h2>Drawing Priority</h2></a>
|
||||
<p>Both backgrounds and objects can have "priority" values associated with them.
|
||||
TONC and GBATEK have <em>opposite</em> ideas of what it means to have the "highest"
|
||||
priority. TONC goes by highest numerical value, and GBATEK goes by what's on the
|
||||
z-layer closest to the user. Let's list out the rules as clearly as we can:</p>
|
||||
<ul>
|
||||
<li>Priority is always two bits, so 0 through 3.</li>
|
||||
<li>Priority conceptually proceeds in drawing passes that count <em>down</em>, so any
|
||||
priority 3 things can get covered up by priority 2 things. In truth there's
|
||||
probably depth testing and buffering stuff going on so it's all one single
|
||||
pass, but conceptually we will imagine it happening as all of the 3 elements,
|
||||
then all of 2, and so on.</li>
|
||||
<li>Objects always draw over top of backgrounds of equal priority.</li>
|
||||
<li>Within things of the same type and priority, the lower numbered element "wins"
|
||||
and gets its pixel drawn (bg0 is favored over bg1, obj0 is favored over obj1,
|
||||
etc).</li>
|
||||
</ul>
|
||||
|
||||
</main>
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.4.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html" class="active"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/regular_objects.html"><strong aria-hidden="true">5.4.</strong> Regular Objects</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html" class="active"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
|
BIN
docs/ch03/obj_memory_2d1d.jpg
Normal file
BIN
docs/ch03/obj_memory_2d1d.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 147 KiB |
|
@ -1,201 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html lang="en" class="sidebar-visible no-js">
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
<title>Object Basics - Rust GBA Guide</title>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="theme-color" content="#ffffff" />
|
||||
|
||||
<link rel="shortcut icon" href="../favicon.png">
|
||||
<link rel="stylesheet" href="../css/variables.css">
|
||||
<link rel="stylesheet" href="../css/general.css">
|
||||
<link rel="stylesheet" href="../css/chrome.css">
|
||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
||||
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800" rel="stylesheet" type="text/css">
|
||||
<link href="https://fonts.googleapis.com/css?family=Source+Code+Pro:500" rel="stylesheet" type="text/css">
|
||||
|
||||
<!-- Highlight.js Stylesheets -->
|
||||
<link rel="stylesheet" href="../highlight.css">
|
||||
<link rel="stylesheet" href="../tomorrow-night.css">
|
||||
<link rel="stylesheet" href="../ayu-highlight.css">
|
||||
|
||||
<!-- Custom theme stylesheets -->
|
||||
|
||||
|
||||
|
||||
</head>
|
||||
<body class="light">
|
||||
<!-- Provide site root to javascript -->
|
||||
<script type="text/javascript">var path_to_root = "../";</script>
|
||||
|
||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||
<script type="text/javascript">
|
||||
try {
|
||||
var theme = localStorage.getItem('mdbook-theme');
|
||||
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||
|
||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||
}
|
||||
|
||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||
}
|
||||
} catch (e) { }
|
||||
</script>
|
||||
|
||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||
<script type="text/javascript">
|
||||
var theme;
|
||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||
if (theme === null || theme === undefined) { theme = 'light'; }
|
||||
document.body.className = theme;
|
||||
document.querySelector('html').className = theme + ' js';
|
||||
</script>
|
||||
|
||||
<!-- Hide / unhide sidebar before it is displayed -->
|
||||
<script type="text/javascript">
|
||||
var html = document.querySelector('html');
|
||||
var sidebar = 'hidden';
|
||||
if (document.body.clientWidth >= 1080) {
|
||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||
sidebar = sidebar || 'visible';
|
||||
}
|
||||
html.classList.remove('sidebar-visible');
|
||||
html.classList.add("sidebar-" + sidebar);
|
||||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/object_basics.html" class="active"><strong aria-hidden="true">5.4.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
||||
<div class="page">
|
||||
|
||||
<div id="menu-bar" class="menu-bar">
|
||||
<div id="menu-bar-sticky-container">
|
||||
<div class="left-buttons">
|
||||
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||
<i class="fa fa-bars"></i>
|
||||
</button>
|
||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||
<i class="fa fa-paint-brush"></i>
|
||||
</button>
|
||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||
<li role="none"><button role="menuitem" class="theme" id="light">Light <span class="default">(default)</span></button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||
</ul>
|
||||
|
||||
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
<h1 class="menu-title">Rust GBA Guide</h1>
|
||||
|
||||
<div class="right-buttons">
|
||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
||||
<i id="print-button" class="fa fa-print"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="search-wrapper" class="hidden">
|
||||
<form id="searchbar-outer" class="searchbar-outer">
|
||||
<input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||
</form>
|
||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||
<div id="searchresults-header" class="searchresults-header"></div>
|
||||
<ul id="searchresults">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||
<script type="text/javascript">
|
||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="content" class="content">
|
||||
<main>
|
||||
<a class="header" href="#object-basics" id="object-basics"><h1>Object Basics</h1></a>
|
||||
<p>TODO</p>
|
||||
|
||||
</main>
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
|
||||
<a rel="prev" href="../ch03/regular_backgrounds.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
<a rel="next" href="../ch03/gba_rng.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
|
||||
<div style="clear: both"></div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
|
||||
<a href="../ch03/regular_backgrounds.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
<a href="../ch03/gba_rng.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<script src="../elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../mark.min.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../searcher.js" type="text/javascript" charset="utf-8"></script>
|
||||
|
||||
|
||||
<script src="../clipboard.min.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../highlight.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../book.js" type="text/javascript" charset="utf-8"></script>
|
||||
|
||||
<!-- Custom JS scripts -->
|
||||
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -72,7 +72,7 @@
|
|||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html" class="active"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.4.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html" class="active"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/regular_objects.html"><strong aria-hidden="true">5.4.</strong> Regular Objects</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
@ -136,8 +136,291 @@
|
|||
|
||||
<div id="content" class="content">
|
||||
<main>
|
||||
<a class="header" href="#tiled-backgrounds" id="tiled-backgrounds"><h1>Tiled Backgrounds</h1></a>
|
||||
<p>TODO</p>
|
||||
<a class="header" href="#regular-backgrounds" id="regular-backgrounds"><h1>Regular Backgrounds</h1></a>
|
||||
<p>So, backgrounds, they're cool. Why do we call the ones here "regular"
|
||||
backgrounds? Because there's also "affine" backgrounds. However, affine math
|
||||
stuff adds a complication, so for now we'll just work with regular backgrounds.
|
||||
The non-affine backgrounds are sometimes called "text mode" backgrounds by other
|
||||
guides.</p>
|
||||
<p>To get your background image working you generally need to perform all of the
|
||||
following steps, though I suppose the exact ordering is up to you.</p>
|
||||
<a class="header" href="#tiled-video-modes" id="tiled-video-modes"><h2>Tiled Video Modes</h2></a>
|
||||
<p>When you want regular tiled display, you must use video mode 0 or 1.</p>
|
||||
<ul>
|
||||
<li>Mode 0 allows for using all four BG layers (0 through 3) as regular
|
||||
backgrounds.</li>
|
||||
<li>Mode 1 allows for using BG0 and BG1 as regular backgrounds, BG2 as an affine
|
||||
background, and BG3 not at all.</li>
|
||||
<li>Mode 2 allows for BG2 and BG3 to be used as affine backgrounds, while BG0 and
|
||||
BG1 cannot be used at all.</li>
|
||||
</ul>
|
||||
<p>We will not cover affine backgrounds in this chapter, so we will naturally be
|
||||
using video mode 0.</p>
|
||||
<p>Also, note that you have to enable each background layer that you want to use
|
||||
within the display control register.</p>
|
||||
<a class="header" href="#get-your-palette-ready" id="get-your-palette-ready"><h2>Get Your Palette Ready</h2></a>
|
||||
<p>Background palette starts at <code>0x5000000</code> and is 256 <code>u16</code> values long. It'd
|
||||
potentially be possible declare a static array starting at a fixed address and
|
||||
use a linker script to make sure that it ends up at the right spot in the final
|
||||
program, but since we have to use volatile reads and writes with PALRAM anyway,
|
||||
we'll just reuse our <code>VolatilePtr</code> type. Something like this:</p>
|
||||
<pre><pre class="playpen"><code class="language-rust">
|
||||
# #![allow(unused_variables)]
|
||||
#fn main() {
|
||||
pub const PALRAM_BG_BASE: VolatilePtr<u16> = VolatilePtr(0x500_0000 as *mut u16);
|
||||
|
||||
pub fn bg_palette(slot: usize) -> u16 {
|
||||
assert!(slot < 256);
|
||||
unsafe { PALRAM_BG_BASE.offset(slot as isize).read() }
|
||||
}
|
||||
|
||||
pub fn set_bg_palette(slot: usize, color: u16) {
|
||||
assert!(slot < 256);
|
||||
unsafe { PALRAM_BG_BASE.offset(slot as isize).write(color) }
|
||||
}
|
||||
#}</code></pre></pre>
|
||||
<p>As we discussed with the tile color depths, the palette can be utilized as a
|
||||
single block of palette values (<code>[u16; 256]</code>) or as 16 palbanks of 16 palette
|
||||
values each (<code>[[u16;16]; 16]</code>). This setting is assigned per background layer
|
||||
via IO register.</p>
|
||||
<a class="header" href="#get-your-tiles-ready" id="get-your-tiles-ready"><h2>Get Your Tiles Ready</h2></a>
|
||||
<p>Tile data is placed into charblocks. A charblock is always 16kb, so depending on
|
||||
color depth it will have either 256 or 512 tiles within that charblock.
|
||||
Charblocks 0, 1, 2, and 3 are all for background tiles. That's a maximum of 2048
|
||||
tiles for backgrounds, but as you'll see in a moment a particular tilemap entry
|
||||
can't even index that high. Instead, each background layer is assigned a
|
||||
"character base block", and then tilemap entries index relative to the character
|
||||
base block of that background layer.</p>
|
||||
<p>Now, if you want to move in a lot of tile data you'll probably want to use a DMA
|
||||
routine, or at least write a function like memcopy32 for fast <code>u32</code> copying from
|
||||
ROM into VRAM. However, for now, and because we're being very explicit since
|
||||
this is our first time doing it, we'll write it as functions for individual tile
|
||||
reads and writes.</p>
|
||||
<p>The math works like indexing a pointer, except that we have two sizes we need to
|
||||
go by. First you take the base address for VRAM (<code>0x600_0000</code>), then add the
|
||||
size of a charblock (16kb) times the charblock you want to place the tile
|
||||
within, and then you add the index of the tile slot you're placing it into times
|
||||
the size of that type of tile. Like this:</p>
|
||||
<pre><pre class="playpen"><code class="language-rust">
|
||||
# #![allow(unused_variables)]
|
||||
#fn main() {
|
||||
pub fn bg_tile_4pp(base_block: usize, tile_index: usize) -> Tile4bpp {
|
||||
assert!(base_block < 4);
|
||||
assert!(tile_index < 512);
|
||||
let address = VRAM + size_of::<Charblock4bpp>() * base_block + size_of::<Tile4bpp>() * tile_index;
|
||||
unsafe { VolatilePtr(address as *mut Tile4bpp).read() }
|
||||
}
|
||||
|
||||
pub fn set_bg_tile_4pp(base_block: usize, tile_index: usize, tile: Tile4bpp) {
|
||||
assert!(base_block < 4);
|
||||
assert!(tile_index < 512);
|
||||
let address = VRAM + size_of::<Charblock4bpp>() * base_block + size_of::<Tile4bpp>() * tile_index;
|
||||
unsafe { VolatilePtr(address as *mut Tile4bpp).write(tile) }
|
||||
}
|
||||
|
||||
pub fn bg_tile_8pp(base_block: usize, tile_index: usize) -> Tile8bpp {
|
||||
assert!(base_block < 4);
|
||||
assert!(tile_index < 256);
|
||||
let address = VRAM + size_of::<Charblock8bpp>() * base_block + size_of::<Tile8bpp>() * tile_index;
|
||||
unsafe { VolatilePtr(address as *mut Tile8bpp).read() }
|
||||
}
|
||||
|
||||
pub fn set_bg_tile_8pp(base_block: usize, tile_index: usize, tile: Tile8bpp) {
|
||||
assert!(base_block < 4);
|
||||
assert!(tile_index < 256);
|
||||
let address = VRAM + size_of::<Charblock8bpp>() * base_block + size_of::<Tile8bpp>() * tile_index;
|
||||
unsafe { VolatilePtr(address as *mut Tile8bpp).write(tile) }
|
||||
}
|
||||
#}</code></pre></pre>
|
||||
<p>For bulk operations, you'd do the exact same math to get your base destination
|
||||
pointer, and then you'd get the base source pointer for the tile you're copying
|
||||
out of ROM, and then you'd do the bulk copy for the correct number of <code>u32</code>
|
||||
values that you're trying to move (8 per tile moved for 4bpp, or 16 per tile
|
||||
moved for 8bpp).</p>
|
||||
<p><strong>GBA Limitation Note:</strong> on a modern PC (eg: <code>x86</code> or <code>x86_64</code>) you're probably
|
||||
used to index based loops and iterator based loops being the same speed. The CPU
|
||||
has the ability to do a "fused multiply add", so the base address of the array
|
||||
plus desired index * size per element is a single CPU operation to compute. It's
|
||||
slightly more complicated if there's arrays within arrays like there are here,
|
||||
but with normal arrays it's basically the same speed to index per loop cycle as
|
||||
it is to take a base address and then add +1 offset per loop cycle. However, the
|
||||
GBA's CPU <em>can't do any of that</em>. On the GBA, there's a genuine speed difference
|
||||
between looping over indexes and then indexing each loop (slow) compared to
|
||||
using an iterator that just stores an internal pointer and does +1 offset per
|
||||
loop until it reaches the end (fast). The repeated indexing itself can by itself
|
||||
be an expensive step. If it's like a 3 element array it's no big deal, but if
|
||||
you've got a big slice of data to process, be sure to go over it with <code>.iter()</code>
|
||||
and <code>.iter_mut()</code> if you can, instead of looping by index. This is Rust and all,
|
||||
so probably you were gonna do that anyway, but just a heads up.</p>
|
||||
<a class="header" href="#get-your-tilemap-ready" id="get-your-tilemap-ready"><h2>Get your Tilemap ready</h2></a>
|
||||
<p>I believe that at one point I alluded to a tilemap existing. Well, just as the
|
||||
tiles are arranged into charblocks, the data describing what tile to show in
|
||||
what location is arranged into a thing called a <strong>screenblock</strong>.</p>
|
||||
<p>A screenblock is placed into VRAM the same as the tile data charblocks. Starting
|
||||
at the base of VRAM (<code>0x600_0000</code>) there are 32 slots for the screenblock array.
|
||||
Each screenblock is 2048 bytes (<code>0x800</code>). Naturally, if our tiles are using up
|
||||
charblock space within VRAM and our tilemaps are using up screenblock space
|
||||
within the same VRAM... well it would just be a <em>disaster</em> if they ran in to
|
||||
each other. Once again, it's up to you as the programmer to determine how much
|
||||
space you want to devote to each thing. Each complete charblock uses up 8
|
||||
screenblocks worth of space, but you don't have to fill a complete charblock
|
||||
with tiles, so you can be very fiddly with how you split the memory.</p>
|
||||
<p>Each screenblock is composed of a series of <em>screenblock entry</em> values, which
|
||||
describe what tile index to use and if the tile should be flipped and what
|
||||
palbank it should use (if any). Because both regular backgrounds and affine
|
||||
backgrounds are composed of screenblocks with entries, and because the affine
|
||||
background has a smaller format for screenblock entries, we'll name
|
||||
appropriately.</p>
|
||||
<pre><pre class="playpen"><code class="language-rust">
|
||||
# #![allow(unused_variables)]
|
||||
#fn main() {
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(transparent)]
|
||||
pub struct RegularScreenblock {
|
||||
data: [RegularScreenblockEntry; 32 * 32],
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
#[repr(transparent)]
|
||||
pub struct RegularScreenblockEntry(u16);
|
||||
#}</code></pre></pre>
|
||||
<p>So, with one entry per tile, a single screenblock allows for 32x32 tiles worth of
|
||||
background.</p>
|
||||
<p>The format of a regular screenblock entry is quite simple compared to some of
|
||||
the IO register stuff:</p>
|
||||
<ul>
|
||||
<li>10 bits for tile index (base off of the character base block of the background)</li>
|
||||
<li>1 bit for horizontal flip</li>
|
||||
<li>1 bit for vertical flip</li>
|
||||
<li>4 bits for picking which palbank to use (if 4bpp, otherwise it's ignored)</li>
|
||||
</ul>
|
||||
<pre><pre class="playpen"><code class="language-rust">
|
||||
# #![allow(unused_variables)]
|
||||
#fn main() {
|
||||
impl RegularScreenblockEntry {
|
||||
pub fn tile_id(self) -> u16 {
|
||||
self.0 & 0b11_1111_1111
|
||||
}
|
||||
pub fn set_tile_id(&mut self, id: u16) {
|
||||
self.0 &= !0b11_1111_1111;
|
||||
self.0 |= id;
|
||||
}
|
||||
pub fn horizontal_flip(self) -> bool {
|
||||
(self.0 & (1 << 0xA)) > 0
|
||||
}
|
||||
pub fn set_horizontal_flip(&mut self, bit: bool) {
|
||||
if bit {
|
||||
self.0 |= 1 << 0xA;
|
||||
} else {
|
||||
self.0 &= !(1 << 0xA);
|
||||
}
|
||||
}
|
||||
pub fn vertical_flip(self) -> bool {
|
||||
(self.0 & (1 << 0xB)) > 0
|
||||
}
|
||||
pub fn set_vertical_flip(&mut self, bit: bool) {
|
||||
if bit {
|
||||
self.0 |= 1 << 0xB;
|
||||
} else {
|
||||
self.0 &= !(1 << 0xB);
|
||||
}
|
||||
}
|
||||
pub fn palbank_index(self) -> u16 {
|
||||
self.0 >> 12
|
||||
}
|
||||
pub fn set_palbank_index(&mut self, palbank_index: u16) {
|
||||
self.0 &= 0b1111_1111_1111;
|
||||
self.0 |= palbank_index;
|
||||
}
|
||||
}
|
||||
#}</code></pre></pre>
|
||||
<p>Now, at either 256 or 512 tiles per charblock, you might be thinking that with a
|
||||
10 bit index you can index past the end of one charblock and into the next.
|
||||
You'd be right, mostly.</p>
|
||||
<p>As long as you stay within the background memory region for charblocks (that is,
|
||||
0 through 3), then it all works out. However, if you try to get the background
|
||||
rendering to reach outside of the background charblocks you'll get an
|
||||
implementation defined result. It's not the dreaded "undefined behavior" we're
|
||||
often worried about in programming, but the results <em>are</em> determined by what
|
||||
you're running the game on. With GBA hardware you get a bizarre result
|
||||
(basically another way to put garbage on the screen). With a DS it acts as if
|
||||
the tiles were all 0s. If you use an emulator it might or might not allow for
|
||||
you to do this, it's up to the emulator writers.</p>
|
||||
<a class="header" href="#set-your-io-registers" id="set-your-io-registers"><h2>Set Your IO Registers</h2></a>
|
||||
<p>Instead of being just a single IO register to learn about this time, there's two
|
||||
separate groups of related registers.</p>
|
||||
<a class="header" href="#background-control" id="background-control"><h3>Background Control</h3></a>
|
||||
<ul>
|
||||
<li>BG0CNT (<code>0x400_0008</code>): BG0 Control</li>
|
||||
<li>BG1CNT (<code>0x400_000A</code>): BG1 Control</li>
|
||||
<li>BG2CNT (<code>0x400_000C</code>): BG2 Control</li>
|
||||
<li>BG3CNT (<code>0x400_000E</code>): BG3 Control</li>
|
||||
</ul>
|
||||
<p>Each of these are a read/write <code>u16</code> location. This is where we get to all of
|
||||
the important details that we've been putting off.</p>
|
||||
<ul>
|
||||
<li>2 bits for the priority.</li>
|
||||
<li>2 bits for "character base block", the charblock that all of the tile indexes
|
||||
for this background are offset from.</li>
|
||||
<li>1 bit for mosaic effect being enabled (we'll get to that below).</li>
|
||||
<li>1 bit to enable 8bpp, otherwise 4bpp is used.</li>
|
||||
<li>5 bits to pick the "screen base block", the screen block that serves as the
|
||||
<em>base</em> value for this background.</li>
|
||||
<li>1 bit that is <em>not</em> used in regular mode, but in affine mode it can be enabled
|
||||
to cause the affine background to wrap around at the edges.</li>
|
||||
<li>2 bits for the background size.</li>
|
||||
</ul>
|
||||
<p>The size works a little funny. When size is 0 only the base screen block is
|
||||
used. If size is 1 or 2 then the base screenblock and the following screenblock
|
||||
are placed next to each other (horizontally for 1, vertically for 2). If the
|
||||
size is 3 then the base screenblock and the following three screenblocks are
|
||||
arranged into a 2x2 grid of screenblocks.</p>
|
||||
<a class="header" href="#background-offset" id="background-offset"><h3>Background Offset</h3></a>
|
||||
<ul>
|
||||
<li>BG0HOFS (<code>0x400_0010</code>): BG0 X-Offset</li>
|
||||
<li>BG0VOFS (<code>0x400_0012</code>): BG0 Y-Offset</li>
|
||||
<li>BG1HOFS (<code>0x400_0014</code>): BG1 X-Offset</li>
|
||||
<li>BG1VOFS (<code>0x400_0016</code>): BG1 Y-Offset</li>
|
||||
<li>BG2HOFS (<code>0x400_0018</code>): BG2 X-Offset</li>
|
||||
<li>BG2VOFS (<code>0x400_001A</code>): BG2 Y-Offset</li>
|
||||
<li>BG3HOFS (<code>0x400_001C</code>): BG3 X-Offset</li>
|
||||
<li>BG3VOFS (<code>0x400_001E</code>): BG3 Y-Offset</li>
|
||||
</ul>
|
||||
<p>Each of these are a <em>write only</em> <code>u16</code> location. Bits 0 through 8 are used, so
|
||||
the offsets can be 0 through 511. They also only apply in regular backgrounds.
|
||||
If a background is in an affine state then you'll use different IO registers to
|
||||
control it (discussed in a later chapter).</p>
|
||||
<p>The offset that you assign determines the pixel offset of the display area
|
||||
relative to the start of the background scene, as if the screen was a camera
|
||||
looking at the scene. In other words, as a BG X offset value increases, you can
|
||||
think of it as the camera moving to the right, or as that background moving to
|
||||
the left. Like when mario walks toward the goal. Similarly, when a BG Y offset
|
||||
increases the camera is moving down, or the background is moving up, like when
|
||||
mario falls down from a high platform.</p>
|
||||
<p>Depending on how much the background is scrolled and the size of the background,
|
||||
it will loop.</p>
|
||||
<a class="header" href="#mosaic" id="mosaic"><h2>Mosaic</h2></a>
|
||||
<p>As a special effect, you can apply mosaic to backgrounds and objects. It's just
|
||||
a single flag for each background, so all backgrounds will use the same mosaic
|
||||
settings when they have it enabled. What it actually does is split the normal
|
||||
image into "blocks" and then each block gets the color of the top left pixel of
|
||||
that block. This is the effect you see when link hits an electric foe with his
|
||||
sword and the whole screen "buzzes" at you.</p>
|
||||
<p>The mosaic control is a <em>write only</em> <code>u16</code> IO register at <code>0x400_004C</code>.</p>
|
||||
<p>There's 4 bits each for:</p>
|
||||
<ul>
|
||||
<li>Horizontal BG stretch</li>
|
||||
<li>Vertical BG stretch</li>
|
||||
<li>Horizontal object stretch</li>
|
||||
<li>Vertical object stretch</li>
|
||||
</ul>
|
||||
<p>The inputs should be 1 <em>less</em> than the desired block size. So if you set a
|
||||
stretch value of 5 then pixels 0-5 would be part of the first block (6 pixels),
|
||||
then 6-11 is the next block (another 6 pixels) and so on.</p>
|
||||
<p>If you need to make a pixel other than the top left part of each block the one
|
||||
that determines the mosaic color you can carefully offset the background or
|
||||
image by a tiny bit, but of course that makes every mosaic block change its
|
||||
target pixel. You can't change the target pixel on a block by block basis.</p>
|
||||
|
||||
</main>
|
||||
|
||||
|
@ -150,7 +433,7 @@
|
|||
|
||||
|
||||
|
||||
<a rel="next" href="../ch03/object_basics.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next" href="../ch03/regular_objects.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
|
@ -168,7 +451,7 @@
|
|||
|
||||
|
||||
|
||||
<a href="../ch03/object_basics.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a href="../ch03/regular_objects.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
|
|
568
docs/ch03/regular_objects.html
Normal file
568
docs/ch03/regular_objects.html
Normal file
|
@ -0,0 +1,568 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html lang="en" class="sidebar-visible no-js">
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
<title>Regular Objects - Rust GBA Guide</title>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="theme-color" content="#ffffff" />
|
||||
|
||||
<link rel="shortcut icon" href="../favicon.png">
|
||||
<link rel="stylesheet" href="../css/variables.css">
|
||||
<link rel="stylesheet" href="../css/general.css">
|
||||
<link rel="stylesheet" href="../css/chrome.css">
|
||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
||||
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800" rel="stylesheet" type="text/css">
|
||||
<link href="https://fonts.googleapis.com/css?family=Source+Code+Pro:500" rel="stylesheet" type="text/css">
|
||||
|
||||
<!-- Highlight.js Stylesheets -->
|
||||
<link rel="stylesheet" href="../highlight.css">
|
||||
<link rel="stylesheet" href="../tomorrow-night.css">
|
||||
<link rel="stylesheet" href="../ayu-highlight.css">
|
||||
|
||||
<!-- Custom theme stylesheets -->
|
||||
|
||||
|
||||
|
||||
</head>
|
||||
<body class="light">
|
||||
<!-- Provide site root to javascript -->
|
||||
<script type="text/javascript">var path_to_root = "../";</script>
|
||||
|
||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||
<script type="text/javascript">
|
||||
try {
|
||||
var theme = localStorage.getItem('mdbook-theme');
|
||||
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||
|
||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||
}
|
||||
|
||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||
}
|
||||
} catch (e) { }
|
||||
</script>
|
||||
|
||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||
<script type="text/javascript">
|
||||
var theme;
|
||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||
if (theme === null || theme === undefined) { theme = 'light'; }
|
||||
document.body.className = theme;
|
||||
document.querySelector('html').className = theme + ' js';
|
||||
</script>
|
||||
|
||||
<!-- Hide / unhide sidebar before it is displayed -->
|
||||
<script type="text/javascript">
|
||||
var html = document.querySelector('html');
|
||||
var sidebar = 'hidden';
|
||||
if (document.body.clientWidth >= 1080) {
|
||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||
sidebar = sidebar || 'visible';
|
||||
}
|
||||
html.classList.remove('sidebar-visible');
|
||||
html.classList.add("sidebar-" + sidebar);
|
||||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/regular_objects.html" class="active"><strong aria-hidden="true">5.4.</strong> Regular Objects</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
||||
<div class="page">
|
||||
|
||||
<div id="menu-bar" class="menu-bar">
|
||||
<div id="menu-bar-sticky-container">
|
||||
<div class="left-buttons">
|
||||
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||
<i class="fa fa-bars"></i>
|
||||
</button>
|
||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||
<i class="fa fa-paint-brush"></i>
|
||||
</button>
|
||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||
<li role="none"><button role="menuitem" class="theme" id="light">Light <span class="default">(default)</span></button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||
</ul>
|
||||
|
||||
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
<h1 class="menu-title">Rust GBA Guide</h1>
|
||||
|
||||
<div class="right-buttons">
|
||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
||||
<i id="print-button" class="fa fa-print"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="search-wrapper" class="hidden">
|
||||
<form id="searchbar-outer" class="searchbar-outer">
|
||||
<input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||
</form>
|
||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||
<div id="searchresults-header" class="searchresults-header"></div>
|
||||
<ul id="searchresults">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||
<script type="text/javascript">
|
||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="content" class="content">
|
||||
<main>
|
||||
<a class="header" href="#regular-objects" id="regular-objects"><h1>Regular Objects</h1></a>
|
||||
<p>As with backgrounds, objects can be used in both an affine and non-affine way.
|
||||
For this section we'll focus on the non-affine elements, and then we'll do all
|
||||
the affine stuff in a later chapter.</p>
|
||||
<a class="header" href="#objects-vs-sprites" id="objects-vs-sprites"><h2>Objects vs Sprites</h2></a>
|
||||
<p>As <a href="https://www.coranac.com/tonc/text/regobj.htm">TONC</a> helpfully reminds us
|
||||
(and then proceeds to not follow its own advice), we should always try to think
|
||||
in terms of <em>objects</em>, not <em>sprites</em>. A sprite is a logical / software concern,
|
||||
perhaps a player concern, whereas an object is a hardware concern.</p>
|
||||
<p>What's more, a given sprite that the player sees might need more than one object
|
||||
to display. Objects must be either square or rectangular (so sprite bits that
|
||||
stick out probably call for a second object), and can only be from 8x8 to 64x64
|
||||
(so anything bigger has to be two objects lined up to appear as one).</p>
|
||||
<a class="header" href="#general-object-info" id="general-object-info"><h2>General Object Info</h2></a>
|
||||
<p>Unlike with backgrounds, you can enable the object layer in any video mode.
|
||||
There's space for 128 object definitions in OAM.</p>
|
||||
<p>The display gets a number of cycles per scanline to process objects: 1210 by
|
||||
default, but only 954 if you enable the "HBlank interval free" setting in the
|
||||
display control register. The <a href="http://problemkaputt.de/gbatek.htm#lcdobjoverview">cycle cost per
|
||||
object</a> depends on the
|
||||
object's size and if it's using affine or regular mode, so enabling the HBlank
|
||||
interval free setting doesn't cut the number of objects displayable by an exact
|
||||
number of objects. The objects are processed in order of their definitions and
|
||||
if you run out of cycles then the rest just don't get shown. If there's a
|
||||
concern that you might run out of cycles you can place important objects (such
|
||||
as the player) at the start of the list and then less important animation
|
||||
objects later on.</p>
|
||||
<a class="header" href="#ready-the-palette" id="ready-the-palette"><h2>Ready the Palette</h2></a>
|
||||
<p>Objects use the palette the same as the background does. The only difference is
|
||||
that the palette data for objects starts at <code>0x500_0200</code>.</p>
|
||||
<pre><pre class="playpen"><code class="language-rust">
|
||||
# #![allow(unused_variables)]
|
||||
#fn main() {
|
||||
pub const PALRAM_OBJECT_BASE: VolatilePtr<u16> = VolatilePtr(0x500_0200 as *mut u16);
|
||||
|
||||
pub fn object_palette(slot: usize) -> u16 {
|
||||
assert!(slot < 256);
|
||||
unsafe { PALRAM_OBJECT_BASE.offset(slot as isize).read() }
|
||||
}
|
||||
|
||||
pub fn set_object_palette(slot: usize, color: u16) {
|
||||
assert!(slot < 256);
|
||||
unsafe { PALRAM_OBJECT_BASE.offset(slot as isize).write(color) }
|
||||
}
|
||||
#}</code></pre></pre>
|
||||
<a class="header" href="#ready-the-tiles" id="ready-the-tiles"><h2>Ready the Tiles</h2></a>
|
||||
<p>Objects, as with backgrounds, are composed of 8x8 tiles, and if you want
|
||||
something bigger than 8x8 you have to use more than one tile put together.
|
||||
Object tiles go into the final two charblocks of VRAM (indexes 4 and 5). Because
|
||||
there's only two of them, they are sometimes called the lower block
|
||||
(<code>0x601_0000</code>) and the higher/upper block (<code>0x601_4000</code>).</p>
|
||||
<p>Tile indexes for sprites always offset from the base of the lower block, and
|
||||
they always go 32 bytes at a time, regardless of if the object is set for 4bpp
|
||||
or 8bpp. From this we can determine that there's 512 tile slots in each of the
|
||||
two object charblocks. However, in video modes 3, 4, and 5 the space for the
|
||||
background cuts into the lower charblock, so you can only safely use the upper
|
||||
charblock.</p>
|
||||
<p>With backgrounds you picked every single tile individually with a bunch of
|
||||
screen entry values. Objects don't do that at all. Instead you pick a base tile,
|
||||
size, and shape, then it figures out the rest from there. However, you may
|
||||
recall back with the display control register something about an "object memory
|
||||
1d" bit. This is where that comes into play.</p>
|
||||
<ul>
|
||||
<li>If object memory is set to be 2d (the default) then each charblock is treated
|
||||
as 32 tiles by 32 tiles square. Each object has a base tile and dimensions,
|
||||
and that just extracts directly from the charblock picture as if you were
|
||||
selecting an area. This mode probably makes for the easiest image editing.</li>
|
||||
<li>If object memory is set to be 1d then the tiles are loaded sequentially from
|
||||
the starting point, enough to fill in the object's dimensions. This most
|
||||
probably makes it the easiest to program with about things, since programming
|
||||
languages are pretty good at 1d things.</li>
|
||||
</ul>
|
||||
<p>I'm not sure I explained that well, here's a picture:</p>
|
||||
<p><img src="obj_memory_2d1d.jpg" alt="2d1d-diagram" /></p>
|
||||
<p>In 2d mode, a new row of tiles starts every 32 tile indexes.</p>
|
||||
<p>Of course, the mode that you actually end up using is not particularly
|
||||
important, since it should be the job of your image conversion routine to get
|
||||
everything all lined up and into place anyway.</p>
|
||||
<a class="header" href="#set-the-object-attributes" id="set-the-object-attributes"><h2>Set the Object Attributes</h2></a>
|
||||
<p>The final step is to assign the correct attributes to an object. Each object has
|
||||
three <code>u16</code> values that make up its overall attributes.</p>
|
||||
<p>Before we go into the details, I want to remind you that the hardware will
|
||||
attempt to process every single object every single frame, and also that all of
|
||||
the GBA's memory is cleared to 0 at startup. Why do these two things matter
|
||||
right now? As you'll see in a second an "all zero" set of object attributes
|
||||
causes an 8x8 object to appear at 0,0 using object tile index 0. This is usually
|
||||
<em>not</em> what you want your unused objects to do. When your game first starts you
|
||||
should take a moment to mark any objects you won't be using as objects to not
|
||||
render.</p>
|
||||
<a class="header" href="#objectattributesattr0" id="objectattributesattr0"><h3>ObjectAttributes.attr0</h3></a>
|
||||
<ul>
|
||||
<li>8 bits for row coordinate (marks the top of the sprite)</li>
|
||||
<li>2 bits for object rendering: 0 = Normal, 1 = Affine, 2 = Disabled, 3 = Affine with double rendering area</li>
|
||||
<li>2 bits for object mode: 0 = Normal, 1 = Alpha Blending, 2 = Object Window, 3 = Forbidden</li>
|
||||
<li>1 bit for mosaic enabled</li>
|
||||
<li>1 bit 8bpp color enabled</li>
|
||||
<li>2 bits for shape: 0 = Square, 1 = Horizontal, 2 = Vertical, 3 = Forbidden</li>
|
||||
</ul>
|
||||
<p>If an object is 128 pixels big at Y > 128 you'll get a strange looking result
|
||||
where it acts like Y > -128 and then displays partly off screen to the top.</p>
|
||||
<a class="header" href="#objectattributesattr1" id="objectattributesattr1"><h3>ObjectAttributes.attr1</h3></a>
|
||||
<ul>
|
||||
<li>9 bit for column coordinate (marks the left of the sprite)</li>
|
||||
<li>Either:
|
||||
<ul>
|
||||
<li>3 empty bits, 1 bit for horizontal flip, 1 bit for vertical flip (non-affine)</li>
|
||||
<li>5 bits for affine index (affine)</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>2 bits for size.</li>
|
||||
</ul>
|
||||
<table><thead><tr><th align="center"> Size </th><th align="center"> Square </th><th align="center"> Horizontal </th><th align="center"> Vertical</th></tr></thead><tbody>
|
||||
<tr><td align="center"> 0 </td><td align="center"> 8x8 </td><td align="center"> 16x8 </td><td align="center"> 8x16 </td></tr>
|
||||
<tr><td align="center"> 1 </td><td align="center"> 16x16 </td><td align="center"> 32x8 </td><td align="center"> 8x32 </td></tr>
|
||||
<tr><td align="center"> 2 </td><td align="center"> 32x32 </td><td align="center"> 32x16 </td><td align="center"> 16x32 </td></tr>
|
||||
<tr><td align="center"> 3 </td><td align="center"> 64x64 </td><td align="center"> 64x32 </td><td align="center"> 32x64 </td></tr>
|
||||
</tbody></table>
|
||||
<a class="header" href="#objectattributesattr2" id="objectattributesattr2"><h3>ObjectAttributes.attr2</h3></a>
|
||||
<ul>
|
||||
<li>10 bits for the base tile index</li>
|
||||
<li>2 bits for priority</li>
|
||||
<li>4 bits for the palbank index (4bpp mode only, ignored in 8bpp)</li>
|
||||
</ul>
|
||||
<a class="header" href="#objectattributes-summary" id="objectattributes-summary"><h3>ObjectAttributes summary</h3></a>
|
||||
<p>So I said in the GBA memory mapping section that C people would tell you that
|
||||
the object attributes should look like this:</p>
|
||||
<pre><pre class="playpen"><code class="language-rust">
|
||||
# #![allow(unused_variables)]
|
||||
#fn main() {
|
||||
#[repr(C)]
|
||||
pub struct ObjectAttributes {
|
||||
attr0: u16,
|
||||
attr1: u16,
|
||||
attr2: u16,
|
||||
filler: i16,
|
||||
}
|
||||
#}</code></pre></pre>
|
||||
<p>Except that:</p>
|
||||
<ol>
|
||||
<li>It's wasteful when we store object attributes on their own outside of OAM
|
||||
(which we definitely might want to do).</li>
|
||||
<li>In Rust we can't access just one field through a volatile pointer (our
|
||||
pointers aren't actually volatile to begin with, just the ops we do with them
|
||||
are). We have to read or write the whole pointer's value at a time.
|
||||
Similarly, we can't do things like <code>|=</code> and <code>&=</code> with volatile in Rust. So in
|
||||
rust we can't have a volatile pointer to an ObjectAttributes and then write
|
||||
to just the three "real" values and not touch the filler field. Having the
|
||||
filler value in there just means we have to dance around it more, not less.</li>
|
||||
<li>We want to newtype this whole thing to prevent accidental invalid states from
|
||||
being written into memory.</li>
|
||||
</ol>
|
||||
<p>So we will not be using that representation. At the same time we want to have no
|
||||
overhead, so we will stick to three <code>u16</code> values. We could newtype each
|
||||
individual field to be its own type (<code>ObjectAttributesAttr0</code> or something silly
|
||||
like that), since there aren't actual dependencies between two different fields
|
||||
such that a change in one can throw another into a forbidden state. The worst
|
||||
that can happen is if we disable or enable affine mode (<code>attr0</code>) it can change
|
||||
the meaning of <code>attr1</code>. The changed meaning isn't actually in invalid state
|
||||
though, so we <em>could</em> make each field its own type if we wanted.</p>
|
||||
<p>However, when you think about it, I can't imagine a common situation where we do
|
||||
something like make an <code>attr0</code> value that we then want to save on its own and
|
||||
apply to several different <code>ObjectAttributes</code> that we make during a game. That
|
||||
just doesn't sound likely to me. So, we'll go the route where <code>ObjectAttributes</code>
|
||||
is just a big black box to the outside world and we don't need to think about
|
||||
the three fields internally as being separate.</p>
|
||||
<p>First we make it so that we can get and set object attributes from memory:</p>
|
||||
<pre><pre class="playpen"><code class="language-rust">
|
||||
# #![allow(unused_variables)]
|
||||
#fn main() {
|
||||
pub const OAM: usize = 0x700_0000;
|
||||
|
||||
pub fn object_attributes(slot: usize) -> ObjectAttributes {
|
||||
assert!(slot < 128);
|
||||
let ptr = VolatilePtr((OAM + slot * (size_of::<u16>() * 4)) as *mut u16);
|
||||
unsafe {
|
||||
ObjectAttributes {
|
||||
attr0: ptr.read(),
|
||||
attr1: ptr.offset(1).read(),
|
||||
attr2: ptr.offset(2).read(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_object_attributes(slot: usize, obj: ObjectAttributes) {
|
||||
assert!(slot < 128);
|
||||
let ptr = VolatilePtr((OAM + slot * (size_of::<u16>() * 4)) as *mut u16);
|
||||
unsafe {
|
||||
ptr.write(obj.attr0);
|
||||
ptr.offset(1).write(obj.attr1);
|
||||
ptr.offset(2).write(obj.attr2);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct ObjectAttributes {
|
||||
attr0: u16,
|
||||
attr1: u16,
|
||||
attr2: u16,
|
||||
}
|
||||
#}</code></pre></pre>
|
||||
<p>Then we add a billion methods to the <code>ObjectAttributes</code> type so that we can
|
||||
actually set all the different values that we want to set.</p>
|
||||
<p>This code block is the last thing on this page so if you don't wanna scroll past
|
||||
the whole thing you can just go to the next page.</p>
|
||||
<pre><pre class="playpen"><code class="language-rust">
|
||||
# #![allow(unused_variables)]
|
||||
#fn main() {
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ObjectRenderMode {
|
||||
Normal,
|
||||
Affine,
|
||||
Disabled,
|
||||
DoubleAreaAffine,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ObjectMode {
|
||||
Normal,
|
||||
AlphaBlending,
|
||||
ObjectWindow,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ObjectShape {
|
||||
Square,
|
||||
Horizontal,
|
||||
Vertical,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ObjectOrientation {
|
||||
Normal,
|
||||
HFlip,
|
||||
VFlip,
|
||||
BothFlip,
|
||||
Affine(u8),
|
||||
}
|
||||
|
||||
impl ObjectAttributes {
|
||||
pub fn row(&self) -> u16 {
|
||||
self.attr0 & 0b1111_1111
|
||||
}
|
||||
pub fn column(&self) -> u16 {
|
||||
self.attr1 & 0b1_1111_1111
|
||||
}
|
||||
pub fn rendering(&self) -> ObjectRenderMode {
|
||||
match (self.attr0 >> 8) & 0b11 {
|
||||
0 => ObjectRenderMode::Normal,
|
||||
1 => ObjectRenderMode::Affine,
|
||||
2 => ObjectRenderMode::Disabled,
|
||||
3 => ObjectRenderMode::DoubleAreaAffine,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
pub fn mode(&self) -> ObjectMode {
|
||||
match (self.attr0 >> 0xA) & 0b11 {
|
||||
0 => ObjectMode::Normal,
|
||||
1 => ObjectMode::AlphaBlending,
|
||||
2 => ObjectMode::ObjectWindow,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
pub fn mosaic(&self) -> bool {
|
||||
((self.attr0 << 3) as i16) < 0
|
||||
}
|
||||
pub fn two_fifty_six_colors(&self) -> bool {
|
||||
((self.attr0 << 2) as i16) < 0
|
||||
}
|
||||
pub fn shape(&self) -> ObjectShape {
|
||||
match (self.attr0 >> 0xE) & 0b11 {
|
||||
0 => ObjectShape::Square,
|
||||
1 => ObjectShape::Horizontal,
|
||||
2 => ObjectShape::Vertical,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
pub fn orientation(&self) -> ObjectOrientation {
|
||||
if (self.attr0 >> 8) & 1 > 0 {
|
||||
ObjectOrientation::Affine((self.attr1 >> 9) as u8 & 0b1_1111)
|
||||
} else {
|
||||
match (self.attr1 >> 0xC) & 0b11 {
|
||||
0 => ObjectOrientation::Normal,
|
||||
1 => ObjectOrientation::HFlip,
|
||||
2 => ObjectOrientation::VFlip,
|
||||
3 => ObjectOrientation::BothFlip,
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn size(&self) -> u16 {
|
||||
self.attr1 >> 0xE
|
||||
}
|
||||
pub fn tile_index(&self) -> u16 {
|
||||
self.attr2 & 0b11_1111_1111
|
||||
}
|
||||
pub fn priority(&self) -> u16 {
|
||||
self.attr2 >> 0xA
|
||||
}
|
||||
pub fn palbank(&self) -> u16 {
|
||||
self.attr2 >> 0xC
|
||||
}
|
||||
//
|
||||
pub fn set_row(&mut self, row: u16) {
|
||||
self.attr0 &= !0b1111_1111;
|
||||
self.attr0 |= row & 0b1111_1111;
|
||||
}
|
||||
pub fn set_column(&mut self, col: u16) {
|
||||
self.attr1 &= !0b1_1111_1111;
|
||||
self.attr2 |= col & 0b1_1111_1111;
|
||||
}
|
||||
pub fn set_rendering(&mut self, rendering: ObjectRenderMode) {
|
||||
const RENDERING_MASK: u16 = 0b11 << 8;
|
||||
self.attr0 &= !RENDERING_MASK;
|
||||
self.attr0 |= (rendering as u16) << 8;
|
||||
}
|
||||
pub fn set_mode(&mut self, mode: ObjectMode) {
|
||||
const MODE_MASK: u16 = 0b11 << 0xA;
|
||||
self.attr0 &= MODE_MASK;
|
||||
self.attr0 |= (mode as u16) << 0xA;
|
||||
}
|
||||
pub fn set_mosaic(&mut self, bit: bool) {
|
||||
const MOSAIC_BIT: u16 = 1 << 0xC;
|
||||
if bit {
|
||||
self.attr0 |= MOSAIC_BIT
|
||||
} else {
|
||||
self.attr0 &= !MOSAIC_BIT
|
||||
}
|
||||
}
|
||||
pub fn set_two_fifty_six_colors(&mut self, bit: bool) {
|
||||
const COLOR_MODE_BIT: u16 = 1 << 0xD;
|
||||
if bit {
|
||||
self.attr0 |= COLOR_MODE_BIT
|
||||
} else {
|
||||
self.attr0 &= !COLOR_MODE_BIT
|
||||
}
|
||||
}
|
||||
pub fn set_shape(&mut self, shape: ObjectShape) {
|
||||
self.attr0 &= 0b0011_1111_1111_1111;
|
||||
self.attr0 |= (shape as u16) << 0xE;
|
||||
}
|
||||
pub fn set_orientation(&mut self, orientation: ObjectOrientation) {
|
||||
const AFFINE_INDEX_MASK: u16 = 0b1_1111 << 9;
|
||||
self.attr1 &= !AFFINE_INDEX_MASK;
|
||||
let bits = match orientation {
|
||||
ObjectOrientation::Affine(index) => (index as u16) << 9,
|
||||
ObjectOrientation::Normal => 0,
|
||||
ObjectOrientation::HFlip => 1 << 0xC,
|
||||
ObjectOrientation::VFlip => 1 << 0xD,
|
||||
ObjectOrientation::BothFlip => 0b11 << 0xC,
|
||||
};
|
||||
self.attr1 |= bits;
|
||||
}
|
||||
pub fn set_size(&mut self, size: u16) {
|
||||
self.attr1 &= 0b0011_1111_1111_1111;
|
||||
self.attr1 |= size << 14;
|
||||
}
|
||||
pub fn set_tile_index(&mut self, index: u16) {
|
||||
self.attr2 &= !0b11_1111_1111;
|
||||
self.attr2 |= 0b11_1111_1111 & index;
|
||||
}
|
||||
pub fn set_priority(&mut self, priority: u16) {
|
||||
self.attr2 &= !0b0000_1100_0000_0000;
|
||||
self.attr2 |= (priority & 0b11) << 0xA;
|
||||
}
|
||||
pub fn set_palbank(&mut self, palbank: u16) {
|
||||
self.attr2 &= !0b1111_0000_0000_0000;
|
||||
self.attr2 |= (palbank & 0b1111) << 0xC;
|
||||
}
|
||||
}
|
||||
#}</code></pre></pre>
|
||||
|
||||
</main>
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
|
||||
<a rel="prev" href="../ch03/regular_backgrounds.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
<a rel="next" href="../ch03/gba_rng.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
|
||||
<div style="clear: both"></div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
|
||||
<a href="../ch03/regular_backgrounds.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
<a href="../ch03/gba_rng.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<script src="../elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../mark.min.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../searcher.js" type="text/javascript" charset="utf-8"></script>
|
||||
|
||||
|
||||
<script src="../clipboard.min.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../highlight.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../book.js" type="text/javascript" charset="utf-8"></script>
|
||||
|
||||
<!-- Custom JS scripts -->
|
||||
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -72,7 +72,7 @@
|
|||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html" class="active"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/object_basics.html"><strong aria-hidden="true">5.4.</strong> Object Basics</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
<ol class="chapter"><li><a href="../introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="../ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="../ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="../ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="../ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="../ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="../ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="../ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="../ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="../ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="../ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="../ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="../ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="../ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="../ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="../ch03/tile_data.html" class="active"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="../ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="../ch03/regular_objects.html"><strong aria-hidden="true">5.4.</strong> Regular Objects</a></li><li><a href="../ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="../ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<ol class="chapter"><li><a href="introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="ch03/object_basics.html"><strong aria-hidden="true">5.4.</strong> Object Basics</a></li><li><a href="ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
<ol class="chapter"><li><a href="introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="ch03/regular_objects.html"><strong aria-hidden="true">5.4.</strong> Regular Objects</a></li><li><a href="ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
@ -157,7 +157,9 @@ directory</a> of the repo
|
|||
if you want to get them that way.</p>
|
||||
<a class="header" href="#expected-knowledge" id="expected-knowledge"><h2>Expected Knowledge</h2></a>
|
||||
<p>I will try not to ask too much of the reader ahead of time, but you are expected
|
||||
to have already read <a href="https://doc.rust-lang.org/book/">The Rust Book</a>.</p>
|
||||
to have already read <a href="https://doc.rust-lang.org/book/">The Rust Book</a>. Having
|
||||
also read through the <a href="https://doc.rust-lang.org/nomicon/">Rustonomicon</a> is
|
||||
appreciated but not required.</p>
|
||||
<p>It's very difficult to know when you've said something that someone else won't
|
||||
already know about, or if you're presenting ideas out of order. If things aren't
|
||||
clear please <a href="https://github.com/rust-console/gba/issues">file an issue</a> and
|
||||
|
@ -176,14 +178,11 @@ folks in the server as well (there's a few hundred folks).</p>
|
|||
<p>If you want to read more about developing on the GBA there are some other good
|
||||
resources as well:</p>
|
||||
<ul>
|
||||
<li><a href="https://www.coranac.com/tonc/text/toc.htm">Tonc</a>, a tutorial series written
|
||||
<li><a href="https://www.coranac.com/tonc/text/toc.htm">TONC</a>, a tutorial series written
|
||||
for C, but it's what I based the ordering of this book's sections on.</li>
|
||||
<li><a href="http://problemkaputt.de/gbatek.htm">GBATEK</a>, a homebrew tech manual for
|
||||
GBA/NDS/DSi. We will regularly link to parts of it when talking about various
|
||||
bits of the GBA.</li>
|
||||
<li><a href="https://www.cs.rit.edu/%7Etjh8300/CowBite/CowBiteSpec.htm">CowBite</a> is another
|
||||
tech specification that's more GBA specific. It's sometimes got more ASCII
|
||||
art diagrams and example C struct layouts than GBATEK does.</li>
|
||||
</ul>
|
||||
|
||||
</main>
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<ol class="chapter"><li><a href="introduction.html" class="active"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="ch03/object_basics.html"><strong aria-hidden="true">5.4.</strong> Object Basics</a></li><li><a href="ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
<ol class="chapter"><li><a href="introduction.html" class="active"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="ch03/regular_objects.html"><strong aria-hidden="true">5.4.</strong> Regular Objects</a></li><li><a href="ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
@ -157,7 +157,9 @@ directory</a> of the repo
|
|||
if you want to get them that way.</p>
|
||||
<a class="header" href="#expected-knowledge" id="expected-knowledge"><h2>Expected Knowledge</h2></a>
|
||||
<p>I will try not to ask too much of the reader ahead of time, but you are expected
|
||||
to have already read <a href="https://doc.rust-lang.org/book/">The Rust Book</a>.</p>
|
||||
to have already read <a href="https://doc.rust-lang.org/book/">The Rust Book</a>. Having
|
||||
also read through the <a href="https://doc.rust-lang.org/nomicon/">Rustonomicon</a> is
|
||||
appreciated but not required.</p>
|
||||
<p>It's very difficult to know when you've said something that someone else won't
|
||||
already know about, or if you're presenting ideas out of order. If things aren't
|
||||
clear please <a href="https://github.com/rust-console/gba/issues">file an issue</a> and
|
||||
|
@ -176,14 +178,11 @@ folks in the server as well (there's a few hundred folks).</p>
|
|||
<p>If you want to read more about developing on the GBA there are some other good
|
||||
resources as well:</p>
|
||||
<ul>
|
||||
<li><a href="https://www.coranac.com/tonc/text/toc.htm">Tonc</a>, a tutorial series written
|
||||
<li><a href="https://www.coranac.com/tonc/text/toc.htm">TONC</a>, a tutorial series written
|
||||
for C, but it's what I based the ordering of this book's sections on.</li>
|
||||
<li><a href="http://problemkaputt.de/gbatek.htm">GBATEK</a>, a homebrew tech manual for
|
||||
GBA/NDS/DSi. We will regularly link to parts of it when talking about various
|
||||
bits of the GBA.</li>
|
||||
<li><a href="https://www.cs.rit.edu/%7Etjh8300/CowBite/CowBiteSpec.htm">CowBite</a> is another
|
||||
tech specification that's more GBA specific. It's sometimes got more ASCII
|
||||
art diagrams and example C struct layouts than GBATEK does.</li>
|
||||
</ul>
|
||||
|
||||
</main>
|
||||
|
|
700
docs/print.html
700
docs/print.html
|
@ -72,7 +72,7 @@
|
|||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<ol class="chapter"><li><a href="introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="ch03/object_basics.html"><strong aria-hidden="true">5.4.</strong> Object Basics</a></li><li><a href="ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
<ol class="chapter"><li><a href="introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><a href="ch00/index.html"><strong aria-hidden="true">2.</strong> Ch 0: Development Setup</a></li><li><a href="ch01/index.html"><strong aria-hidden="true">3.</strong> Ch 1: Hello GBA</a></li><li><ol class="section"><li><a href="ch01/hello1.html"><strong aria-hidden="true">3.1.</strong> hello1</a></li><li><a href="ch01/volatile.html"><strong aria-hidden="true">3.2.</strong> Volatile</a></li><li><a href="ch01/io_registers.html"><strong aria-hidden="true">3.3.</strong> IO Registers</a></li><li><a href="ch01/the_display_control_register.html"><strong aria-hidden="true">3.4.</strong> The Display Control Register</a></li><li><a href="ch01/video_memory_intro.html"><strong aria-hidden="true">3.5.</strong> Video Memory Intro</a></li><li><a href="ch01/hello2.html"><strong aria-hidden="true">3.6.</strong> hello2</a></li></ol></li><li><a href="ch02/index.html"><strong aria-hidden="true">4.</strong> Ch 2: User Input</a></li><li><ol class="section"><li><a href="ch02/the_key_input_register.html"><strong aria-hidden="true">4.1.</strong> The Key Input Register</a></li><li><a href="ch02/the_vcount_register.html"><strong aria-hidden="true">4.2.</strong> The VCount Register</a></li><li><a href="ch02/light_cycle.html"><strong aria-hidden="true">4.3.</strong> light_cycle</a></li></ol></li><li><a href="ch03/index.html"><strong aria-hidden="true">5.</strong> Ch 3: Memory and Objects</a></li><li><ol class="section"><li><a href="ch03/gba_memory_mapping.html"><strong aria-hidden="true">5.1.</strong> GBA Memory Mapping</a></li><li><a href="ch03/tile_data.html"><strong aria-hidden="true">5.2.</strong> Tile Data</a></li><li><a href="ch03/regular_backgrounds.html"><strong aria-hidden="true">5.3.</strong> Regular Backgrounds</a></li><li><a href="ch03/regular_objects.html"><strong aria-hidden="true">5.4.</strong> Regular Objects</a></li><li><a href="ch03/gba_rng.html"><strong aria-hidden="true">5.5.</strong> GBA RNG</a></li><li><a href="ch03/memory_game.html"><strong aria-hidden="true">5.6.</strong> memory_game</a></li></ol></li></ol>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
@ -157,7 +157,9 @@ directory</a> of the repo
|
|||
if you want to get them that way.</p>
|
||||
<a class="header" href="#expected-knowledge" id="expected-knowledge"><h2>Expected Knowledge</h2></a>
|
||||
<p>I will try not to ask too much of the reader ahead of time, but you are expected
|
||||
to have already read <a href="https://doc.rust-lang.org/book/">The Rust Book</a>.</p>
|
||||
to have already read <a href="https://doc.rust-lang.org/book/">The Rust Book</a>. Having
|
||||
also read through the <a href="https://doc.rust-lang.org/nomicon/">Rustonomicon</a> is
|
||||
appreciated but not required.</p>
|
||||
<p>It's very difficult to know when you've said something that someone else won't
|
||||
already know about, or if you're presenting ideas out of order. If things aren't
|
||||
clear please <a href="https://github.com/rust-console/gba/issues">file an issue</a> and
|
||||
|
@ -176,14 +178,11 @@ folks in the server as well (there's a few hundred folks).</p>
|
|||
<p>If you want to read more about developing on the GBA there are some other good
|
||||
resources as well:</p>
|
||||
<ul>
|
||||
<li><a href="https://www.coranac.com/tonc/text/toc.htm">Tonc</a>, a tutorial series written
|
||||
<li><a href="https://www.coranac.com/tonc/text/toc.htm">TONC</a>, a tutorial series written
|
||||
for C, but it's what I based the ordering of this book's sections on.</li>
|
||||
<li><a href="http://problemkaputt.de/gbatek.htm">GBATEK</a>, a homebrew tech manual for
|
||||
GBA/NDS/DSi. We will regularly link to parts of it when talking about various
|
||||
bits of the GBA.</li>
|
||||
<li><a href="https://www.cs.rit.edu/%7Etjh8300/CowBite/CowBiteSpec.htm">CowBite</a> is another
|
||||
tech specification that's more GBA specific. It's sometimes got more ASCII
|
||||
art diagrams and example C struct layouts than GBATEK does.</li>
|
||||
</ul>
|
||||
<a class="header" href="#chapter-0-development-setup" id="chapter-0-development-setup"><h1>Chapter 0: Development Setup</h1></a>
|
||||
<p>Before you can build a GBA game you'll have to follow some special steps to
|
||||
|
@ -1302,6 +1301,23 @@ without trading away too much in terms of quality.</p>
|
|||
<p>To top it all off, we'll make a simple "memory game" sort of thing. There's some
|
||||
face down cards in a grid, you pick one to check, then you pick the other to
|
||||
check, and then if they match the pair disappears.</p>
|
||||
<a class="header" href="#drawing-priority" id="drawing-priority"><h2>Drawing Priority</h2></a>
|
||||
<p>Both backgrounds and objects can have "priority" values associated with them.
|
||||
TONC and GBATEK have <em>opposite</em> ideas of what it means to have the "highest"
|
||||
priority. TONC goes by highest numerical value, and GBATEK goes by what's on the
|
||||
z-layer closest to the user. Let's list out the rules as clearly as we can:</p>
|
||||
<ul>
|
||||
<li>Priority is always two bits, so 0 through 3.</li>
|
||||
<li>Priority conceptually proceeds in drawing passes that count <em>down</em>, so any
|
||||
priority 3 things can get covered up by priority 2 things. In truth there's
|
||||
probably depth testing and buffering stuff going on so it's all one single
|
||||
pass, but conceptually we will imagine it happening as all of the 3 elements,
|
||||
then all of 2, and so on.</li>
|
||||
<li>Objects always draw over top of backgrounds of equal priority.</li>
|
||||
<li>Within things of the same type and priority, the lower numbered element "wins"
|
||||
and gets its pixel drawn (bg0 is favored over bg1, obj0 is favored over obj1,
|
||||
etc).</li>
|
||||
</ul>
|
||||
<a class="header" href="#gba-memory-mapping" id="gba-memory-mapping"><h1>GBA Memory Mapping</h1></a>
|
||||
<p>The <a href="http://problemkaputt.de/gbatek.htm#gbamemorymap">GBA Memory Map</a> has
|
||||
several memory portions to it, each with their own little differences. Most of
|
||||
|
@ -1391,6 +1407,20 @@ and then a <em>separate</em> setting outside of the graphical data determines wh
|
|||
palbank is to be used for that background or object (the screen entry data for
|
||||
backgrounds, and the object attributes for objects).</li>
|
||||
</ul>
|
||||
<a class="header" href="#transparency" id="transparency"><h3>Transparency</h3></a>
|
||||
<p>When a pixel within a background or object specifies index 0 as its palette
|
||||
entry it is treated as a transparent pixel. This means that in 8bpp mode there's
|
||||
only 255 actual color options (0 being transparent), and in 4bpp mode there's
|
||||
only 15 actual color options available within each palbank (the 0th entry of
|
||||
<em>each</em> palbank is transparent).</p>
|
||||
<p>Individual backgrounds, and individual objects, each determine if they're 4bpp
|
||||
or 8bpp separately, so a given overall palette slot might map to a used color in
|
||||
8bpp and an unused/transparent color in 4bpp. If you're a palette wizard.</p>
|
||||
<p>Palette slot 0 of the overall background palette is used to determine the
|
||||
"backdrop" color. That's the color you see if no background or object ends up
|
||||
being rendered within a given pixel.</p>
|
||||
<p>Since display mode 3 and display mode 5 don't use the palette, they cannot
|
||||
benefit from transparency.</p>
|
||||
<a class="header" href="#video-ram--vram" id="video-ram--vram"><h2>Video RAM / VRAM</h2></a>
|
||||
<ul>
|
||||
<li><code>0x6000000</code> to <code>0x6017FFF</code> (96k)</li>
|
||||
|
@ -1630,10 +1660,660 @@ example</a></li>
|
|||
macro to have the formatted resource be available as a const value you can
|
||||
load at runtime.</li>
|
||||
</ol>
|
||||
<a class="header" href="#tiled-backgrounds" id="tiled-backgrounds"><h1>Tiled Backgrounds</h1></a>
|
||||
<p>TODO</p>
|
||||
<a class="header" href="#object-basics" id="object-basics"><h1>Object Basics</h1></a>
|
||||
<p>TODO</p>
|
||||
<a class="header" href="#regular-backgrounds" id="regular-backgrounds"><h1>Regular Backgrounds</h1></a>
|
||||
<p>So, backgrounds, they're cool. Why do we call the ones here "regular"
|
||||
backgrounds? Because there's also "affine" backgrounds. However, affine math
|
||||
stuff adds a complication, so for now we'll just work with regular backgrounds.
|
||||
The non-affine backgrounds are sometimes called "text mode" backgrounds by other
|
||||
guides.</p>
|
||||
<p>To get your background image working you generally need to perform all of the
|
||||
following steps, though I suppose the exact ordering is up to you.</p>
|
||||
<a class="header" href="#tiled-video-modes" id="tiled-video-modes"><h2>Tiled Video Modes</h2></a>
|
||||
<p>When you want regular tiled display, you must use video mode 0 or 1.</p>
|
||||
<ul>
|
||||
<li>Mode 0 allows for using all four BG layers (0 through 3) as regular
|
||||
backgrounds.</li>
|
||||
<li>Mode 1 allows for using BG0 and BG1 as regular backgrounds, BG2 as an affine
|
||||
background, and BG3 not at all.</li>
|
||||
<li>Mode 2 allows for BG2 and BG3 to be used as affine backgrounds, while BG0 and
|
||||
BG1 cannot be used at all.</li>
|
||||
</ul>
|
||||
<p>We will not cover affine backgrounds in this chapter, so we will naturally be
|
||||
using video mode 0.</p>
|
||||
<p>Also, note that you have to enable each background layer that you want to use
|
||||
within the display control register.</p>
|
||||
<a class="header" href="#get-your-palette-ready" id="get-your-palette-ready"><h2>Get Your Palette Ready</h2></a>
|
||||
<p>Background palette starts at <code>0x5000000</code> and is 256 <code>u16</code> values long. It'd
|
||||
potentially be possible declare a static array starting at a fixed address and
|
||||
use a linker script to make sure that it ends up at the right spot in the final
|
||||
program, but since we have to use volatile reads and writes with PALRAM anyway,
|
||||
we'll just reuse our <code>VolatilePtr</code> type. Something like this:</p>
|
||||
<pre><pre class="playpen"><code class="language-rust">
|
||||
# #![allow(unused_variables)]
|
||||
#fn main() {
|
||||
pub const PALRAM_BG_BASE: VolatilePtr<u16> = VolatilePtr(0x500_0000 as *mut u16);
|
||||
|
||||
pub fn bg_palette(slot: usize) -> u16 {
|
||||
assert!(slot < 256);
|
||||
unsafe { PALRAM_BG_BASE.offset(slot as isize).read() }
|
||||
}
|
||||
|
||||
pub fn set_bg_palette(slot: usize, color: u16) {
|
||||
assert!(slot < 256);
|
||||
unsafe { PALRAM_BG_BASE.offset(slot as isize).write(color) }
|
||||
}
|
||||
#}</code></pre></pre>
|
||||
<p>As we discussed with the tile color depths, the palette can be utilized as a
|
||||
single block of palette values (<code>[u16; 256]</code>) or as 16 palbanks of 16 palette
|
||||
values each (<code>[[u16;16]; 16]</code>). This setting is assigned per background layer
|
||||
via IO register.</p>
|
||||
<a class="header" href="#get-your-tiles-ready" id="get-your-tiles-ready"><h2>Get Your Tiles Ready</h2></a>
|
||||
<p>Tile data is placed into charblocks. A charblock is always 16kb, so depending on
|
||||
color depth it will have either 256 or 512 tiles within that charblock.
|
||||
Charblocks 0, 1, 2, and 3 are all for background tiles. That's a maximum of 2048
|
||||
tiles for backgrounds, but as you'll see in a moment a particular tilemap entry
|
||||
can't even index that high. Instead, each background layer is assigned a
|
||||
"character base block", and then tilemap entries index relative to the character
|
||||
base block of that background layer.</p>
|
||||
<p>Now, if you want to move in a lot of tile data you'll probably want to use a DMA
|
||||
routine, or at least write a function like memcopy32 for fast <code>u32</code> copying from
|
||||
ROM into VRAM. However, for now, and because we're being very explicit since
|
||||
this is our first time doing it, we'll write it as functions for individual tile
|
||||
reads and writes.</p>
|
||||
<p>The math works like indexing a pointer, except that we have two sizes we need to
|
||||
go by. First you take the base address for VRAM (<code>0x600_0000</code>), then add the
|
||||
size of a charblock (16kb) times the charblock you want to place the tile
|
||||
within, and then you add the index of the tile slot you're placing it into times
|
||||
the size of that type of tile. Like this:</p>
|
||||
<pre><pre class="playpen"><code class="language-rust">
|
||||
# #![allow(unused_variables)]
|
||||
#fn main() {
|
||||
pub fn bg_tile_4pp(base_block: usize, tile_index: usize) -> Tile4bpp {
|
||||
assert!(base_block < 4);
|
||||
assert!(tile_index < 512);
|
||||
let address = VRAM + size_of::<Charblock4bpp>() * base_block + size_of::<Tile4bpp>() * tile_index;
|
||||
unsafe { VolatilePtr(address as *mut Tile4bpp).read() }
|
||||
}
|
||||
|
||||
pub fn set_bg_tile_4pp(base_block: usize, tile_index: usize, tile: Tile4bpp) {
|
||||
assert!(base_block < 4);
|
||||
assert!(tile_index < 512);
|
||||
let address = VRAM + size_of::<Charblock4bpp>() * base_block + size_of::<Tile4bpp>() * tile_index;
|
||||
unsafe { VolatilePtr(address as *mut Tile4bpp).write(tile) }
|
||||
}
|
||||
|
||||
pub fn bg_tile_8pp(base_block: usize, tile_index: usize) -> Tile8bpp {
|
||||
assert!(base_block < 4);
|
||||
assert!(tile_index < 256);
|
||||
let address = VRAM + size_of::<Charblock8bpp>() * base_block + size_of::<Tile8bpp>() * tile_index;
|
||||
unsafe { VolatilePtr(address as *mut Tile8bpp).read() }
|
||||
}
|
||||
|
||||
pub fn set_bg_tile_8pp(base_block: usize, tile_index: usize, tile: Tile8bpp) {
|
||||
assert!(base_block < 4);
|
||||
assert!(tile_index < 256);
|
||||
let address = VRAM + size_of::<Charblock8bpp>() * base_block + size_of::<Tile8bpp>() * tile_index;
|
||||
unsafe { VolatilePtr(address as *mut Tile8bpp).write(tile) }
|
||||
}
|
||||
#}</code></pre></pre>
|
||||
<p>For bulk operations, you'd do the exact same math to get your base destination
|
||||
pointer, and then you'd get the base source pointer for the tile you're copying
|
||||
out of ROM, and then you'd do the bulk copy for the correct number of <code>u32</code>
|
||||
values that you're trying to move (8 per tile moved for 4bpp, or 16 per tile
|
||||
moved for 8bpp).</p>
|
||||
<p><strong>GBA Limitation Note:</strong> on a modern PC (eg: <code>x86</code> or <code>x86_64</code>) you're probably
|
||||
used to index based loops and iterator based loops being the same speed. The CPU
|
||||
has the ability to do a "fused multiply add", so the base address of the array
|
||||
plus desired index * size per element is a single CPU operation to compute. It's
|
||||
slightly more complicated if there's arrays within arrays like there are here,
|
||||
but with normal arrays it's basically the same speed to index per loop cycle as
|
||||
it is to take a base address and then add +1 offset per loop cycle. However, the
|
||||
GBA's CPU <em>can't do any of that</em>. On the GBA, there's a genuine speed difference
|
||||
between looping over indexes and then indexing each loop (slow) compared to
|
||||
using an iterator that just stores an internal pointer and does +1 offset per
|
||||
loop until it reaches the end (fast). The repeated indexing itself can by itself
|
||||
be an expensive step. If it's like a 3 element array it's no big deal, but if
|
||||
you've got a big slice of data to process, be sure to go over it with <code>.iter()</code>
|
||||
and <code>.iter_mut()</code> if you can, instead of looping by index. This is Rust and all,
|
||||
so probably you were gonna do that anyway, but just a heads up.</p>
|
||||
<a class="header" href="#get-your-tilemap-ready" id="get-your-tilemap-ready"><h2>Get your Tilemap ready</h2></a>
|
||||
<p>I believe that at one point I alluded to a tilemap existing. Well, just as the
|
||||
tiles are arranged into charblocks, the data describing what tile to show in
|
||||
what location is arranged into a thing called a <strong>screenblock</strong>.</p>
|
||||
<p>A screenblock is placed into VRAM the same as the tile data charblocks. Starting
|
||||
at the base of VRAM (<code>0x600_0000</code>) there are 32 slots for the screenblock array.
|
||||
Each screenblock is 2048 bytes (<code>0x800</code>). Naturally, if our tiles are using up
|
||||
charblock space within VRAM and our tilemaps are using up screenblock space
|
||||
within the same VRAM... well it would just be a <em>disaster</em> if they ran in to
|
||||
each other. Once again, it's up to you as the programmer to determine how much
|
||||
space you want to devote to each thing. Each complete charblock uses up 8
|
||||
screenblocks worth of space, but you don't have to fill a complete charblock
|
||||
with tiles, so you can be very fiddly with how you split the memory.</p>
|
||||
<p>Each screenblock is composed of a series of <em>screenblock entry</em> values, which
|
||||
describe what tile index to use and if the tile should be flipped and what
|
||||
palbank it should use (if any). Because both regular backgrounds and affine
|
||||
backgrounds are composed of screenblocks with entries, and because the affine
|
||||
background has a smaller format for screenblock entries, we'll name
|
||||
appropriately.</p>
|
||||
<pre><pre class="playpen"><code class="language-rust">
|
||||
# #![allow(unused_variables)]
|
||||
#fn main() {
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(transparent)]
|
||||
pub struct RegularScreenblock {
|
||||
data: [RegularScreenblockEntry; 32 * 32],
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
#[repr(transparent)]
|
||||
pub struct RegularScreenblockEntry(u16);
|
||||
#}</code></pre></pre>
|
||||
<p>So, with one entry per tile, a single screenblock allows for 32x32 tiles worth of
|
||||
background.</p>
|
||||
<p>The format of a regular screenblock entry is quite simple compared to some of
|
||||
the IO register stuff:</p>
|
||||
<ul>
|
||||
<li>10 bits for tile index (base off of the character base block of the background)</li>
|
||||
<li>1 bit for horizontal flip</li>
|
||||
<li>1 bit for vertical flip</li>
|
||||
<li>4 bits for picking which palbank to use (if 4bpp, otherwise it's ignored)</li>
|
||||
</ul>
|
||||
<pre><pre class="playpen"><code class="language-rust">
|
||||
# #![allow(unused_variables)]
|
||||
#fn main() {
|
||||
impl RegularScreenblockEntry {
|
||||
pub fn tile_id(self) -> u16 {
|
||||
self.0 & 0b11_1111_1111
|
||||
}
|
||||
pub fn set_tile_id(&mut self, id: u16) {
|
||||
self.0 &= !0b11_1111_1111;
|
||||
self.0 |= id;
|
||||
}
|
||||
pub fn horizontal_flip(self) -> bool {
|
||||
(self.0 & (1 << 0xA)) > 0
|
||||
}
|
||||
pub fn set_horizontal_flip(&mut self, bit: bool) {
|
||||
if bit {
|
||||
self.0 |= 1 << 0xA;
|
||||
} else {
|
||||
self.0 &= !(1 << 0xA);
|
||||
}
|
||||
}
|
||||
pub fn vertical_flip(self) -> bool {
|
||||
(self.0 & (1 << 0xB)) > 0
|
||||
}
|
||||
pub fn set_vertical_flip(&mut self, bit: bool) {
|
||||
if bit {
|
||||
self.0 |= 1 << 0xB;
|
||||
} else {
|
||||
self.0 &= !(1 << 0xB);
|
||||
}
|
||||
}
|
||||
pub fn palbank_index(self) -> u16 {
|
||||
self.0 >> 12
|
||||
}
|
||||
pub fn set_palbank_index(&mut self, palbank_index: u16) {
|
||||
self.0 &= 0b1111_1111_1111;
|
||||
self.0 |= palbank_index;
|
||||
}
|
||||
}
|
||||
#}</code></pre></pre>
|
||||
<p>Now, at either 256 or 512 tiles per charblock, you might be thinking that with a
|
||||
10 bit index you can index past the end of one charblock and into the next.
|
||||
You'd be right, mostly.</p>
|
||||
<p>As long as you stay within the background memory region for charblocks (that is,
|
||||
0 through 3), then it all works out. However, if you try to get the background
|
||||
rendering to reach outside of the background charblocks you'll get an
|
||||
implementation defined result. It's not the dreaded "undefined behavior" we're
|
||||
often worried about in programming, but the results <em>are</em> determined by what
|
||||
you're running the game on. With GBA hardware you get a bizarre result
|
||||
(basically another way to put garbage on the screen). With a DS it acts as if
|
||||
the tiles were all 0s. If you use an emulator it might or might not allow for
|
||||
you to do this, it's up to the emulator writers.</p>
|
||||
<a class="header" href="#set-your-io-registers" id="set-your-io-registers"><h2>Set Your IO Registers</h2></a>
|
||||
<p>Instead of being just a single IO register to learn about this time, there's two
|
||||
separate groups of related registers.</p>
|
||||
<a class="header" href="#background-control" id="background-control"><h3>Background Control</h3></a>
|
||||
<ul>
|
||||
<li>BG0CNT (<code>0x400_0008</code>): BG0 Control</li>
|
||||
<li>BG1CNT (<code>0x400_000A</code>): BG1 Control</li>
|
||||
<li>BG2CNT (<code>0x400_000C</code>): BG2 Control</li>
|
||||
<li>BG3CNT (<code>0x400_000E</code>): BG3 Control</li>
|
||||
</ul>
|
||||
<p>Each of these are a read/write <code>u16</code> location. This is where we get to all of
|
||||
the important details that we've been putting off.</p>
|
||||
<ul>
|
||||
<li>2 bits for the priority.</li>
|
||||
<li>2 bits for "character base block", the charblock that all of the tile indexes
|
||||
for this background are offset from.</li>
|
||||
<li>1 bit for mosaic effect being enabled (we'll get to that below).</li>
|
||||
<li>1 bit to enable 8bpp, otherwise 4bpp is used.</li>
|
||||
<li>5 bits to pick the "screen base block", the screen block that serves as the
|
||||
<em>base</em> value for this background.</li>
|
||||
<li>1 bit that is <em>not</em> used in regular mode, but in affine mode it can be enabled
|
||||
to cause the affine background to wrap around at the edges.</li>
|
||||
<li>2 bits for the background size.</li>
|
||||
</ul>
|
||||
<p>The size works a little funny. When size is 0 only the base screen block is
|
||||
used. If size is 1 or 2 then the base screenblock and the following screenblock
|
||||
are placed next to each other (horizontally for 1, vertically for 2). If the
|
||||
size is 3 then the base screenblock and the following three screenblocks are
|
||||
arranged into a 2x2 grid of screenblocks.</p>
|
||||
<a class="header" href="#background-offset" id="background-offset"><h3>Background Offset</h3></a>
|
||||
<ul>
|
||||
<li>BG0HOFS (<code>0x400_0010</code>): BG0 X-Offset</li>
|
||||
<li>BG0VOFS (<code>0x400_0012</code>): BG0 Y-Offset</li>
|
||||
<li>BG1HOFS (<code>0x400_0014</code>): BG1 X-Offset</li>
|
||||
<li>BG1VOFS (<code>0x400_0016</code>): BG1 Y-Offset</li>
|
||||
<li>BG2HOFS (<code>0x400_0018</code>): BG2 X-Offset</li>
|
||||
<li>BG2VOFS (<code>0x400_001A</code>): BG2 Y-Offset</li>
|
||||
<li>BG3HOFS (<code>0x400_001C</code>): BG3 X-Offset</li>
|
||||
<li>BG3VOFS (<code>0x400_001E</code>): BG3 Y-Offset</li>
|
||||
</ul>
|
||||
<p>Each of these are a <em>write only</em> <code>u16</code> location. Bits 0 through 8 are used, so
|
||||
the offsets can be 0 through 511. They also only apply in regular backgrounds.
|
||||
If a background is in an affine state then you'll use different IO registers to
|
||||
control it (discussed in a later chapter).</p>
|
||||
<p>The offset that you assign determines the pixel offset of the display area
|
||||
relative to the start of the background scene, as if the screen was a camera
|
||||
looking at the scene. In other words, as a BG X offset value increases, you can
|
||||
think of it as the camera moving to the right, or as that background moving to
|
||||
the left. Like when mario walks toward the goal. Similarly, when a BG Y offset
|
||||
increases the camera is moving down, or the background is moving up, like when
|
||||
mario falls down from a high platform.</p>
|
||||
<p>Depending on how much the background is scrolled and the size of the background,
|
||||
it will loop.</p>
|
||||
<a class="header" href="#mosaic" id="mosaic"><h2>Mosaic</h2></a>
|
||||
<p>As a special effect, you can apply mosaic to backgrounds and objects. It's just
|
||||
a single flag for each background, so all backgrounds will use the same mosaic
|
||||
settings when they have it enabled. What it actually does is split the normal
|
||||
image into "blocks" and then each block gets the color of the top left pixel of
|
||||
that block. This is the effect you see when link hits an electric foe with his
|
||||
sword and the whole screen "buzzes" at you.</p>
|
||||
<p>The mosaic control is a <em>write only</em> <code>u16</code> IO register at <code>0x400_004C</code>.</p>
|
||||
<p>There's 4 bits each for:</p>
|
||||
<ul>
|
||||
<li>Horizontal BG stretch</li>
|
||||
<li>Vertical BG stretch</li>
|
||||
<li>Horizontal object stretch</li>
|
||||
<li>Vertical object stretch</li>
|
||||
</ul>
|
||||
<p>The inputs should be 1 <em>less</em> than the desired block size. So if you set a
|
||||
stretch value of 5 then pixels 0-5 would be part of the first block (6 pixels),
|
||||
then 6-11 is the next block (another 6 pixels) and so on.</p>
|
||||
<p>If you need to make a pixel other than the top left part of each block the one
|
||||
that determines the mosaic color you can carefully offset the background or
|
||||
image by a tiny bit, but of course that makes every mosaic block change its
|
||||
target pixel. You can't change the target pixel on a block by block basis.</p>
|
||||
<a class="header" href="#regular-objects" id="regular-objects"><h1>Regular Objects</h1></a>
|
||||
<p>As with backgrounds, objects can be used in both an affine and non-affine way.
|
||||
For this section we'll focus on the non-affine elements, and then we'll do all
|
||||
the affine stuff in a later chapter.</p>
|
||||
<a class="header" href="#objects-vs-sprites" id="objects-vs-sprites"><h2>Objects vs Sprites</h2></a>
|
||||
<p>As <a href="https://www.coranac.com/tonc/text/regobj.htm">TONC</a> helpfully reminds us
|
||||
(and then proceeds to not follow its own advice), we should always try to think
|
||||
in terms of <em>objects</em>, not <em>sprites</em>. A sprite is a logical / software concern,
|
||||
perhaps a player concern, whereas an object is a hardware concern.</p>
|
||||
<p>What's more, a given sprite that the player sees might need more than one object
|
||||
to display. Objects must be either square or rectangular (so sprite bits that
|
||||
stick out probably call for a second object), and can only be from 8x8 to 64x64
|
||||
(so anything bigger has to be two objects lined up to appear as one).</p>
|
||||
<a class="header" href="#general-object-info" id="general-object-info"><h2>General Object Info</h2></a>
|
||||
<p>Unlike with backgrounds, you can enable the object layer in any video mode.
|
||||
There's space for 128 object definitions in OAM.</p>
|
||||
<p>The display gets a number of cycles per scanline to process objects: 1210 by
|
||||
default, but only 954 if you enable the "HBlank interval free" setting in the
|
||||
display control register. The <a href="http://problemkaputt.de/gbatek.htm#lcdobjoverview">cycle cost per
|
||||
object</a> depends on the
|
||||
object's size and if it's using affine or regular mode, so enabling the HBlank
|
||||
interval free setting doesn't cut the number of objects displayable by an exact
|
||||
number of objects. The objects are processed in order of their definitions and
|
||||
if you run out of cycles then the rest just don't get shown. If there's a
|
||||
concern that you might run out of cycles you can place important objects (such
|
||||
as the player) at the start of the list and then less important animation
|
||||
objects later on.</p>
|
||||
<a class="header" href="#ready-the-palette" id="ready-the-palette"><h2>Ready the Palette</h2></a>
|
||||
<p>Objects use the palette the same as the background does. The only difference is
|
||||
that the palette data for objects starts at <code>0x500_0200</code>.</p>
|
||||
<pre><pre class="playpen"><code class="language-rust">
|
||||
# #![allow(unused_variables)]
|
||||
#fn main() {
|
||||
pub const PALRAM_OBJECT_BASE: VolatilePtr<u16> = VolatilePtr(0x500_0200 as *mut u16);
|
||||
|
||||
pub fn object_palette(slot: usize) -> u16 {
|
||||
assert!(slot < 256);
|
||||
unsafe { PALRAM_OBJECT_BASE.offset(slot as isize).read() }
|
||||
}
|
||||
|
||||
pub fn set_object_palette(slot: usize, color: u16) {
|
||||
assert!(slot < 256);
|
||||
unsafe { PALRAM_OBJECT_BASE.offset(slot as isize).write(color) }
|
||||
}
|
||||
#}</code></pre></pre>
|
||||
<a class="header" href="#ready-the-tiles" id="ready-the-tiles"><h2>Ready the Tiles</h2></a>
|
||||
<p>Objects, as with backgrounds, are composed of 8x8 tiles, and if you want
|
||||
something bigger than 8x8 you have to use more than one tile put together.
|
||||
Object tiles go into the final two charblocks of VRAM (indexes 4 and 5). Because
|
||||
there's only two of them, they are sometimes called the lower block
|
||||
(<code>0x601_0000</code>) and the higher/upper block (<code>0x601_4000</code>).</p>
|
||||
<p>Tile indexes for sprites always offset from the base of the lower block, and
|
||||
they always go 32 bytes at a time, regardless of if the object is set for 4bpp
|
||||
or 8bpp. From this we can determine that there's 512 tile slots in each of the
|
||||
two object charblocks. However, in video modes 3, 4, and 5 the space for the
|
||||
background cuts into the lower charblock, so you can only safely use the upper
|
||||
charblock.</p>
|
||||
<p>With backgrounds you picked every single tile individually with a bunch of
|
||||
screen entry values. Objects don't do that at all. Instead you pick a base tile,
|
||||
size, and shape, then it figures out the rest from there. However, you may
|
||||
recall back with the display control register something about an "object memory
|
||||
1d" bit. This is where that comes into play.</p>
|
||||
<ul>
|
||||
<li>If object memory is set to be 2d (the default) then each charblock is treated
|
||||
as 32 tiles by 32 tiles square. Each object has a base tile and dimensions,
|
||||
and that just extracts directly from the charblock picture as if you were
|
||||
selecting an area. This mode probably makes for the easiest image editing.</li>
|
||||
<li>If object memory is set to be 1d then the tiles are loaded sequentially from
|
||||
the starting point, enough to fill in the object's dimensions. This most
|
||||
probably makes it the easiest to program with about things, since programming
|
||||
languages are pretty good at 1d things.</li>
|
||||
</ul>
|
||||
<p>I'm not sure I explained that well, here's a picture:</p>
|
||||
<p><img src="obj_memory_2d1d.jpg" alt="2d1d-diagram" /></p>
|
||||
<p>In 2d mode, a new row of tiles starts every 32 tile indexes.</p>
|
||||
<p>Of course, the mode that you actually end up using is not particularly
|
||||
important, since it should be the job of your image conversion routine to get
|
||||
everything all lined up and into place anyway.</p>
|
||||
<a class="header" href="#set-the-object-attributes" id="set-the-object-attributes"><h2>Set the Object Attributes</h2></a>
|
||||
<p>The final step is to assign the correct attributes to an object. Each object has
|
||||
three <code>u16</code> values that make up its overall attributes.</p>
|
||||
<p>Before we go into the details, I want to remind you that the hardware will
|
||||
attempt to process every single object every single frame, and also that all of
|
||||
the GBA's memory is cleared to 0 at startup. Why do these two things matter
|
||||
right now? As you'll see in a second an "all zero" set of object attributes
|
||||
causes an 8x8 object to appear at 0,0 using object tile index 0. This is usually
|
||||
<em>not</em> what you want your unused objects to do. When your game first starts you
|
||||
should take a moment to mark any objects you won't be using as objects to not
|
||||
render.</p>
|
||||
<a class="header" href="#objectattributesattr0" id="objectattributesattr0"><h3>ObjectAttributes.attr0</h3></a>
|
||||
<ul>
|
||||
<li>8 bits for row coordinate (marks the top of the sprite)</li>
|
||||
<li>2 bits for object rendering: 0 = Normal, 1 = Affine, 2 = Disabled, 3 = Affine with double rendering area</li>
|
||||
<li>2 bits for object mode: 0 = Normal, 1 = Alpha Blending, 2 = Object Window, 3 = Forbidden</li>
|
||||
<li>1 bit for mosaic enabled</li>
|
||||
<li>1 bit 8bpp color enabled</li>
|
||||
<li>2 bits for shape: 0 = Square, 1 = Horizontal, 2 = Vertical, 3 = Forbidden</li>
|
||||
</ul>
|
||||
<p>If an object is 128 pixels big at Y > 128 you'll get a strange looking result
|
||||
where it acts like Y > -128 and then displays partly off screen to the top.</p>
|
||||
<a class="header" href="#objectattributesattr1" id="objectattributesattr1"><h3>ObjectAttributes.attr1</h3></a>
|
||||
<ul>
|
||||
<li>9 bit for column coordinate (marks the left of the sprite)</li>
|
||||
<li>Either:
|
||||
<ul>
|
||||
<li>3 empty bits, 1 bit for horizontal flip, 1 bit for vertical flip (non-affine)</li>
|
||||
<li>5 bits for affine index (affine)</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>2 bits for size.</li>
|
||||
</ul>
|
||||
<table><thead><tr><th align="center"> Size </th><th align="center"> Square </th><th align="center"> Horizontal </th><th align="center"> Vertical</th></tr></thead><tbody>
|
||||
<tr><td align="center"> 0 </td><td align="center"> 8x8 </td><td align="center"> 16x8 </td><td align="center"> 8x16 </td></tr>
|
||||
<tr><td align="center"> 1 </td><td align="center"> 16x16 </td><td align="center"> 32x8 </td><td align="center"> 8x32 </td></tr>
|
||||
<tr><td align="center"> 2 </td><td align="center"> 32x32 </td><td align="center"> 32x16 </td><td align="center"> 16x32 </td></tr>
|
||||
<tr><td align="center"> 3 </td><td align="center"> 64x64 </td><td align="center"> 64x32 </td><td align="center"> 32x64 </td></tr>
|
||||
</tbody></table>
|
||||
<a class="header" href="#objectattributesattr2" id="objectattributesattr2"><h3>ObjectAttributes.attr2</h3></a>
|
||||
<ul>
|
||||
<li>10 bits for the base tile index</li>
|
||||
<li>2 bits for priority</li>
|
||||
<li>4 bits for the palbank index (4bpp mode only, ignored in 8bpp)</li>
|
||||
</ul>
|
||||
<a class="header" href="#objectattributes-summary" id="objectattributes-summary"><h3>ObjectAttributes summary</h3></a>
|
||||
<p>So I said in the GBA memory mapping section that C people would tell you that
|
||||
the object attributes should look like this:</p>
|
||||
<pre><pre class="playpen"><code class="language-rust">
|
||||
# #![allow(unused_variables)]
|
||||
#fn main() {
|
||||
#[repr(C)]
|
||||
pub struct ObjectAttributes {
|
||||
attr0: u16,
|
||||
attr1: u16,
|
||||
attr2: u16,
|
||||
filler: i16,
|
||||
}
|
||||
#}</code></pre></pre>
|
||||
<p>Except that:</p>
|
||||
<ol>
|
||||
<li>It's wasteful when we store object attributes on their own outside of OAM
|
||||
(which we definitely might want to do).</li>
|
||||
<li>In Rust we can't access just one field through a volatile pointer (our
|
||||
pointers aren't actually volatile to begin with, just the ops we do with them
|
||||
are). We have to read or write the whole pointer's value at a time.
|
||||
Similarly, we can't do things like <code>|=</code> and <code>&=</code> with volatile in Rust. So in
|
||||
rust we can't have a volatile pointer to an ObjectAttributes and then write
|
||||
to just the three "real" values and not touch the filler field. Having the
|
||||
filler value in there just means we have to dance around it more, not less.</li>
|
||||
<li>We want to newtype this whole thing to prevent accidental invalid states from
|
||||
being written into memory.</li>
|
||||
</ol>
|
||||
<p>So we will not be using that representation. At the same time we want to have no
|
||||
overhead, so we will stick to three <code>u16</code> values. We could newtype each
|
||||
individual field to be its own type (<code>ObjectAttributesAttr0</code> or something silly
|
||||
like that), since there aren't actual dependencies between two different fields
|
||||
such that a change in one can throw another into a forbidden state. The worst
|
||||
that can happen is if we disable or enable affine mode (<code>attr0</code>) it can change
|
||||
the meaning of <code>attr1</code>. The changed meaning isn't actually in invalid state
|
||||
though, so we <em>could</em> make each field its own type if we wanted.</p>
|
||||
<p>However, when you think about it, I can't imagine a common situation where we do
|
||||
something like make an <code>attr0</code> value that we then want to save on its own and
|
||||
apply to several different <code>ObjectAttributes</code> that we make during a game. That
|
||||
just doesn't sound likely to me. So, we'll go the route where <code>ObjectAttributes</code>
|
||||
is just a big black box to the outside world and we don't need to think about
|
||||
the three fields internally as being separate.</p>
|
||||
<p>First we make it so that we can get and set object attributes from memory:</p>
|
||||
<pre><pre class="playpen"><code class="language-rust">
|
||||
# #![allow(unused_variables)]
|
||||
#fn main() {
|
||||
pub const OAM: usize = 0x700_0000;
|
||||
|
||||
pub fn object_attributes(slot: usize) -> ObjectAttributes {
|
||||
assert!(slot < 128);
|
||||
let ptr = VolatilePtr((OAM + slot * (size_of::<u16>() * 4)) as *mut u16);
|
||||
unsafe {
|
||||
ObjectAttributes {
|
||||
attr0: ptr.read(),
|
||||
attr1: ptr.offset(1).read(),
|
||||
attr2: ptr.offset(2).read(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_object_attributes(slot: usize, obj: ObjectAttributes) {
|
||||
assert!(slot < 128);
|
||||
let ptr = VolatilePtr((OAM + slot * (size_of::<u16>() * 4)) as *mut u16);
|
||||
unsafe {
|
||||
ptr.write(obj.attr0);
|
||||
ptr.offset(1).write(obj.attr1);
|
||||
ptr.offset(2).write(obj.attr2);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct ObjectAttributes {
|
||||
attr0: u16,
|
||||
attr1: u16,
|
||||
attr2: u16,
|
||||
}
|
||||
#}</code></pre></pre>
|
||||
<p>Then we add a billion methods to the <code>ObjectAttributes</code> type so that we can
|
||||
actually set all the different values that we want to set.</p>
|
||||
<p>This code block is the last thing on this page so if you don't wanna scroll past
|
||||
the whole thing you can just go to the next page.</p>
|
||||
<pre><pre class="playpen"><code class="language-rust">
|
||||
# #![allow(unused_variables)]
|
||||
#fn main() {
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ObjectRenderMode {
|
||||
Normal,
|
||||
Affine,
|
||||
Disabled,
|
||||
DoubleAreaAffine,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ObjectMode {
|
||||
Normal,
|
||||
AlphaBlending,
|
||||
ObjectWindow,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ObjectShape {
|
||||
Square,
|
||||
Horizontal,
|
||||
Vertical,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ObjectOrientation {
|
||||
Normal,
|
||||
HFlip,
|
||||
VFlip,
|
||||
BothFlip,
|
||||
Affine(u8),
|
||||
}
|
||||
|
||||
impl ObjectAttributes {
|
||||
pub fn row(&self) -> u16 {
|
||||
self.attr0 & 0b1111_1111
|
||||
}
|
||||
pub fn column(&self) -> u16 {
|
||||
self.attr1 & 0b1_1111_1111
|
||||
}
|
||||
pub fn rendering(&self) -> ObjectRenderMode {
|
||||
match (self.attr0 >> 8) & 0b11 {
|
||||
0 => ObjectRenderMode::Normal,
|
||||
1 => ObjectRenderMode::Affine,
|
||||
2 => ObjectRenderMode::Disabled,
|
||||
3 => ObjectRenderMode::DoubleAreaAffine,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
pub fn mode(&self) -> ObjectMode {
|
||||
match (self.attr0 >> 0xA) & 0b11 {
|
||||
0 => ObjectMode::Normal,
|
||||
1 => ObjectMode::AlphaBlending,
|
||||
2 => ObjectMode::ObjectWindow,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
pub fn mosaic(&self) -> bool {
|
||||
((self.attr0 << 3) as i16) < 0
|
||||
}
|
||||
pub fn two_fifty_six_colors(&self) -> bool {
|
||||
((self.attr0 << 2) as i16) < 0
|
||||
}
|
||||
pub fn shape(&self) -> ObjectShape {
|
||||
match (self.attr0 >> 0xE) & 0b11 {
|
||||
0 => ObjectShape::Square,
|
||||
1 => ObjectShape::Horizontal,
|
||||
2 => ObjectShape::Vertical,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
pub fn orientation(&self) -> ObjectOrientation {
|
||||
if (self.attr0 >> 8) & 1 > 0 {
|
||||
ObjectOrientation::Affine((self.attr1 >> 9) as u8 & 0b1_1111)
|
||||
} else {
|
||||
match (self.attr1 >> 0xC) & 0b11 {
|
||||
0 => ObjectOrientation::Normal,
|
||||
1 => ObjectOrientation::HFlip,
|
||||
2 => ObjectOrientation::VFlip,
|
||||
3 => ObjectOrientation::BothFlip,
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn size(&self) -> u16 {
|
||||
self.attr1 >> 0xE
|
||||
}
|
||||
pub fn tile_index(&self) -> u16 {
|
||||
self.attr2 & 0b11_1111_1111
|
||||
}
|
||||
pub fn priority(&self) -> u16 {
|
||||
self.attr2 >> 0xA
|
||||
}
|
||||
pub fn palbank(&self) -> u16 {
|
||||
self.attr2 >> 0xC
|
||||
}
|
||||
//
|
||||
pub fn set_row(&mut self, row: u16) {
|
||||
self.attr0 &= !0b1111_1111;
|
||||
self.attr0 |= row & 0b1111_1111;
|
||||
}
|
||||
pub fn set_column(&mut self, col: u16) {
|
||||
self.attr1 &= !0b1_1111_1111;
|
||||
self.attr2 |= col & 0b1_1111_1111;
|
||||
}
|
||||
pub fn set_rendering(&mut self, rendering: ObjectRenderMode) {
|
||||
const RENDERING_MASK: u16 = 0b11 << 8;
|
||||
self.attr0 &= !RENDERING_MASK;
|
||||
self.attr0 |= (rendering as u16) << 8;
|
||||
}
|
||||
pub fn set_mode(&mut self, mode: ObjectMode) {
|
||||
const MODE_MASK: u16 = 0b11 << 0xA;
|
||||
self.attr0 &= MODE_MASK;
|
||||
self.attr0 |= (mode as u16) << 0xA;
|
||||
}
|
||||
pub fn set_mosaic(&mut self, bit: bool) {
|
||||
const MOSAIC_BIT: u16 = 1 << 0xC;
|
||||
if bit {
|
||||
self.attr0 |= MOSAIC_BIT
|
||||
} else {
|
||||
self.attr0 &= !MOSAIC_BIT
|
||||
}
|
||||
}
|
||||
pub fn set_two_fifty_six_colors(&mut self, bit: bool) {
|
||||
const COLOR_MODE_BIT: u16 = 1 << 0xD;
|
||||
if bit {
|
||||
self.attr0 |= COLOR_MODE_BIT
|
||||
} else {
|
||||
self.attr0 &= !COLOR_MODE_BIT
|
||||
}
|
||||
}
|
||||
pub fn set_shape(&mut self, shape: ObjectShape) {
|
||||
self.attr0 &= 0b0011_1111_1111_1111;
|
||||
self.attr0 |= (shape as u16) << 0xE;
|
||||
}
|
||||
pub fn set_orientation(&mut self, orientation: ObjectOrientation) {
|
||||
const AFFINE_INDEX_MASK: u16 = 0b1_1111 << 9;
|
||||
self.attr1 &= !AFFINE_INDEX_MASK;
|
||||
let bits = match orientation {
|
||||
ObjectOrientation::Affine(index) => (index as u16) << 9,
|
||||
ObjectOrientation::Normal => 0,
|
||||
ObjectOrientation::HFlip => 1 << 0xC,
|
||||
ObjectOrientation::VFlip => 1 << 0xD,
|
||||
ObjectOrientation::BothFlip => 0b11 << 0xC,
|
||||
};
|
||||
self.attr1 |= bits;
|
||||
}
|
||||
pub fn set_size(&mut self, size: u16) {
|
||||
self.attr1 &= 0b0011_1111_1111_1111;
|
||||
self.attr1 |= size << 14;
|
||||
}
|
||||
pub fn set_tile_index(&mut self, index: u16) {
|
||||
self.attr2 &= !0b11_1111_1111;
|
||||
self.attr2 |= 0b11_1111_1111 & index;
|
||||
}
|
||||
pub fn set_priority(&mut self, priority: u16) {
|
||||
self.attr2 &= !0b0000_1100_0000_0000;
|
||||
self.attr2 |= (priority & 0b11) << 0xA;
|
||||
}
|
||||
pub fn set_palbank(&mut self, palbank: u16) {
|
||||
self.attr2 &= !0b1111_0000_0000_0000;
|
||||
self.attr2 |= (palbank & 0b1111) << 0xC;
|
||||
}
|
||||
}
|
||||
#}</code></pre></pre>
|
||||
<a class="header" href="#gba-rng" id="gba-rng"><h1>GBA RNG</h1></a>
|
||||
<p>TODO</p>
|
||||
<a class="header" href="#memory_game" id="memory_game"><h1>memory_game</h1></a>
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -286,3 +286,208 @@ impl RegularScreenblockEntry {
|
|||
self.0 |= palbank_index;
|
||||
}
|
||||
}
|
||||
|
||||
pub const PALRAM_OBJECT_BASE: VolatilePtr<u16> = VolatilePtr(0x500_0200 as *mut u16);
|
||||
|
||||
pub fn object_palette(slot: usize) -> u16 {
|
||||
assert!(slot < 256);
|
||||
unsafe { PALRAM_OBJECT_BASE.offset(slot as isize).read() }
|
||||
}
|
||||
|
||||
pub fn set_object_palette(slot: usize, color: u16) {
|
||||
assert!(slot < 256);
|
||||
unsafe { PALRAM_OBJECT_BASE.offset(slot as isize).write(color) }
|
||||
}
|
||||
|
||||
pub const OAM: usize = 0x700_0000;
|
||||
|
||||
pub fn object_attributes(slot: usize) -> ObjectAttributes {
|
||||
assert!(slot < 128);
|
||||
let ptr = VolatilePtr((OAM + slot * (size_of::<u16>() * 4)) as *mut u16);
|
||||
unsafe {
|
||||
ObjectAttributes {
|
||||
attr0: ptr.read(),
|
||||
attr1: ptr.offset(1).read(),
|
||||
attr2: ptr.offset(2).read(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_object_attributes(slot: usize, obj: ObjectAttributes) {
|
||||
assert!(slot < 128);
|
||||
let ptr = VolatilePtr((OAM + slot * (size_of::<u16>() * 4)) as *mut u16);
|
||||
unsafe {
|
||||
ptr.write(obj.attr0);
|
||||
ptr.offset(1).write(obj.attr1);
|
||||
ptr.offset(2).write(obj.attr2);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct ObjectAttributes {
|
||||
attr0: u16,
|
||||
attr1: u16,
|
||||
attr2: u16,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ObjectRenderMode {
|
||||
Normal,
|
||||
Affine,
|
||||
Disabled,
|
||||
DoubleAreaAffine,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ObjectMode {
|
||||
Normal,
|
||||
AlphaBlending,
|
||||
ObjectWindow,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ObjectShape {
|
||||
Square,
|
||||
Horizontal,
|
||||
Vertical,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ObjectOrientation {
|
||||
Normal,
|
||||
HFlip,
|
||||
VFlip,
|
||||
BothFlip,
|
||||
Affine(u8),
|
||||
}
|
||||
|
||||
impl ObjectAttributes {
|
||||
pub fn row(&self) -> u16 {
|
||||
self.attr0 & 0b1111_1111
|
||||
}
|
||||
pub fn column(&self) -> u16 {
|
||||
self.attr1 & 0b1_1111_1111
|
||||
}
|
||||
pub fn rendering(&self) -> ObjectRenderMode {
|
||||
match (self.attr0 >> 8) & 0b11 {
|
||||
0 => ObjectRenderMode::Normal,
|
||||
1 => ObjectRenderMode::Affine,
|
||||
2 => ObjectRenderMode::Disabled,
|
||||
3 => ObjectRenderMode::DoubleAreaAffine,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
pub fn mode(&self) -> ObjectMode {
|
||||
match (self.attr0 >> 0xA) & 0b11 {
|
||||
0 => ObjectMode::Normal,
|
||||
1 => ObjectMode::AlphaBlending,
|
||||
2 => ObjectMode::ObjectWindow,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
pub fn mosaic(&self) -> bool {
|
||||
((self.attr0 << 3) as i16) < 0
|
||||
}
|
||||
pub fn two_fifty_six_colors(&self) -> bool {
|
||||
((self.attr0 << 2) as i16) < 0
|
||||
}
|
||||
pub fn shape(&self) -> ObjectShape {
|
||||
match (self.attr0 >> 0xE) & 0b11 {
|
||||
0 => ObjectShape::Square,
|
||||
1 => ObjectShape::Horizontal,
|
||||
2 => ObjectShape::Vertical,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
pub fn orientation(&self) -> ObjectOrientation {
|
||||
if (self.attr0 >> 8) & 1 > 0 {
|
||||
ObjectOrientation::Affine((self.attr1 >> 9) as u8 & 0b1_1111)
|
||||
} else {
|
||||
match (self.attr1 >> 0xC) & 0b11 {
|
||||
0 => ObjectOrientation::Normal,
|
||||
1 => ObjectOrientation::HFlip,
|
||||
2 => ObjectOrientation::VFlip,
|
||||
3 => ObjectOrientation::BothFlip,
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn size(&self) -> u16 {
|
||||
self.attr1 >> 0xE
|
||||
}
|
||||
pub fn tile_index(&self) -> u16 {
|
||||
self.attr2 & 0b11_1111_1111
|
||||
}
|
||||
pub fn priority(&self) -> u16 {
|
||||
self.attr2 >> 0xA
|
||||
}
|
||||
pub fn palbank(&self) -> u16 {
|
||||
self.attr2 >> 0xC
|
||||
}
|
||||
//
|
||||
pub fn set_row(&mut self, row: u16) {
|
||||
self.attr0 &= !0b1111_1111;
|
||||
self.attr0 |= row & 0b1111_1111;
|
||||
}
|
||||
pub fn set_column(&mut self, col: u16) {
|
||||
self.attr1 &= !0b1_1111_1111;
|
||||
self.attr2 |= col & 0b1_1111_1111;
|
||||
}
|
||||
pub fn set_rendering(&mut self, rendering: ObjectRenderMode) {
|
||||
const RENDERING_MASK: u16 = 0b11 << 8;
|
||||
self.attr0 &= !RENDERING_MASK;
|
||||
self.attr0 |= (rendering as u16) << 8;
|
||||
}
|
||||
pub fn set_mode(&mut self, mode: ObjectMode) {
|
||||
const MODE_MASK: u16 = 0b11 << 0xA;
|
||||
self.attr0 &= MODE_MASK;
|
||||
self.attr0 |= (mode as u16) << 0xA;
|
||||
}
|
||||
pub fn set_mosaic(&mut self, bit: bool) {
|
||||
const MOSAIC_BIT: u16 = 1 << 0xC;
|
||||
if bit {
|
||||
self.attr0 |= MOSAIC_BIT
|
||||
} else {
|
||||
self.attr0 &= !MOSAIC_BIT
|
||||
}
|
||||
}
|
||||
pub fn set_two_fifty_six_colors(&mut self, bit: bool) {
|
||||
const COLOR_MODE_BIT: u16 = 1 << 0xD;
|
||||
if bit {
|
||||
self.attr0 |= COLOR_MODE_BIT
|
||||
} else {
|
||||
self.attr0 &= !COLOR_MODE_BIT
|
||||
}
|
||||
}
|
||||
pub fn set_shape(&mut self, shape: ObjectShape) {
|
||||
self.attr0 &= 0b0011_1111_1111_1111;
|
||||
self.attr0 |= (shape as u16) << 0xE;
|
||||
}
|
||||
pub fn set_orientation(&mut self, orientation: ObjectOrientation) {
|
||||
const AFFINE_INDEX_MASK: u16 = 0b1_1111 << 9;
|
||||
self.attr1 &= !AFFINE_INDEX_MASK;
|
||||
let bits = match orientation {
|
||||
ObjectOrientation::Affine(index) => (index as u16) << 9,
|
||||
ObjectOrientation::Normal => 0,
|
||||
ObjectOrientation::HFlip => 1 << 0xC,
|
||||
ObjectOrientation::VFlip => 1 << 0xD,
|
||||
ObjectOrientation::BothFlip => 0b11 << 0xC,
|
||||
};
|
||||
self.attr1 |= bits;
|
||||
}
|
||||
pub fn set_size(&mut self, size: u16) {
|
||||
self.attr1 &= 0b0011_1111_1111_1111;
|
||||
self.attr1 |= size << 14;
|
||||
}
|
||||
pub fn set_tile_index(&mut self, index: u16) {
|
||||
self.attr2 &= !0b11_1111_1111;
|
||||
self.attr2 |= 0b11_1111_1111 & index;
|
||||
}
|
||||
pub fn set_priority(&mut self, priority: u16) {
|
||||
self.attr2 &= !0b0000_1100_0000_0000;
|
||||
self.attr2 |= (priority & 0b11) << 0xA;
|
||||
}
|
||||
pub fn set_palbank(&mut self, palbank: u16) {
|
||||
self.attr2 &= !0b1111_0000_0000_0000;
|
||||
self.attr2 |= (palbank & 0b1111) << 0xC;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue