Martes, 6 de febrero de 2024

Pues nada, con este post vamos a terminar las explicaciones de las tres rutinas de scroll utilizadas en QBIQS, viendo cómo se realiza el scroll de los laterales. Si no has leído los anteriores, aquí te dejo los enlaces a los dos:
El scroll de los laterales

En primer lugar, tal y como comentamos en el anterior post, recordemos que al diseñar el scroll de las piezas se necesitaron un total de 183 tiles gráficos para representar las diferentes combinaciones de QBIQS en vertical desplazadas de 0 a 7 pixels. Como los QBIQS atraviesan las tres zonas en las que se divide la pantalla, ya tenemos ocupados 183 tiles en todas ellas, lo que nos deja un total de 73 tiles en total para cada zona. La tercera zona (la inferior) es la que muestra los marcadores, por lo que esos 73 tiles se utilizan para los marcadores, la barra de energía que separa los QBIQS de donde está la nave y también para la nave, que es una mezcla entre tiles y sprites. Como no se trata de unos gráficos muy variados, la cantidad de tiles libres fue más que suficiente para definirlos todos.

Sin embargo, en las dos zonas superiores, tenemos únicamente disponibles esos 73 tiles para definir los gráficos de los laterales. Vamos a ver cuál fue el proceso que comenzó con unos laterales estáticos que luego se movieron al tile y, finalmente, al pixel si se ejecuta en (casi cualquier) MSX2.

Pongamos como ejemplo la decoración del nivel 0. En este nivel podemos ver unos cuadrados grandes de colores rojo, verde y azul. Cada uno de esos cuadrados está formado, a su vez, por 16 tiles formando una matriz de 4x4. Esto hace un total de 48 tiles diferentes y como tenemos 73 tiles libres, cabe sin problemas. Aunque el diseño final no sea el mismo, podemos recordar el vídeo del anterior post en el que se ve cómo los laterales (formados por cuadrados RGB de 5x5 tiles) son estáticos:
Ahora viene el siguiente paso, que es bastante inmediato: hacer que los laterales se desplacen al tile. Si nos fijamos en el siguiente vídeo en el que los laterales ya se desplazan:
Podemos ver que la decoración se repite: debajo de un cuadrado rojo hay uno verde y debajo de este uno azul, que está encima de uno rojo y así sucesivamente. Así pues, la idea es tener definido el scroll con los tiles dispuestos de esa forma y, para hacer que las piezas avancen más rápido que los laterales, desplazar el puntero al scroll una vez por cada 16 pixels que avancen las piezas. Se vuelcan a la nametable los tiles y de esta forma los laterales se están desplazando al tile y ya no son tan estáticos como en el primer vídeo.

Y así es como se ve el juego en un MSX1 o en una Coleco, ya que no hay forma de hacer un scroll más fino. Si quisiéramos usar la misma técnica utilizada para el scroll de las piezas, tendríamos que multiplicar por 8 la cantidad de tiles usadas, que sería un total de 384 tiles... que no tenemos ni siquiera aunque no hubiera nada más. Por otro lado, si queremos usar la misma técnica que el scroll de los créditos, acabaríamos con unos laterales que se desplazan lentamente y tampoco es que haya suficiente tiempo como para poder volcar todo y ejecutar toda la lógica del juego.

Así que en MSX2, el scroll es exactamente el mismo: se desplaza el puntero al scroll una vez por cada 16 pixels que avancen las piezas, volcándose los tiles a la nametable para hacer un scroll al tile de los laterales.

¿Qué? ¡Me estás engañando! ¡En MSX2 los laterales se desplazan al pixel! ¡El scroll no puede ser exactamente el mismo!

