lunes, 6 de junio de 2016

VOLCADO DEL BUFFER CON LDI (V): GUARDANDO EL FONDO DEL BUFFER



Una vez que hemos actualizado las coordenadas de todos los sprites vamos a proceder a su impresión. Esto requiere unos cuantos pasos:


  • Primero guardamos el fondo existente en el buffer donde vamos a meter el sprite para que no se modifique a su paso.
  • Luego imprimimos el sprite en el buffer.
  • Cuando hemos hecho esto con todos los sprites, se vuelca el buffer en la pantalla real.
  • Por último recuperamos todos los fondos del buffer que se modificaron al pintar el sprite. Así el buffer queda totalmente limpio para la próxima impresión de sprites.

En esta entrada voy a explicar cómo guardo el fondo del buffer donde voy a imprimir los sprites.

Lo primero que tenemos que saber es cómo hallar la dirección del buffer correspondiente a unas coordenadas dadas. Yo uso una tabla, donde meto la dirección del primer carácter de cada línea del buffer. Esta tabla se crea en CONTENIDA.ASM.

La tabla empieza en TABCOOR (F800h). Metemos el byte bajo de las direcciones del primer caracter de cada línea del buffer en F8nn y el byte bajo en F9nn.



Cargamos DE con PANTVIR, que es el inicio del buffer (8000h) y HL con TABCOOR (F800h). Esto corresponde con (coordY=0, coorX=0). Iniciamos B con el número de líneas que tiene el buffer.

En F800h metemos el byte bajo de la dirección del buffer (00h) incrementamos H (HL=F900h) y metemos el byte alto (80h). Decrementamos H, incrementamos L y le sumamos el ancho del buffer (ANPAN) para que HL tenga la dirección de la siguiente línea del buffer (coordY=1, coorX=0) y repetimos esto con todas las líneas del buffer.

Una vez que sabemos la dirección del primer carácter de la línea del buffer donde está el sprite, sólo tenemos que sumarle la coordenada X para hallar su dirección exacta. En realidad su coordenada X dividida por 8, ya que tenemos que sumarle caracteres y no pixeles.

Veamos un ejemplo práctico. Supongamos que un sprite está en las coordenadas Y=20h X=18h.
Primero vamos a hallar la dirección del primer carácter de la línea del buffer donde está el sprite.
Para eso hacemos lo siguiente;




El registro L se carga con la coordenada Y del sprite. L=20h. H se carga con la tabla que tiene los bytes altos de las direcciones del buffer. H=F9h. Por lo que HL=F920h Al hacer LD D,(HL) en D metemos el byte alto de la dirección del primer carácter del buffer correspondiente a la coordenada 20h.

Ahora metemos en A la coordenada X del sprite. A=18h y la dividimos por 8. A=3, ya que la coordenada X son pixeles y a nosotros nos hace falta saber el número de caracteres a sumar a la dirección del primer caracter de la línea. Al hacer DEC H, HL=F820h que es donde está el byte bajo de la dirección del primer caracter de la línea 20h del fuffer. Se lo sumamos a la coordenada X en caracteres (teniendo cuidado de incrementar D si ha habido acarreo) y así lo metemos en E. De esta manera, DE tiene la dirección donde se va a imprimir el sprite.

Con este método, aunque ocupa algo de memoria, las direcciones de impresión en el buffer se hallan rápidamente.

Una vez guardados los "cachos" del buffer que ocupan los sprites hay que recuperarlos. Para eso se crea una tabla para cada cacho. Cada una consta de 6 bytes:

byte 0: Altura del cacho dividida por 2
byte 1: Anchura del cacho
byte 3 y 4: dirección del buffer donde se debe reponer el cacho
byte 5 y 6: dirección donde se ha guardado el cacho

Estos datos se empiezan a guardar en DATFON (al final de APRINCIPAL.ASM) y se manejan con el registro IY.


