Difference between revisions of "Sprite Attribute Upload"

From SpecNext official Wiki
Jump to: navigation, search
(further details from Jim in forum post)
m
 
(6 intermediate revisions by 3 users not shown)
Line 1: Line 1:
 
{{Port
 
{{Port
 
|Number=$xx57
 
|Number=$xx57
 +
|NumberDec=87
 +
|PortMask=%---- ---- 0101 0111
 
|ShortDesc=Uploads sprite positions, visibility, colour type and effect flags.
 
|ShortDesc=Uploads sprite positions, visibility, colour type and effect flags.
|PortMask=%---- ---- 0101 0111
 
 
|Readable=No
 
|Readable=No
 
|Writable=Yes
 
|Writable=Yes
 
|Subsystem=Sprites
 
|Subsystem=Sprites
 
}}
 
}}
Uploads attributes of the sprite slot selected by {{PortNo|$303B}}. Attributes are in 4-5 byte blocks sent in the following order; after sending 4 or 5 bytes the address auto-increments to the next sprite. This auto-increment is independent of other sprite ports. The 4-5 bytes are as follows:
+
Uploads attributes of the sprite slot selected by {{PortNo|$303B}}. 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 {{NextRegNo|$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.
 +
 
 +
'''Anchor''' (normal) sprites have 9 bit coordinate system (values 0..511), wrapping around (511 is like -1). 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] (320x256 pixel area) are coordinates of visible over-border sprite area.
 +
 
 +
The '''relative''' sprites have only signed 8 bit coordinate system (values -128..+127), with [0,0] origin being equal to anchor sprite position.
 +
 
 +
The coordinate space of '''composite''' relative sprite is identical to global sprite coordinates except the offsetted origin. The mirror/rotate/scale of anchor sprite does NOT affect the global position and pattern of relative sprites, those effects are applied independently.
 +
 
 +
The coordinate space of '''big-sprite''' relative sprite is transformed by mirror/rotate/scale features of anchor sprite, so the visual layout of "big" sprite composed from multiple relative ones remain the same when anchor is being rotated/mirrored/scaled. The local mirror/rotate bits can be still used to adjust pattern's final orientation.
  
Byte 1 is the low bits of the X position. The MSB is in byte 3.
+
Global coordinates 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).
  
Byte 2 is the low bits of the Y position. The MSB is in optional byte 5.
+
=== The 4-5 bytes sprite-attribute structure is as follows: ===
  
Byte 3 is bitmapped:
+
'''Byte 1''' is the low eight bits of the X position. The MSB is in byte 3 (anchor sprite only).
 +
 
 +
'''Byte 2''' is the low eight bits of the Y position. The MSB is in optional byte 5 (anchor sprite only).
 +
 
 +
'''Byte 3''' is bitmapped:
 
{|class="wikitable"
 
{|class="wikitable"
 
! Bit !! Description
 
! Bit !! Description
Line 25: Line 40:
 
| 1 || Enable rotation
 
| 1 || Enable rotation
 
|-
 
|-
| 0 || MSB of X coordinate
+
| 0 || '''anchor''' sprite: MSB of X coordinate<br />
 +
'''relative''' sprite: enable relative Palette offset (1 = the anchor Palette offset is added, 0 = independent Palette offset)
 
|}
 
|}
  
Byte 4 is bitmapped:
+
'''Byte 4''' is bitmapped:
 
{|class="wikitable"
 
{|class="wikitable"
 
! Bit !! Description
 
! Bit !! Description
Line 40: Line 56:
 
|}
 
|}
  
Optional (when bit 6 is set in byte 4) byte 5 is bitmapped:
+
Optional (when bit 6 is set in byte 4) '''byte 5''' is bitmapped:
 +
:For '''anchor''' sprites:
 
