-
Notifications
You must be signed in to change notification settings - Fork 10
/
chapter-next-sprites.tex
555 lines (408 loc) · 26.7 KB
/
chapter-next-sprites.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
\section{Sprites}
\label{zx_next_sprites}
% ───────────────────────────────────────────────────────────────────────────────────────────
% ─██████████████─██████████████─████████████████───██████████─██████████████─██████████████─
% ─██░░░░░░░░░░██─██░░░░░░░░░░██─██░░░░░░░░░░░░██───██░░░░░░██─██░░░░░░░░░░██─██░░░░░░░░░░██─
% ─██░░██████████─██░░██████░░██─██░░████████░░██───████░░████─██████░░██████─██░░██████████─
% ─██░░██─────────██░░██──██░░██─██░░██────██░░██─────██░░██───────██░░██─────██░░██─────────
% ─██░░██████████─██░░██████░░██─██░░████████░░██─────██░░██───────██░░██─────██░░██████████─
% ─██░░░░░░░░░░██─██░░░░░░░░░░██─██░░░░░░░░░░░░██─────██░░██───────██░░██─────██░░░░░░░░░░██─
% ─██████████░░██─██░░██████████─██░░██████░░████─────██░░██───────██░░██─────██░░██████████─
% ─────────██░░██─██░░██─────────██░░██──██░░██───────██░░██───────██░░██─────██░░██─────────
% ─██████████░░██─██░░██─────────██░░██──██░░██████─████░░████─────██░░██─────██░░██████████─
% ─██░░░░░░░░░░██─██░░██─────────██░░██──██░░░░░░██─██░░░░░░██─────██░░██─────██░░░░░░░░░░██─
% ─██████████████─██████─────────██████──██████████─██████████─────██████─────██████████████─
% ───────────────────────────────────────────────────────────────────────────────────────────
One of the frequently used ``my computer is better'' arguments from owners and developers of contemporary systems such as Commodore 64 was hardware supported sprites. To be fair, they had a point - poor old Speccy had none. But Next finally rectifies this with a sprite system that far supersedes even later 16-bit era machines such as Amiga. And as we'll see, it's really simple to program too!
Some of the capabilities of Next sprites:
\begin{itemize}[topsep=1pt,itemsep=1pt]
\item 128 simultaneous sprites
\item 16x16 pixels per sprite
\item Magnification of 2x, 4x or 8x horizontally and vertically
\item Mirroring and rotation
\item Sprite grouping to form larger objects
\item 512 colours from 2 256 colour palettes
\item Per sprite palette
\item Built-in sprite editor
\end{itemize}
So lots of reasons to get excited! Let's dig in!
\subsection{Editing}
Before describing how sprites hardware works, it would be beneficial to know how to draw them. As mentioned, Next comes with a built-in sprite editor. To use it, change to desired folder, then enter {\tt .spredit <filename>} in BASIC or command line. The editor is quite capable and can even be used with a mouse if you have one attached to your Next (or in the emulator).
Alternatively, if you're developing cross-platform, the most feature-complete application for converting images to sprite data in my experience is Next Graphics\footnote{\url{https://github.com/infromthecold/Next-Graphics}}. It takes images from your preferred editor and converts them into a format that can be easily consumed by Next hardware. Other options I found are UDGeed-Next\footnote{\url{http://zxbasic.uk/files/UDGeedNext-current.rar}} or Remy's Sprite, Tile and Palette editor\footnote{\url{https://zx.remysharp.com/sprites/}}. In contrast to Next Graphics, the latter two are not just exporters but also editors and share very similar feature sets. So try them out and decide for yourself.
\subsection{Patterns}
Next sprites have a fixed size of 16x16 pixels. Their display surface is 320x256, overlapping the ULA by 32 pixels on each side. Or in other words, to draw the sprite fully on-screen, we need to position it to (32,32) coordinate. And the last coordinate where the sprite is fully visible at the bottom-right edge is (271,207). This allows sprites to be animated in and out of the visible area. Sprites can be made visible or invisible when over the border as well as rendered on top or below Layer 2 and ULA, all specified by \PortTextXRef{15}. It's also possible to further restrict sprite visibility within provided clip window using \PortTextXRef{19}.
Sprite patterns (or pixel data) are stored in Next FPGA internal 16K memory. As mentioned, sprites are always 16x16 pixels but can be 8-bit or 4-bit.
\begin{itemize}[topsep=1pt,itemsep=1pt]
\item 8-bit sprites use full 8-bits to specify colour, so each pixel can be of any of 256 colours from the sprite palette of which one acts as transparent. Hence each sprite occupies 256 bytes of memory and 64 sprites can be stored.
\item 4-bit sprites use only 4-bits for colour, so each pixel can only choose from 16 colours, one of which is reserved for transparency. However this allows us to store 2 colours per byte, so these sprites take half the memory of 8-bit ones: 128 bytes each, meaning 128 sprites can be stored in available memory.
\end{itemize}
\subsection{Palette}
Each sprite can specify its own palette offset. This allows sprites to share image data but use different colours. 4 bits are used for palette offset, therefore the final colour index within the current sprite palette (as defined by \PortTextXRef{43}) is determined using the following formula:
\begin{multicols}{2}
8-bit sprites
\begin{tabular}{ccccccccc}
& \BitHead{7} & \BitHead{6} & \BitHead{5} & \BitHead{4} & \BitHead{3} & \BitHead{2} & \BitHead{1} & \BitHead{0} \\
\hline
& $P_3$ & $P_2$ & $P_1$ & $P_0$ & 0 & 0 & 0 & 0 \\
+ & $S_7$ & $S_6$ & $S_5$ & $S_4$ & $S_3$ & $S_2$ & $S_1$ & $S_0$ \\
\hline
= & $C_7$ & $C_6$ & $C_5$ & $C_4$ & $C_3$ & $C_2$ & $C_1$ & $C_0$ \\
\end{tabular}
If default palette offset and default palette are used, sprite colour index can be interpretted as RGB332 colour.
\columnbreak
4-bit sprites
\begin{tabular}{ccccccccc}
& \BitHead{7} & \BitHead{6} & \BitHead{5} & \BitHead{4} & \BitHead{3} & \BitHead{2} & \BitHead{1} & \BitHead{0} \\
\hline
& $P_3$ & $P_2$ & $P_1$ & $P_0$ & 0 & 0 & 0 & 0 \\
+ & 0 & 0 & 0 & 0 & $S_3$ & $S_2$ & $S_1$ & $S_0$ \\
\hline
= & $C_7$ & $C_6$ & $C_5$ & $C_4$ & $C_3$ & $C_2$ & $C_1$ & $C_0$ \\
\end{tabular}
Palette offset can be thought of as if selecting one of 16 different 16-colour palettes.
\end{multicols}
$P_n$ is palette offset bit, $S_n$ sprite colour index bit and $C_n$ final colour index.
Transparent colour is defined with \PortTextXRef{4B}.
\pagebreak
\subsection{Combined Sprites}
\subsubsection{Anchor Sprites}
These are ``normal'' 16x16 pixel sprites, as described in previous sections. They act as standalone sprites.
The reason they are called ``anchors'' is because multiple sprites can be grouped together to form larger sprites. In such case ``anchor'' acts as a parent and all its ``relative'' sprites are tied to it. In order to combine sprites, anchor needs to be defined first, immediately followed by all its relative sprites. The group ends with the next anchor sprite which can either be another standalone sprite, or an anchor for another sprite group. For example, if sprite 5 is setup as an anchor, its relative sprites must be followed at 6, 7, 8... until another sprite that's setup as ``anchor''.
There are 2 types of relative sprites: composite and unified sprites.
\subsubsection{Composite Relative Sprites}
Composite sprites inherit certain attributes from their anchor.
\begin{multicols}{2}
Inherited attributes:
\begin{itemize}[topsep=1pt,itemsep=1pt]
\item Visibility
\item X
\item Y
\item Palette offset
\item Pattern number
\item 4 or 8-bit pattern
\end{itemize}
\columnbreak
\textbf{NOT} inherited:
\begin{itemize}[topsep=1pt,itemsep=1pt]
\item Rotation
\item X \& Y mirroring
\item X \& Y scaling
\end{itemize}
\end{multicols}
Relative sprites only have 8-bits for X and Y coordinates (ninth bits are used for other purposes). But as the name suggests, these coordinates are relative to their parent anchor sprite so they are usually positioned close by. When the anchor sprite is moved to a different position on the screen, all its relatives are also moved by the same amount.
Visibility of relative sprites is determined as {\tt AND} between anchor visibility and relative sprite visibility. This way individual relative sprites can be made invisible independently from their anchor, but if the anchor is invisible, then all its relative sprites will also be invisible.
Relative sprites inherit 4 or 8-bit setup from their anchor. They can't use a different type but can use a different palette offset than its anchor.
It's also possible to tie relative sprite's pattern number to act as an offset on top of its anchor's pattern number and thus easily animate the whole sprite group simply by changing the anchor's pattern number.
\subsubsection{Unified Relative Sprites}
Unified relative sprites are an extension of the composite type. Everything described above applies here as well.
The main difference is the hardware will automatically adjust relative sprites X, Y, rotation, mirroring and scaling attributes according to changes in anchor. So relatives will rotate, mirror and scale around the anchor as if it was a single larger sprite.
\subsection{Attributes}
% note: we only show page number on second port xref since both are declared on the same page, but if this changes in the future, we should update this text accordingly
Attributes are 4 or 5 bytes that define where and how the sprite is drawn. The data can be set either by selecting sprite index with \PortTextXRef[]{303B} and then continuously sending bytes to \PortTextXRef[]{xx57} (details on page \PortPage{303B}) which automatically increments sprite index after all data for single sprite is transferred or by calling individual direct access Next registers \PortAddr{35}-\PortAddr{39}~or their auto-increment variants \PortAddr{75}-\PortAddr{79}. See ports and registers section \XRef{zx_next_sprites_registers} for a description of individual bytes:
\begin{itemize}[topsep=1pt,itemsep=1pt]
\item Byte 0: \PortTextXRef{35}
\item Byte 1: \PortTextXRef{36}
\item Byte 2: \PortTextXRef{37}
\item Byte 3: \PortTextXRef{38}
\item Byte 4: \PortTextXRef{39}
\end{itemize}
\subsection{Examples}
Reading about sprites may seem complicated, but in practice, it's quite simple. The following pages include sample code for working with sprites.
To preserve space, only partial code demonstrating relevant parts is included. You can find fully working example in companion code on GitHub in folder {\tt sprites}. Besides demonstrating anchor and relative sprites, it also includes some very crude animations as a bonus.
\pagebreak
\subsubsection{Loading Patterns into FPGA Memory}
Before we can use sprites, we need to load their data into FPGA memory. This example introduces a generic routine that uses DMA\footnote{\url{https://wiki.specnext.dev/DMA}} to copy from given memory to FPGA. Don't worry if it seems like magic - it's implemented as a reusable routine, just copy it to your project. Routine requires 3 parameters:
\begin{itemize}[topsep=1pt,itemsep=1pt]
\item {\tt HL} Source address of sprites to copy from
\item {\tt BC} Number of bytes to copy
\item {\tt A} Starting sprite number to copy to
\end{itemize}
\begin{tcblisting}{}
LoadSprites:
LD (.dmaSource), HL ; Copy sprite sheet address from HL
LD (.dmaLength), BC ; Copy length in bytes from BC
LD BC, &303B ; Prepare port for sprite index
OUT (C), A ; Load index of first sprite
LD HL, .dmaProgram ; Setup source for OTIR
LD B, .dmaProgramLength ; Setup length for OTIR
LD C, &6B ; Setup DMA port
OTIR ; Invoke DMA code
RET
.dmaProgram:
DB %10000011 ; WR6 - Disable DMA
DB %01111101 ; WR0 - append length + port A address, A->B
.dmaSource:
DW 0 ; WR0 par 1Band2 - port A start address
.dmaLength:
DW 0 ; WR0 par 3Band4 - transfer length
DB %00010100 ; WR1 - A incr., A=memory
DB %00101000 ; WR2 - B fixed, B=I/O
DB %10101101 ; WR4 - continuous, append port B address
DW &005B ; WR4 par 1Band2 - port B address
DB %10000010 ; WR5 - stop on end of block, CE only
DB %11001111 ; WR6 - load addresses into DMA counters
DB %10000111 ; WR6 - enable DMA
.dmaProgramLength = &-.dmaProgram
\end{tcblisting}
See section \XRef{zx_next_dma} for details on how to program the zxnDMA.
\pagebreak
\subsubsection{Loading Sprites}
Using {\tt loadSprites} routine is very simple. This example assumes you've edited sprites with one of the editors and saved them as {\tt sprites.spr} file in the same folder as the assembler code:
\begin{tcblisting}{}
LD HL, sprites ; Sprites data source
LD BC, 16*16*5 ; Copy 5 sprites, each 16x16 pixels
LD A, 0 ; Start with first sprite
CALL LoadSprites ; Load sprites to FPGA
sprites:
INCBIN "sprites.spr" ; Sprite sheets file
\end{tcblisting}
\subsubsection{Enabling Sprites}
After sprites are loaded into FPGA memory, we need to enable them:
\begin{tcblisting}{}
NEXTREG &15, %01000001 ; Sprite 0 on top, SLU, sprites visible
\end{tcblisting}
\subsubsection{Displaying a Sprite}
Sprites are now loaded into FPGA memory, they are enabled, so we can start displaying them. This example displays the same sprite pattern twice, as two separate sprites:
\begin{tcblisting}{}
NEXTREG &34, 0 ; First sprite
NEXTREG &35, 100 ; X=100
NEXTREG &36, 80 ; Y=80
NEXTREG &37, %00000000 ; Palette offset, no mirror, no rotation
NEXTREG &38, %10000000 ; Visible, no byte 4, pattern 0
NEXTREG &34, 1 ; Second sprite
NEXTREG &35, 86 ; X=86
NEXTREG &36, 80 ; Y=80
NEXTREG &37, %00000000 ; Palette offset, no mirror, no rotation
NEXTREG &38, %10000000 ; Visible, no byte 4, pattern 0
\end{tcblisting}
\pagebreak
\subsubsection{Displaying Combined Sprites}
Even handling combined sprites is much simpler in practice than in theory! This example combines 4 sprites into a single one using unified relative sprites. Note use of ``inc'' register \MemAddr{79} which auto-increments sprite index for next sprite:
\begin{tcblisting}{}
NEXTREG &34, 2 ; Select third sprite
NEXTREG &35, 150 ; X=150
NEXTREG &36, 80 ; Y=80
NEXTREG &37, %00000000 ; Palette offset, no mirror, no rotation
NEXTREG &38, %11000001 ; Visible, use byte 4, pattern 1
NEXTREG &79, %00100000 ; Anchor with unified relatives, no scaling
NEXTREG &35, 16 ; X=AnchorX+16
NEXTREG &36, 0 ; Y=AnchorY+0
NEXTREG &37, %00000000 ; Palette offset, no mirror, no rotation
NEXTREG &38, %11000010 ; Visible, use byte 4, pattern 2
NEXTREG &79, %01000000 ; Relative sprite
NEXTREG &35, 0 ; X=AnchorX+0
NEXTREG &36, 16 ; Y=AnchorY+16
NEXTREG &37, %00000000 ; Palette offset, no mirror, no rotation
NEXTREG &38, %11000011 ; Visible, use byte 4, pattern 3
NEXTREG &79, %01000000 ; Relative sprite
NEXTREG &35, 16 ; X=AnchorX+16
NEXTREG &36, 16 ; Y=AnchorY+16
NEXTREG &37, %00000000 ; Palette offset, no mirror, no rotation
NEXTREG &38, %11000100 ; Visible, use byte 4, pattern 4
NEXTREG &79, %01000000 ; Relative sprite
\end{tcblisting}
Because we use combined sprite, we only need to update the anchor to change all its relatives. And because we set it up as unified relative sprites, even rotation, mirroring and scaling is inherited as if it was a single sprite!
\begin{tcblisting}{}
NEXTREG &34, 1 ; Select second sprite
NEXTREG &35, 200 ; X=200
NEXTREG &36, 100 ; Y=100
NEXTREG &37, %00001010 ; Palette offset, mirror X, rotate
NEXTREG &38, %11000001 ; Visible, use byte 4, pattern 1
NEXTREG &39, %00101010 ; Anchor with unified relatives, scale X&Y
\end{tcblisting}
\pagebreak
\subsection{Sprite Ports and Registers}
\label{zx_next_sprites_registers}
\subsubsection{\PortDeclaration{303B}}
Write: sets active sprite attribute and pattern slot index used by \PortTextXRef[]{xx57} and \PortTextXRef[]{xx5B} (see below).
\begin{NextPort}
\PortBits{7}
\PortDesc{Set to {\tt 1} to offset reads and writes by 128 bytes}
\PortBits{6-0}
\PortDesc{{\tt 0-63} for pattern slots and {\tt 0-127} for attribute slots}
\end{NextPort}
Read: returns sprite status information
\begin{NextPort}
\PortBits{7-2}
\PortDesc{Reserved}
\PortBits{1}
\PortDesc{{\tt 1} if sprite renderer was not able to render all sprites; read will reset to {\tt 0}}
\PortBits{0}
\PortDesc{{\tt 1} when collision between any 2 sprites occurred; read will reset to {\tt 0}}
\end{NextPort}
\subsubsection{\PortDeclaration{xx57}}
Uploads the attributes for the currently selected sprite slot. Attributes require 4 or 5 bytes. After all bytes are sent, the sprite index slot automatically increments. See the following Next registers that directly set the value for specific bytes:
\begin{itemize}[topsep=1pt,itemsep=1pt]
\item Byte 0: \PortTextXRef{35}
\item Byte 1: \PortTextXRef{36}
\item Byte 2: \PortTextXRef{37}
\item Byte 3: \PortTextXRef{38}
\item Byte 4: \PortTextXRef{39}
\end{itemize}
\subsubsection{\PortDeclaration{xx5B}}
Uploads sprite pattern data. 256 bytes are needed for each sprite. For 8-bit sprites, each pattern slot contains a single sprite. For 4-bit sprites, it contains 2 128 byte sprites. After 256 bytes are sent, the target pattern slot is auto-incremented.
\begin{NextPort}
\PortBits{7-0}
\PortDesc{Next byte of pattern data for current sprite}
\end{NextPort}
\subsubsection{\PortDeclaration{09}}
\begin{NextPort}
\PortBits{7}
\PortDesc{{\tt 1} to enable AY2 ``mono'' output (A+B+C is sent to both R and L channels, makes it a bit louder than stereo mode)}
\PortBits{6}
\PortDesc{{\tt 1} to enable AY1 ``mono'' output, {\tt 0} default}
\PortBits{5}
\PortDesc{{\tt 1} to enable AY0 ``mono'' output ({\tt 0} after hard reset)}
\PortBits{4}
\PortDesc{{\tt 1} to lockstep \PortTextXRef{34} and \PortTextXRef{303B}}
\PortBits{3}
\PortDesc{{\tt 1} to reset mapram bit in DivMMC}
\PortBits{2}
\PortDesc{{\tt 1} to silence HDMI audio (0 after hard reset) (since core 3.0.5)}
\PortBits{1-0}
\PortDesc{Scanlines weight ({\tt 0} after hard reset)}
\PortDescOnly{
\begin{tabular}{lll}
& \BitHead{Core 3.1.1+} & \BitHead{Older cores} \\
\BitMono{00} & Scanlines off & Scalines off \\
\BitMono{01} & Scanlines 50\% & Scanlines 75\% \\
\BitMono{10} & Scanlines 50\% & Scanlines 25\% \\
\BitMono{11} & Scanlines 25\% & Scanlines 12.5\% \\
\end{tabular}
}
\end{NextPort}
\subsubsection{\PortTextXRef[]{15}}
\PortDeclarationXRef{Tilemap}{15}
\subsubsection{\PortDeclaration{19}}
\begin{NextPort}
\PortBits{7-0}
\PortDesc{Reads or writes clip-window coordinates for Sprites}
\end{NextPort}
4 coordinates need to be set: X1, X2, Y1 and Y2. Sprites will only be visible within these coordinates. Positions are inclusive. Default values are {\tt 0}, {\tt 255}, {\tt 0}, {\tt 191}. Origin (0,0) is located 32 pixels to the top-left of ULA top-left coordinate.
Which coordinate gets set, is determined by index. As each write to this register will also increment index, the usual flow is to reset the index to 0 with \PortTextXRef{1C}, then write all 4 coordinates in succession.
% note: we use comma for referencing port declaration page to avoid double closing parenthesis, more readable this way
When ``over border'' mode is enabled (bit 1 of \PortTextXRef[,]{15}), X coordinates are doubled internally.
\subsubsection{\PortTextXRef[]{1C}}
\PortDeclarationXRef{Layer 2}{1C}
\subsubsection{\PortDeclaration{34}}
If sprite id lockstep in \PortTextXRef{09} is enabled, write to this registers has same effect as writing to \PortTextXRef{303B}.
\begin{NextPort}
\PortBits{7}
\PortDesc{Set to {\tt 1} to offset reads and writes by 128 bytes}
\PortBits{6-0}
\PortDesc{{\tt 0-63} for pattern slots and {\tt 0-127} for attribute slots}
\end{NextPort}
\subsubsection{\PortDeclaration{35}}
\begin{NextPort}
\PortBits{7-0}
\PortDesc{Low 8 bits of X position}
\end{NextPort}
\subsubsection{\PortDeclaration{36}}
\begin{NextPort}
\PortBits{7-0}
\PortDesc{Low 8 bits of Y position}
\end{NextPort}
\subsubsection{\PortDeclaration{37}}
\begin{NextPort}
\PortBits{7-4}
\PortDesc{Palette offset}
\PortBits{3}
\PortDesc{{\tt 1} to enable X mirroring, {\tt 0} to disable}
\PortBits{2}
\PortDesc{{\tt 1} to enable Y mirroring, {\tt 0} to disable}
\PortBits{1}
\PortDesc{{\tt 1} to rotate sprite 90\Deg clockwise, {\tt 0} to disable}
\PortBits{0}
\PortDesc{Anchor sprite: most significant bit of X coordinate}
\PortDescOnly{Relative sprite: {\tt 1} to add anchor palette offset, {\tt 0} to use independent palette offset}
\end{NextPort}
\subsubsection{\PortDeclaration{38}}
\begin{NextPort}
\PortBits{7}
\PortDesc{{\tt 1} to make sprite visible, {\tt 0} to hide it}
\PortBits{6}
\PortDesc{{\tt 1} to enable optional byte 4, {\tt 0} to disable it}
\PortBits{5-0}
\PortDesc{Pattern index {\tt 0-63} (7th, MSB for 4-bit sprites is configured with byte 4)}
\end{NextPort}
\pagebreak
\subsubsection{\PortDeclaration{39}}
For anchor sprites:
\begin{NextPort}
\PortBits{7-6}
\PortDesc{{\tt H+N6} where {\tt H} is 4/8-bit data selector and {\tt N6} is sub-pattern selector for 4-bit sprites}
\PortDescOnly{
\begin{PortBitConfig}
\PortBitLine{00}{Anchor sprite, 8-bit}
\PortBitLine{10}{Anchor sprite, 4-bit using bytes 0-127 of pattern slot}
\PortBitLine{11}{Anchor sprite, 4-bit using bytes 128-255 of pattern slot}
\end{PortBitConfig}
}
\PortBits{5}
\PortDesc{{\tt 0} if this anchor's relative sprites are composite, {\tt 1} for unified sprite}
\PortBits{4-3}
\PortDesc{X axis scale factor}
\PortDescOnly{
\begin{PortBitConfig}
\PortBitLine{00}{1x}
\PortBitLine{01}{2x}
\PortBitLine{10}{4x}
\PortBitLine{11}{8x}
\end{PortBitConfig}
}
\PortBits{2-1}
\PortDesc{Y axis scale factor, see above}
\PortBits{0}
\PortDesc{Most significant bit of Y coordinate}
\end{NextPort}
For composite relative sprites:
\begin{NextPort}
\PortBits{7-6}
\PortDesc{{\tt 01} needs to be used for relative sprites}
\PortBits{5}
\PortDesc{4-bit mode: {\tt N6}, {\tt 1} to use bytes 0-127, {\tt 0} to use bytes 128-255 of pattern slot}
\PortDescOnly{8-bit mode: not used, set to {\tt 0}}
\PortBits{4-3}
\PortDesc{X axis scale factor, see below}
\PortBits{2-1}
\PortDesc{Y axis scale factor, see below}
\PortBits{0}
\PortDesc{{\tt 1} to enable relative pattern offset, {\tt 0} to use independent pattern index}
\end{NextPort}
For unified relative sprites
\begin{NextPort}
\PortBits{7-6}
\PortDesc{{\tt 01} needs to be used for relative sprites}
\PortBits{5}
\PortDesc{4-bit mode: {\tt N6}, {\tt 1} to use bytes 0-127, {\tt 0} to use bytes 128-255 of pattern slot}
\PortDescOnly{8-bit mode: not used, set to {\tt 0}}
\PortBits{4-1}
\PortDesc{Set to {\tt 0}; scaling is defined by anchor sprite}
\PortBits{0}
\PortDesc{{\tt 1} to enable relative pattern offset, {\tt 0} to use independent pattern index}
\end{NextPort}
\pagebreak
\subsubsection{\PortTextXRef[]{40}}
\vspace*{-2ex}
\subsubsection{\PortTextXRef[]{41}}
\vspace*{-2ex}
\subsubsection{\PortTextXRef[]{43}}
\vspace*{-2ex}
\subsubsection{\PortTextXRef[]{44}}
\PortDeclarationXRefCustom{Palette}{section \ref{\PortReference{40}}, pages \PortPage{40}-\PortPage{44}}
\subsubsection{\PortDeclaration{4B}}
\begin{NextPort}
\PortBits{7-0}\PortDesc{Sets index of transparent colour inside sprites palette.}
\end{NextPort}
For 4-bit sprites, low 4 bits of this register are used.
\subsubsection{\PortDeclaration{75}}
\vspace*{-2ex}
\subsubsection{\PortDeclaration{76}}
\vspace*{-2ex}
\subsubsection{\PortDeclaration{77}}
\vspace*{-2ex}
\subsubsection{\PortDeclaration{78}}
\vspace*{-2ex}
\subsubsection{\PortDeclaration{79}}
This set of registers work the same as their non-inc counterpart in \MemAddr{35}-\MemAddr{39}; writes byte 0-4 of Sprite attributes for currently selected sprite, except \MemAddr{7X} variants also increment \PortTextXRef{34} after write. When batch updating multiple sprites, typically the first sprite is selected explicitly, then \MemAddr{3X} registers are used until the last write, which occurs through \MemAddr{7X} register. This way we'll also increment the sprite index for the next iteration.
\pagebreak