Sprites em Assembly


  A criação e manipulação de sprites em Assembly é feita diretamente nas tabelas de padrão e atributos dos sprites.


  A tabela de padrões dos sprites

  A tabela de padrões define 256 padrões para sprites no modo 8x8 e 64 padrões para o modo 16x16. O padrão do sprite é definido por 8 bytes no modo 8x8 e por 32 bytes no modo 16x16.
  Exemplo de padrão para um sprite 8x8 (valores em binário):
00111000 - Byte 0
01111100 - Byte 1
11111110 - Byte 2
11111110 - Byte 3
11111110 - Byte 4
01111100 - Byte 5
00111000 - Byte 6
00000000 - Byte 7

  No MSX 1, essa tabela se localiza no endereço de 14336 (3800H) a 16383 (3FFFH) da VRAM, onde a cada 8 bytes temos um padrão de sprite para o modo 8x8 ou a cada 32 bytes temos um padrão de sprite para o modo 16x6:
         Modo 8x8                     Modo 16x16

3800H  ┌────────────┐        3800H  ┌────────────┐
       │  Padrão 0  │               │  Padrão 0  │
3808H  ├────────────┤        3820H  ├────────────┤
       │  Padrão 1  │               │  Padrão 1  │
3810H  ├────────────┤        3840H  ├────────────┤
       │    ...     │               │    ...     │ 
3FF8H  ├────────────┤        3FE0H  ├────────────┤
       │ Padrão 255 │               │ Padrão 63  │
3FFFH  └────────────┘        3FFFH  └────────────┘

  No modo 16x16, o desenho na tela de 16x16 pixels é formado pelos 32 bytes consecutivos da seguinte forma:
byte 0  | byte 16
byte 1  | byte 17
byte 2  | byte 18
byte 3  | byte 19
byte 4  | byte 20
byte 5  | byte 21
byte 6  | byte 22
byte 7  | byte 23
--------+--------
byte 8  | byte 24
byte 9  | byte 25
byte 10 | byte 26
byte 11 | byte 27
byte 12 | byte 28
byte 13 | byte 29
byte 14 | byte 30
byte 15 | byte 31


  A tabela de atributos dos sprites

  A tabela de atributos do sprite define 32 sprites. Cada sprite ocupa 4 bytes nessa tabela, onde possui suas coordenadas na tela e cor. Quanto menor o índice do sprite nessa tabela, ele terá prioridade sobre os outros sprites (nível) quando houver superposição.
  Os atributos de cada sprite são definidos por 4 bytes, onde:
Byte 0 - Coordenada Y (topo da tela = 255, Y=Y+1)
Byte 1 - Coordenada X
Byte 2 - Número do padrão (qual padrão usar)
Byte 3 - | EC | 0 | 0 | 0 | Código da cor |
  EC - Se 1, desloca o sprite 32 pontos à esquerda de X.

  No MSX 1, essa tabela se localiza no endereço de 6912 (1B00H) a 7039 (1B7FH) da VRAM, onde a cada 4 bytes temos um sprite em qualquer modo:
1B00H  ┌────────────┐
       │  Sprite 0  │
1B04H  ├────────────┤
       │  Sprite 1  │
1B08H  ├────────────┤
       │    ...     │
1B7CH  ├────────────┤
       │ Sprite 31  │
1B7FH  └────────────┘


  Exemplo em Basic de como criar 2 sprites

  O programa a seguir cria um padrão de uma "bola", cria dois sprites que utilizam esse padrão de desenho e coloca os sprites na tela.
10 SCREEN 2
15 '
20 ' Tabela de padrões dos sprites
25 '
30 P=0 : EP=&H3800 : E=EP+P*8
40  VPOKE E  ,&B00111000
50  VPOKE E+1,&B01111100
60  VPOKE E+2,&B11111110
70  VPOKE E+3,&B11111110
80  VPOKE E+4,&B11111110
90  VPOKE E+5,&B01111100
100 VPOKE E+6,&B00111000
110 VPOKE E+7,&B00000000
115 '
120 ' Tabela de atributos dos sprites
125 '
127 EA=&H1B00
130 S=0 : E=EA+S*4 : ' Sprite 0
140 VPOKE E,100    : ' Y=100+1
150 VPOKE E+1,100  : ' X=100
160 VPOKE E+2,0    : ' Usar padrão 0 da Tab. Pad.
170 VPOKE E+3,4    : ' Cor = 4
180 S=1 : E=EA+S*4 : ' Sprite 1
190 VPOKE E,100    : ' Y=100+1
200 VPOKE E+1,105  : ' X=105
210 VPOKE E+2,0    : ' Usar padrão 0 da Tab. Pad.
220 VPOKE E+3,14   : ' Cor = 14
230 GOTO 230

  Observe que o sprite 0 (azul) tem prioridade sobre o sprite 1 (cinza).

  Podemos movimentar os sprites alterando constantemente os valores das coordenadas na tabela. Acrescente as seguintes linhas ao código anterior.