{|class="wikitable"
 
{|class="wikitable"
 
! Bit !! Description
 
! 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)
+
| 7-6 || "H N6" - "H" is 4/8 bit graphics selector, "N6" is sub-pattern selector for 4 bit modes.<br />
 +
%00 = 8-bit colour patterns (256 bytes), this sprite is "'''anchor'''"<br />
 +
%01 = this sprite is "'''relative'''" (4/8-bit colour is selected by "anchor" sprite) → see tables below<br />
 +
%10 = 4-bit colour pattern (128 bytes) using bytes 0..127 of pattern slot, this sprite is "'''anchor'''"<br />
 +
%11 = 4-bit colour pattern (128 bytes) using bytes 128..255 of pattern slot, this sprite is "'''anchor'''"
 +
|-
 +
| 5 || Type for following '''relative''' sprites: 0 = "composite", 1 = "big sprite"
 +
|-
 +
| 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
 +
|}
 +
:For '''composite relative''' sprites:
 +
{|class="wikitable"
 +
! Bit !! Description
 
|-
 
|-
| 6 || Chooses top/bottom part of pattern slot (for 4-bit colour patterns)
+
| 7-6 ||%01 = relative sprite
0 will target bytes 0..127 of pattern "Name" (byte 4), 1 will target bytes 128..255 of pattern "Name".
 
 
|-
 
|-
| 5 || Reserved, use always 0
+
| 5 || "N6" bit, in 4-bit colour mode 0 = using bytes 0..127 of pattern slot, 1 = using bytes 128..255 of pattern slot. In 8-bit mode use 0.
 
|-
 
|-
 
| 4-3 || x-axis scale factor: %00 = 1x (16 pixels), %01 = 2x, %10 = 4x, %11 = 8x (128 pixels)
 
| 4-3 || x-axis scale factor: %00 = 1x (16 pixels), %01 = 2x, %10 = 4x, %11 = 8x (128 pixels)
Line 55: Line 87:
 
| 2-1 || y-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
+
| 0 || Enable relative pattern offset (1 = Pattern index is added to anchor pattern index, 0 = independent pattern index)
 +
|}
 +
:For '''big-sprite relative''' sprites:
 +
{|class="wikitable"
 +
! Bit !! Description
 +
|-
 +
| 7-6 ||%01 = relative sprite
 +
|-
 +
| 5 || "N6" bit, in 4-bit colour mode 0 = using bytes 0..127 of pattern slot, 1 = using bytes 128..255 of pattern slot. In 8-bit mode use 0.
 +
|-
 +
| 4-1 || use 0 (scaling is defined by '''anchor''' sprite)
 +
|-
 +
| 0 || Enable relative pattern offset (1 = Pattern index is added to anchor pattern index, 0 = independent pattern index)
 
|}
 
|}
  
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).
+
=== 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").
 +
 
 +
