Volcar imágenes en la pantalla del QL

graphiql_demo

Pantalla demo creada con GraphiQL

Siguiendo con la fórmula de la semana pasada de recuperar artículos de QForum, hoy hablaremos de mostrar imágenes en la pantalla del QL. No entraré a explicar cómo es esta pantalla, pues existe documentación específica para ello en este mismo blog, pero sí indicaré cómo hacer para, por ejemplo, poner una pantalla de inicio a un juego o mostrar una imagen de un tamaño determinado en píxeles en una posición determinada de la pantalla.

Pantalla de inicio

Imaginad que tenemos terminado nuestro flamante nuevo juego para QL y queremos poner una pantalla de carga. El QL nos facilita la tarea desde el SuperBASIC con el comano LBYTES. Con un programa de dibujo creamos la pantalla y la guardaremos en un fichero. Este fichero será un volcado bit a bit de cada posición de pantalla. Podemos usar la extensión _scr o bien la extensión _qs8 para indicar que se trata de una pantalla en modo 8 colores (256×256 pixels) o bien _qs4 para una pantalla en modo 4 colores (512×256 pixels). Ambas pantallas completas ocuparan siempre lo mismo. La pantalla del QL ocupa un área de memoria de 32 Kb (32768 bytes) y va toda junta desde la posición de memoria 131072.

Pongamos que la imagen resultante se llame “pantalla_qs8”. Podemos usar entonces la siguiente instrucción para cargar en la memoria de pantalla nuestra imagen (aseguraros de estar en MODE 8):

 LBYTES win1_pantalla_qs8,131072 : PAUSE

La pausa del final (PAUSE) espera a que pulses una tecla para volver a mostrarte el cursor. En un listado de nuestro cargador del juego no la pondremos. Simplemente cargamos la pantalla y seguimos cargando el juego.

Es conveniente saber que si vamos a ver nuestra pantalla en una TV, esta se come un 15% aproximadamente a la derecha, a la izquierda y arriba de la imagen. Debemos tener esto en cuenta cuando creemos nuestra imagen de pantalla de inicio.

Pantalla inicio software PSION retocado por Afx.

Pantalla inicio software PSION retocado por Afx.

Desde el punto de vista de almacenamiento, si hacemos que ocupe solo media pantalla en altura, recortaríamos la imagen almacenada a 16 Kb. Algo parecido podemos ver en la carga del paquete PSION con el logo de la empresa. Esto evita que usemos tanto espacio de almacenamiento en un microdrive. Cada microdrive tiene aproximadamente algo más de 100 Kb de capacidad. una pantalla de 32 Kb es casi un tercio el almacenamiento disponible.

Si nada más necesitamos mostrar un logo o dibujo en la parte central de la pantalla, desechando el espacio negro de arriba (25%) y abajo (25%), sólo tendremos que almacenar 16 Kb. Hay que indicar que la imagen que vamos a emplear ocupa siempre todo el ancho de la pantalla.. Esta es la solución que se usó en la carga del juego OSUSQL de Afx que nos servirá de ejemplo en este artículo.

A la hora de mostrarlo en pantalla con el comando LBYTES (cargar bytes),  tenemos que decir en que dirección de la pantalla poner la imagen y se cargaran los 16 Kb. todo en bloque a partir de ahí.

Volcando pantallas

Para calcular la posición en pantalla para LBYTES tenemos que hacer unos cálculos. Veamos:

Inicio de pantalla en la posición de memoria: 131072
Tamaño de la pantalla: 32768 bytes
Número de líneas de pantalla (en ambos modos): 256
Tamaño de cada línea de pantalla: 32768 / 256 = 128 bytes
Nota: luego la posición en pantalla irá desde 0 a 255.

Así pues, si queremos colocar nuestra imagen en por ejemplo la linea 100 de la pantalla deberemos realizar el siguiente cálculo:

LBYTES win1_pantalla_qs8,131072+((100-1)*128)

Restamos 1 a 100 para que la primera línea  sume 0 al cálculo (recuerda, 0 a 255).

Pongamos que tenemos una imagen como la propuesta, que ocupa justo la mitad de la pantalla, y queremos ponerla centrada, es decir, que ocupe el mismo medio de la pantalla. Más cálculos.

Tenemos que averiguar en que posición (altura en líneas de pantalla) irá nuestra imagen. si ocupa la mitad de 256 obvio serán 128, pero vamos a ver como sería con un valor variable:

