El taller de Juanan: 0x08 Efectos de barrido de pantalla
27/04/2025
En esta nueva entrega de El taller de Juanan voy a mostraros cinco rutinas que limpian la pantalla de distinta manera, aunque en realidad solo cambio los atributos de la misma. Todas las rutinas reciben en la dirección de memoria $5CB0 (23728) los colores a aplicar en la pantalla y son reubicables, por lo que las podréis cargarlas en cualquier posición de memoria.
Efectos de barrido de pantalla
Antes de comenzar voy a explicar brevemente como es el área de atributos del ZX Spectrum. El área de atributos empieza en la posición de memoria $5800 (22528) y tiene una longitud de $300 bytes (768) que es el resultado de multiplicar 32 columnas por 24 líneas, siendo la última posición la $5AFF (23295).
En este caso las rutinas son compatibles con modelos de 16, 48 y 128K.
Vamos a ello.
Por defecto
Esta es la forma por defecto y la más rápida, consiste en cambiar todos los atributos de la pantalla sin aplicar ningún tipo de efecto, cambia los atributos de la primera posición y luego copia este atributo al resto.
El código ensamblador es el siguiente:
; ----------------------------------------------------------------------------- ; Barrido por defecto. Limpia todos los atributos de la pantalla sin aplicar ; ningún efecto. ; ; Entrada: $5CB0 atributos para el barrido. ; ; Altera el valor de los registros AF, BC, DE y HL. ; ; 16 bytes. ; ----------------------------------------------------------------------------- Default: ld a, ($5CB0) ; A = atributos para el barrido ld hl, $5800 ; HL = Inicio de área de atributos ld de, $5801 ; DE = segundo byte del área de atributos ld bc, $2ff ; BC = longitud del área de atributos - 1 ld (hl), a ; Pone el atributo en la primera posición ldir ; Vuelca el atributo al resto del área ret
Esta rutina toma los atributos desde la posición de memoria 23728 y los aplica a toda el área de atributos.
De izquierda a derecha y de arriba abajo
En realidad esta rutina hace lo mismo que la anterior, pero da tiempo a que el ojo humano perciba parte del proceso.
; ----------------------------------------------------------------------------- ; Barrido de izquierda a derecha y de arriba a abajo. ; ; Entrada: $5CB0 atributos para el barrido. ; ; Altera el valor de los registros AF, BC y HL. ; ; 20 bytes. ; ----------------------------------------------------------------------------- Left2Right: ld a, ($5CB0) ; A = atributos para el barrido ld hl, $5800 ; HL = inicio del área de atributos ld c, $18 ; C = 24 líneas left2Right_lpC: ld b, $20 ; B = 32 columnas left2Right_lpR: ld (hl), a ; Carga el atributo inc hl ; HL = siguiente columna djnz left2Right_lpR ; Bucle hasta que recorra las 32 columnas halt halt ; Pausa para que se aprecie el efecto dec c jr nz, left2Right_lpC ; Bucle hasta que recorra 24 líneas ret
Esta rutina recorre las 24 líneas de la pantalla y por cada una de ellas aplica el atributo pasado a las 32 columnas de la línea. Antes de pasar a la línea siguiente hace una pausa para que se pueda ver el efecto.
De derecha a izquierda y de abaja a arriba
Esta rutina limpia la pantalla de manera inversa a la anterior.
; ----------------------------------------------------------------------------- ; Barrido de derecha a izquierda y de abajo a arriba. ; ; Entrada: $5CB0 atributos para el barrido. ; ; Altera el valor de los registros AF, BC, y HL. ; ; 20 bytes. ; ----------------------------------------------------------------------------- Right2Left: ld a, ($5CB0) ; A = atributos para el barrido ld hl, $5AFF ; HL = fin del área de atributos ld c, $18 ; C = 24 líneas right2Left_lpC: ld b, $20 ; B = 32 columnas right2Left_lpR: ld (hl), a ; Carga el atributo dec hl ; HL = columna anterior djnz right2Left_lpR ; Bucle hasta recorrer las 32 columnas halt halt ; Pausa para que se aprecie el efecto dec c jr nz, right2Left_lpC ; Bucle hasta recorrer 24 líneas ret
En este caso empieza por la última posición del área de atributos, la columna 32 de la línea 24, limpia todas las columnas de la línea hacia la derecha y hace una pausa antes de pasar a la línea anterior.
De arriba a abajo y de izquierda a derecha
En este caso la rutina aplica los atributos a la primera columna de arriba a abajo, luego a la segunda y así hasta limpiar las 32 columnas.
; ----------------------------------------------------------------------------- ; Barrido de arriba a abajo y de izquierda a derecha. ; ; Entrada: $5CB0 atributos para el barrido. ; ; Altera el valor de los registros AF, BC, D y HL. ; ; 30 bytes. ; ----------------------------------------------------------------------------- Up2Down: ld a, ($5CB0) ; A = atributos para el barrido ld d, a ; D = atributos para el barrido ld hl, $5800 ; HL = inicio del área de atributos ld c, $20 ; C = 32 columnas up2Down_lpC: push hl ; Preserva HL ld b, $18 ; B = 24 líneas up2Down_lpR: ld (hl), d ; Carga el atributo ld a, l add a, $20 ; Suma 32 para pasar a la línea siguiente ld l, a ; HL = línea siguiente jr nc, up2Down_lpRend ; Si no hay acarreo salta inc h ; Si hay acarreo se lo aplica a H up2Down_lpRend: djnz up2Down_lpR ; Bucle hasta recorrer 24 líneas pop hl ; Recupera HL inc l ; HL = siguiente columna halt halt ; Pausa para que se aprecie el efecto dec c jr nz, up2Down_lpC ; Bucle hasta recorrer 32 columnas ret
En el caso de esta rutina, primero limpia el atributo de la columna 1 y las 24 filas y hace una pausa antes de pasar a la siguiente columna para que se observe el efecto.
De abajo a arriba y de derecha a izquierda
Esta rutina limpia la pantalla de manera inversa a la anterior, empieza por la columna 32 de la línea 24 y termina en la columna 1 de la fila 1.
; ----------------------------------------------------------------------------- ; Barrido de abajo a arriba y de derecha a izquierda. ; ; Entrada: $5CB0 atributos para el barrido. ; ; Altera el valor de los registros AF, BC, D y HL. ; ; 30 bytes. ; ----------------------------------------------------------------------------- Down2Up: ld a, ($5CB0) ; A = atributos para el barrido ld d, a ; D = atributos para el barrido ld hl, $5AFF ; HL = fin del área de atributos ld c, $20 ; C = 32 columnas down2Up_lpC: push hl ; Preserva HL ld b, $18 ; B = 24 líneas down2Up_lpR: ld (hl), d ; Carga el atributo ld a, l sub $20 ld l, a ; HL = linea anterior jr nc, down2Up_lpRend ; Si no hay acarreo salta dec h ; Si hay acarreo se lo aplica a H down2Up_lpRend: djnz down2Up_lpR ; Bucle hasta recorrer 24 líneas pop hl ; Recupera HL dec hl ; HL = columna anterior halt halt ; Pausa para que se aprecie el efecto dec c jr nz, down2Up_lpC ; Bucle hasta recorrer 32 columnas ret
Rutinas auxiliares
En este caso voy a usar unas rutinas auxiliares para el programa BASIC, que si bien no son necesarias, nos van a venir bien para probar todas las rutinas de golpe sin necesidad de recargar el programa.
Save y Restore
Con estas rutinas voy a cargar los atributos de la pantalla a la posición de memoria $7000 (28672) y luego los voy a recuperar desde allí.
; ----------------------------------------------------------------------------- ; Graba los atributos de la pantalla a partir de la posición $7000 ; ; Altera el valor de los registros BC, DE y HL. ; ; 12 bytes ; ----------------------------------------------------------------------------- SaveAttr: ld hl, $5800 ; HL = dirección de inicio de los atributos ld de, $7000 ; DE = dirección dónde se cargan los atributos ld bc, $0300 ; BC = longitud de los atributos ldir ; Vuelca los atribtos desde $5800 a $7000 ret ; ----------------------------------------------------------------------------- ; Recupera los atributos de la pantalla desde la posición $7000 ; ; Altera el valor de los registros BC, DE y HL. ; ; 12 bytes ; ----------------------------------------------------------------------------- RestoreAttr: ld hl, $7000 ; HL = dirección desde la que se vuelca ld de, $5800 ; DE = dirección de inicio de los atributos ld bc, $0300 ; BC = longitud de los atributos ldir ; Vuelca los atributos desde $7000 a $5800 ret
Entrada el programa
Para poder probar el programa voy a implementar una rutina de entrada. Esta rutina recibirá en la dirección de memoria $5CB1 (23729) el tipo de barrido a hacer, del 1 al 5.
; ----------------------------------------------------------------------------- ; Inicio del programa ; ; Entrada: $5CB1 tipo de barrido. ; $5CB0 atributos para el barrido. ; ; Altera el valor de los registros AF. ; ----------------------------------------------------------------------------- Start: ld a, ($5CB1) ; A = tipo de barrido dec a jr z, Default ; Barrido por defecto dec a jr z, Left2Right ; Barrido de izquierda a derecha y de arriba a abajo dec a jr z, Right2Left ; Barrido de derecha a izquierda y de abajo a arriba dec a jr z, Up2Down ; Barrido de arriba a abajo de de izquierda a derecha dec a jr z, Down2Up ; Barrido de abajo a arriba y de derecha a izquierda ret
Uso desde BASIC
Y ahora toca ver cómo usar estas rutinas desde BASIC.
Aunque cada rutina es independiente, en este caso las voy incluir todas en un mismo programa con el único fin de que veáis el resultado de una sola vez.
10 LOAD""SCREEN$ 20 RESTORE 1000:FOR I=0 TO 134:READ D:POKE 26500+I,D:NEXT I 30 RESTORE 2000:FOR I=0 TO 23:READ D:POKE 29696+I,D:NEXT I 40 LET T=23729:LET C=23728:RANDOMIZE USR 29696:REM Tipo de barrido, Color 50 POKE T,1:POKE C,41:RANDOMIZE USR 26500:PAUSE 50:RANDOMIZE USR 29708: PAUSE 50: REM MODE 1 Default 60 POKE T,2:RANDOMIZE USR 26500:PAUSE 50:RANDOMIZE USR 29708:PAUSE 50: REM MODE 2 Left2Right 70 POKE T,3:RANDOMIZE USR 26500:PAUSE 50:RANDOMIZE USR 29708:PAUSE 50: REM MODE 3 Right2Left 80 POKE T,4:RANDOMIZE USR 26500:PAUSE 50:RANDOMIZE USR 29708:PAUSE 50: REM MODE 4 Up2Down 90 POKE T,5:RANDOMIZE USR 26500:PAUSE 50:RANDOMIZE USR 29708:PAUSE 50: REM MODE 5 Down2Up 100 STOP 1000 DATA 58,177,92,61,40,13,61,40,26,61,40,43,61,40,60,61,40,87,201: REM Start, 19 bytes 1010 DATA 58,176,92,33,0,88,17,1,88,1,255,2,119,237,176,201: REM Default, 16 bytes 1020 DATA 58,176,92,33,0,88,14,24,6,32,119,35,16,252,118,118,13,32,245,201: REM Izquierda-Derecha, Arriba-Abajo, 20 bytes 1030 DATA 58,176,92,33,255,90,14,24,6,32,119,43,16,252,118,118,13,32,245,201: REM Derecha-Izquierda, Abajo-Arriba, 20 bytes 1040 DATA 58,176,92,87,33,0,88,14,32,229,6,24,114,125,198,32,111,48,1,36,16, 246,225,44,118,118,13,32,236,201: REM Arriba-Abajo, Izquierda-Derecha, 30 bytes 1050 DATA 58,176,92,87,33,255,90,14,32,229,6,24,114,125,214,32,111,48,1,37,16, 246,225,43,118,118,13,32,236,201: REM Abajo-Arriba, Derecha-Izquierda, 30 bytes 2000 DATA 33,0,88,17,0,112,1,0,3,237,176,201: REM SaveAttr, 12 bytes
2010 DATA 33,0,112,17,0,88,1,0,3,237,176,201: REM RestoreAttr, 12 bytes
En las línea 1000 están los bytes de la rutina de entrada. De las líneas 1010 a la 1050 están los bytes, por separado, de cada una de las rutinas de barrido, para que podáis incluir fácilmente en vuestros programas sólo la/las que os interesen. En las líneas 2000 y 2010 están las rutinas que guardan y restauran los atributos de la pantalla.
En la línea 20 cargo las rutinas de entrada y las de barrido a partir de la dirección de memoria 26500. En la línea 30 algo lo propio con las rutinas de salvado y restauración de atributos, en este caso a partir de la dirección de memoria 29696.
En la línea 40 declaro una variables para las direcciones de memoria en la cuales paso los datos y llamo a la rutina de guardado de los atributos.
En la línea 50 especifico que el tipo de barrido es 1 y los atributos a aplicar, en mi caso tinta azul y papel cielo. Llamo a la rutina de entrada, hago una pausa, llamo a la rutina de restauración de los atributos y hago otra pausa.
Las líneas de la 60 a la 90 son similares a la 50, pero en este caso solo especifico el tipo de barrido a hacer; el resto de la línea no cambia.
En la línea 100 finalizo el programa.
Como en ocasiones anteriores, he usado la pantalla de carga de Sir Fred para hacer la demo. Para saber cómo convertirla a .tap y cómo crear el .tap final podéis revisar el método en este capítulo.
Podéis ver el resultado final en este vídeo.
Espero que os pueda ser utilidad. Podéis bajar todos los archivos que he usado desde aquí.
BASICEnsambladorZX Spectrum