Sprite engine remembers attributes of last anchor sprite (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.H''' (bit 7 of byte 5) 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 ("N6" bit)
 +
* if relative palette offset is enabled, the '''anchor.palette offset''' is also added to final colour index (colour index wraps around within 0..255 range, transparency index is matched before palette offset is added)
 +
* if relative pattern offset is enabled, the '''anchor.pattern (name)''' is also added to final pattern index (pattern index wraps around within 0..63 range)
 +
 
 +
The '''composite relative''' sprites then:
 +
* use '''[(anchor.x + x), (anchor.y + y)]''' coordinates, the relative coordinates are sign-extended to 9 bits to add with anchor 9b global coordinates.
  
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.
+
The '''big-sprite relative''' sprites then:
 +
* use sign-extended relative coordinates in local transformed coordinate space defined by anchor (its global position and mirror/rotate/scale features), so the visual result of changing mirror/rotate/scale of anchor sprite works as if single large sprite (anchor and relative sprites graphics together) was manipulated.
 +
* the mirror/rotate features of relative sprites "XOR"-ed together with anchor values to affect final transformation of pattern pixels (not affecting sprite relative position within "big sprite")
  
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).
+
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 {{NextRegNo|$15}} (sprites in the sprite-engine are processed always in order from Sprite 0 to Sprite 127).

Latest revision as of 11:49, 4 May 2020

Number $xx57
Decimal 87
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.

Anchor (normal) sprites have 9 bit coordinate system (values 0..511), wrapping around (511 is like -1). 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] (320x256 pixel area) are coordinates of visible over-border sprite area.

The relative sprites have only signed 8 bit coordinate system (values -128..+127), with [0,0] origin being equal to anchor sprite position.

The coordinate space of composite relative sprite is identical to global sprite coordinates except the offsetted origin. The mirror/rotate/scale of anchor sprite does NOT affect the global position and pattern of relative sprites, those effects are applied independently.

The coordinate space of big-sprite relative sprite is transformed by mirror/rotate/scale features of anchor sprite, so the visual layout of "big" sprite composed from multiple relative ones remain the same when anchor is being rotated/mirrored/scaled. The local mirror/rotate bits can be still used to adjust pattern's final orientation.

Global coordinates 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).

The 4-5 bytes sprite-attribute structure is as follows:

Byte 1 is the low eight bits of the X position. The MSB is in byte 3 (anchor sprite only).

Byte 2 is the low eight bits of the Y position. The MSB is in optional byte 5 (anchor sprite only).

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 anchor sprite: MSB of X coordinate

relative sprite: enable relative Palette offset (1 = the anchor Palette offset is added, 0 = independent Palette offset)

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:

For anchor sprites:
Bit Description
7-6 "H N6" - "H" is 4/8 bit graphics selector, "N6" is sub-pattern selector for 4 bit modes.

%00 = 8-bit colour patterns (256 bytes), this sprite is "anchor"
%01 = this sprite is "relative" (4/8-bit colour is selected by "anchor" sprite) → see tables below
%10 = 4-bit colour pattern (128 bytes) using bytes 0..127 of pattern slot, this sprite is "anchor"
%11 = 4-bit colour pattern (128 bytes) using bytes 128..255 of pattern slot, this sprite is "anchor"

5 Type for following relative sprites: 0 = "composite", 1 = "big sprite"
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
For composite relative sprites:
Bit Description
7-6 %01 = relative sprite
5 "N6" bit, in 4-bit colour mode 0 = using bytes 0..127 of pattern slot, 1 = using bytes 128..255 of pattern slot. In 8-bit mode use 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 Enable relative pattern offset (1 = Pattern index is added to anchor pattern index, 0 = independent pattern index)
For big-sprite relative sprites:
Bit Description
7-6 %01 = relative sprite
5 "N6" bit, in 4-bit colour mode 0 = using bytes 0..127 of pattern slot, 1 = using bytes 128..255 of pattern slot. In 8-bit mode use 0.
4-1 use 0 (scaling is defined by anchor sprite)
0 Enable relative pattern offset (1 = Pattern index is added to anchor pattern index, 0 = independent pattern index)

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").

Sprite engine remembers attributes of last anchor sprite (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.H (bit 7 of byte 5) 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 ("N6" bit)
  • if relative palette offset is enabled, the anchor.palette offset is also added to final colour index (colour index wraps around within 0..255 range, transparency index is matched before palette offset is added)
  • if relative pattern offset is enabled, the anchor.pattern (name) is also added to final pattern index (pattern index wraps around within 0..63 range)

The composite relative sprites then:

  • use [(anchor.x + x), (anchor.y + y)] coordinates, the relative coordinates are sign-extended to 9 bits to add with anchor 9b global coordinates.

The big-sprite relative sprites then:

  • use sign-extended relative coordinates in local transformed coordinate space defined by anchor (its global position and mirror/rotate/scale features), so the visual result of changing mirror/rotate/scale of anchor sprite works as if single large sprite (anchor and relative sprites graphics together) was manipulated.
  • the mirror/rotate features of relative sprites "XOR"-ed together with anchor values to affect final transformation of pattern pixels (not affecting sprite relative position within "big sprite")

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).