h=128 : LBYTES win1_pantalla_qs8,131072+(((256-h)/2)*128)

Indico todos los paréntesis para que quede claro el orden de operaciones. El valor de h será de 1 a 256. No es muy complicado.

¿Y si queremos poner una imagen más pequeña, por ejemplo en nuestro juego, con unas medidas concretas? Vamos a verlo a continuación.

Ahora toca incorporar lo aprendido en un fichero BOOT. Sirva como ejemplo el código del juego OSUSQL:

10 disp$="flp1_"
90 :
100 OPEN #5,scr_512x256a0x0
110 PAPER #5,0 : CLS #5
120 PAUSE 1
130 CLOSE #5
140 LBYTES disp$&"osusq_scr",139264
150 PRINT #0,"Cargando..."
160 PAUSE 1
170 MRUN disp$&"osusq_bas"

Los PAUSE 1 no tienen un uso práctico, pero están incluidos para que a los emuladores les de tiempo a mostrar bien la pantalla antes de ejecutar la siguiente instrucción. Cosas raras que se aprenden con la practica.

Volcando imágenes

Pero todo esto tiene una limitación, y es que la imagen debe ocupar forzosamente el ancho de pantalla, como dijimos. ¿Y si quiero mostrar una imagen de por ejemplo 48×32 pixel en la pantalla?

Paso a explicar ahora como realizar el volcado de imágenes en pantalla. Es un ejemplo con una imágen en modo 4, concretamente, en este caso con el dragón pequeño del, juego OSUSQL:

Pasos a seguir:
1.- Crear el diseño con las medidas y la posición del dibujo adecuadas.
2.- Usar programa para convertir el área de memoria de pantalla correspondiente a fichero secuencial.
3.- Usar procedimiento para volcar el fichero secuencial con la imagen en la posición de pantalla adecuada.

dragonPaso 1

Creamos el diseño del dragón que ocupará 96×48 pixels con cualquier programa de dibujo para QL o convirtiendolo desde PC y lo colocamos en la posición superior izquierda de la imagen por comodidad. dicha imagen ocupará toda la pantalla o al menos todo el ancho de la pantalla, y lo guardamos.

Paso 2

Mediante el programa guardar_bas volcamos el dragón (dragon_scr) en pantalla y tomamos lo que nos interesa de la imagen.

100 REMark guarda en modo 4
110 fichero$ = "dragon"
120 LBYTES fichero$ & "_scr", 131072
130 pos = 131072
140 ancho = 96 : alto = 48
150 ancho = ancho / 4
160 reserva = ancho * alto
170 salto = 128 : incremento = 0 : suma = 0
180 mem = RESPR(reserva)
190 FOR bu = 0 TO alto - 1
200   FOR i = 0 TO ancho - 4 STEP 4
210     despla = incremento + i
220     POKE_L mem + suma, PEEK_L(pos + despla)
230     suma = suma + 4
240   END FOR i
250   incremento = incremento + salto
260 END FOR bu
270 SBYTES fichero$ & "_spr", mem, reserva

El ancho en pixels de la imagen ha de ser múltiplo de 16. Esta imagen tendrá 96×48 pixels.

El programa carga la imagen del dragón y la vuelca linea a linea, secuencialmente, a una zona de memoria que luego guarda en el fichero dragon_spr con SBYTES.

Paso 3

Una vez guardado, sólo tenemos que crear un PROCedure para colocar la imagen en la posición de pantalla deseada. este PROCedure lo podremos incorporar a nuestros programas.

100 dragon = RESPR(1152)
110 LBYTES dragon_spr, dragon
120 :
130 volcar dragon, 96, 48, 32, 20
140 :
150 DEFine PROCedure volcar(mem, ancho, alto, pos_x, pos_y)
160 REMark procedure para modo 4
170 REMark pos_x debe ser multiplo de 16
180 LOCal pantalla, salto, bu, incremento, suma, despla, pos, i
190 pantalla = 131072 : ancho = ancho / 4
200 salto = 128 : incremento = 0 : suma = 0
210 pos = ((pos_x / 4) + pantalla) + (pos_y * salto)
220 FOR bu = 0 TO alto - 1
230   FOR i = 0 TO ancho - 4 STEP 4
240     despla = incremento + i
250     POKE_L pos + despla, PEEK_L(mem + suma)
260     suma = suma + 4
270   END FOR i
280   incremento = incremento + salto
290 END FOR bu
300 END DEFine volcar

