Sprite Attribute Upload
Number | $xx57 |
---|---|
Decimal | |
Short desc. | Uploads sprite positions, visibility, colour type and effect flags. |
Bit Mask | %---- ---- 0101 0111 |
Readable | No |
Writable | Yes |
Subsystem | Sprites |
Uploads attributes of the sprite slot selected by Sprite Status/Slot Select ($303B / 12347). Attributes are sent in 4-5 byte blocks. After sending 4 or 5 bytes block the sprite-index (slot) auto-increments to the next sprite. This auto-increment is independent of other sprite ports, but may be interlinked with Sprite port-mirror Index Register ($34) (see details there). The auto-increment from value 127 is officially "undefined behaviour" and index must be explicitly reset back to 0..127 after such auto-increment to make the code behave predictably in future.
The 4-5 bytes sprite-attribute structure is as follows:
Byte 1 is the low bits of the X position. The MSB is in byte 3.
Byte 2 is the low bits of the Y position. The MSB is in optional byte 5.
Byte 3 is bitmapped:
Bit | Description |
---|---|
4-7 | Palette offset, added to each palette index from pattern before drawing |
3 | Enable X mirror |
2 | Enable Y mirror |
1 | Enable rotation |
0 | MSB of X coordinate |
Byte 4 is bitmapped:
Bit | Description |
---|---|
7 | Enable visibility |
6 | If 1, the optional 5th attribute byte should follow fourth one.
If 0, only four attribute bytes are expected (accidental fifth byte send to port will be treated as first byte of next sprite attributes), and all extra sprite features (not covered by 4 byte block) will be reset to zero (as if 5th byte equal to value zero was explicitly sent). |
5-0 | Pattern index ("Name") |
Optional (when bit 6 is set in byte 4) byte 5 is bitmapped:
Bit | Description |
---|---|
7 | If 1, the pattern will be treated as 4-bit colour one (128 bytes), 0 is for 8-bit colour patterns (256 bytes) |
6 | (if bit 7 = 1): Chooses top/bottom part of pattern slot when 4-bit colour pattern
0 will target bytes 0..127 of pattern "Name" (byte 4), 1 will target bytes 128..255 of pattern "Name". (if bit 7 = 0): make this sprite "relative" one: 1 = relative, 0 = normal (anchor) type |
5 | (if bit 7-6 = %01) for "relative" sprite, this bit chooses top/bottom part of pattern slot for 4-bit colour mode (4 or 8 bit mode is set by anchor sprite, relative sprite can't switch the colour mode). See Bit 6 description above, if anchor sprite is in 4-bit mode. If anchor sprite is in 8-bit mode, use always 0
(else) For normal (anchor) sprites this is reserved, use always 0 |
4-3 | x-axis scale factor: %00 = 1x (16 pixels), %01 = 2x, %10 = 4x, %11 = 8x (128 pixels) |
2-1 | y-axis scale factor: %00 = 1x (16 pixels), %01 = 2x, %10 = 4x, %11 = 8x (128 pixels) |
0 | MSB of Y coordinate |
Normal (= anchor) sprites
About [X,Y] coordinates: 9 bit values allow for 0..511 coordinate. The top-left ULA pixel ("paper" area) is at [32,32] and bottom-right ULA pixel is at [287,223] (256x192 pixel area).
When sprites are configured to be drawn "over border", there is fixed-size 32 pixels wide area around pixel area (so called "border" in BASIC terms), i.e. coordinates [0,0] to [319,255] are coordinates of visible over-border sprite area.
All coordinates beyond these act as wrap-around 0..511 coordinate system, with sprite getting outside of drawing area, i.e. [X,Y]=[511,510] will render sprite in top left corner over "border" area, with left-most column already not visible (511 works as "-1" X coordinate) and two top-most rows not visible (510 works as "-2" Y coordinate), only remaining 15x14 pixels of sprite pattern are visible in top-left corner. Similarly sprite at coordinates [310,250] will render only 10x6 pixels of pattern in bottom right corner, rest of pattern being already outside of rendering area and not visible (assuming the over-border is enabled and not clipped by sprite clip-window).
Relative sprites
Every normal sprite works as "anchor" sprite for all following relative sprites (i.e. sprite 12 is anchor for relative sprites 13, 14, ..., until another normal sprite sets up new "anchor").
Every anchor sprite sets anchor.x, anchor.y (coordinates), anchor.H (4-bit or 8-bit colour pattern mode) and anchor.visibility variables in sprite engine (anchor.visibility is zero at beginning of line rendering, before sprite 0 is processed). All following relative sprites then:
- use (anchor.visibility AND relative.visibility) to determine visibility status of relative sprite
- use [(anchor.x + x), (anchor.y + y)] coordinates (i.e. relative.x = 510 works as "-2": X = (anchor.x - 2), and relative.x = 5 works as X = (anchor.x + 5))
- use anchor.H to select 4 or 8 bit colour rendering mode for pattern (relative sprite can't have different colour mode than anchor has)
- if anchor.H is set (4-bit colour mode), then bit 5 in fifth attribute byte of relative sprite determines the top/bottom part of pattern to draw (instead of bit 6 having this function for normal sprites)
This allows to create "clusters" of sprites where each processed "normal" (non-relative) sprite is new "anchor", providing global display position, visibility-master and colour mode for all following "relative" sprites. Those are positioned relatively against that last "anchor" sprite. To move such cluster of sprites on the screen, you need to update only the anchor position in attributes data (or to hide whole cluster, set anchor.visibility to 0). The relative sprites are always drawn above or below anchor pattern, depending on the rendering priority set in bit 6 of Sprite and Layers System Register ($15) (sprites in the sprite-engine are processed always in order from Sprite 0 to Sprite 127).