El cacho de buffer que se guarda de un sprite no ocupa siempre lo mismo. Debido a que en el Spectrum siempre se imprime en baja resolución, si queremos que su movimiento (byte 12 de la tabla) horizontal sea de menos que 8 pixeles (en este caso puede ser de 2,4 ó 6; siempre par), debido a que hay que desplazar los gráficos, el trozo a guardar ocupará un caracter más si su coordenada X no es cero o múltiplo de 8.
En resumen, un sprite que tenga n caracteres de ancho, si su coordenada X no es cero o múltipo de 8, ocupa n+1 caracteres.
Para saber si un número es múltiplo de 8, basta con hacerle un AND 7. Si este resultado es igual a cero, es que lo es y por lo tanto ocupa n caracteres. Eso es lo que se hace con la coordenada X.
De todas formas, el tema de las rotaciones de los gráficos lo explicaré en la rutina de impresión.


Una última consideración. Como ya he explicado, las tablas de los sprites que se tienen que imprimir se van metiendo en una cola que empieza en SPIMP. Para ir cogiendo estos datos uso la pila, que es un método muy rápido.

Supongamos que en la cola de impresión de sprites he metido: ENEM2,ENEM3,ENEM4,PROTA.
Primero cargo SP con SPIMP (LD SP,SPIMP). Para recuperar el primer dato hago POP IX con lo que IX=ENEM2. Una vez que termino con este sprite hago de nuevo POP IX con lo que ahora IX=ENEM3 y así sucesivamente hasta IX=PROTA.

Para usar la pila de esta manera hay que tener en cuenta que:

  • Las interrupciones han de estar deshabilitadas, ya que al saltar una interrupción se guarda la dirección de retorno en la pila, con lo que se nos machacarían los datos y a saber a dónde retorna.
  • No se puede usar ninguna instrucción que maneje la pila, tal como CALL, hacer PUSH para guardar registros, etc. Obviamente esto también nos machacaría los datos. 

Después de todo este rollo, vamos a ver la rutina en sí.




Cargamos en IY la dirección donde se van a ir guardando las tablas de los cachos del buffer-6.
Guardamos el registro de la pila, ya que lo vamos a usar para ir sacando las tablas de los sprites de la cola de impresión.
Metemos en GFONDI+1 el inicio de la zona donde vamos a guardar los cachos.
Apuntamos la pila a la cola de impresíón.
Aquí aparece CSPIM que es el número de sprites que hay en la cola y que se actualiza en METEIMPS cada vez que metemos uno.
Ya que está en A, lo metemos también en CSPIMR+1 que es el contador del bucle para restaurar los fondos.
Con POP IX cogemos el primer dato de la cola de impresión, osea, IX=tabla del primer sprite a imprimir.
Después hallamos la dirección del buffer a partir de las coordenadas como vimos antes, y la metemos en la tabla. Luego metemos en la tabla la dirección a partir de donde se guarda el cacho.
Miramos si la coordenada X es múltipo de 8. Si no lo es, el trozo a guardar tiene un caracter más que el ancho del sprite.
Antes comenté que para hallar la dirección inmediatamente inferior a una dada en el buffer había que sumarla ANPAN. Como al ir guardando líneas esta dirección se va a incrementar en el ancho del trozo a guardar, la dirección inmediatamente inferior a la  del inicio del trozo será de ANPAN-(ancho del cacho).
Guardamos la (altura/2) en la tabla .

Ponemos B=0 ya que el bucle en GF2 se repetirá hasta que BC=0  y volcamos la primera línea con LDI. Para ir a la segunda, se le suma ANPAN-(ancho del trozo).
Se vuelve a repetir el asunto (ya que el bucle dura  (altura del sprite/2)) y se guarda la dirección de inicio donde se va a meter el siguiente trozo.


Ya estamos preparados para imprimir el sprite.






4 comentarios:

  1. Hola Climacus. Para tener una idea, tienes en mente la cantidad de capítulos que nos demandara el curso?.

    ResponderEliminar
    Respuestas
    1. Hola. Pues no tengo ni idea. Mi intención es ir poniendo rutinas interesantes y explicándolas lo mejor posible para que los interesados podáis ir aprendiendo distintas técnicas de programación.

      Eliminar
  2. Una cosa mas. Todos los capítulos subidos (y por subir) explican el ejemplo de la primer clase?.

    ResponderEliminar
    Respuestas
    1. No. De momento estoy explicando la técnica de volcado del buffer con LDI. Después iré explicando otros métodos y lo interesante sería acabar haciendo un juego completo.

      Eliminar