El PROCedure volcar sólo sirve en principio para modo 4, y el valor de pos_x ha de ser múltiplo de 16 forzosamente.

Lo que hace es invertir el proceso del programa anterior. Lee los datos secuenciales que cargó a una zona de memoria y los vuelca en pantalla línea a linea.

Los parámetros del PROCedure volcar son:

mem = indica la posición de memoria donde se guarda la imagen

ancho = indica la anchura en pixels de la imagen (múltiplo de 16)

alto = indica la altura en pixels de la imagen

pos_x = indica la coordenada x de la pantalla donde se visualizará la imagen (desde 0 a 511-ancho en valores múltiplos de 16)

pos_y = indica la coordenada y de la pantalla donde se visualizará la imagen (desde 0 a 255-alto)

osusqEl volcado se hace mediante palabras largas, es decir, de 32 en 32 bits para aligerar la representación en pantalla. Si queremos que la imagen se posicione en una coordenada X que no sea multiplo de 16 podemos recurrir al siguiente truco o emplear un código que mueva palabras o bytes en vez de palabras largas:

Esta técnica de copiar y volcar nos sirve también para las imágenes de inicio de programa que decíamos antes.

La imagen del dragón que vemos en la captura de pantalla es el resultado de usar todo esto. Útil, ¿verdad? Podemos usar esta técnica para, por ejemplo, colocar un marcador o un título molón en nuestro juego. Para sprites no nos servirá, pues quizá necesitemos otras técnicas más específicas.

Podemos descargar el juego desde aquí.

Truco cutre pero efectivo

Creamos una ventana que ocupe al menos lo mismo de alto que la imagen y de ancho el ancho de la imagen mas la suma de los pixels que queremos mover dicha imagen a derecha o a izquierda. La ventana estará justo debajo de la imagen.

Volcamos entonces la imagen a la pantalla en una posición x múltiplo de 16 como se indicó alineada a derecha o izquierda en la ventana.

Una vez volcada la imagen usamos el comando PAN (desplazamiento PANorámico de la ventana) X pixels (positivos o negativos) y tendremos la imagen en la posición deseada.

Sobre el método

Para realizar todo esto, en primer lugar pensé en usar DATAs, evitando tener que crear un fichero externo como en el caso propuesto, pero topé de frente con el sistema de conversión de números del SuperBASIC. Cuando los números son demasiado grandes, el QL emplea redondeo y notación científica para escribirlos, así pues esos datos que volcaba a los DATAs luego al ser leídos y mostrados por pantalla no reproducían la misma imagen. En fin, peculiaridades del SuperBASIC.

Lo único que solucionó el problema es usar la sentencia PEEK dentro de la misma instrucción P0KE (ver listados), y de esta forma los datos almacenados si son exactamente los mismos que los que se leyeron por pantalla.

POKEs para pantalla

mediante estos POKEs vamos a poder acceder a algunas características del QDOS.

Apaga la pantalla (la pantalla se deja de ver en la TV o el monitor) Muy útil cuando queremos escribir en pantalla algo sin que se vea:

POKE 98403,2
Enciende / cambia la pantalla en modo 8:
POKE 98403,8

Enciende / cambia la pantalla en modo 4:

POKE 98403,0

Usa estos POKEs con cuidado y moderación. Prueba bien con seguridad antes de usarlos porque si por ejemplo, apagas la pantalla y no tienes un mecanismo para volver a activarla (pulsación de tecla, etc) tendrás que reiniciar el ordenador.

Cuando cambiamos el modo de pantalla con los POKEs se dan efectos curiosos.

Por último, podrás saber que modo de pantalla es el modo actual con:

modo=PEEK(98403): PRINT modo

Bueno, esto es todo por ahora.

Las dudas ya sabéis, no dejéis de preguntarlas.

Anuncios
3 comentarios
  1. badaman dijo:

    Estupendo enlace. Actualizo el artículo con él en el primer párrafo.

    Lo próximo serán los sprites y el juego de caracteres. Y luego ya veré, porque vuelvo a estar ocupao…

    ¿Habrá quien se anime a hacer un nuevo juego para QL o convertir alguno de otra máquina?

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s