224 FOR X=0 TO 255
225 VPOKE 6913,X
226 VPOKE 6917,255-X

  Para inibir a vizualização de um sprite, defina a cor dele como sendo 0 (transparente).


  Exemplo em Assembly de como criar e movimentar 1 sprite

  O programa a seguir cria um sprite em Assembly e o desenha na screen 2.
End.  Código     Mnemônicos
                   5 CHGMOD: EQU &H5F
                   6 CHGET:  EQU &H9F
                   7 LDIRVM: EQU &H5C
                   8 ; ----------------------
C000              10 ORG &HC000
C000  3E 02       20 LD A,2
C002  CD 5F 00    30 CALL CHGMOD      ; Screen 2
C005  01 08 00    40 LD BC,8
C008  11 00 38    50 LD DE,&H3800
C00B  21 25 C0    60 LD HL,PAT
C00E  CD 5C 00    70 CALL LDIRVM      ; Copia padrão para tabela
C011  01 04 00    80 LD BC,4
C014  11 00 1B    90 LD DE,&H1B00
C017  21 2D C0   100 LD HL,SPR
C01A  CD 5C 00   110 CALL LDIRVM      ; Copia sprite para tabela
C01D  CD 9F 00   120 CALL CHGET
C020  AF         130 XOR A
C021  CD 5F 00   140 CALL CHGMOD
C024  C9         150 RET
                 190 ; ----------------------
C025  38 7C FE   200 PAT: DEFB &H38,&H7C,&HFE,&HFE,&HFE,&H7C,&H38,&H00
      FE FE 7C
      38 00
C02D  00 64 00   210 SPR: DEFB 0,100,0,8
      08

  Esse outro exemplo irá criar um sprite e movimentá-lo pela tela.
End.  Código     Mnemônicos
                   4 WRTVRM: EQU &H4D
                   5 CHGMOD: EQU &H5F
                   6 CHGET:  EQU &H9F
                   7 LDIRVM: EQU &H5C
                   8 ; ----------------------
C000              10 ORG &HC000
C000  3E 02       20 LD A,2
C002  CD 5F 00    30 CALL CHGMOD      ; Screen 2
C005  01 08 00    40 LD BC,8
C008  11 00 38    50 LD DE,&H3800
C00B  21 31 C0    60 LD HL,PAT
C00E  CD 5C 00    70 CALL LDIRVM      ; Copia padrão para tabela
C011  01 04 00    80 LD BC,4
C014  11 00 1B    90 LD DE,&H1B00
C017  21 39 C0   100 LD HL,SPR
C01A  CD 5C 00   110 CALL LDIRVM      ; Copia sprite para tabela
C01D  AF         120 XOR A
C01E  21 01 1B   130 LD HL,6913
C021  06 00      140 LD B,0
C023  CD 4D 00   150 LOOP: CALL WRTVRM
C026  3C         160 INC A
C027  10 FA      170 DJNZ LOOP
C029  CD 9F 00   180 CALL CHGET
C02C  AF         190 XOR A
C02D  CD 5F 00   200 CALL CHGMOD
C030  C9         210 RET
                 290 ; ----------------------
C031  38 7C FE   300 PAT: DEFB &H38,&H7C,&HFE,&HFE,&HFE,&H7C,&H38,&H00
      FE FE 7C
      38 00
C039  64 00 00   310 SPR: DEFB 100,0,0,8
      08
  Alguém anotou a placa do caminhão? A movimentação de sprites em Assembly é extremamente rápida!

  Vamos acrescentar um retardo em cada iteração, de modo a tornar o movimento do sprite mais lento.
