There are four tilemap layers, numbered 0 to 3.
Each is a 32×32 (or 64×32 if Extend Mode is enabled) grid of tiles, represented by an array of 32-bit values.
Each tile references a 16×16px texture, defined in rom, with up to 64 colors (including transparent) per tile.
Tilemaps can be scaled on both axes, with a range of 50.2% to infinity vertically, and 100% to 25600% horizontally.
Scrolling and Scaling
We can calculate which pixel of the tilemap will be displayed at a given position on-screen.
For the X axis, we use:
Where: x is the current x screen position (in screen pixels) y is the current scanline tnum is the tilemap number Xglobal is the tilemap's X Global Scroll (in texture pixels) Xadjust is its X Scroll Adjust (in texture pixels) on a given scanline Xzoom is its X Zoom (in texture pixels per screen pixel) on a given scanline
The Y axis is more complicated, because the offset of each row depends on the rows above.
Each tilemap has a "Y Scroll Accumulator", which is in units of texture pixels (with a precision of 1/128).
At the beginning of each scanline, if Y Scroll Sync is set (usually on scanline 0), each tilemap's Y Scroll Accumulator is set from its Y Global Scroll register. Otherwise, the accumulator is incremented by the Y Zoom Register. (note that this happens at the beginning of the scanline, not the end)
Then, the scanline is rendered. The source row for each tilemap is determined by its Y Scroll Accumulator + Y Scroll Adjust.
(note that Y Scroll Accumulator is not reset automatically, and carries over from the previous frame until Scroll Sync is set)
Thus, to calculate the y source position, we can use:
Where: y is the current scanline Yglobal is the tilemap's Y Global Scroll (in texture pixels) Yadjust is its Y Scroll Adjust (in texture pixels) on a given scanline Yzoom is its Y Zoom (in texture pixels per screen pixel) on a given scanline sync is the most recent scanline on which Scroll Sync was set (usually scanline 0).
Note that this assumes y ≥ sync.
Tilemap Tile Data
Address (normal) ($610000+)
⋯,0,0,1,0,num:3,y:5,x:5,-:2
Address (extend mode) ($610000+)
⋯,0,0,1,num:3,y:5,x:6,-:2
num
tilemap number (0-3,4-5)
N (0-3)
Tilemap N: normal data
4
Tilemap 2: alternate data
5
Tilemap 3: alternate data
y
tile y index (0-31)
x
tile x index (0-31 or 0-63)
Data
v,h,tex2:2,bpp:2,as,palette:9,texture:16
texture
Texture Id (lower 16 bits)
Texture Id = texture | tex2<<16
palette
palette id (0-511)
as
Alpha Select (note how this is stored per-tile rather than per-scanline)
bpp
texture bit planes (bits per pixel select)better wording for bpp
0
4bpp (16-color)
1
5bpp (32-color)
2
?
3
6bpp (64-color)
tex2
Texture Id (upper 2 bits)
h
1
horizontal flip
v
1
vertical flip
Scroll Registers 0-3 Tilemap X Scroll
Address ($660000+)
⋯,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,num:2,-
num
tilemap number N (0-3)
Data
ipart:10,fpart:6
fpart
Tilemap N: X Global Scroll (negative fractional part; in steps of 1/64)
ipart
Tilemap N: X Global Scroll (integer part; 0-1024)
X Global Scroll (in texture pixels) = ipart − fpart/64
Scroll Registers 4-7 - Tilemap Y Scroll
Address ($660004+)
⋯,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,num:2,-
num
tilemap number N (0-3)
Data
ipart:9,fpart:7
fpart
Tilemap N: Y Global Scroll (fractional part; in steps of 1/128) is this negative like x scroll?
ipart
Tilemap N: Y Global Scroll (integer part; 0-511)
Y Global Scroll (in texture pixels) = ipart + fpart/128
Scroll Register 15 - ?
Address ($66001F)
⋯,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,-
Data
#:8,ex,#:5,B,L
L
??: lock?
1 = (all further writes to this register are ignored until next reset. clears blank and extend mode)what? also these don't belong on tilemaps page
B
??: blank video?
1 = (no color signal, invalid sync signal)
ex
Tilemaps: Extend Mode
0
32×32 tilemaps
1
64×32 tilemaps
what do the other bits do?
Line Registers 0.N "4400" "4600"
Note: supported on tilemaps 2 and 3 only.typeset this better
Data
#:6,alt,yscroll:9
yscroll
Tilemap N: Y Scroll Adjust (integer; 0-511)
Y Scroll Adjust (in texture pixels) = yscroll
alt
Tilemap N: Alternate Tile Data
0
normal
1
use alternate tile data
Line Register 2.0 "6000"
Data
#:4,y,#:11
y
Tilemaps: Y Scroll Sync
1
initialize y scroll accumulators from the y global scroll registers
(basically: you should set this on the first scanline, or the tilemaps' y positions will be unstable)
Line Register 2.2 "6400"
Data
#:12,p3,p2,p1,p0
pN
Tilemap N: Mosaic Enable
Line Registers 4.N "8000" "8200" "8400" "8600"
Data
xzoom:8,yzoom:8
yzoom
Tilemap N*: Y Zoom
*bug: tilemaps 1 and 3 have their vertical zooms swapped
Y Zoom (in texture pixels per screen pixel) = yzoom / 128
Example scale factors: (in screen pixels per texture pixel)
$00
∞×
$40
2.0×
$80
1.0×
$C0
0.667×
$FF
0.502×
xzoom
Tilemap N: X Zoom
X Zoom (in texture pixels per screen pixel) = 1 − xzoom / 256
Example scale factors: (in screen pixels per texture pixel)
$00
1.0×
$40
1.333×
$80
2.0×
$C0
4.0×
$FF
256.0×
Line Registers 5.N "9000" "9200" "9400" "9600"
Data
#:10,palette:6
palette
Tilemap N: Palette Adjust (added to the palette of all tiles)
Line Registers 6.N "A000" "A200" "A400" "A600"
Data
xscroll:16
xscroll
Tilemap N: X Scroll Adjust (same format as X Global Scroll)
Line Registers 7.N "B000" "B200" "B400" "B600"
Data
bm:2,clip:10,prio:4
prio
Tilemap N: Priority (0-15)
clip
Tilemap N: Clip Settings
bm
Tilemap N: Blend Mode
0
both
1
A
2
B
3
none
per-tilemap values:
- name | type | set per:
- x global scroll | texture pixels | frame
- y global scroll | texture pixels | frame
- y scroll accumulator | texture pixels | internal, per-scanline
- x scroll adjust | texture pixels | scanline
- y scroll adjust | texture pixels | scanline
- alternate tile data | boolean | scanline
- x zoom | texture pixels per screen pixel | scanline
- y zoom | texture pixels per screen pixel | scanline
- palette adjust | palette id | scanline
shared values:
- y scroll sync | boolean | scanline
- extend mode | boolean | frame
per-tile values:
- texture id | texture id
- palette id | palette id
- alpha select | alpha id (common setting but special, do we list it?)
- texture bpp | enum?
- x flip | boolean
- y flip | boolean
the register descriptors should say the name of the field they affect, and how to map the raw value into something we can use. e.g. how to map blend mode number to one of the enum values, or how to map x zoom to a value in texture pixels per screen pixels.
then, we should have a list of fields with their types and ranges/precisions and how they are used. so tired...
(later) ah but idk maybe not. i mean, it's like.. we may as well use the registers AS our fields list. tbh. put the descs there
Scroll Register Settings
Global Scroll X
Global Scroll Y
Tilemap Extend Mode (shared)
Lineram Settings
X Scroll Adjust
Y Scroll Adjust (tilemaps 2 and 3 only)
Alternate Tile Data (tilemaps 2 and 3 only)
Y Scroll Sync (shared)
Zoom X
Zoom Y
Palette Adjust
the mathbox styling is nice but i think we should have like, consistent styling for:
- the formula for the value of an abstract field
- other definitions of abstract fields
or i mean like, i want a consistent "look over here, here is where an abstract field is being defined" box styling. whether it has a math equation or something else.