Bueno, dije exactamente, en cursiva. Cierto, la rutina de scroll no es idéntica, solo se diferencia en un "pequeño trocito de código" cuando se ejecuta en un MSX2 o superior. Y no, no se trata del "registro de scroll vertical" que tienen los MSX2, ya que ese registro mueve la pantalla completa. Usarlo movería los laterales, las piezas que bajan, los marcadores, los QBIQS lanzados, la nave... ¡TODO! Es decir, que para usarlo tendría que estar ajustando todos los demás elementos de la pantalla y eso se complica muchísimo. Ese registro es el que emplea Quarth para desplazar piezas y laterales a la misma velocidad, mientras que los marcadores están separados de la parte superior por una franja negra que aprovechan para hacer un screen-split:
El truco que emplea QBIQS es una mezcla entre el scroll de los créditos y el de las piezas: para cada uno de los ocho pixels que forman un tile, se precalcula el contenido de las tablas de patrones y colores para los tiles utilizados en la decoración de los laterales (igual que en el scroll de las piezas), para lo cual se desplazan hacia abajo los datos de las columnas de tiles (igual que en el scroll de los créditos).

Vale, pero aún así hay algo más, ¡justo antes has dicho que eso no cabe en VRAM ni da tiempo a volcarlo desde RAM!

En efecto, si tenemos (en el nivel 0) 48 tiles diferentes en cuatro columnas. Calculando, necesitaríamos, como ya vimos, 384 tiles diferentes que no caben en VRAM o bien volcar un total de 768 bytes entre las tablas de patrones y colores (768 bytes = 48 tiles x 16 bytes/tile) que se deberían actualizar cada vez que los laterales avancen un pixel. Nada, que no hay manera.

Sin embargo, hay un detalle en el razonamiento anterior que no es cierto: estamos en un MSX2 y tenemos un mínimo de 64K de VRAM. ¿Por qué no la aprovechamos? Si cada pantalla en SC2 ocupa 16K de VRAM, con 64K podríamos almacenar 4 pantallas y con 128K un total de 8 pantallas. Aprovechemos que las tablas en VRAM no tienen una posición fija y que podemos moverlas a nuestro antojo. ¿Qué pasaría si tuviésemos cargadas en VRAM 4 u 8 tablas de patrones y colores todas idénticas salvo por los tiles de los laterales?

Y ese es el truco: en primer lugar se comprueba cuanta VRAM tiene disponible el VDP, ya que hay cinco modelos de MSX2 que pueden tener solo 64K de VRAM. Así pues, tendremos 4 u 8 páginas de 16K disponibles. Mientras la pantalla está en negro antes de comenzar el nivel, se vuelcan a VRAM los patrones y colores de piezas, marcadores y naves, una vez a cada página de 16K que haya disponible en VRAM. Esos patrones y colores no cambian con el desplazamiento de los laterales, así que son compartidos por todas las tablas en VRAM. Después, se van calculando las tablas de patrones y colores para los laterales desplazadas de 0 a 7 pixels y se vuelcan en su lugar en las páginas de 16K en VRAM. Si tenemos 128K de VRAM (lo más normal), habrá una página por cada desplazamiento, pero si únicamente hay 64K, solo se vuelcan las tablas con desplazamiento par (la 0, la 2, la 4 y la 6). Es decir, con 128K de VRAM vemos los laterales desplazarse al pixel, pero con 64K de VRAM los vemos desplazándose de dos en dos pixels.

Así, ese "trocito de código" que faltaba consiste en cambiar los punteros de la tabla de nombres y patrones a la página de 16K que contenga los patrones y colores de los laterales desplazados. Eso sí que da tiempo a hacerlo incluso durante el vblank (solo hay que cambiar dos registros del VDP) y desde fuera da la ilusión de que los laterales se han desplazado un pixel hacia abajo, pero lo que en realidad ha ocurrido es que se cambia el origen de los gráficos por otros desplazados un pixel hacia abajo y el contenido en VRAM representando los laterales no se ha actualizado. Después, al volver al desplazamiento 0, se actualiza la tabla de nombres igual que se hace en MSX1 y el scroll está completo:
Eso sí, en algunos niveles el scroll se complica un poquito más. A veces incluso los 73 tiles no bastan y al hacer el scroll al pixel no había suficientes tiles como para que quedase bien y hay que tirar de sprites en negro para enmascarar los fallitos. Y no olvidemos que, en el último nivel, las cabezas de los Moai abren y cierran los ojos de forma aleatoria, efecto que se consigue modificando en RAM los datos de la zona de scroll para que se vuelquen unos gráficos u otros.

Y con esto ya hemos terminado esta pequeña serie de posts comentando cómo funcionan los scrolls del QBIQS. ¡Espero que os haya gustado!