205 PUSH BC
206 LD B,0
207 WAIT: DJNZ WAIT
208 POP BC


  Como alterar o tamanho e a magnitude dos sprites

  O tamanho e a magnitude dos sprites pode ser definida alterando-se 2 bits do registrador #1 do VDP:
bit 7 - Tipo do VDP: 0-4KB / 1-16KB
bit 6 - Exibe tela: 0-Não / 1-Sim
bit 5 - Interrupção do VDP: 0-Não / 1-Sim
bit 4 - M1
bit 3 - M2
bit 2 - 0
bit 1 - Tamanho do sprite: 0-8x8 / 1-16x16
bit 0 - Magnitude do sprite: 0-Normal / 1-Dobro
  Entretanto, esse registrador contém outras informações que deverão ser preservardas. Dessa forma, teremos que ler esse registrador e alterar somente os bits 0 e/ou 1.
  Os registradores de modo do MSX não podem ser lidos, mas somente gravados. Apesar disso, a variável de sistema RG1SAV (F3E0H) contém uma cópia do conteúdo do registrador #1.
  A instrução da BIOS WRTVDP escreve em um dos registradores do VDP:
Ponteiro:  0047H
Endereço:  057FH
Entrada:   B=Byte de dado, C=Número do registro de modo do VDP
Saída:     Nada
Modifica:  AF, B, EI

  O exemplo a seguir mostra como ler o registrador #1 e ajustar o tamanho dos sprites para 16x16 (bit 1=1):
LD A,(&HF3E0)    ; Lê Reg#1
OR &B00000010    ; Seta bit 1
LD B,A           ; Dado p/ Reg#1
LD C,1           ; Define Reg=1
CALL &H47        ; Escreve

  O programa a seguir desenha um sprite de 16x16 pixels.
End.  Código     Mnemônicos
                   4 WRTVDP: EQU &H47
                   5 CHGMOD: EQU &H5F
                   6 CHGET:  EQU &H9F
                   7 LDIRVM: EQU &H5C
                   8 ; ----------------------
C000              10 ORG &HC000
C000  3E 02       20 LD A,2
C002  CD 5F 00    30 CALL CHGMOD      ; Screen 2
C005  3A E0 F3    31 LD A,(&HF3E0)
C008  F6 02       32 OR &B00000010
C00A  47          33 LD B,A
C00B  0E 01       34 LD C,1
C00D  CD 47 00    35 CALL WRTVDP      ; Seta sprite modo 16x16
C010  01 20 00    40 LD BC,32
C013  11 00 38    50 LD DE,&H3800
C016  21 30 C0    60 LD HL,PAT
C019  CD 5C 00    70 CALL LDIRVM      ; Copia padrão para tabela
C01C  01 04 00    80 LD BC,4
C01F  11 00 1B    90 LD DE,&H1B00
C022  21 50 C0   100 LD HL,SPR
C025  CD 5C 00   110 CALL LDIRVM      ; Copia sprite para tabela
C028  CD 9F 00   120 CALL CHGET
C02B  AF         130 XOR A
C02C  CD 5F 00   140 CALL CHGMOD
C02F  C9         150 RET
                 190 ; ----------------------
C030  00 03 03   200 PAT: DEFB &H00,&H03,&H03,&H03,&H03,&H03,&H03,&H02
      03 03 03
      03 02
C038  06 06 07   210 DEFB &H06,&H06,&H07,&H4F,&H79,&H75,&H44,&H00
      4F 79 75
      44 00
C040  00 80 80   220 DEFB &H00,&H80,&H80,&H80,&H80,&H80,&H80,&H80
      80 80 80
      80 80
C048  C0 C0 C0   220 DEFB &HC0,&HC0,&HC0,&HE4,&H3C,&H5C,&H44,&H00
      E4 3C 5C
      44 00
C050  64 64 00   240 SPR: DEFB 100,100,0,8
      08

  Para testar em Basic:
10 E=&HC000
20 READ A$
30 IF A$="M" THEN 70
40 POKE E,VAL("&H"+A$)
50 E=E+1
60 GOTO 20
70 DEFUSR=&HC000:X=USR(0)
100 DATA 3E,02,CD,5F,00,3A,E0,F3,F6,02,47,0E,01,CD,47,00
110 DATA 01,20,00,11,00,38,21,30,C0,CD,5C,00,01,04,00,11
120 DATA 00,1B,21,50,C0,CD,5C,00,CD,9F,00,AF,CD,5F,00,C9
130 DATA 00,03,03,03,03,03,03,02,06,06,07,4F,79,75,44,00
140 DATA 00,80,80,80,80,80,80,80,C0,C0,C0,E4,3C,5C,44,00
150 DATA 64,64,00,08,M


  Sprites modo 2 - MSX 2

  Os sprites do modo 2 não diferem muito em termo de organização em memória dos sprites modo 1. A diferença está na localização da memória de vídeo das tabelas de atributo e padrões dos sprites, além de possuir uma tabela extra para definir as cores de cada linha do sprite. A partir da screen 4, os sprites funcionam como modo 2.

  As tabelas de atributo e padrões dos sprites na screen 4 possuem os mesmos endereços que a screen 2. Entretanto, da screen 5 até a screen 8, as tabelas se localizam em um endereço ao final da página ativa (SET PAGE) do modo de tela em questão.

  A organização da VRAM para as screen 5 e 6 do MSX 2 é a seguinte:
       Página 0
0000H  +------+ -
       |      |
       |      |
       |      |    Padrões
       |      |
       |      |
6A00H  +------+ -
       |      |
7400H  +------+ - Cores dos sprites
7600H  +------+ - Atributos dos sprites
7800H  +------+ -
       |      |   Padrões dos sprites
7FFFH  +------+ -

Para as páginas:
1 - Some 8000H aos endereços
2 - Some 10000H aos endereços
3 - Some 18000H aos endereços
  A tabela de cores das linhas dos sprites se localiza sempre 512 bytes antes da tabela de atributos.

  A organização da VRAM para as screen 7 e 8 do MSX 2 é a seguinte:
       Página 0
0000H  +------+ -
       |      |
       |      |
       |      |    Padrões
       |      |
       |      |
D400H  +------+ -
       |      |
F000H  +------+ - Padrões dos sprites
       |      |
F800H  +------+ - Cores dos sprites
FA00H  +------+ - Atributos dos sprites
FFFFH  +------+

Para as página:
1 - Some 10000H aos endereços

  Podemos obter o endereço de cada tabela no Basic através da instrução BASE(n).
Tabela de padrões:                BASE(20 + (SCREEN - 4)*5)
Tabela de atributos dos sprites:  BASE(23 + (SCREEN - 4)*5)
Tabela de padrões dos sprites:    BASE(24 + (SCREEN - 4)*5)
  Onde SCREEN é o número da screen de 4 a 8.

  A tabela de atributos nos sprites modo 2 se difere por não possuir mais o byte relativo à cor. O espaço continua existindo, mas sem função.
Byte 0 - Coordenada Y (topo da tela = 255, Y=Y+1)
Byte 1 - Coordenada X
Byte 2 - Número do padrão (qual padrão usar)
Byte 3 - Sem função
  Isso porque agora a cor de cada linha é controlada individualmente na nova tabela de cores dos sprites. Mesmo quando um sprite é criado como se fosse no modo 1 nas screens 4-8, o que ele faz e preencher todas as 16 linhas referentes ao sprite nessa nova tabela.

  A tabela de cores de sprites possui 16 bytes, onde cada byte controla uma linha, mesmo para os sprites 8x8. Cada byte (linha) dessa tabela é configurada da seguinte maneira:
+----+----+----+----+----+----+----+----+
| 7  |  6 |  5 |  4 |  3 |  2 |  1 |  0 |  Bit
+----+----+----+----+----+----+----+----+
| EC | CC | IC | 00 |   Código da cor   |  Configuração
+----+----+----+----+----+----+----+----+
  Onde:
  Programa em Basic para alterar uma linha do sprite de branco para vermelho.
10 SCREEN 5
20 FOR T=1 TO 8
30 READ A$:S$=S$+CHR$(VAL("&B"+A$))
40 NEXT T
50 SPRITE$(0)=S$
60 PUT SPRITE 0,(128,95),15,0
70 VPOKE &H7402,8 ' Altera uma linha do sprite
80 GOTO 80
100 DATA 00111100
110 DATA 01111110
120 DATA 11111111
130 DATA 11111111
140 DATA 11111111
150 DATA 11111111
160 DATA 01111110
170 DATA 00111100


  Referências:

  [1] - MSX2 Technical Handbook, ASCII Corporation, 1987.
  [2] - MSX Top Secret 2, Edison Moraes, 2004.


MARMSX/cursos/assembly