Diferencias
Muestra las diferencias entre dos versiones de la página.
Ambos lados, revisión anteriorRevisión previaPróxima revisión | Revisión previa | ||
cursos:ensamblador:gfx5_mapeados [18-12-2023 18:05] – sromero | cursos:ensamblador:gfx5_mapeados [19-01-2024 08:27] (actual) – sromero | ||
---|---|---|---|
Línea 1: | Línea 1: | ||
====== Gráficos (y V): Técnicas de mapeado por bloques ====== | ====== Gráficos (y V): Técnicas de mapeado por bloques ====== | ||
- | En el amplio catálogo de software del Spectrum existen juegos con decenas y hasta cientos de pantallas. ¿Cómo es posible que, a 7KB por pantalla, quepan tantas " | + | En el amplio catálogo de software del Spectrum existen juegos con decenas y hasta cientos de pantallas. ¿Cómo es posible que, a 7KB por pantalla, quepan tantas " |
Lo que posibilita esta variedad de pantallas de juego es la técnica de mapeado por bloques. | Lo que posibilita esta variedad de pantallas de juego es la técnica de mapeado por bloques. | ||
- | En esta técnica se utiliza un spriteset de bitmaps denominados tiles y se definen en memoria mapas basados en identificadores numéricos donde cada valor representa un tile concreto. Así, se compone cada pantalla de juego como una matriz de " | + | En esta técnica se utiliza un spriteset de bitmaps denominados tiles y se definen en memoria mapas basados en identificadores numéricos donde cada valor representa un tile concreto. Así, se compone cada pantalla de juego como una matriz de " |
Un sólo spriteset (tileset) lo suficientemente variado y la habilidad del diseñador y del programador pueden dar lugar a gran cantidad de pantallas y un amplio mapeado con un mínimo uso de memoria, todo basado en la composición de la pantalla como repetición de tiles. | Un sólo spriteset (tileset) lo suficientemente variado y la habilidad del diseñador y del programador pueden dar lugar a gran cantidad de pantallas y un amplio mapeado con un mínimo uso de memoria, todo basado en la composición de la pantalla como repetición de tiles. | ||
Línea 78: | Línea 78: | ||
\\ | \\ | ||
- | {{ : | + | {{ : |
\\ | \\ | ||
Línea 92: | Línea 92: | ||
<code z80> | <code z80> | ||
- | | + | |
</ | </ | ||
Línea 98: | Línea 98: | ||
<code z80> | <code z80> | ||
- | | + | |
</ | </ | ||
- | + | ||
| | ||
<code z80> | <code z80> | ||
- | | + | |
</ | </ | ||
Línea 115: | Línea 115: | ||
sokoban_LEVEL1_h: | sokoban_LEVEL1_h: | ||
- | | + | |
- | DEFB 8, | + | DEFB 8, |
- | DEFB 8, | + | DEFB 8, |
- | DEFB 8, | + | DEFB 8, |
- | DEFB 8, | + | DEFB 8, |
- | DEFB 8, | + | DEFB 8, |
- | DEFB 8, | + | DEFB 8, |
- | DEFB 8, | + | DEFB 8, |
- | DEFB 8, | + | DEFB 8, |
- | DEFB 8, | + | DEFB 8, |
- | DEFB 8, | + | DEFB 8, |
- | DEFB 8, | + | DEFB 8, |
</ | </ | ||
- | Hemos ubicado los datos en una representación visual clara mediante un DEFB por cada fila horizontal, pero el aspecto real de los datos en memoria es totalmente lineal: | + | Hemos ubicado los datos en una representación visual clara mediante un '' |
<code z80> | <code z80> | ||
sokoban_LEVEL1_h: | sokoban_LEVEL1_h: | ||
- | DEFB 8, | + | |
</ | </ | ||
Línea 144: | Línea 144: | ||
**Organización vertical** | **Organización vertical** | ||
- | En el anterior ejemplo hemos organizado el mapa en formato horizontal. También habría cabido la posibilidad de organizarlo verticalmente, | + | En el anterior ejemplo hemos organizado el mapa en formato horizontal. También habría cabido la posibilidad de organizarlo verticalmente, |
| | ||
\\ | \\ | ||
- | {{ : | + | {{ : |
\\ | \\ | ||
Línea 155: | Línea 155: | ||
<code z80> | <code z80> | ||
- | | + | |
- | DEFB 8, | + | DEFB 8, |
- | DEFB 8, | + | DEFB 8, |
- | DEFB 8, | + | DEFB 8, |
</ | </ | ||
Línea 164: | Línea 164: | ||
<code z80> | <code z80> | ||
- | | + | |
</ | </ | ||
Línea 170: | Línea 170: | ||
<code z80> | <code z80> | ||
- | | + | |
</ | </ | ||
Línea 181: | Línea 181: | ||
sokoban_LEVEL1_v: | sokoban_LEVEL1_v: | ||
- | | + | |
- | DEFB 8, | + | DEFB 8, |
- | DEFB 8, | + | DEFB 8, |
- | DEFB 8, | + | DEFB 8, |
- | DEFB 8, | + | DEFB 8, |
- | DEFB 8, | + | DEFB 8, |
- | DEFB 8, | + | DEFB 8, |
- | DEFB 8, | + | DEFB 8, |
- | DEFB 8, | + | DEFB 8, |
- | DEFB 8, | + | DEFB 8, |
- | DEFB 8, | + | DEFB 8, |
- | DEFB 8, | + | DEFB 8, |
- | DEFB 8, | + | DEFB 8, |
- | DEFB 8, | + | DEFB 8, |
- | DEFB 8, | + | DEFB 8, |
- | DEFB 8, | + | DEFB 8, |
</ | </ | ||
- | En este caso nuestros | + | En este caso nuestros |
| | ||
Línea 213: | Línea 213: | ||
==== Rutinas de impresión de pantallas ==== | ==== Rutinas de impresión de pantallas ==== | ||
- | En este apartado vamos a ver rutinas diseñadas para dibujar una pantalla estática formada a base de tiles. La rutina debe imprimir un mapa de ANCHOxALTO tiles a partir de una posición inicial (X_INICIO, | + | En este apartado vamos a ver rutinas diseñadas para dibujar una pantalla estática formada a base de tiles. La rutina debe imprimir un mapa de ANCHOxALTO tiles a partir de una posición inicial ('' |
| | ||
Línea 226: | Línea 226: | ||
;;; Aproximacion 1: | ;;; Aproximacion 1: | ||
FOR Y=0 TO ALTO_PANTALLA_EN_TILES: | FOR Y=0 TO ALTO_PANTALLA_EN_TILES: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | CALL Draw_Sprite | + | call Draw_Sprite |
</ | </ | ||
- | La implementación de esta rutina no sería óptima porque implica gran cantidad de cálculos tanto en el bucle interior como dentro de la rutina Draw_Sprite. Para cada tile de pantalla se realizaría un cálculo de dirección de memoria a partir de las coordenadas X,Y. | + | La implementación de esta rutina no sería óptima porque implica gran cantidad de cálculos tanto en el bucle interior como dentro de la rutina Draw_Sprite. Para cada tile de pantalla se realizaría un cálculo de dirección de memoria a partir de las coordenadas X,Y. |
| | ||
Línea 243: | Línea 243: | ||
| | ||
- | 1.- Teniendo en cuenta que los datos de la pantalla son consecutivos en memoria, vamos a utilizar un puntero para obtener los datos de los tiles linealmente sin tener que calcular la posición dentro del array de datos una y otra vez. Bastará con incrementar nuestro puntero (DIR_PANTALLA) para apuntar al siguiente dato. | + | 1.- Teniendo en cuenta que los datos de la pantalla son consecutivos en memoria, vamos a utilizar un puntero para obtener los datos de los tiles linealmente sin tener que calcular la posición dentro del array de datos una y otra vez. Bastará con incrementar nuestro puntero ('' |
- | 2.- En lugar de calcular la posición en videomemoria (DIR_MEM) de cada tile, calcularemos una sóla vez esta posición para el primer tile de cada fila y avanzaremos diferencialmente a lo largo de la misma. De esta forma sólo realizamos un cálculo de dirección de videomemoria por fila, y no por tile. | + | 2.- En lugar de calcular la posición en videomemoria ('' |
Línea 256: | Línea 256: | ||
DIR_PANTALLA = Direccion de memoria de los datos de la PANTALLA actual | DIR_PANTALLA = Direccion de memoria de los datos de la PANTALLA actual | ||
FOR Y=0 TO ALTO: | FOR Y=0 TO ALTO: | ||
- | | + | |
- | FOR X=0 TO ANCHO_PANTALLA: | + | FOR X=0 TO ANCHO_PANTALLA: |
- | | + | TILE = [DIR_PANTALLA] |
- | | + | DIR_PANTALLA = DIR_PANTALLA + 1 |
- | PUSH DIR_MEM | + | |
- | | + | DIR_SPRITE = BASE_TILESET + (TILE*ANCHO_TILE*ALTO_TILE) |
- | | + | Dibujar Sprite desde DIR_SPRITE a DIR_MEM |
- | POP DIR_MEM | + | |
- | | + | DIR_MEM = DIR_MEM + ANCHO_TILE |
</ | </ | ||
- | Esta rutina sólo realiza un cálculo de posición de videomemoria por fila y además accede a nuestra pantalla de mapa linealmente. Antes de dibujar el tile en pantalla hacemos un PUSH de la dirección actual de memoria ya que la rutina de impresión la modifica. El posterior POP nos recupera la posición de impresión inicial de forma que baste un simple incremento de la misma para apuntar en videomemoria a la posición del siguiente tile que tenemos que dibujar. | + | Esta rutina sólo realiza un cálculo de posición de videomemoria por fila y además accede a nuestra pantalla de mapa linealmente. Antes de dibujar el tile en pantalla hacemos un '' |
Vamos a desarrollar un poco más la rutina en un pseudocódigo más parecido a ASM y con más detalles. Para ello establecemos las siguientes premisas: | Vamos a desarrollar un poco más la rutina en un pseudocódigo más parecido a ASM y con más detalles. Para ello establecemos las siguientes premisas: | ||
\\ | \\ | ||
- | * Utilizaremos IX como puntero de la pantalla del mapa (DIR_PANTALLA). | + | * Utilizaremos IX como puntero de la pantalla del mapa ('' |
* Utilizaremos el valor de tile 255 como un tile " | * Utilizaremos el valor de tile 255 como un tile " | ||
Línea 288: | Línea 288: | ||
| | ||
A = (IX) | A = (IX) | ||
- | | + | |
- | Si A == 255 : | + | Si A == 255 : |
- | JR saltar_bloque | + | jr saltar_bloque |
- | | + | |
DIR_SPRITE = BASE_TILESET + (A*ANCHO_TILE*ALTO_TILE) | DIR_SPRITE = BASE_TILESET + (A*ANCHO_TILE*ALTO_TILE) | ||
HL = BASE_TILESET + (A*8*TAMAÑO_BLOQUES_EN_CADA_TILE) | HL = BASE_TILESET + (A*8*TAMAÑO_BLOQUES_EN_CADA_TILE) | ||
- | | + | |
Imprimir_Sprite_de_HL_a_DE | Imprimir_Sprite_de_HL_a_DE | ||
Convertir DIR HL imagen en DIR HL atributos | Convertir DIR HL imagen en DIR HL atributos | ||
Imprimir_Atributos_Sprite | Imprimir_Atributos_Sprite | ||
- | | + | |
| | ||
HL = HL + ANCHO_TILE | HL = HL + ANCHO_TILE | ||
- | | + | |
- | | + | |
</ | </ | ||
Línea 319: | Línea 319: | ||
Con tiles de 16x16 píxeles podemos generar una pantalla de hasta 16x12 tiles utilizando 192 tiles por pantalla. Con tiles referenciadas por variables de 1 byte, cada pantalla ocuparía, pues, 192 bytes. | Con tiles de 16x16 píxeles podemos generar una pantalla de hasta 16x12 tiles utilizando 192 tiles por pantalla. Con tiles referenciadas por variables de 1 byte, cada pantalla ocuparía, pues, 192 bytes. | ||
- | | + | |
Tiles de mayores tamaños darían poca " | Tiles de mayores tamaños darían poca " | ||
Línea 346: | Línea 346: | ||
; | ; | ||
DrawMap_16x16: | DrawMap_16x16: | ||
- | + | ||
- | | + | ;;;;;; Impresion de la parte grafica de los tiles ;;;;;; |
- | LD IX, (DM_MAP) | + | ld ix, (DM_MAP) |
- | LD A, (DM_HEIGHT) | + | ld a, (DM_HEIGHT) |
- | LD B, A ; B = ALTO_EN_TILES (para bucle altura) | + | ld b, a ; B = ALTO_EN_TILES (para bucle altura) |
drawm16_yloop: | drawm16_yloop: | ||
- | PUSH BC ; Guardamos el valor de B | + | push bc ; Guardamos el valor de B |
- | LD A, (DM_HEIGHT) | + | ld a, (DM_HEIGHT) |
- | SUB B ; A = ALTO - iteracion_bucle = Y actual | + | sub b ; A = ALTO - iteracion_bucle = Y actual |
- | RLCA ; A = Y * 2 | + | |
- | ;;; Calculamos la direccion destino en pantalla como | + | |
- | | + | ;;; DIR_PANT = DIRECCION(X_INICIAL, |
- | LD BC, (DM_COORD_X) | + | ld bc, (DM_COORD_X) |
- | ADD A, B | + | add a, b |
- | LD B, A | + | ld b, a |
- | LD A, B | + | ld a, b |
- | AND $18 | + | |
- | ADD A, $40 | + | add a, $40 |
- | LD H, A | + | ld h, a |
- | LD A, B | + | ld a, b |
- | AND 7 | + | |
- | RRCA | + | rrca |
- | RRCA | + | rrca |
- | RRCA | + | rrca |
- | ADD A, C | + | add a, c |
- | LD L, A ; HL = DIR_PANTALLA(X_INICIAL, | + | ld l, a ; HL = DIR_PANTALLA(X_INICIAL, |
- | LD A, (DM_WIDTH) | + | ld a, (DM_WIDTH) |
- | LD B, A ; B = ANCHO_EN_TILES | + | ld b, a ; B = ANCHO_EN_TILES |
drawm16_xloop: | drawm16_xloop: | ||
- | PUSH BC ; Nos guardamos el contador del bucle | + | push bc ; Nos guardamos el contador del bucle |
- | LD A, (IX+0) ; Leemos un byte del mapa | + | ld a, (ix+0) ; Leemos un byte del mapa |
- | INC IX ; Apuntamos al siguiente byte del mapa | + | inc ix ; Apuntamos al siguiente byte del mapa |
- | | + | cp 255 ; Bloque especial a saltar: no se dibuja |
- | JP Z, drawm16_next | + | jp z, drawm16_next |
- | LD B, A | + | ld b, a |
- | EX AF, AF' | + | ex af, af' |
- | LD A, B | + | ld a, b |
- | ;;; Calcular posicion origen (array sprites) en HL como: | + | |
- | | + | ;;; |
- | EX DE, HL ; Intercambiamos DE y HL (DE=destino) | + | ex de, hl ; Intercambiamos DE y HL (DE=destino) |
- | LD BC, (DM_SPRITES) | + | ld bc, (DM_SPRITES) |
- | LD L, 0 | + | ld l, 0 |
- | SRL A | + | srl a |
- | RR L | + | rr l |
- | RRA | + | rra |
- | RR L | + | rr l |
- | RRA | + | rra |
- | RR L | + | rr l |
- | LD H, A | + | ld h, a |
- | ADD HL, BC ; HL = BC + HL = DS_SPRITES + (DS_NUMSPR * 32) | + | add hl, bc ; HL = BC + HL = DS_SPRITES + (DS_NUMSPR * 32) |
- | EX DE, HL ; Intercambiamos DE y HL (DE=origen, HL=destino) | + | ex de, hl ; Intercambiamos DE y HL (DE=origen, HL=destino) |
- | PUSH HL ; Guardamos el puntero a pantalla recien calculado | + | push hl ; Guardamos el puntero a pantalla recien calculado |
- | PUSH HL | + | push hl |
- | ;;; Impresion de los primeros 2 bloques horizontales del tile | + | |
- | + | ||
- | LD B, 8 | + | ld b, 8 |
drawm16_loop1: | drawm16_loop1: | ||
- | LD A, (DE) ; Bloque 1: Leemos dato del sprite | + | ld a, (de) ; Bloque 1: Leemos dato del sprite |
- | LD (HL), A ; Copiamos dato a pantalla | + | |
- | INC DE ; Incrementar puntero en sprite | + | inc de ; Incrementar puntero en sprite |
- | INC L ; Incrementar puntero en pantalla | + | inc l ; Incrementar puntero en pantalla |
- | LD A, (DE) ; Bloque 2: Leemos dato del sprite | + | ld a, (de) ; Bloque 2: Leemos dato del sprite |
- | LD (HL), A ; Copiamos dato a pantalla | + | |
- | INC DE ; Incrementar puntero en sprite | + | inc de ; Incrementar puntero en sprite |
- | INC H ; Hay que sumar 256 para ir al siguiente scanline | + | inc h ; Hay que sumar 256 para ir al siguiente scanline |
- | DEC L ; pero hay que restar el INC L que hicimos. | + | dec l ; pero hay que restar el inc l que hicimos. |
- | DJNZ drawm16_loop1 | + | |
- | INC L ; Decrementar el ultimo incrementado en el bucle | + | inc l ; Decrementar el ultimo incrementado en el bucle |
- | + | ||
- | | + | ; Avanzamos HL 1 scanline (codigo de incremento de HL en 1 scanline) |
- | | + | ; desde el septimo scanline de la fila Y+1 al primero de la Y+2 |
- | LD A, L | + | ld a, l |
- | ADD A, 31 | + | add a, 31 |
- | LD L, A | + | ld l, a |
- | JR C, drawm16_nofix_abajop | + | jr c, drawm16_nofix_abajop |
- | LD A, H | + | ld a, h |
- | SUB 8 | + | |
- | LD H, A | + | ld h, a |
drawm16_nofix_abajop: | drawm16_nofix_abajop: | ||
- | + | ||
- | | + | ;;; Impresion de los segundos 2 bloques horizontales: |
- | LD B, 8 | + | ld b, 8 |
drawm16_loop2: | drawm16_loop2: | ||
- | LD A, (DE) ; Bloque 1: Leemos dato del sprite | + | ld a, (de) ; Bloque 1: Leemos dato del sprite |
- | LD (HL), A ; Copiamos dato a pantalla | + | |
- | INC DE ; Incrementar puntero en sprite | + | inc de ; Incrementar puntero en sprite |
- | INC L ; Incrementar puntero en pantalla | + | inc l ; Incrementar puntero en pantalla |
- | LD A, (DE) ; Bloque 2: Leemos dato del sprite | + | ld a, (de) ; Bloque 2: Leemos dato del sprite |
- | LD (HL), A ; Copiamos dato a pantalla | + | |
- | INC DE ; Incrementar puntero en sprite | + | inc de ; Incrementar puntero en sprite |
- | INC H ; Hay que sumar 256 para ir al siguiente scanline | + | inc h ; Hay que sumar 256 para ir al siguiente scanline |
- | DEC L ; pero hay que restar el INC L que hicimos. | + | dec l ; pero hay que restar el inc l que hicimos. |
- | DJNZ drawm16_loop2 | + | |
+ | |||
+ | |||
+ | ;;; En este punto, los 16 scanlines del tile estan dibujados. | ||
+ | ;;;;;; Impresion de la parte de atributos del tile ;;;;;; | ||
- | ;;; En este punto, los 16 scanlines del tile estan dibujados. | + | pop hl |
- | ;;;;;; Impresion de la parte de atributos | + | |
+ | ld a, h ; Codigo de Get_Attr_Offset_From_Image | ||
+ | rrca | ||
+ | rrca | ||
+ | rrca | ||
+ | and 3 | ||
+ | or $58 | ||
+ | ld d, a | ||
+ | ld e, l ; DE tiene el offset del attr de HL | ||
- | POP HL | + | ld hl, (DM_ATTRIBS) |
+ | ex af, af' | ||
+ | ld c, a | ||
+ | ld b, 0 | ||
+ | add hl, bc | ||
+ | add hl, bc | ||
+ | add hl, bc | ||
+ | add hl, bc ; HL = HL+HL=(DS_NUMSPR*4) = Origen | ||
- | ;;; Calcular posicion destino en area de atributos | + | ldi |
- | LD A, H ; Codigo de Get_Attr_Offset_From_Image | + | ldi ; Imprimimos la primeras fila de atributos |
- | | + | |
- | | + | |
- | | + | |
- | AND 3 | + | |
- | OR $58 | + | |
- | LD D, A | + | |
- | LD E, L ; DE tiene el offset del attr de HL | + | |
- | LD HL, (DM_ATTRIBS) | + | |
- | EX AF, AF' | + | ld a, e ; A = E |
- | LD C, A | + | add a, 30 ; Sumamos A = A + 30 mas los 2 INCs de ldi. |
- | LD B, 0 | + | ld e, a ; Guardamos en E (E = E+30 + 2 por ldi=E+32) |
- | ADD HL, BC | + | jr nc, drawm16_att_noinc |
- | ADD HL, BC | + | inc d |
- | ADD HL, BC | + | |
- | ADD HL, BC ; HL = HL+HL=(DS_NUMSPR*4) = Origen de atributo | + | |
- | + | ||
- | LDI | + | |
- | | + | |
- | + | ||
- | ;;; Avance diferencial a la siguiente linea de atributos | + | |
- | LD A, E ; A = E | + | |
- | ADD A, 30 ; Sumamos A = A + 30 mas los 2 INCs de LDI. | + | |
- | LD E, A ; Guardamos en E (E = E+30 + 2 por LDI=E+32) | + | |
- | JR NC, drawm16_att_noinc | + | |
- | INC D | + | |
drawm16_att_noinc: | drawm16_att_noinc: | ||
- | LDI | + | ldi |
- | LDI ; Imprimimos la segunda fila de atributos | + | |
- | POP HL ; Recuperamos el puntero al inicio | + | pop hl ; Recuperamos el puntero al inicio |
drawm16_next: | drawm16_next: | ||
- | INC L ; Avanzamos al siguiente tile en pantalla | + | inc l ; Avanzamos al siguiente tile en pantalla |
- | INC L ; horizontalmente | + | inc l ; horizontalmente |
- | POP BC ; Recuperamos el contador para el bucle | + | pop bc ; Recuperamos el contador para el bucle |
- | DEC B ; DJNZ se sale de rango, hay que usar DEC+JP | + | dec b ; djnz se sale de rango, hay que usar DEC+jp |
- | JP NZ, drawm16_xloop | + | jp nz, drawm16_xloop |
- | ;;; En este punto, hemos dibujado ANCHO tiles en pantalla (1 fila) | + | |
- | POP BC | + | pop bc |
- | DEC B ; Bucle vertical | + | dec b ; Bucle vertical |
- | JP NZ, drawm16_yloop | + | jp nz, drawm16_yloop |
- | RET | + | ret |
</ | </ | ||
Línea 514: | Línea 514: | ||
\\ | \\ | ||
- | 1.- Eliminar el **INC L** tras el **DJNZ | + | 1.- Eliminar el '' |
- | 2.- Eliminar los **INC DE**, **INC H** y **DEC L** antes del **DJNZ | + | 2.- Eliminar los '' |
\\ | \\ | ||
Línea 529: | Línea 529: | ||
<code z80> | <code z80> | ||
- | | + | ; Ejemplo impresion mapa de 16x16 |
- | ORG 32768 | + | ORG 35000 |
- | CALL ClearScreen_Pattern | + | call ClearScreen_Pattern |
- | LD HL, sokoban1_gfx | + | ld hl, sokoban1_gfx |
- | | + | |
- | LD HL, sokoban1_attr | + | ld hl, sokoban1_attr |
- | | + | |
- | LD HL, sokoban_LEVEL1 | + | ld hl, sokoban_LEVEL1 |
- | | + | |
- | LD A, 16 | + | ld a, 16 |
- | | + | |
- | LD A, 12 | + | ld a, 12 |
- | | + | |
- | XOR A | + | xor a |
- | | + | |
- | | + | |
- | + | ||
- | CALL DrawMap_16x16 | + | |
- | loop: | + | call DrawMap_16x16 |
- | JR loop | + | |
+ | loop: | ||
+ | jr loop | ||
; | ; | ||
ClearScreen_Pattern: | ClearScreen_Pattern: | ||
- | (...) ; Rellenado de fondo con un patron | + | |
- | RET ; (del capitulo de Sprites Lowres) | + | |
- | + | ||
; | ; | ||
- | DM_SPRITES | + | DM_SPRITES |
- | DM_ATTRIBS | + | DM_ATTRIBS |
- | DM_MAP | + | DM_MAP |
- | DM_COORD_X | + | DM_COORD_X |
- | DM_COORD_Y | + | DM_COORD_Y |
- | DM_WIDTH | + | DM_WIDTH |
- | DM_HEIGHT | + | DM_HEIGHT |
; | ; | ||
; Level 1 from Sokoban: | ; Level 1 from Sokoban: | ||
; | ; | ||
- | sokoban_LEVEL1: | + | sokoban_LEVEL1: |
- | DEFB 255, | + | DEFB 255, |
- | DEFB 255, | + | DEFB 255, |
- | DEFB 255, | + | DEFB 255, |
- | DEFB 255, | + | DEFB 255, |
- | DEFB 255, | + | DEFB 255, |
- | DEFB 255, | + | DEFB 255, |
- | DEFB 255, | + | DEFB 255, |
- | DEFB 255, | + | DEFB 255, |
- | DEFB 255, | + | DEFB 255, |
- | DEFB 255, | + | DEFB 255, |
- | DEFB 255, | + | DEFB 255, |
- | DEFB 255, | + | DEFB 255, |
- | + | ||
; | ; | ||
- | ; ASM source file created by SevenuP v1.20 | + | ; ASM source file created by SevenuP v1.20 |
; SevenuP (C) Copyright 2002-2006 by Jaime Tejedor Gomez, aka Metalbrain | ; SevenuP (C) Copyright 2002-2006 by Jaime Tejedor Gomez, aka Metalbrain | ||
; Pixel Size: ( 16, 128) - Char Size: | ; Pixel Size: ( 16, 128) - Char Size: | ||
Línea 597: | Línea 593: | ||
sokoban1_gfx: | sokoban1_gfx: | ||
- | | + | |
- | DEFB | + | DEFB |
- | DEFB 127, | + | DEFB 127, |
- | DEFB | + | DEFB |
- | DEFB 127, | + | DEFB 127, |
- | DEFB 131, | + | DEFB 131, |
- | DEFB 255, | + | DEFB 255, |
- | DEFB 255, | + | DEFB 255, |
- | DEFB 127, | + | DEFB 127, |
- | DEFB 195, | + | DEFB 195, |
- | DEFB 255, | + | DEFB 255, |
- | DEFB 255, | + | DEFB 255, |
- | DEFB | + | DEFB |
- | DEFB 107, | + | DEFB 107, |
- | DEFB | + | DEFB |
- | DEFB 96, 6, 96, 6, 0, 0, 96, 6, 96, 6, | + | DEFB 96, 6, 96, 6, 0, 0, 96, 6, 96, 6, |
sokoban1_attr: | sokoban1_attr: | ||
- | | + | |
- | DEFB 5, 69, 69, 71, 69, 69, 71, 71, 2, 66, 66, 67, 6, 70, 70, 71 | + | DEFB 5, 69, 69, 71, 69, 69, 71, 71, 2, 66, 66, 67, 6, 70, 70, 71 |
+ | |||
+ | END 35000 | ||
</ | </ | ||
Línea 622: | Línea 620: | ||
\\ | \\ | ||
- | {{ : | + | {{ : |
\\ | \\ | ||
- | | + | |
La misma pantalla codificada con un tamaño de 7x9 e impresa a partir de las coordenadas de pantalla (8,3) ocuparía 63 bytes en lugar de 192 y produciría el mismo resultado visual: | La misma pantalla codificada con un tamaño de 7x9 e impresa a partir de las coordenadas de pantalla (8,3) ocuparía 63 bytes en lugar de 192 y produciría el mismo resultado visual: | ||
Línea 633: | Línea 631: | ||
; Level 1 from Sokoban (7x9): | ; Level 1 from Sokoban (7x9): | ||
; | ; | ||
- | sokoban_LEVEL1: | + | sokoban_LEVEL1: |
- | DEFB 255, | + | DEFB 255, |
- | DEFB | + | DEFB |
- | DEFB | + | DEFB |
- | DEFB | + | DEFB |
- | DEFB | + | DEFB |
- | DEFB | + | DEFB |
- | DEFB 255, | + | DEFB 255, |
- | DEFB 255, | + | DEFB 255, |
- | DEFB 255, | + | DEFB 255, |
</ | </ | ||
Línea 648: | Línea 646: | ||
<code z80> | <code z80> | ||
- | LD HL, sokoban1_gfx | + | ld hl, sokoban1_gfx |
- | | + | |
- | LD HL, sokoban1_attr | + | ld hl, sokoban1_attr |
- | | + | |
- | LD HL, sokoban_LEVEL1 | + | ld hl, sokoban_LEVEL1 |
- | | + | |
- | LD A, 7 | + | ld a, 7 |
- | | + | |
- | LD A, 9 | + | ld a, 9 |
- | | + | |
- | LD A, 8 | + | ld a, 8 |
- | | + | |
- | LD A, 3 | + | ld a, 3 |
- | | + | |
- | | + | |
</ | </ | ||
- | Si tenemos pantallas de diferentes tamaños podemos almacenarlas en memoria utilizando una estructura de datos con 4 bytes de información por pantalla: ancho, alto, x_inicial e y_inicial. De esta forma cada pantalla ocuparía en memoria sólo el espacio necesario para definirla, sin necesidad de que todas las pantallas se adapten a un tamaño común. Nuestra rutina de cambio de pantalla recogería estos 4 bytes de datos de la tabla de " | + | Si tenemos pantallas de diferentes tamaños podemos almacenarlas en memoria utilizando una estructura de datos con 4 bytes de información por pantalla: |
Esto puede valer para juegos como Sokoban (donde cada pantalla puede tener un tamaño diferente) pero no para juegos tipo plataformas/ | Esto puede valer para juegos como Sokoban (donde cada pantalla puede tener un tamaño diferente) pero no para juegos tipo plataformas/ | ||
Línea 680: | Línea 678: | ||
; | ; | ||
DrawMap_8x8: | DrawMap_8x8: | ||
- | + | ||
- | | + | ;;;;;; Impresion de la parte grafica de los tiles ;;;;;; |
- | LD IX, (DM_MAP) | + | ld ix, (DM_MAP) |
- | LD A, (DM_HEIGHT) | + | ld a, (DM_HEIGHT) |
- | LD B, A ; B = ALTO_EN_TILES (para bucle altura) | + | ld b, a ; B = ALTO_EN_TILES (para bucle altura) |
drawm8_yloop: | drawm8_yloop: | ||
- | PUSH BC ; Guardamos el valor de B | + | push bc ; Guardamos el valor de B |
- | LD A, (DM_HEIGHT) | + | ld a, (DM_HEIGHT) |
- | SUB B ; A = ALTO - iteracion_bucle = Y actual | + | sub b ; A = ALTO - iteracion_bucle = Y actual |
- | | + | ;;; NUEVO: Eliminamos |
- | ;;; Calculamos la direccion destino en pantalla como | + | |
- | | + | ;;; DIR_PANT = DIRECCION(X_INICIAL, |
- | LD BC, (DM_COORD_X) | + | ld bc, (DM_COORD_X) |
- | ADD A, B | + | add a, b |
- | LD B, A | + | ld b, a |
- | LD A, B | + | ld a, b |
- | AND $18 | + | |
- | ADD A, $40 | + | add a, $40 |
- | LD H, A | + | ld h, a |
- | LD A, B | + | ld a, b |
- | AND 7 | + | |
- | RRCA | + | rrca |
- | RRCA | + | rrca |
- | RRCA | + | rrca |
- | ADD A, C | + | add a, c |
- | LD L, A ; HL = DIR_PANTALLA(X_INICIAL, | + | ld l, a ; HL = DIR_PANTALLA(X_INICIAL, |
- | LD A, (DM_WIDTH) | + | ld a, (DM_WIDTH) |
- | LD B, A ; B = ANCHO_EN_TILES | + | ld b, a ; B = ANCHO_EN_TILES |
drawm8_xloop: | drawm8_xloop: | ||
- | PUSH BC ; Nos guardamos el contador del bucle | + | push bc ; Nos guardamos el contador del bucle |
+ | |||
+ | ld a, (ix+0) | ||
+ | inc ix ; Apuntamos al siguiente byte del mapa | ||
- | LD A, (IX+0) | + | cp 255 ; Bloque especial a saltar: no se dibuja |
- | INC IX ; Apuntamos al siguiente byte del mapa | + | jp z, drawm8_next |
- | CP 255 | + | ld b, a |
- | JP Z, drawm8_next | + | ex af, af' |
+ | ld a, b | ||
- | LD B, A | + | ;;; Calcular posicion origen (array sprites) en HL como: |
- | EX AF, AF' | + | ;;; |
- | LD A, B | + | ex de, hl ; Intercambiamos DE y HL (DE=destino) |
+ | ld bc, (DM_SPRITES) | ||
+ | ld l, a | ||
+ | ld h, 0 | ||
+ | add hl, hl | ||
+ | add hl, hl | ||
+ | add hl, hl ;;; NUEVO: NUM_SPRITE*8 | ||
+ | add hl, bc ; HL = BC + HL = DM_SPRITES + (DM_NUMSPR * 8) | ||
+ | ex de, hl ; Intercambiamos DE y HL (DE=origen, HL=destino) | ||
- | ;;; Calcular posicion origen (array sprites) en HL como: | + | |
- | ;;; | + | push hl |
- | EX DE, HL ; Intercambiamos DE y HL (DE=destino) | + | |
- | LD BC, (DM_SPRITES) | + | |
- | LD L, A | + | |
- | LD H, 0 | + | |
- | ADD HL, HL | + | |
- | ADD HL, HL | + | |
- | ADD HL, HL ;;; NUEVO: NUM_SPRITE*8 en lugar de *32 | + | |
- | ADD HL, BC ; HL = BC + HL = DM_SPRITES + (DM_NUMSPR * 8) | + | |
- | EX DE, HL ; Intercambiamos DE y HL (DE=origen, HL=destino) | + | |
- | PUSH HL ; Guardamos el puntero a pantalla recien calculado | + | |
- | PUSH HL | + | ld b, 8 |
- | ;;; Impresion | + | drawm8_loop: |
- | LD B, 8 | + | ld a, (de) ; Bloque 1: Leemos dato del sprite |
+ | ld (hl), a ; Copiamos dato a pantalla | ||
+ | inc de ; Incrementar puntero en sprite | ||
+ | inc h ; Hay que sumar 256 para ir al siguiente scanline | ||
+ | djnz drawm8_loop | ||
- | drawm8_loop: | + | |
- | LD A, (DE) ; Bloque 1: Leemos dato del sprite | + | |
- | LD (HL), A ; Copiamos dato a pantalla | + | |
- | INC DE ; Incrementar puntero en sprite | + | |
- | INC H ; Hay que sumar 256 para ir al siguiente scanline | + | |
- | DJNZ drawm8_loop | + | |
- | + | ||
- | ;;; En este punto, los 8 scanlines del tile estan dibujados. | + | |
- | ;;;;;; Impresion de la parte de atributos del tile ;;;;;; | + | |
- | POP HL ; Recuperar puntero a inicio de tile | + | pop hl ; Recuperar puntero a inicio de tile |
- | ;;; Calcular posicion destino en area de atributos en DE. | + | |
- | LD A, H ; Codigo de Get_Attr_Offset_From_Image | + | ld a, h ; Codigo de Get_Attr_Offset_From_Image |
- | RRCA | + | rrca |
- | RRCA | + | rrca |
- | RRCA | + | rrca |
- | AND 3 | + | |
- | OR $58 | + | |
- | LD D, A | + | ld d, a |
- | LD E, L ; DE tiene el offset del attr de HL | + | ld e, l ; DE tiene el offset del attr de HL |
- | LD HL, (DM_ATTRIBS) | + | ld hl, (DM_ATTRIBS) |
- | EX AF, AF' | + | ex af, af' |
- | LD C, A | + | ld c, a |
- | LD B, 0 ;;; NUEVO: HL = HL+DM_NUMSPR (NO *4) | + | ld b, 0 ;;; NUEVO: HL = HL+DM_NUMSPR (NO *4) |
- | ADD HL, BC ; HL = HL+DM_NUMSPR = Origen de atributo | + | add hl, bc ; HL = HL+DM_NUMSPR = Origen de atributo |
- | LD A, (HL) | + | ld a, (hl) |
- | LD (DE), A ;;; NUEVO: Impresion de un unico atributo. | + | |
- | POP HL ; Recuperamos el puntero al inicio | + | pop hl ; Recuperamos el puntero al inicio |
drawm8_next: | drawm8_next: | ||
- | INC L ; Avanzamos al siguiente tile en pantalla | + | inc l ; Avanzamos al siguiente tile en pantalla |
- | POP BC ; Recuperamos el contador para el bucle | + | pop bc ; Recuperamos el contador para el bucle |
- | DEC B ; DJNZ se sale de rango, hay que usar DEC+JP | + | dec b ; djnz se sale de rango, hay que usar DEC+jp |
- | JP NZ, drawm8_xloop | + | jp nz, drawm8_xloop |
- | ;;; En este punto, hemos dibujado ANCHO tiles en pantalla (1 fila) | + | |
- | POP BC | + | pop bc |
- | DEC B ; Bucle vertical | + | dec b ; Bucle vertical |
- | JP NZ, drawm8_yloop | + | jp nz, drawm8_yloop |
- | RET | + | ret |
</ | </ | ||
Línea 812: | Línea 810: | ||
Hay 2 posibilidades de agrupación de las pantallas: como un **array de pantallas**, | Hay 2 posibilidades de agrupación de las pantallas: como un **array de pantallas**, | ||
- | + | ||
\\ | \\ | ||
==== Mapa como array de pantallas ==== | ==== Mapa como array de pantallas ==== | ||
Línea 819: | Línea 817: | ||
Para hacer uso de este sistema debemos almacenar cada pantalla en memoria con una etiqueta identificativa para nuestro programa ensamblador: | Para hacer uso de este sistema debemos almacenar cada pantalla en memoria con una etiqueta identificativa para nuestro programa ensamblador: | ||
- | + | ||
<code z80> | <code z80> | ||
Pantalla_Inicio: | Pantalla_Inicio: | ||
- | | + | |
- | + | ||
Pantalla_Salon: | Pantalla_Salon: | ||
- | | + | |
- | + | ||
Pantalla_Pasillo: | Pantalla_Pasillo: | ||
- | | + | |
- | + | ||
Pantalla_Escalera: | Pantalla_Escalera: | ||
- | | + | |
(...) | (...) | ||
Línea 840: | Línea 838: | ||
<code z80> | <code z80> | ||
Mapa: | Mapa: | ||
- | | + | |
- | DW Pantalla_Salon | + | DW Pantalla_Salon |
- | DW Pantalla_Pasillo | + | DW Pantalla_Pasillo |
- | DW Pantalla_Escalera | + | DW Pantalla_Escalera |
- | (...) ; (etc...) | + | (...) ; (etc...) |
- | DW 0000 ; Fin de pantalla | + | DW 0000 ; Fin de pantalla |
</ | </ | ||
Línea 863: | Línea 861: | ||
<code z80> | <code z80> | ||
- | | + | |
- | LD BC, Mapa ; BC = Inicio de la tabla Mapa | + | ld bc, Mapa ; BC = Inicio de la tabla Mapa |
- | LD A, (pantalla_actual) | + | ld a, (pantalla_actual) |
- | LD L, A | + | ld l, a |
- | LD H, 0 ; HL = Pantalla actual | + | ld h, 0 ; HL = Pantalla actual |
- | SLA L | + | sla l |
- | | + | |
- | ADD HL, BC ; HL = Mapa + (Pantalla actual * 2) | + | add hl, bc ; HL = Mapa + (Pantalla actual * 2) |
- | + | ||
- | ;;; Ahora leemos de (HL) la dirección de dibujado en el mismo HL | + | ;;; Ahora leemos de (HL) la dirección de dibujado en el mismo HL |
- | LD A, (HL) ; Leemos la parte baja de la direccion en A | + | ld a, (hl) ; Leemos la parte baja de la direccion en A |
- | INC HL ; ... para no corromper HL y poder leer ... | + | inc hl ; ... para no corromper HL y poder leer ... |
- | PUSH HL | + | push hl |
- | LD H, (HL) ; ... la parte alta sobre H ... | + | ld h, (hl) ; ... la parte alta sobre H ... |
- | LD L, A | + | ld l, a |
- | | + | |
- | | + | |
</ | </ | ||
Línea 897: | Línea 895: | ||
;;; conexion con otras pantallas: | ;;; conexion con otras pantallas: | ||
;;; | ;;; | ||
- | ;;; Formato de cada pantalla + conexiones: | + | ;;; Formato de cada pantalla + conexiones: |
;;; | ;;; | ||
;;; DW DIR_DATOSPANTALLA | ;;; DW DIR_DATOSPANTALLA | ||
Línea 903: | Línea 901: | ||
Mapa: | Mapa: | ||
- | | + | |
- | DB -1, 1 ; Conexiones izq y derecha ID 0 | + | DB -1, 1 ; Conexiones izq y derecha ID 0 |
- | DW Pantalla_Salon | + | DW Pantalla_Salon |
- | DB 0, 2 ; Conexiones izq y derecha ID 1 | + | DB 0, 2 ; Conexiones izq y derecha ID 1 |
- | DW Pantalla_Pasillo | + | DW Pantalla_Pasillo |
- | DB 1, 3 ; Conexiones izq y derecha ID 2 | + | DB 1, 3 ; Conexiones izq y derecha ID 2 |
- | DW Pantalla_Escalera | + | DW Pantalla_Escalera |
- | DB 3, -1 ; Conexiones izq y derecha ID 3 | + | DB 3, -1 ; Conexiones izq y derecha ID 3 |
- | (...) | + | (...) |
</ | </ | ||
Línea 926: | Línea 924: | ||
<code z80> | <code z80> | ||
BYTES_POR_PANTALLA | BYTES_POR_PANTALLA | ||
- | RUTINA_ROM_HL_POR_DE | + | RUTINA_ROM_HL_POR_DE |
; | ; | ||
; Obtener direccion donde se alojan los datos de la pantalla | ; Obtener direccion donde se alojan los datos de la pantalla | ||
- | ; Entrada: | + | ; Entrada: |
; L = pantalla | ; L = pantalla | ||
; BC = Mapa (direccion base) | ; BC = Mapa (direccion base) | ||
Línea 937: | Línea 935: | ||
; | ; | ||
Get_Screen_Pointer: | Get_Screen_Pointer: | ||
- | LD H, 0 | + | ld h, 0 |
- | LD D, H ; HL = PANTALLA | + | ld d, h ; HL = PANTALLA |
- | LD E, BYTES_POR_PANTALLA | + | ld e, BYTES_POR_PANTALLA |
- | | + | |
- | ADD HL, BC ; Lo sumamos al inicio del MAPA | + | add hl, bc ; Lo sumamos al inicio del MAPA |
- | | + | |
</ | </ | ||
Para realizar la multiplicación hemos utilizado la rutina HL=HL*DE de la ROM del Spectrum. Si no estamos en un Spectrum sino que estamos programando para otro sistema Z80, bastará con llamar a la rutina de multiplicación adecuada. | Para realizar la multiplicación hemos utilizado la rutina HL=HL*DE de la ROM del Spectrum. Si no estamos en un Spectrum sino que estamos programando para otro sistema Z80, bastará con llamar a la rutina de multiplicación adecuada. | ||
- | | + | |
Ahora ya podemos acceder a los datos de una pantalla concreta: | Ahora ya podemos acceder a los datos de una pantalla concreta: | ||
<code z80> | <code z80> | ||
- | | + | |
- | LD HL, sokoban1_gfx | + | ld hl, sokoban1_gfx |
- | | + | |
- | LD HL, sokoban1_attr | + | ld hl, sokoban1_attr |
- | | + | |
- | LD A, 16 | + | ld a, 16 |
- | | + | |
- | LD A, 12 | + | ld a, 12 |
- | | + | |
- | XOR A | + | xor a |
- | | + | |
- | | + | |
- | | + | |
- | + | ||
- | ;;; En el bucle principal de nuestro programa: | + | ;;; En el bucle principal de nuestro programa: |
DibujarPantalla: | DibujarPantalla: | ||
- | LD BC, Mapa | + | ld bc, Mapa |
- | LD A, (pantalla_actual) | + | ld a, (pantalla_actual) |
- | LD L, A | + | ld l, a |
- | | + | |
- | LD A, (HL) ; Leemos la parte baja de la direccion en A | + | ld a, (hl) ; Leemos la parte baja de la direccion en A |
- | INC HL ; ... para no corromper HL y poder leer ... | + | inc hl ; ... para no corromper HL y poder leer ... |
- | PUSH HL | + | push hl |
- | LD H, (HL) ; ... la parte alta sobre H ... | + | ld h, (hl) ; ... la parte alta sobre H ... |
- | LD L, A | + | ld l, a |
- | | + | |
- | | + | |
- | POP HL ; Recuperamos el puntero a datos de pantalla | + | pop hl ; Recuperamos el puntero a datos de pantalla |
- | INC HL ; Avanzamos hasta el primer ID de conexion | + | inc hl ; Avanzamos hasta el primer ID de conexion |
- | LD A, (HL) ; Leemos conexion izquierda | + | ld a, (hl) ; Leemos conexion izquierda |
- | | + | |
- | INC HL ; Avanzamos hasta el segundo ID de conexion | + | inc hl ; Avanzamos hasta el segundo ID de conexion |
- | LD A, (HL) ; Leemos conexion a derecha | + | ld a, (hl) ; Leemos conexion a derecha |
- | | + | |
</ | </ | ||
Línea 996: | Línea 994: | ||
<code z80> | <code z80> | ||
Mapa: | Mapa: | ||
- | | + | |
- | DW Pantalla_Salon | + | DW Pantalla_Salon |
- | DW Pantalla_Pasillo | + | DW Pantalla_Pasillo |
- | DW Pantalla_Escalera | + | DW Pantalla_Escalera |
- | (...) | + | (...) |
- | + | ||
Conexiones: | Conexiones: | ||
- | | + | |
- | DB 0, 2 ; Conexiones izq y derecha ID 1 | + | DB 0, 2 ; Conexiones izq y derecha ID 1 |
- | DB 1, 3 ; Conexiones izq y derecha ID 2 | + | DB 1, 3 ; Conexiones izq y derecha ID 2 |
- | DB 3, -1 ; Conexiones izq y derecha ID 3 | + | DB 3, -1 ; Conexiones izq y derecha ID 3 |
- | (...) | + | (...) |
</ | </ | ||
Línea 1031: | Línea 1029: | ||
<code z80> | <code z80> | ||
Mapa: | Mapa: | ||
- | | + | |
- | DW -1, 1 ; Conexiones izq y derecha ID 0 | + | DW -1, 1 ; Conexiones izq y derecha ID 0 |
</ | </ | ||
Línea 1042: | Línea 1040: | ||
;;; Vector de direcciones de pantalla. | ;;; Vector de direcciones de pantalla. | ||
Mapa: | Mapa: | ||
- | | + | |
- | DB -1, 1 ; Conexiones izq y derecha ID 0 | + | DB -1, 1 ; Conexiones izq y derecha ID 0 |
- | DW titulo_inicio | + | DW titulo_inicio |
- | DW Pantalla_Salon | + | DW Pantalla_Salon |
- | DB 0, 2 ; Conexiones izq y derecha ID 1 | + | DB 0, 2 ; Conexiones izq y derecha ID 1 |
- | DW titulo_salon | + | DW titulo_salon |
- | DW Pantalla_Pasillo | + | DW Pantalla_Pasillo |
- | DB 1, 3 ; Conexiones izq y derecha ID 2 | + | DB 1, 3 ; Conexiones izq y derecha ID 2 |
- | DW titulo_pasillo | + | DW titulo_pasillo |
- | DW Pantalla_Escalera | + | DW Pantalla_Escalera |
- | DW titulo_escalera | + | DW titulo_escalera |
- | DB 3, -1 ; Conexiones izq y derecha ID 3 | + | DB 3, -1 ; Conexiones izq y derecha ID 3 |
- | (...) | + | (...) |
titulo_inicio | titulo_inicio | ||
Línea 1086: | Línea 1084: | ||
<code z80> | <code z80> | ||
Mapa: | Mapa: | ||
- | | + | |
- | DB -1, 1 ; Conexiones izq y derecha ID 0 | + | DB -1, 1 ; Conexiones izq y derecha ID 0 |
- | DW Pantalla_Salon | + | DW Pantalla_Salon |
- | DB 0, 2 ; Conexiones izq y derecha ID 1 | + | DB 0, 2 ; Conexiones izq y derecha ID 1 |
- | DW Pantalla_Pasillo | + | DW Pantalla_Pasillo |
- | DB 1, 3 ; Conexiones izq y derecha ID 2 | + | DB 1, 3 ; Conexiones izq y derecha ID 2 |
- | DW Pantalla_Pasillo | + | DW Pantalla_Pasillo |
- | DB 2, 4 ; Conexiones izq y derecha ID 3 | + | DB 2, 4 ; Conexiones izq y derecha ID 3 |
- | DW Pantalla_Pasillo | + | DW Pantalla_Pasillo |
- | DB 3, 5 ; Conexiones izq y derecha ID 4 | + | DB 3, 5 ; Conexiones izq y derecha ID 4 |
- | DW Pantalla_Escalera | + | DW Pantalla_Escalera |
- | DB 4, -1 ; Conexiones izq y derecha ID 5 | + | DB 4, -1 ; Conexiones izq y derecha ID 5 |
- | (...) | + | (...) |
</ | </ | ||
Línea 1136: | Línea 1134: | ||
Mapa | Mapa | ||
- | DB A, | + | |
- | DB A, | + | DB A, |
- | DB A, | + | DB A, |
- | DB A, | + | DB A, |
- | DB A, | + | DB A, |
- | DB A, | + | DB A, |
- | DB A, | + | DB A, |
- | DB A, | + | DB A, |
- | DB C, | + | DB C, |
- | DB C, | + | DB C, |
- | DB C, | + | DB C, |
- | DB C, | + | DB C, |
- | DB C, | + | DB C, |
- | DB C, | + | DB C, |
- | DB C, | + | DB C, |
- | DB C, | + | DB C, |
</ | </ | ||
Línea 1160: | Línea 1158: | ||
Por ejemplo, supongamos que la posición inicial del área de visión es (0,0), con lo que la primera pantalla impresa serán los 8x8 bloques " | Por ejemplo, supongamos que la posición inicial del área de visión es (0,0), con lo que la primera pantalla impresa serán los 8x8 bloques " | ||
- | La impresión de este tipo de pantallas requiere una rutina similar a las rutinas de impresión sin agrupación que ya hemos visto (DrawMap_16x16), | + | La impresión de este tipo de pantallas requiere una rutina similar a las rutinas de impresión sin agrupación que ya hemos visto ('' |
\\ | \\ | ||
- | * Cambio 1: Debe de calcular la posición inicial de lectura de datos para la impresión como **Mapa + (ymapa*ANCHO_MAPA) + xmapa**. | + | * Cambio 1: Debe de calcular la posición inicial de lectura de datos para la impresión como '' |
- | * Cambio 2: Una vez impreso un scanline horizontal de ANCHO_PANTALLA datos, debe de avanzar el registro usado como puntero de datos en el mapa un total de **ANCHO_MAPA-ANCHO_PANTALLA** bytes (para posicionarse en el siguiente scanline de datos del mapa). | + | * Cambio 2: Una vez impreso un scanline horizontal de '' |
\\ | \\ | ||
Línea 1171: | Línea 1169: | ||
<code z80> | <code z80> | ||
DrawMap_16x16_Map: | DrawMap_16x16_Map: | ||
- | |||
- | LD IX, (DM_MAP) | ||
- | ;;; NUEVO: Posicionamos el puntero de mapa en posicion inicial. | + | ld ix, (DM_MAP) |
- | LD HL, (DM_MAPY) | + | |
- | LD DE, ANCHO_MAPA_TILES | + | ;;; NUEVO: Posicionamos el puntero de mapa en posicion inicial. |
- | CALL MULT_HL_POR_DE | + | ld hl, (DM_MAPY) |
- | LD BC, (DM_MAPX) | + | ld de, ANCHO_MAPA_TILES |
- | ADD HL, BC ; HL = MAPA_X + (ANCHO_MAPA * MAPA_Y) | + | |
- | EX DE, HL | + | ld bc, (DM_MAPX) |
- | ADD IX, DE ; IX = Inicio_Mapa + HL | + | add hl, bc ; HL = MAPA_X + (ANCHO_MAPA * MAPA_Y) |
- | | + | ex de, hl |
+ | add ix, de ; IX = Inicio_Mapa + HL | ||
+ | ;;; FIN NUEVO | ||
</ | </ | ||
Línea 1188: | Línea 1186: | ||
<code z80> | <code z80> | ||
- | ;;; NUEVO: Incrementar puntero de mapa a siguiente linea | + | |
- | LD BC, ANCHO_MAPA_TILES - ANCHO_PANTALLA | + | ld bc, ANCHO_MAPA_TILES - ANCHO_PANTALLA |
- | ADD IX, BC | + | add ix, bc |
- | | + | ;;; FIN NUEVO |
- | ;;; En este punto, hemos dibujado ANCHO tiles en pantalla (1 fila) | + | |
- | POP BC | + | pop bc |
- | DEC B ; Bucle vertical | + | dec b ; Bucle vertical |
- | JP NZ, drawmg16_yloop | + | jp nz, drawmg16_yloop |
- | RET | + | ret |
</ | </ | ||
Línea 1205: | Línea 1203: | ||
<code z80> | <code z80> | ||
; | ; | ||
- | DM_SPRITES | + | DM_SPRITES |
- | DM_ATTRIBS | + | DM_ATTRIBS |
- | DM_MAP | + | DM_MAP |
- | DM_COORD_X | + | DM_COORD_X |
- | DM_COORD_Y | + | DM_COORD_Y |
- | DM_WIDTH | + | DM_WIDTH |
- | DM_HEIGHT | + | DM_HEIGHT |
- | DM_MAPX | + | DM_MAPX |
- | DM_MAPY | + | DM_MAPY |
; | ; | ||
Línea 1224: | Línea 1222: | ||
ALTO_PANTALLA | ALTO_PANTALLA | ||
- | ;;; Rutina de la ROM del Spectrum, en otros sistemas | + | ;;; Rutina de la ROM del Spectrum, en otros sistemas |
;;; sustituir por una rutina especifica de multiplicacion | ;;; sustituir por una rutina especifica de multiplicacion | ||
- | MULT_HL_POR_DE | + | MULT_HL_POR_DE |
; | ; | ||
Línea 1247: | Línea 1244: | ||
; | ; | ||
DrawMap_16x16_Map: | DrawMap_16x16_Map: | ||
- | |||
- | LD IX, (DM_MAP) | ||
- | ;;; NUEVO: Posicionamos el puntero de mapa en posicion inicial. | + | ld ix, (DM_MAP) |
- | LD HL, (DM_MAPY) | + | |
- | LD DE, ANCHO_MAPA_TILES | + | |
- | CALL MULT_HL_POR_DE | + | |
- | LD BC, (DM_MAPX) | + | |
- | ADD HL, BC ; HL = MAPA_X + (ANCHO_MAPA * MAPA_Y) | + | |
- | EX DE, HL | + | |
- | | + | |
- | ;;; FIN NUEVO | + | |
- | LD A, (DM_HEIGHT) | + | ;;; NUEVO: Posicionamos el puntero de mapa en posicion inicial. |
- | LD B, A ; B = ALTO_EN_TILES (para bucle altura) | + | ld hl, (DM_MAPY) |
+ | ld de, ANCHO_MAPA_TILES | ||
+ | call MULT_HL_POR_DE | ||
+ | ld bc, (DM_MAPX) | ||
+ | add hl, bc ; HL = MAPA_X + (ANCHO_MAPA * MAPA_Y) | ||
+ | ex de, hl | ||
+ | add ix, de ; IX = Inicio_Mapa + HL | ||
+ | ;;; FIN NUEVO | ||
+ | |||
+ | ld a, (DM_HEIGHT) | ||
+ | ld b, a ; B = ALTO_EN_TILES (para bucle altura) | ||
drawmg16_yloop: | drawmg16_yloop: | ||
- | PUSH BC ; Guardamos el valor de B | + | push bc ; Guardamos el valor de B |
- | LD A, (DM_HEIGHT) | + | ld a, (DM_HEIGHT) |
- | SUB B ; A = ALTO - iteracion_bucle = Y actual | + | sub b ; A = ALTO - iteracion_bucle = Y actual |
- | RLCA ; A = Y * 2 | + | |
- | ;;; Calculamos la direccion destino en pantalla como | + | |
- | | + | ;;; DIR_PANT = DIRECCION(X_INICIAL, |
- | LD BC, (DM_COORD_X) | + | ld bc, (DM_COORD_X) |
- | ADD A, B | + | add a, b |
- | LD B, A | + | ld b, a |
- | LD A, B | + | ld a, b |
- | AND $18 | + | |
- | ADD A, $40 | + | add a, $40 |
- | LD H, A | + | ld h, a |
- | LD A, B | + | ld a, b |
- | AND 7 | + | |
- | RRCA | + | rrca |
- | RRCA | + | rrca |
- | RRCA | + | rrca |
- | ADD A, C | + | add a, c |
- | LD L, A ; HL = DIR_PANTALLA(X_INICIAL, | + | ld l, a ; HL = DIR_PANTALLA(X_INICIAL, |
- | LD A, (DM_WIDTH) | + | ld a, (DM_WIDTH) |
- | LD B, A ; B = ANCHO_EN_TILES | + | ld b, a ; B = ANCHO_EN_TILES |
drawmg16_xloop: | drawmg16_xloop: | ||
- | PUSH BC ; Nos guardamos el contador del bucle | + | push bc ; Nos guardamos el contador del bucle |
- | LD A, (IX+0) ; Leemos un byte del mapa | + | ld a, (ix+0) ; Leemos un byte del mapa |
- | INC IX ; Apuntamos al siguiente byte del mapa | + | inc ix ; Apuntamos al siguiente byte del mapa |
- | | + | cp 255 ; Bloque especial a saltar: no se dibuja |
- | JP Z, drawmg16_next | + | jp z, drawmg16_next |
- | LD B, A | + | ld b, a |
- | EX AF, AF' | + | ex af, af' |
- | LD A, B | + | ld a, b |
- | ;;; Calcular posicion origen (array sprites) en HL como: | + | |
- | | + | ;;; |
- | EX DE, HL ; Intercambiamos DE y HL (DE=destino) | + | ex de, hl ; Intercambiamos DE y HL (DE=destino) |
- | LD BC, (DM_SPRITES) | + | ld bc, (DM_SPRITES) |
- | LD L, 0 | + | ld l, 0 |
- | SRL A | + | srl a |
- | RR L | + | rr l |
- | RRA | + | rra |
- | RR L | + | rr l |
- | RRA | + | rra |
- | RR L | + | rr l |
- | LD H, A | + | ld h, a |
- | ADD HL, BC ; HL = BC + HL = DM_SPRITES + (DM_NUMSPR * 32) | + | add hl, bc ; HL = BC + HL = DM_SPRITES + (DM_NUMSPR * 32) |
- | EX DE, HL ; Intercambiamos DE y HL (DE=origen, HL=destino) | + | ex de, hl ; Intercambiamos DE y HL (DE=origen, HL=destino) |
- | PUSH HL ; Guardamos el puntero a pantalla recien calculado | + | push hl ; Guardamos el puntero a pantalla recien calculado |
- | PUSH HL | + | push hl |
- | ;;; Impresion de los primeros 2 bloques horizontales del tile | + | |
- | LD B, 8 | + | ld b, 8 |
drawmg16_loop1: | drawmg16_loop1: | ||
- | + | ||
- | LD A, (DE) ; Bloque 1: Leemos dato del sprite | + | ld a, (de) ; Bloque 1: Leemos dato del sprite |
- | LD (HL), A ; Copiamos dato a pantalla | + | |
- | INC DE ; Incrementar puntero en sprite | + | inc de ; Incrementar puntero en sprite |
- | INC L ; Incrementar puntero en pantalla | + | inc l ; Incrementar puntero en pantalla |
- | LD A, (DE) ; Bloque 2: Leemos dato del sprite | + | ld a, (de) ; Bloque 2: Leemos dato del sprite |
- | LD (HL), A ; Copiamos dato a pantalla | + | |
- | INC DE ; Incrementar puntero en sprite | + | inc de ; Incrementar puntero en sprite |
- | INC H ; Hay que sumar 256 para ir al siguiente scanline | + | inc h ; Hay que sumar 256 para ir al siguiente scanline |
- | DEC L ; pero hay que restar el INC L que hicimos. | + | dec l ; pero hay que restar el inc l que hicimos. |
- | DJNZ drawmg16_loop1 | + | |
- | INC L ; Decrementar el ultimo incrementado en el bucle | + | inc l ; Decrementar el ultimo incrementado en el bucle |
- | + | ||
- | | + | ; Avanzamos HL 1 scanline (codigo de incremento de HL en 1 scanline) |
- | | + | ; desde el septimo scanline de la fila Y+1 al primero de la Y+2 |
- | LD A, L | + | ld a, l |
- | ADD A, 31 | + | add a, 31 |
- | LD L, A | + | ld l, a |
- | JR C, drawmg16_nofix_abajop | + | jr c, drawmg16_nofix_abajop |
- | LD A, H | + | ld a, h |
- | SUB 8 | + | |
- | LD H, A | + | ld h, a |
drawmg16_nofix_abajop: | drawmg16_nofix_abajop: | ||
- | + | ||
- | | + | ;;; Impresion de los segundos 2 bloques horizontales: |
- | LD B, 8 | + | ld b, 8 |
drawmg16_loop2: | drawmg16_loop2: | ||
- | LD A, (DE) ; Bloque 1: Leemos dato del sprite | + | ld a, (de) ; Bloque 1: Leemos dato del sprite |
- | LD (HL), A ; Copiamos dato a pantalla | + | |
- | INC DE ; Incrementar puntero en sprite | + | inc de ; Incrementar puntero en sprite |
- | INC L ; Incrementar puntero en pantalla | + | inc l ; Incrementar puntero en pantalla |
- | LD A, (DE) ; Bloque 2: Leemos dato del sprite | + | ld a, (de) ; Bloque 2: Leemos dato del sprite |
- | LD (HL), A ; Copiamos dato a pantalla | + | |
- | INC DE ; Incrementar puntero en sprite | + | inc de ; Incrementar puntero en sprite |
- | INC H ; Hay que sumar 256 para ir al siguiente scanline | + | inc h ; Hay que sumar 256 para ir al siguiente scanline |
- | DEC L ; pero hay que restar el INC L que hicimos. | + | dec l ; pero hay que restar el inc l que hicimos. |
- | DJNZ drawmg16_loop2 | + | |
- | ;;; En este punto, los 16 scanlines del tile estan dibujados. | + | |
- | ;;;;;; Impresion de la parte de atributos del tile ;;;;;; | + | |
- | POP HL ; Recuperar puntero a inicio de tile | + | pop hl ; Recuperar puntero a inicio de tile |
- | ;;; Calcular posicion destino en area de atributos en DE. | + | |
- | LD A, H ; Codigo de Get_Attr_Offset_From_Image | + | ld a, h ; Codigo de Get_Attr_Offset_From_Image |
- | RRCA | + | rrca |
- | RRCA | + | rrca |
- | RRCA | + | rrca |
- | AND 3 | + | |
- | OR $58 | + | |
- | LD D, A | + | ld d, a |
- | LD E, L ; DE tiene el offset del attr de HL | + | ld e, l ; DE tiene el offset del attr de HL |
- | LD HL, (DM_ATTRIBS) | + | ld hl, (DM_ATTRIBS) |
- | EX AF, AF' | + | ex af, af' |
- | LD C, A | + | ld c, a |
- | LD B, 0 | + | ld b, 0 |
- | ADD HL, BC | + | add hl, bc |
- | ADD HL, BC | + | add hl, bc |
- | ADD HL, BC | + | add hl, bc |
- | ADD HL, BC ; HL = HL+HL=(DM_NUMSPR*4) = Origen de atributo | + | add hl, bc ; HL = HL+HL=(DM_NUMSPR*4) = Origen de atributo |
- | + | ||
- | LDI | + | ldi |
- | LDI ; Imprimimos la primeras fila de atributos | + | |
- | + | ||
- | | + | ;;; Avance diferencial a la siguiente linea de atributos |
- | LD A, E ; A = E | + | ld a, e ; A = E |
- | ADD A, 30 ; Sumamos A = A + 30 mas los 2 INCs de LDI. | + | add a, 30 ; Sumamos A = A + 30 mas los 2 INCs de ldi. |
- | LD E, A ; Guardamos en E (E = E+30 + 2 por LDI=E+32) | + | ld e, a ; Guardamos en E (E = E+30 + 2 por ldi=E+32) |
- | JR NC, drawmg16_att_noinc | + | jr nc, drawmg16_att_noinc |
- | INC D | + | inc d |
drawmg16_att_noinc: | drawmg16_att_noinc: | ||
- | LDI | + | ldi |
- | LDI ; Imprimimos la segunda fila de atributos | + | |
- | POP HL ; Recuperamos el puntero al inicio | + | pop hl ; Recuperamos el puntero al inicio |
drawmg16_next: | drawmg16_next: | ||
- | INC L ; Avanzamos al siguiente tile en pantalla | + | inc l ; Avanzamos al siguiente tile en pantalla |
- | INC L ; horizontalmente | + | inc l ; horizontalmente |
- | POP BC ; Recuperamos el contador para el bucle | + | pop bc ; Recuperamos el contador para el bucle |
- | DEC B ; DJNZ se sale de rango, hay que usar DEC+JP | + | dec b ; djnz se sale de rango, hay que usar DEC+jp |
- | JP NZ, drawmg16_xloop | + | jp nz, drawmg16_xloop |
- | ;;; NUEVO: Incrementar puntero de mapa a siguiente linea | + | |
- | LD BC, ANCHO_MAPA_TILES - ANCHO_PANTALLA | + | ld bc, ANCHO_MAPA_TILES - ANCHO_PANTALLA |
- | ADD IX, BC | + | add ix, bc |
- | | + | ;;; FIN NUEVO |
- | ;;; En este punto, hemos dibujado ANCHO tiles en pantalla (1 fila) | + | |
- | POP BC | + | pop bc |
- | DEC B ; Bucle vertical | + | dec b ; Bucle vertical |
- | JP NZ, drawmg16_yloop | + | jp nz, drawmg16_yloop |
- | RET | + | ret |
</ | </ | ||
- | | + | |
<code z80> | <code z80> | ||
Línea 1431: | Línea 1428: | ||
; | ; | ||
Map_Inc_X: | Map_Inc_X: | ||
- | LD HL, (DM_MAPX) | + | ld hl, (DM_MAPX) |
- | | + | |
- | LD A, H | + | ld a, h |
- | CP (ANCHO_MAPA_TILES-ANCHO_PANTALLA) / 256 | + | CP (ANCHO_MAPA_TILES-ANCHO_PANTALLA) / 256 |
- | RET NZ | + | ret nz |
- | LD A, L | + | ld a, l |
- | CP (ANCHO_MAPA_TILES-ANCHO_PANTALLA) % 256 | + | CP (ANCHO_MAPA_TILES-ANCHO_PANTALLA) % 256 |
- | RET Z | + | ret z |
- | INC HL ; No eran iguales, podemos incrementar. | + | inc hl ; No eran iguales, podemos incrementar. |
- | | + | |
- | RET | + | ret |
; | ; | ||
Línea 1449: | Línea 1446: | ||
; | ; | ||
Map_Inc_Y: | Map_Inc_Y: | ||
- | LD HL, (DM_MAPY) | + | ld hl, (DM_MAPY) |
- | | + | |
- | LD A, H | + | ld a, h |
- | CP (ALTO_MAPA_TILES-ALTO_PANTALLA) / 256 | + | CP (ALTO_MAPA_TILES-ALTO_PANTALLA) / 256 |
- | RET NZ | + | ret nz |
- | LD A, L | + | ld a, l |
- | CP (ALTO_MAPA_TILES-ALTO_PANTALLA) % 256 | + | CP (ALTO_MAPA_TILES-ALTO_PANTALLA) % 256 |
- | RET Z | + | ret z |
- | INC HL ; No eran iguales, podemos incrementar. | + | inc hl ; No eran iguales, podemos incrementar. |
- | | + | |
- | RET | + | ret |
; | ; | ||
Línea 1467: | Línea 1464: | ||
; | ; | ||
Map_Dec_X: | Map_Dec_X: | ||
- | LD HL, (DM_MAPX) | + | ld hl, (DM_MAPX) |
- | LD A, H | + | ld a, h |
- | AND A | + | and a |
- | JR NZ, mapdecx_doit | + | jr nz, mapdecx_doit |
- | LD A, L | + | ld a, l |
- | AND A | + | and a |
- | RET Z | + | ret z |
- | mapdecx_doit: | + | mapdecx_doit: |
- | DEC HL | + | dec hl |
- | | + | |
- | RET | + | ret |
; | ; | ||
Línea 1483: | Línea 1480: | ||
; | ; | ||
Map_Dec_Y: | Map_Dec_Y: | ||
- | LD HL, (DM_MAPY) | + | ld hl, (DM_MAPY) |
- | LD A, H | + | ld a, h |
- | AND A | + | and a |
- | JR NZ, mapdecy_doit | + | jr nz, mapdecy_doit |
- | LD A, L | + | ld a, l |
- | AND A | + | and a |
- | RET Z | + | ret z |
- | mapdecy_doit: | + | mapdecy_doit: |
- | DEC HL | + | dec hl |
- | | + | |
- | RET | + | ret |
</ | </ | ||
- | El incremento de DM_MAPX y DM_MAPY requiere verificar que ninguna de las 2 variables excede ANCHO_MAPA-ANCHO_PANTALLA y ALTO_MAPA-ALTO_PANTALLA respectivamente. Sus decrementos requieren comprobar que el valor actual de estas variables no es cero. | + | El incremento de '' |
| | ||
<code z80> | <code z80> | ||
- | | + | ; Ejemplo impresion mapa de 16x16 desde array global |
- | ORG 32768 | + | ORG 35000 |
- | LD HL, sokoban1_gfx | + | ld hl, sokoban1_gfx |
- | | + | |
- | LD HL, sokoban1_attr | + | ld hl, sokoban1_attr |
- | | + | |
- | LD HL, mapa_ejemplo | + | ld hl, mapa_ejemplo |
- | | + | |
- | LD A, ANCHO_PANTALLA | + | ld a, ANCHO_PANTALLA |
- | | + | |
- | LD A, ALTO_PANTALLA | + | ld a, ALTO_PANTALLA |
- | | + | |
- | XOR A | + | xor a |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
redraw: | redraw: | ||
- | CALL DrawMap_16x16_Map | + | call DrawMap_16x16_Map |
bucle: | bucle: | ||
- | CALL LEER_TECLADO | + | call LEER_TECLADO |
- | BIT 0, A ; Modificamos MAPX y MAPY segun OPQA | + | bit 0, a ; Modificamos MAPX y MAPY segun OPQA |
- | JR Z, nopulsada_q | + | jr z, nopulsada_q |
- | | + | |
- | | + | |
nopulsada_q: | nopulsada_q: | ||
- | BIT 1, A | + | bit 1, a |
- | JR Z, nopulsada_a | + | jr z, nopulsada_a |
- | | + | |
- | | + | |
nopulsada_a: | nopulsada_a: | ||
- | BIT 2, A | + | bit 2, a |
- | JR Z, nopulsada_p | + | jr z, nopulsada_p |
- | | + | |
- | | + | |
nopulsada_p: | nopulsada_p: | ||
- | BIT 3, A | + | bit 3, a |
- | JR Z, nopulsada_o | + | jr z, nopulsada_o |
- | | + | |
- | | + | |
nopulsada_o: | nopulsada_o: | ||
- | JR bucle | + | jr bucle |
loop: | loop: | ||
- | | + | |
; | ; | ||
Línea 1560: | Línea 1557: | ||
; | ; | ||
LEER_TECLADO: | LEER_TECLADO: | ||
- | LD D, 0 | + | ld d, 0 |
- | LD BC, $FBFE | + | ld bc, $fbfe |
- | IN A, (C) | + | in a, (c) |
- | | + | |
- | JR NZ, Control_no_up | + | jr nz, Control_no_up |
- | | + | |
Control_no_up: | Control_no_up: | ||
- | + | ||
- | LD BC, $FDFE | + | ld bc, $fdfe |
- | IN A, (C) | + | in a, (c) |
- | | + | |
- | JR NZ, Control_no_down | + | jr nz, Control_no_down |
- | | + | |
Control_no_down: | Control_no_down: | ||
- | + | ||
- | LD BC, $DFFE | + | ld bc, $dffe |
- | IN A, (C) | + | in a, (c) |
- | | + | |
- | JR NZ, Control_no_right | + | jr nz, Control_no_right |
- | | + | |
Control_no_right: | Control_no_right: | ||
- | ; BC ya vale $DFFE, (O y P en misma fila) | + | ; BC ya vale $dffe, (O y P en misma fila) |
- | | + | |
- | JR NZ, Control_no_left | + | jr nz, Control_no_left |
- | | + | |
Control_no_left: | Control_no_left: | ||
- | + | ||
- | LD A, D ; Devolvemos en A el estado de las teclas | + | ld a, d ; Devolvemos en A el estado de las teclas |
- | RET | + | ret |
; | ; | ||
- | DM_SPRITES | + | DM_SPRITES |
- | DM_ATTRIBS | + | DM_ATTRIBS |
- | DM_MAP | + | DM_MAP |
- | DM_COORD_X | + | DM_COORD_X |
- | DM_COORD_Y | + | DM_COORD_Y |
- | DM_WIDTH | + | DM_WIDTH |
- | DM_HEIGHT | + | DM_HEIGHT |
- | DM_MAPX | + | DM_MAPX |
- | DM_MAPY | + | DM_MAPY |
; | ; | ||
Línea 1610: | Línea 1608: | ||
ALTO_PANTALLA | ALTO_PANTALLA | ||
- | ;;; Rutina de la ROM del Spectrum, en otros sistemas | + | ;;; Rutina de la ROM del Spectrum, en otros sistemas |
;;; sustituir por una rutina especifica de multiplicacion | ;;; sustituir por una rutina especifica de multiplicacion | ||
- | MULT_HL_POR_DE | + | MULT_HL_POR_DE |
; | ; | ||
;;; Nuestra pantalla de ejemplo de 32x24 bloques: | ;;; Nuestra pantalla de ejemplo de 32x24 bloques: | ||
; | ; | ||
- | mapa_ejemplo: | + | mapa_ejemplo: |
- | DEFB 1, | + | DEFB 1, |
- | DEFB 1, | + | DEFB 1, |
- | DEFB 1, | + | DEFB 1, |
- | DEFB 1, | + | DEFB 1, |
- | DEFB 1, | + | DEFB 1, |
- | DEFB 1, | + | DEFB 1, |
- | DEFB 1, | + | DEFB 1, |
- | DEFB 1, | + | DEFB 1, |
- | DEFB 1, | + | DEFB 1, |
- | DEFB 1, | + | DEFB 1, |
- | DEFB 1, | + | DEFB 1, |
- | DEFB 1, | + | DEFB 1, |
- | DEFB 1, | + | DEFB 1, |
- | DEFB 1, | + | DEFB 1, |
- | DEFB 1, | + | DEFB 1, |
- | DEFB 1, | + | DEFB 1, |
- | DEFB 1, | + | DEFB 1, |
- | DEFB 1, | + | DEFB 1, |
- | DEFB 1, | + | DEFB 1, |
- | DEFB 1, | + | DEFB 1, |
- | DEFB 1, | + | DEFB 1, |
- | DEFB 1, | + | DEFB 1, |
- | DEFB 1, | + | DEFB 1, |
- | DEFB 1, | + | DEFB 1, |
+ | |||
+ | END 35000 | ||
</ | </ | ||
Línea 1647: | Línea 1647: | ||
\\ | \\ | ||
- | {{ : | + | {{ : |
\\ | \\ | ||
El anterior ejemplo es meramente ilustrativo del uso de la rutina de impresión: para un juego basado en scroll (como simula el ejemplo con la pulsación de teclas) resultará mucho más rápido y eficiente realizar un scroll del contenido del área de juego y trazar sólo la fila o columna de datos que " | El anterior ejemplo es meramente ilustrativo del uso de la rutina de impresión: para un juego basado en scroll (como simula el ejemplo con la pulsación de teclas) resultará mucho más rápido y eficiente realizar un scroll del contenido del área de juego y trazar sólo la fila o columna de datos que " | ||
- | Para esta implementación serían necesarias 4 rutinas de scroll de una porción de videomemoria, | + | Para esta implementación serían necesarias 4 rutinas de scroll de una porción de videomemoria, |
- | El scroll mediante instrucciones de transferencia de N-1 FILAS o N-1 COLUMNAS de pantalla | + | El scroll mediante instrucciones de transferencia de N-1 FILAS o N-1 COLUMNAS de pantalla |
Como desventaja principal de los mapeados basados en arrays globales de tiles, en este tipo de mapeados no podemos utilizar de una forma inmediata las técnicas de " | Como desventaja principal de los mapeados basados en arrays globales de tiles, en este tipo de mapeados no podemos utilizar de una forma inmediata las técnicas de " | ||
Línea 1665: | Línea 1665: | ||
Una pantalla de 16x12 tiles que ocupe todo el área visible ocupa 192 bytes, lo que nos permite un total de 85 pantallas en 16 KB de memoria. Si tenemos en cuenta que necesitamos espacio para los gráficos de personajes y enemigos, el tileset, fuentes de texto, código del programa, textos, sonido, variables, nos encontramos con que se establece un límite de cantidad de pantallas que podemos incorporar en nuestro programa en función de la memoria libre que nos queda tras incorporar todos los elementos del mismo. | Una pantalla de 16x12 tiles que ocupe todo el área visible ocupa 192 bytes, lo que nos permite un total de 85 pantallas en 16 KB de memoria. Si tenemos en cuenta que necesitamos espacio para los gráficos de personajes y enemigos, el tileset, fuentes de texto, código del programa, textos, sonido, variables, nos encontramos con que se establece un límite de cantidad de pantallas que podemos incorporar en nuestro programa en función de la memoria libre que nos queda tras incorporar todos los elementos del mismo. | ||
- | Para reducir el espacio que ocupan nuestras pantallas y por tanto poder incluir más pantallas en la misma cantidad de memoria podemos utilizar diferentes métodos de codificación. | + | Para reducir el espacio que ocupan nuestras pantallas y por tanto poder incluir más pantallas en la misma cantidad de memoria podemos utilizar diferentes métodos. |
+ | |||
+ | El primero | ||
+ | |||
+ | En la mayoría de las ocasiones la compresión es la solución más eficiente a la necesidad de reducir el tamaño de mapas, sprites, textos o músicas. En el siguiente capítulo entraremos en detalle en rutinas de compresión, | ||
- | Uno de ellos podría basarse en la compresión | + | Pero no siempre |
- | Por esto, lo mejor es codificar o " | + | Este segundo método, la **codificación**, |
- | La técnica que vamos a ver no es una compresión en sí misma sino que se basa en no almacenar | + | La técnica que vamos a ver se basa en no almacenar el total de datos de la pantalla, sino que ignoraremos |
Si tenemos una fila de 16 tiles pero sólo 5 de ellos deben de ser dibujados, es absurdo almacenar la información de los 11 tiles "en blanco" | Si tenemos una fila de 16 tiles pero sólo 5 de ellos deben de ser dibujados, es absurdo almacenar la información de los 11 tiles "en blanco" | ||
Línea 1712: | Línea 1716: | ||
<code z80> | <code z80> | ||
sokoban_LEVEL1: | sokoban_LEVEL1: | ||
- | | + | |
- | DEFB 0, | + | DEFB 0, |
- | DEFB 0, | + | DEFB 0, |
- | DEFB 0, | + | DEFB 0, |
- | DEFB 0, | + | DEFB 0, |
- | DEFB 0, | + | DEFB 0, |
- | DEFB 0, | + | DEFB 0, |
- | DEFB 0, | + | DEFB 0, |
- | DEFB 0, | + | DEFB 0, |
- | DEFB 0, | + | DEFB 0, |
- | DEFB 0, | + | DEFB 0, |
- | DEFB 0, | + | DEFB 0, |
</ | </ | ||
Línea 1930: | Línea 1934: | ||
for valor in mapa_codificado: | for valor in mapa_codificado: | ||
CONTADOR_DB += 1 | CONTADOR_DB += 1 | ||
- | if CONTADOR_DB == 0: | + | if CONTADOR_DB == 0: |
print " DB", str(valor), | print " DB", str(valor), | ||
- | elif CONTADOR_DB == 11: | + | elif CONTADOR_DB == 11: |
print ",", | print ",", | ||
| | ||
Línea 1942: | Línea 1946: | ||
if __name__ == ' | if __name__ == ' | ||
- | # Variables que utilizaremos | + | # Variables que utilizaremos |
| | ||
| | ||
Línea 2041: | Línea 2045: | ||
El script codifica esta pantalla con 106 bytes cuando el tamaño original era de 192, consiguiendo una compresión de aprox. el 46% (casi la mitad de tamaño). Esto quiere decir que el mapeado de nuestro programa podría ser (manteniendo este ratio de compresión en todas las pantallas), hasta casi el doble de grande que el mapa máximo actual. | El script codifica esta pantalla con 106 bytes cuando el tamaño original era de 192, consiguiendo una compresión de aprox. el 46% (casi la mitad de tamaño). Esto quiere decir que el mapeado de nuestro programa podría ser (manteniendo este ratio de compresión en todas las pantallas), hasta casi el doble de grande que el mapa máximo actual. | ||
- | | + | |
<code z80> | <code z80> | ||
Línea 2060: | Línea 2064: | ||
; | ; | ||
DrawMap_16x16_Cod_Basica: | DrawMap_16x16_Cod_Basica: | ||
- | + | ||
- | LD HL, (DM_SPRITES) | + | ld hl, (DM_SPRITES) |
- | LD (DS_SPRITES), | + | |
- | LD HL, (DM_ATTRIBS) | + | ld hl, (DM_ATTRIBS) |
- | LD (DS_ATTRIBS), | + | |
- | LD BC, (DM_COORD_X) | + | ld bc, (DM_COORD_X) |
- | LD DE, (DM_MAP) | + | ld de, (DM_MAP) |
drawm16cb_loop: | drawm16cb_loop: | ||
- | LD A, (DE) ; Leemos el valor de COORD_X_TILE | + | ld a, (de) ; Leemos el valor de COORD_X_TILE |
- | INC DE ; Apuntamos al siguiente byte del mapa | + | inc de ; Apuntamos al siguiente byte del mapa |
- | | + | cp 255 ; Bloque especial fin de pantalla |
- | RET Z ; En ese caso, salir | + | ret z ; En ese caso, salir |
- | ADD A, C ; A = (X_INICIO + COORD_X_TILE) | + | add a, c ; A = (X_INICIO + COORD_X_TILE) |
- | RLCA ; A = (X_INICIO + COORD_X_TILE) * 2 | + | |
- | LD (DS_COORD_X), | + | |
- | LD A, (DE) ; Leemos el valor de COORD_Y_TILE | + | ld a, (de) ; Leemos el valor de COORD_Y_TILE |
- | INC DE | + | inc de |
- | ADD A, B ; A = (X_INICIO + COORD_X_TILE) | + | add a, b ; A = (X_INICIO + COORD_X_TILE) |
- | RLCA ; A = (Y_INICIO + COORD_Y_TILE) | + | |
- | LD (DS_COORD_Y), | + | |
- | LD A, (DE) ; Leemos el valor del TILE | + | ld a, (de) ; Leemos el valor del TILE |
- | INC DE | + | inc de |
- | LD (DS_NUMSPR), | + | |
- | + | ||
- | | + | |
- | CALL DrawSprite_16x16_LD | + | |
- | | + | |
- | JR drawm16cb_loop | + | exx ; Preservar todos los registros en shadows |
+ | call DrawSprite_16x16_LD | ||
+ | exx ; Recuperar valores de los registros | ||
+ | |||
+ | jr drawm16cb_loop | ||
</ | </ | ||
Línea 2100: | Línea 2104: | ||
Por otra parte, como ya no estamos dibujando los bloques 0, antes de llamar a la rutina de dibujado diferencial es necesario borrar el contenido del área donde vamos a dibujar con el color plano del bloque 0 para que el resultado de la impresión incluya los bloques vacíos en aquellas áreas en que no dibujamos. Es decir, vaciaremos los " | Por otra parte, como ya no estamos dibujando los bloques 0, antes de llamar a la rutina de dibujado diferencial es necesario borrar el contenido del área donde vamos a dibujar con el color plano del bloque 0 para que el resultado de la impresión incluya los bloques vacíos en aquellas áreas en que no dibujamos. Es decir, vaciaremos los " | ||
- | Para borrar este área de pantalla podemos utilizar un simple borrado de atributos (establecer todos los atributos a cero) siempre y cuando los personajes del juego que se moverán sobre las áreas " | + | Para borrar este área de pantalla podemos utilizar un simple borrado de atributos (establecer todos los atributos a cero) siempre y cuando los personajes del juego que se moverán sobre las áreas " |
El siguiente programa ejemplo hace uso de la anterior rutina: | El siguiente programa ejemplo hace uso de la anterior rutina: | ||
<code z80> | <code z80> | ||
- | | + | ; Ejemplo impresion mapa de 16x16 codificacion basica |
- | ORG 32768 | + | ORG 35000 |
- | | + | |
- | XOR A | + | xor a |
- | | + | |
- | XOR A | + | xor a |
- | | + | |
- | | + | |
- | LD HL, sokoban1_gfx | + | ld hl, sokoban1_gfx |
- | | + | |
- | LD HL, sokoban1_attr | + | ld hl, sokoban1_attr |
- | | + | |
- | LD HL, sokoban_LEVEL1_codif_basica | + | ld hl, sokoban_LEVEL1_codif_basica |
- | | + | |
- | LD A, 16 | + | ld a, 16 |
- | | + | |
- | LD A, 12 | + | ld a, 12 |
- | | + | |
- | XOR A | + | xor a |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
loop: | loop: | ||
- | JR loop | + | jr loop |
- | + | ||
- | DM_SPRITES | + | DM_SPRITES |
- | DM_ATTRIBS | + | DM_ATTRIBS |
- | DM_MAP | + | DM_MAP |
- | DM_COORD_X | + | DM_COORD_X |
- | DM_COORD_Y | + | DM_COORD_Y |
- | DM_WIDTH | + | DM_WIDTH |
- | DM_HEIGHT | + | DM_HEIGHT |
+ | DM_MAPX | ||
+ | DM_MAPY | ||
+ | |||
+ | DS_SPRITES | ||
+ | DS_ATTRIBS | ||
+ | DS_COORD_X | ||
+ | DS_COORD_Y | ||
+ | DS_NUMSPR | ||
- | DS_SPRITES | + | END 35000 |
- | DS_ATTRIBS | + | |
- | DS_COORD_X | + | |
- | DS_COORD_Y | + | |
- | DS_NUMSPR | + | |
</ | </ | ||
Línea 2153: | Línea 2161: | ||
\\ | \\ | ||
- | {{ : | + | {{ : |
\\ | \\ | ||
Línea 2160: | Línea 2168: | ||
=== Mapeado diferencial con agrupación por scanlines === | === Mapeado diferencial con agrupación por scanlines === | ||
- | La pega de la técnica de codificación básica es que por cada bloque a imprimir estamos añadiendo 2 bytes de datos (coordenada X y coordenada Y) por lo que si más de 1/3 de los bloques totales de la pantalla son tiles a imprimir obtenemos una pantalla con más tamaño que la original. | + | La pega de la técnica de codificación básica es que por cada bloque a imprimir estamos añadiendo 2 bytes de datos (coordenada X y coordenada Y) por lo que si al menos |
La solución es codificar tiles " | La solución es codificar tiles " | ||
<code z80> | <code z80> | ||
- | | + | |
- | DB tile1, tile2, tile3, tile4, 255 | + | DB tile1, tile2, tile3, tile4, 255 |
- | ; (255 = byte de fin de " | + | ; (255 = byte de fin de " |
</ | </ | ||
Línea 2186: | Línea 2194: | ||
<code z80> | <code z80> | ||
- | $ ./ | + | $ ./ |
; Flag codificacion: | ; Flag codificacion: | ||
; Resultado: 87 Bytes | ; Resultado: 87 Bytes | ||
Línea 2220: | Línea 2228: | ||
; | ; | ||
DrawMap_16x16_Cod_Horiz: | DrawMap_16x16_Cod_Horiz: | ||
- | |||
- | LD HL, (DM_SPRITES) | ||
- | LD (DS_SPRITES), | ||
- | LD HL, (DM_ATTRIBS) | ||
- | LD (DS_ATTRIBS), | ||
- | LD BC, (DM_COORD_X) | ||
- | LD DE, (DM_MAP) | ||
- | LD HL, DS_COORD_X | + | ld hl, (DM_SPRITES) |
+ | ld (DS_SPRITES), | ||
+ | ld hl, (DM_ATTRIBS) | ||
+ | ld (DS_ATTRIBS), | ||
+ | ld bc, (DM_COORD_X) | ||
+ | ld de, (DM_MAP) | ||
+ | |||
+ | ld hl, DS_COORD_X | ||
drawm16ch_read: | drawm16ch_read: | ||
- | LD A, (DE) ; Leemos el valor de COORD_X_TILE | + | ld a, (de) ; Leemos el valor de COORD_X_TILE |
- | INC DE ; Apuntamos al siguiente byte del mapa | + | inc de ; Apuntamos al siguiente byte del mapa |
drawm16ch_loop: | drawm16ch_loop: | ||
- | | + | cp 255 ; Bloque especial fin de pantalla |
- | RET Z ; En ese caso, salir | + | ret z ; En ese caso, salir |
- | ADD A, C ; A = (X_INICIO + COORD_X_TILE) | + | add a, c ; A = (X_INICIO + COORD_X_TILE) |
- | RLCA ; A = (X_INICIO + COORD_X_TILE) * 2 | + | |
- | LD (HL), A ; Establecemos COORD_X a imprimir tile | + | |
- | LD A, (DE) ; Leemos el valor de COORD_Y_TILE | + | ld a, (de) ; Leemos el valor de COORD_Y_TILE |
- | INC DE | + | inc de |
- | ADD A, B ; A = (Y_INICIO + COORD_Y_TILE) | + | add a, b ; A = (Y_INICIO + COORD_Y_TILE) |
- | RLCA ; A = (Y_INICIO + COORD_Y_TILE) | + | |
- | LD (DS_COORD_Y), | + | |
+ | |||
+ | ;;; Bucle impresion de todos los tiles del scanline (aunque sea 1 solo) | ||
- | ;;; Bucle impresion de todos los tiles del scanline (aunque sea 1 solo) | ||
- | |||
drawm16ch_tileloop: | drawm16ch_tileloop: | ||
- | LD A, (DE) ; Leemos el valor del TILE de pantalla | + | ld a, (de) ; Leemos el valor del TILE de pantalla |
- | INC DE ; Incrementamos puntero | + | inc de ; Incrementamos puntero |
+ | |||
+ | cp 255 | ||
+ | jr z, drawm16ch_read | ||
- | CP 255 | + | ld (DS_NUMSPR), a ; Establecemos el TILE |
- | JR Z, drawm16ch_read | + | |
- | LD (DS_NUMSPR), | + | exx ; Preservar todos los registros en shadows |
- | + | | |
- | | + | |
- | CALL DrawSprite_16x16_LD | + | |
- | EXX ; Recuperar valores de los registros | + | |
- | | + | inc (hl) ; Avanzamos al siguiente tile |
- | INC (HL) ; COORD_X = COORD_X + 2 | + | |
- | | + | jr drawm16ch_tileloop |
</ | </ | ||
Línea 2276: | Línea 2284: | ||
| | ||
- | Si utilizamos el script en python con el flag **-v** sobre la pantalla de ejemplo, obtenemos la siguiente pantalla codificada: | + | Si utilizamos el script en python con el flag '' |
<code z80> | <code z80> | ||
- | $ ./ | + | $ ./ |
; Flag codificacion: | ; Flag codificacion: | ||
; Resultado: 78 Bytes | ; Resultado: 78 Bytes | ||
Línea 2312: | Línea 2320: | ||
; | ; | ||
DrawMap_16x16_Cod_Vert: | DrawMap_16x16_Cod_Vert: | ||
- | |||
- | LD HL, (DM_SPRITES) | ||
- | LD (DS_SPRITES), | ||
- | LD HL, (DM_ATTRIBS) | ||
- | LD (DS_ATTRIBS), | ||
- | LD BC, (DM_COORD_X) | ||
- | LD DE, (DM_MAP) | ||
- | LD HL, DS_COORD_Y | + | ld hl, (DM_SPRITES) |
+ | ld (DS_SPRITES), | ||
+ | ld hl, (DM_ATTRIBS) | ||
+ | ld (DS_ATTRIBS), | ||
+ | ld bc, (DM_COORD_X) | ||
+ | ld de, (DM_MAP) | ||
+ | |||
+ | ld hl, DS_COORD_Y | ||
drawm16cv_read: | drawm16cv_read: | ||
- | LD A, (DE) ; Leemos el valor de COORD_X_TILE | + | ld a, (de) ; Leemos el valor de COORD_X_TILE |
- | INC DE ; Apuntamos al siguiente byte del mapa | + | inc de ; Apuntamos al siguiente byte del mapa |
drawm16cv_loop: | drawm16cv_loop: | ||
- | | + | cp 255 ; Bloque especial fin de pantalla |
- | RET Z ; En ese caso, salir | + | ret z ; En ese caso, salir |
- | ADD A, C ; A = (X_INICIO + COORD_X_TILE) | + | add a, c ; A = (X_INICIO + COORD_X_TILE) |
- | RLCA ; A = (X_INICIO + COORD_X_TILE) * 2 | + | |
- | LD (DS_COORD_X), | + | |
- | LD A, (DE) ; Leemos el valor de COORD_Y_TILE | + | ld a, (de) ; Leemos el valor de COORD_Y_TILE |
- | INC DE | + | inc de |
- | ADD A, B ; A = (Y_INICIO + COORD_Y_TILE) | + | add a, b ; A = (Y_INICIO + COORD_Y_TILE) |
- | RLCA ; A = (Y_INICIO + COORD_Y_TILE) | + | |
- | LD (HL), A ; CAMBIO: Establecemos COORD_Y a imprimir tile | + | |
- | ;;; Bucle impresion de todos los tiles del scanline (aunque sea 1 solo) | + | |
drawm16cv_tileloop: | drawm16cv_tileloop: | ||
- | LD A, (DE) ; Leemos el valor del TILE de pantalla | + | ld a, (de) ; Leemos el valor del TILE de pantalla |
- | INC DE ; Incrementamos puntero | + | inc de ; Incrementamos puntero |
+ | |||
+ | cp 255 | ||
+ | jr z, drawm16cv_read | ||
+ | |||
+ | ld (DS_NUMSPR), | ||
- | CP 255 | + | exx ; Preservar todos los registros en shadows |
- | JR Z, drawm16cv_read | + | |
- | + | | |
- | LD (DS_NUMSPR), | + | |
- | + | ||
- | | + | |
- | CALL DrawSprite_16x16_LD | + | |
- | EXX ; Recuperar valores de los registros | + | |
- | | + | inc (hl) |
- | INC (HL) ; COORD_Y = COORD_Y + 2 | + | |
- | | + | jr drawm16cv_tileloop |
</ | </ | ||
Línea 2367: | Línea 2375: | ||
\\ | \\ | ||
- | | + | |
Por ejemplo, cabe la posibilidad de que en 3 tiles horizontales consecutivos nos encontremos con el que el de el medio forme parte de una fila vertical de tiles de gran tamaño, por lo que nos interesará codificar ese tile como scanline vertical antes que los 3 como horizontal. | Por ejemplo, cabe la posibilidad de que en 3 tiles horizontales consecutivos nos encontremos con el que el de el medio forme parte de una fila vertical de tiles de gran tamaño, por lo que nos interesará codificar ese tile como scanline vertical antes que los 3 como horizontal. | ||
Línea 2375: | Línea 2383: | ||
El codificador debe codificar todos los scanlines horizontales de tiles acabados en el identificador de fin de scanline 255 menos el último, el cual acabará con un valor 254. A continuación almacenará todos los scanlines verticales de tiles acabados en 255. Un valor 255 final indicará el fin de pantalla. | El codificador debe codificar todos los scanlines horizontales de tiles acabados en el identificador de fin de scanline 255 menos el último, el cual acabará con un valor 254. A continuación almacenará todos los scanlines verticales de tiles acabados en 255. Un valor 255 final indicará el fin de pantalla. | ||
- | El valor 254 permite a la rutina de impresión saber cuándo hemos acabado de imprimir los scanlines horizontales y le indica que debe interpretar todos los scanlines restantes como verticales. De esta forma nos ahorramos el tener que incluir un byte con el tipo de codificación precediendo a cada scanline, y ahorrando así 1 byte adicional por " | + | El valor 254 permite a la rutina de impresión saber cuándo hemos acabado de imprimir los scanlines horizontales y le indica que debe interpretar todos los scanlines restantes como verticales. De esta forma nos ahorramos el tener que incluir un byte con el tipo de codificación precediendo a cada scanline, y ahorrando así 1 byte adicional por " |
Como desventaja, nuestro tileset sólo puede contener ahora 254 tiles (0-253). | Como desventaja, nuestro tileset sólo puede contener ahora 254 tiles (0-253). | ||
- | | + | |
<code z80> | <code z80> | ||
Pantalla: | Pantalla: | ||
- | | + | |
- | DB tile1, tile2, (...), tileN, 255 | + | DB tile1, tile2, (...), tileN, 255 |
- | DB coordenada_x_primer_tile_horiz, | + | DB coordenada_x_primer_tile_horiz, |
- | DB tile1, tile2, (...), tileN, 254 | + | DB tile1, tile2, (...), tileN, 254 |
- | DB coordenada_x_primer_tile_vert, | + | DB coordenada_x_primer_tile_vert, |
- | DB tile1, tile2, (...), tileN, 255 | + | DB tile1, tile2, (...), tileN, 255 |
- | DB coordenada_x_primer_tile_vert, | + | DB coordenada_x_primer_tile_vert, |
- | DB tile1, tile2, (...), tileN, 255 | + | DB tile1, tile2, (...), tileN, 255 |
- | DB 255 | + | DB 255 |
- | + | ||
- | ; Donde: | + | ; Donde: |
- | ; 255 como coordenada_x = fin de pantalla. | + | ; 255 como coordenada_x = fin de pantalla. |
- | ; 255 a final de scanline = byte de fin de " | + | ; 255 a final de scanline = byte de fin de " |
- | ; 254 a final de scanline = cambio de codificacion de horizontal a vertical | + | ; 254 a final de scanline = cambio de codificacion de horizontal a vertical |
</ | </ | ||
Línea 2402: | Línea 2410: | ||
<code z80> | <code z80> | ||
- | $ ./ | + | $ ./ |
; Flag codificacion: | ; Flag codificacion: | ||
; Resultado: 72 Bytes | ; Resultado: 72 Bytes | ||
Línea 2412: | Línea 2420: | ||
DB 5 , 3 , 255 , 4 , 2 , 1 , 4 , 5 , 4 , 5 , 255 , 255 | DB 5 , 3 , 255 , 4 , 2 , 1 , 4 , 5 , 4 , 5 , 255 , 255 | ||
</ | </ | ||
- | + | ||
Hemos reducido el tamaño de la pantalla codificada de 192 bytes a 72 bytes (6 bytes menos que la mejor de las anteriores codificaciones, | Hemos reducido el tamaño de la pantalla codificada de 192 bytes a 72 bytes (6 bytes menos que la mejor de las anteriores codificaciones, | ||
Línea 2423: | Línea 2431: | ||
| | ||
- | | + | |
<code z80> | <code z80> | ||
- | LD DE, DS_COORD_Y | + | ld de, DS_COORD_Y |
- | LD HL, DS_COORD_X | + | ld hl, DS_COORD_X |
</ | </ | ||
- | | + | |
<code z80> | <code z80> | ||
drawm16cm_dir1: | drawm16cm_dir1: | ||
- | NOP | + | nop |
- | INC (HL) | + | |
- | INC (HL) ; COORD = COORD + 2 | + | |
drawm16cm_dir2: | drawm16cm_dir2: | ||
- | NOP | + | nop |
</ | </ | ||
- | | + | |
| | ||
Línea 2448: | Línea 2456: | ||
drawm16cm_tileloop: | drawm16cm_tileloop: | ||
- | (...) | + | |
- | | + | |
- | CP 254 | + | |
- | JR Z, drawm16cm_switch | + | jr z, drawm16cm_switch |
- | | + | |
- | | + | (...) |
drawm16cm_switch: | drawm16cm_switch: | ||
- | ;;; Cambio de codificacion de horizontal a vertical: | + | |
- | LD A, $EB ; Opcode de EX DE, HL | + | ld a, $eb ; Opcode de ex de, hl |
- | LD (drawm16cm_dir1), | + | |
- | LD (drawm16cm_dir2), | + | |
- | JR drawm16cm_read | + | |
</ | </ | ||
- | Es decir, cuando se encuentra un valor 254 como fin de scanline saltamos a drawm16cm_switch, | + | Es decir, cuando se encuentra un valor 254 como fin de scanline saltamos a drawm16cm_switch, |
<code z80> | <code z80> | ||
drawm16cm_dir1: | drawm16cm_dir1: | ||
- | EX DE, HL | + | ex de, hl |
- | INC (HL) | + | |
- | INC (HL) ; COORD = COORD + 2 | + | |
drawm16cm_dir2: | drawm16cm_dir2: | ||
- | EX DE, HL | + | ex de, hl |
</ | </ | ||
- | Esto provoca que, a partir de haber encontrado el 254 y hasta que finalice la rutina (código 255 de fin de pantalla), los INC (HL) incrementen COORD_Y (debido al EX DE, HL) en lugar de COORD_X, convirtiendo la rutina en un sistema de impresión de scanlines horizontales. | + | Esto provoca que, a partir de haber encontrado el 254 y hasta que finalice la rutina (código 255 de fin de pantalla), los inc (hl) incrementen |
- | | + | |
<code z80> | <code z80> | ||
DrawMap_16x16_Cod_Mixta: | DrawMap_16x16_Cod_Mixta: | ||
- | XOR A ; Opcode de "NOP" | + | xor a ; Opcode de "nop" |
- | LD (drawm16cm_dir1), | + | |
- | LD (drawm16cm_dir2), | + | |
</ | </ | ||
Línea 2506: | Línea 2514: | ||
DrawMap_16x16_Cod_Mixta: | DrawMap_16x16_Cod_Mixta: | ||
- | XOR A ; Opcode de "NOP" | + | xor a ; Opcode de "nop" |
- | LD (drawm16cm_dir1), | + | |
- | LD (drawm16cm_dir2), | + | |
- | LD HL, (DM_SPRITES) | + | ld hl, (DM_SPRITES) |
- | LD (DS_SPRITES), | + | |
- | LD HL, (DM_ATTRIBS) | + | ld hl, (DM_ATTRIBS) |
- | LD (DS_ATTRIBS), | + | |
- | LD BC, (DM_COORD_X) | + | ld bc, (DM_COORD_X) |
- | LD IX, (DM_MAP) | + | ld ix, (DM_MAP) |
- | LD DE, DS_COORD_Y | + | ld de, DS_COORD_Y |
- | LD HL, DS_COORD_X | + | ld hl, DS_COORD_X |
drawm16cm_read: | drawm16cm_read: | ||
- | LD A, (IX+0) ; Leemos el valor de COORD_X_TILE | + | ld a, (ix+0) ; Leemos el valor de COORD_X_TILE |
- | INC IX ; Apuntamos al siguiente byte del mapa | + | inc ix ; Apuntamos al siguiente byte del mapa |
drawm16cm_loop: | drawm16cm_loop: | ||
- | | + | cp 255 ; Bloque especial fin de pantalla |
- | RET Z ; En ese caso, salir | + | ret z ; En ese caso, salir |
- | ADD A, C ; A = (X_INICIO + COORD_X_TILE) | + | add a, c ; A = (X_INICIO + COORD_X_TILE) |
- | RLCA ; A = (X_INICIO + COORD_X_TILE) * 2 | + | |
- | LD (HL), A ; Establecemos COORD_X a imprimir tile | + | |
- | LD A, (IX+0) ; Leemos el valor de COORD_Y_TILE | + | ld a, (ix+0) ; Leemos el valor de COORD_Y_TILE |
- | INC IX | + | inc ix |
- | ADD A, B ; A = (Y_INICIO + COORD_Y_TILE) | + | add a, b ; A = (Y_INICIO + COORD_Y_TILE) |
- | RLCA ; A = (Y_INICIO + COORD_Y_TILE) | + | |
- | LD (DE), A ; Establecemos COORD_Y a imprimir tile | + | |
- | ;;; Bucle impresion vertical de los N tiles del scanline | + | |
drawm16cm_tileloop: | drawm16cm_tileloop: | ||
- | LD A, (IX+0) ; Leemos el valor del TILE de pantalla | + | ld a, (ix+0) ; Leemos el valor del TILE de pantalla |
- | INC IX ; Incrementamos puntero | + | inc ix ; Incrementamos puntero |
+ | |||
+ | cp 255 | ||
+ | jr z, drawm16cm_read | ||
- | CP 255 | + | cp 254 |
- | JR Z, drawm16cm_read | + | jr z, drawm16cm_switch |
- | CP 254 | + | ld (DS_NUMSPR), |
- | JR Z, drawm16cm_switch | + | exx ; Preservar todos los registros en shadows |
+ | | ||
+ | exx ; Recuperar valores de los registros | ||
- | LD (DS_NUMSPR), | + | drawm16cm_dir1: |
- | EXX ; Preservar todos los registros en shadows | + | |
- | CALL DrawSprite_16x16_LD | + | |
- | | + | |
- | drawm16cm_dir1: | + | inc (hl) |
- | | + | |
- | + | ||
- | | + | |
- | INC (HL) ; COORD = COORD + 2 | + | |
- | drawm16cm_dir2: | + | drawm16cm_dir2: |
- | NOP ; NOP->INC COORD_X, | + | |
- | | + | jr drawm16cm_tileloop |
drawm16cm_switch: | drawm16cm_switch: | ||
- | ;;; Cambio de codificacion de horizontal a vertical: | + | |
- | LD A, $EB ; Opcode de EX DE, HL | + | ld a, $eb ; Opcode de ex de, hl |
- | LD (drawm16cm_dir1), | + | |
- | LD (drawm16cm_dir2), | + | |
- | JR drawm16cm_read | + | |
</ | </ | ||
- | Con el sistema de " | + | Con el sistema de " |
Esta técnica sirve para gran cantidad de optimizaciones en rutinas de este tipo: podemos por ejemplo en algunas rutinas modificar el código en memoria para evitar saltos (reemplazar la instruccion de comparacion o de salto por instrucciones que no lo provoquen o por NOPs) o evitar la duplicación de código. | Esta técnica sirve para gran cantidad de optimizaciones en rutinas de este tipo: podemos por ejemplo en algunas rutinas modificar el código en memoria para evitar saltos (reemplazar la instruccion de comparacion o de salto por instrucciones que no lo provoquen o por NOPs) o evitar la duplicación de código. | ||
Línea 2595: | Línea 2603: | ||
<code z80> | <code z80> | ||
- | | + | mapa_codificado.append( X ) |
- | mapa_codificado.append( Y ) | + | mapa_codificado.append( Y ) |
</ | </ | ||
Línea 2602: | Línea 2610: | ||
<code z80> | <code z80> | ||
- | | + | mapa_codificado.append( (X * 16) + Y ) |
</ | </ | ||
- | | + | |
Así, con un mapa de 16x14, el máximo tamaño de pantalla que podemos ocupar según las dimensiones de cada tile serían: | Así, con un mapa de 16x14, el máximo tamaño de pantalla que podemos ocupar según las dimensiones de cada tile serían: | ||
+ | |< 70% >| | ||
^ Tamaño de mapa ^ Tamaño de tile ^ Ancho de pantalla ^ Alto de pantalla ^ | ^ Tamaño de mapa ^ Tamaño de tile ^ Ancho de pantalla ^ Alto de pantalla ^ | ||
| 16x14 | 8x8 | 128 píxeles | 112 píxeles | | | 16x14 | 8x8 | 128 píxeles | 112 píxeles | | ||
Línea 2616: | Línea 2625: | ||
Las dimensiones que podemos ver en la tabla hacen esta optimización inusable para juegos con tiles de 8x8 pixeles. | Las dimensiones que podemos ver en la tabla hacen esta optimización inusable para juegos con tiles de 8x8 pixeles. | ||
- | Por otra parte, recordemos que debemos modificar la rutina para que separe los bytes de COORD_X y COORD_Y en 2 valores diferentes, lo que supone un pequeño tiempo adicional de procesado por cada scanline. | + | Por otra parte, recordemos que debemos modificar la rutina para que separe los bytes de '' |
- | | + | |
<code z80> | <code z80> | ||
- | $ ./ | + | $ ./ |
; Flag codificacion: | ; Flag codificacion: | ||
; Resultado: 60 Bytes | ; Resultado: 60 Bytes | ||
Línea 2638: | Línea 2647: | ||
<code z80> | <code z80> | ||
- | ;;; (venimos del LD A, (IX+0) / INC IX de la coordenada X) | + | |
- | + | ||
- | ;;; Sumamos la coordenada X recogida y obtenemos desde el mapa la Y: | + | |
- | ADD A, C ; A = (X_INICIO + COORD_X_TILE) | + | |
- | | + | |
- | LD (HL), A ; Establecemos COORD_X a imprimir tile | + | |
- | LD A, (IX+0) ; Leemos el valor de COORD_Y_TILE | + | ;;; Sumamos la coordenada X recogida y obtenemos desde el mapa la Y: |
- | INC IX | + | add a, c ; A = (X_INICIO + COORD_X_TILE) |
- | ADD A, B ; A = (Y_INICIO + COORD_Y_TILE) | + | rlca ; A = (X_INICIO + COORD_X_TILE) * 2 |
- | RLCA ; A = (Y_INICIO + COORD_Y_TILE) | + | ld (hl), a ; Establecemos COORD_X a imprimir tile |
- | LD (DE), A ; Establecemos COORD_Y a imprimir tile | + | |
+ | ld a, (ix+0) ; Leemos el valor de COORD_Y_TILE | ||
+ | inc ix | ||
+ | add a, b ; A = (Y_INICIO + COORD_Y_TILE) | ||
+ | | ||
+ | | ||
</ | </ | ||
Línea 2655: | Línea 2664: | ||
<code z80> | <code z80> | ||
- | PUSH AF | + | push af |
- | AND %11110000 | + | |
- | RRCA ; Pasamos parte alta a parte baja | + | |
- | RRCA ; con 4 desplazamientos | + | |
- | RRCA | + | rrca |
- | RRCA ; Ya podemos sumar: | + | |
- | ADD A, C ; A = (X_INICIO + COORD_X_TILE) | + | add a, c ; A = (X_INICIO + COORD_X_TILE) |
- | RLCA ; A = (X_INICIO + COORD_X_TILE) * 2 | + | |
- | LD (HL), A ; Establecemos COORD_X a imprimir tile | + | |
- | POP AF | + | pop af |
- | AND %00001111 | + | |
- | ADD A, B ; A = (Y_INICIO + COORD_Y_TILE) | + | add a, b ; A = (Y_INICIO + COORD_Y_TILE) |
- | RLCA ; A = (Y_INICIO + COORD_Y_TILE) | + | |
- | LD (DE), A ; Establecemos COORD_Y a imprimir tile | + | |
</ | </ | ||
- | De la rutina original hemos eliminado las instrucciones | + | De la rutina original hemos eliminado las instrucciones |
La rutina de impresión de 16x16 Mixta con coordenadas X e Y codificadas en un mismo byte quedaría como el código que sigue: | La rutina de impresión de 16x16 Mixta con coordenadas X e Y codificadas en un mismo byte quedaría como el código que sigue: | ||
Línea 2690: | Línea 2699: | ||
DrawMap_16x16_Cod_Mixta_XY: | DrawMap_16x16_Cod_Mixta_XY: | ||
- | XOR A ; Opcode de "NOP" | + | xor a ; Opcode de "nop" |
- | LD (drawm16cmxy_dir1), | + | |
- | LD (drawm16cmxy_dir2), | + | |
- | LD HL, (DM_SPRITES) | + | ld hl, (DM_SPRITES) |
- | LD (DS_SPRITES), | + | |
- | LD HL, (DM_ATTRIBS) | + | ld hl, (DM_ATTRIBS) |
- | LD (DS_ATTRIBS), | + | |
- | LD BC, (DM_COORD_X) | + | ld bc, (DM_COORD_X) |
- | LD IX, (DM_MAP) | + | ld ix, (DM_MAP) |
- | LD DE, DS_COORD_Y | + | ld de, DS_COORD_Y |
- | LD HL, DS_COORD_X | + | ld hl, DS_COORD_X |
drawm16cmxy_read: | drawm16cmxy_read: | ||
- | LD A, (IX+0) ; Leemos el valor de COORDENADAS | + | ld a, (ix+0) ; Leemos el valor de COORDENADAS |
- | INC IX ; Apuntamos al siguiente byte del mapa | + | inc ix ; Apuntamos al siguiente byte del mapa |
drawm16cmxy_loop: | drawm16cmxy_loop: | ||
- | | + | cp 255 ; Bloque especial fin de pantalla |
- | RET Z ; En ese caso, salir | + | ret z ; En ese caso, salir |
- | PUSH AF ; Extraccion de coordenadas XY en X e Y | + | push af ; Extraccion de coordenadas XY en X e Y |
- | AND %11110000 | + | |
- | RRCA ; Pasamos parte alta a parte baja | + | |
- | RRCA ; con 4 desplazamientos | + | |
- | RRCA | + | rrca |
- | RRCA ; Ya podemos sumar | + | |
- | ADD A, C ; A = (X_INICIO + COORD_X_TILE) | + | add a, c ; A = (X_INICIO + COORD_X_TILE) |
- | RLCA ; A = (X_INICIO + COORD_X_TILE) * 2 | + | |
- | LD (HL), A ; Establecemos COORD_X a imprimir tile | + | |
- | POP AF | + | pop af |
- | AND %00001111 | + | |
- | ADD A, B ; A = (Y_INICIO + COORD_Y_TILE) | + | add a, b ; A = (Y_INICIO + COORD_Y_TILE) |
- | RLCA ; A = (Y_INICIO + COORD_Y_TILE) | + | |
- | LD (DE), A ; Establecemos COORD_Y a imprimir tile | + | |
;;; Bucle impresion vertical de los N tiles del scanline | ;;; Bucle impresion vertical de los N tiles del scanline | ||
drawm16cmxy_tileloop: | drawm16cmxy_tileloop: | ||
- | LD A, (IX+0) ; Leemos el valor del TILE de pantalla | + | ld a, (ix+0) ; Leemos el valor del TILE de pantalla |
- | INC IX ; Incrementamos puntero | + | inc ix ; Incrementamos puntero |
- | | + | cp 255 |
- | JR Z, drawm16cmxy_read | + | jr z, drawm16cmxy_read |
- | CP 254 | + | |
- | JR Z, drawm16cmxy_switch | + | jr z, drawm16cmxy_switch |
- | | + | ld (DS_NUMSPR), |
- | EXX ; Preservar todos los registros en shadows | + | |
- | CALL DrawSprite_16x16_LD | + | |
- | EXX ; Recuperar valores de los registros | + | |
- | drawm16cmxy_dir1: | + | drawm16cmxy_dir1: |
- | NOP ; NOP->INC COORD_X, | + | |
- | INC (HL) | + | |
- | INC (HL) ; COORD = COORD + 2 | + | |
- | drawm16cmxy_dir2: | + | drawm16cmxy_dir2: |
- | NOP ; NOP->INC COORD_X, | + | |
- | JR drawm16cmxy_tileloop | + | |
drawm16cmxy_switch: | drawm16cmxy_switch: | ||
- | ;;; Cambio de codificacion de horizontal a vertical: | + | |
- | LD A, $EB ; Opcode de EX DE, HL | + | ld a, $eb ; Opcode de ex de, hl |
- | LD (drawm16cmxy_dir1), | + | |
- | LD (drawm16cmxy_dir2), | + | |
- | JR drawm16cmxy_read | + | |
</ | </ | ||
Línea 2779: | Línea 2788: | ||
La forma más sencilla es que el primer byte de la pantalla contenga el tipo de codificación utilizado. | La forma más sencilla es que el primer byte de la pantalla contenga el tipo de codificación utilizado. | ||
- | Una rutina " | + | Una rutina " |
Como ID de codificación se podría utilizar, por ejemplo: | Como ID de codificación se podría utilizar, por ejemplo: | ||
Línea 2791: | Línea 2800: | ||
</ | </ | ||
- | Es difícil que la codificación básica sea más óptima que ninguna de las anteriores a menos que apenas haya bloques " | + | Es difícil que la codificación básica sea más óptima que ninguna de las anteriores a menos que apenas haya bloques " |
<code z80> | <code z80> | ||
Línea 2799: | Línea 2808: | ||
; | ; | ||
DrawMap_16x16_Codificada: | DrawMap_16x16_Codificada: | ||
- | LD HL, (DM_MAP) | + | ld hl, (DM_MAP) |
- | LD A, (HL) ; Leemos tipo de codificacion | + | ld a, (hl) ; Leemos tipo de codificacion |
- | INC HL ; Incrementamos puntero (a datos) | + | inc hl ; Incrementamos puntero (a datos) |
- | LD (DM_MAP), | + | |
- | | + | |
- | AND A ; Es A == 0? (MAP_CODIF_NONE) | + | and a ; Es A == 0? (MAP_CODIF_NONE) |
- | JR NZ, dm16c_nocero | + | jr nz, dm16c_nocero |
- | CALL DrawMap_16x16 | + | |
- | RET | + | ret |
dm16c_nocero: | dm16c_nocero: | ||
- | CP MAP_CODIF_HORIZ | + | |
- | JR NZ, dm16c_nohoriz | + | jr nz, dm16c_nohoriz |
- | CALL DrawMap_16x16_Cod_Horiz | + | |
- | RET | + | ret |
dm16c_nohoriz: | dm16c_nohoriz: | ||
- | CP MAP_CODIF_VERT | + | |
- | JR NZ, dm16c_novert | + | jr nz, dm16c_novert |
- | CALL DrawMap_16x16_Cod_Vert | + | |
- | RET | + | ret |
dm16c_novert: | dm16c_novert: | ||
- | CP MAP_CODIF_MIXTA | + | |
- | JR NZ, dm16c_nomixta | + | jr nz, dm16c_nomixta |
- | CALL DrawMap_16x16_Cod_Mixta | + | |
- | RET | + | ret |
dm16c_nomixta: | dm16c_nomixta: | ||
- | | + | call DrawMap_16x16_Cod_Basica |
- | RET | + | ret |
</ | </ | ||
Línea 2846: | Línea 2855: | ||
En el caso de la compresión básica no conseguíamos mejoras de tamaño en las pantallas si existían bloques transparentes (255) además de bloques vacíos (0), ya que nosotros sólo podíamos considerar a nivel de codificación uno de los 2 como " | En el caso de la compresión básica no conseguíamos mejoras de tamaño en las pantallas si existían bloques transparentes (255) además de bloques vacíos (0), ya que nosotros sólo podíamos considerar a nivel de codificación uno de los 2 como " | ||
- | Lo bueno de las técnicas de codificación por scanlines horizontales, | + | Lo bueno de las técnicas de codificación por scanlines horizontales, |
| | ||
Línea 2855: | Línea 2864: | ||
<code z80> | <code z80> | ||
- | $ grep -E " | + | $ grep -E " |
IGNORE_VALUES = 255 | IGNORE_VALUES = 255 | ||
BLANK = 255 | BLANK = 255 | ||
Línea 2870: | Línea 2879: | ||
</ | </ | ||
- | En este caso, los bloques " | + | En este caso, los bloques " |
\\ | \\ | ||
- | {{ : | + | {{ : |
\\ | \\ | ||
- | No hay colisión entre el 255 " | + | No hay colisión entre el 255 " |
Línea 2885: | Línea 2894: | ||
\\ | \\ | ||
- | Otro efecto interesante para mejorar la riqueza gráfica de un juego es generar una " | + | Otro efecto interesante para mejorar la riqueza gráfica de un juego es generar una " |
Por ejemplo, la siguiente captura de pantalla de un juego de los //Mojon Twins// muestra cómo los muros verticales rojos cercanos a la " | Por ejemplo, la siguiente captura de pantalla de un juego de los //Mojon Twins// muestra cómo los muros verticales rojos cercanos a la " | ||
\\ | \\ | ||
- | {{ : | + | {{ : |
\\ | \\ | ||
Línea 2913: | Línea 2922: | ||
| | ||
- | - Pintamos el carácter 1 si el tile en (x-1, y-1) es fondo o el tile 1' si es obstáculo. | + | - Pintamos el carácter 1 si el tile en (x-1, y-1) es fondo o el tile 1' si es obstáculo. |
- Pintamos el carácter 2 si el tile en (x, y-1) es fondo o el tile 2' si es obstáculo. | - Pintamos el carácter 2 si el tile en (x, y-1) es fondo o el tile 2' si es obstáculo. | ||
- Pintamos el carácter 3 si el tile en (x-1, y) es fondo o el tile 3' si es obstáculo. | - Pintamos el carácter 3 si el tile en (x-1, y) es fondo o el tile 3' si es obstáculo. | ||
Línea 2928: | Línea 2937: | ||
\\ | \\ | ||
+ | |< 70% >| | ||
^ Codificación ^ Tamaño (bytes) ^ Ocupación 100 pantallas ^ Pantallas en 16KB ^ | ^ Codificación ^ Tamaño (bytes) ^ Ocupación 100 pantallas ^ Pantallas en 16KB ^ | ||
| Datos en crudo | 192 | 18.7 KB | 85 pantallas | | | Datos en crudo | 192 | 18.7 KB | 85 pantallas | | ||
Línea 2974: | Línea 2984: | ||
</ | </ | ||
- | Es decir, para codificar las 3 líneas originales hemos generado 1 ristra de bytes verticales, y ahora 4 horizontales, | + | Es decir, para codificar las 3 líneas originales hemos generado 1 ristra de bytes verticales, y ahora 4 horizontales, |
Sin embargo, hubiera sido mejor codificar primero los scanlines horizontales, | Sin embargo, hubiera sido mejor codificar primero los scanlines horizontales, | ||
Línea 2981: | Línea 2991: | ||
0001234000 | 0001234000 | ||
0000010000 | 0000010000 | ||
- | 0000010000 | + | 0000010000 |
0000010000 | 0000010000 | ||
0000010000 | 0000010000 | ||
Línea 2992: | Línea 3002: | ||
<code z80> | <code z80> | ||
- | $ ./ | + | $ ./ |
; Flag codificacion: | ; Flag codificacion: | ||
; Resultado: 31 Bytes | ; Resultado: 31 Bytes | ||
Línea 2999: | Línea 3009: | ||
DB 5 , 1 , 2 , 3 , 4 , 255 , 255 | DB 5 , 1 , 2 , 3 , 4 , 255 , 255 | ||
- | $ ./ | + | $ ./ |
; Flag codificacion: | ; Flag codificacion: | ||
; Resultado: 34 Bytes | ; Resultado: 34 Bytes | ||
Línea 3006: | Línea 3016: | ||
DB 255 , 4 , 5 , 2 , 255 , 6 , 5 , 4 , 255 , 255 | DB 255 , 4 , 5 , 2 , 255 , 6 , 5 , 4 , 255 , 255 | ||
- | $ ./ | + | $ ./ |
; Flag codificacion: | ; Flag codificacion: | ||
; Resultado: 28 Bytes | ; Resultado: 28 Bytes | ||
Línea 3052: | Línea 3062: | ||
</ | </ | ||
- | Si la separación entre 2 scanlines la forma 1 bloque " | + | Si la separación entre 2 scanlines la forma 1 bloque " |
- | Si la separación entre 2 scanlines la forman 2 bloques " | + | Si la separación entre 2 scanlines la forman 2 bloques " |
Para más de 3 bloques transparentes no se produce ningún ahorro, sino todo lo contrario. | Para más de 3 bloques transparentes no se produce ningún ahorro, sino todo lo contrario. | ||
Línea 3070: | Línea 3080: | ||
<code z80> | <code z80> | ||
Tabla_IDs_Tilesets: | Tabla_IDs_Tilesets: | ||
- | | + | |
- | DW dir_tileset_attrib_1 | + | DW dir_tileset_attrib_1 |
- | DB ancho_tiles_tileset1, | + | DB ancho_tiles_tileset1, |
- | DW dir_tileset_gfx_2 | + | DW dir_tileset_gfx_2 |
- | DW dir_tileset_attrib_2 | + | DW dir_tileset_attrib_2 |
- | DB ancho_tiles_tileset2, | + | DB ancho_tiles_tileset2, |
- | DW dir_tileset_gfx_3 | + | DW dir_tileset_gfx_3 |
- | DW dir_tileset_attrib_3 | + | DW dir_tileset_attrib_3 |
- | DB ancho_tiles_tileset3, | + | DB ancho_tiles_tileset3, |
</ | </ | ||
Línea 3085: | Línea 3095: | ||
<code z80> | <code z80> | ||
Pantalla1: | Pantalla1: | ||
- | DB ID_TILESET, X, Y, ID_TILE, ID_TILESET, X, Y, ID_TILE | + | |
- | | + | DB ID_TILESET, X, Y, ID_TILE, ID_TILESET, X, Y, ID_TILE |
- | | + | DB (...) |
- | | + | DB 255 (fin de pantalla) |
</ | </ | ||
Línea 3103: | Línea 3113: | ||
==== Mapeados de tiles de cualquier tamaño de bloque ==== | ==== Mapeados de tiles de cualquier tamaño de bloque ==== | ||
- | | + | |
Para eso, debemos dejar de pensar en las pantallas como matrices de tiles y visualizarlas y definirlas como " | Para eso, debemos dejar de pensar en las pantallas como matrices de tiles y visualizarlas y definirlas como " | ||
Línea 3111: | Línea 3121: | ||
<code z80> | <code z80> | ||
Tabla_Tiles: | Tabla_Tiles: | ||
- | DW tileset_1_gfx+(0*32) | + | |
- | | + | DW tileset_1_attr+(0*4) |
- | | + | DB 16, 16 |
- | | + | DW tileset_1_gfx+(1*32) |
- | | + | DW tileset_1_attr+(1*4) |
- | | + | DB 16, 16 |
- | | + | DW tileset_1_gfx+(2*32) |
- | | + | DW tileset_1_attr+(2*4) |
- | | + | DB 16, 16 |
- | | + | DW tileset_2_gfx+(0*8) |
- | | + | DW tileset_2_attr+(0*1) |
- | | + | DB 8, 8 |
- | | + | DW tileset_2_gfx+(1*8) |
- | | + | DW tileset_2_attr+(1*0) |
- | | + | DB 8, 8 |
- | | + | DW logotipo_gfx |
- | | + | DW logotipo_attr |
- | | + | DB 32, 16 |
- | | + | DW piedra_gfx |
- | | + | DW piedra_attr |
- | | + | DB 32, 32 |
- | | + | DW muro_grande_gfx |
- | | + | DW muro_grande_attr |
- | | + | DB 64, 64 |
- | | + | DW grafico_escalera_gfx |
- | | + | DW grafico_escalera_attr |
- | | + | DB 16, 32 |
</ | </ | ||
Línea 3149: | Línea 3159: | ||
La pantalla acabará en un valor 255 y los valores de X e Y deberán ser coordenadas exactas de pantalla. La rutina de impresión recorrerá cada byte de la pantalla (hasta encontrar el fin de pantalla o 255) y trazará todos los sprites llamando a la rutina genérica de DrawSprite_MxN. | La pantalla acabará en un valor 255 y los valores de X e Y deberán ser coordenadas exactas de pantalla. La rutina de impresión recorrerá cada byte de la pantalla (hasta encontrar el fin de pantalla o 255) y trazará todos los sprites llamando a la rutina genérica de DrawSprite_MxN. | ||
- | | + | |
Con este sistema se debe de diseñar y codificar manualmente la pantalla, pero nos permite tener una riqueza gráfica que no siempre se puede conseguir sólo con tiles de tamaños fijos. | Con este sistema se debe de diseñar y codificar manualmente la pantalla, pero nos permite tener una riqueza gráfica que no siempre se puede conseguir sólo con tiles de tamaños fijos. | ||
Línea 3160: | Línea 3170: | ||
DrawSprite_MxN_LD_extendida: | DrawSprite_MxN_LD_extendida: | ||
- | LD A, (DS_HEIGHT) | + | ld a, (DS_HEIGHT) |
- | LD B, A | + | ld b, a |
- | LD A, (DS_WIDTH) | + | ld a, (DS_WIDTH) |
- | LD C, A ; Obtenemos datos del sprite | + | ld c, a ; Obtenemos datos del sprite |
- | | + | |
- | | + | ;;; B = ALTO de Sprite |
- | | + | ;;; C = ANCHO de Sprite |
- | | + | |
- | LD A, C ; A = ANCHO | + | ld a, c ; A = ANCHO |
- | CP 16 ; Comparar ancho | + | |
- | JR NZ, dspMN_no16 | + | jr nz, dspMN_no16 |
- | SUB B ; A = Ancho - alto | + | sub b ; A = Ancho - alto |
- | JR NZ, dspMN_generica | + | jr nz, dspMN_generica |
- | | + | ; Es cero, imprimir 16x16: |
- | CALL DrawSprite16x16 | + | |
- | RET | + | ret |
dspMN_no16: | dspMN_no16: | ||
- | LD A, C ; Recuperamos ancho | + | ld a, c ; Recuperamos ancho |
- | CP 8 ; ¿es 8? | + | |
- | JR NZ, dspMN_generica | + | jr nz, dspMN_generica |
- | SUB B ; A = Ancho - alto | + | sub b ; A = Ancho - alto |
- | JR NZ, dspMN_generica | + | jr nz, dspMN_generica |
- | | + | call DrawSprite_8x8 |
- | RET | + | ret |
dspMN_generica: | dspMN_generica: | ||
- | ;;; (resto rutina generica) | + | |
- | RET | + | ret |
</ | </ | ||
Línea 3207: | Línea 3217: | ||
<code z80> | <code z80> | ||
Tiles_Extendidos: | Tiles_Extendidos: | ||
- | DW logotipo_gfx | + | |
- | | + | DW logotipo_attr |
- | | + | DB 32, 16 |
- | | + | DW piedra_gfx |
- | | + | DW piedra_attr |
- | | + | DB 32, 32 |
- | | + | DW muro_grande_gfx |
- | | + | DW muro_grande_attr |
- | | + | DB 64, 64 |
- | | + | DW grafico_escalera_gfx |
- | | + | DW grafico_escalera_attr |
- | | + | DB 16, 32 |
</ | </ | ||
Línea 3239: | Línea 3249: | ||
Si incluímos ahora en el tileset uno o varios tiles específicos para el fondo y los codificamos dentro de las pantallas, entonces dejará de ser posible la compresión ya que todos los tiles de la pantalla tendrían que ser dibujados (ya no " | Si incluímos ahora en el tileset uno o varios tiles específicos para el fondo y los codificamos dentro de las pantallas, entonces dejará de ser posible la compresión ya que todos los tiles de la pantalla tendrían que ser dibujados (ya no " | ||
- | | + | |
<code z80> | <code z80> | ||
Línea 3247: | Línea 3257: | ||
Fondos: | Fondos: | ||
- | DW fondo_piedra_gfx | + | |
- | | + | DW fondo_piedra_attr |
- | | + | DB 16, 16 |
- | | + | DW fondo_baldosas_gfx |
- | | + | DW fondo_baldosas_attr |
- | | + | DB 64, 64 |
- | | + | DW fondo_hierba_gfx |
- | | + | DW fondo_hierba_attr |
- | | + | DB 32, 32 |
</ | </ | ||
Línea 3268: | Línea 3278: | ||
<code z80> | <code z80> | ||
Mapa: | Mapa: | ||
- | | + | |
- | DB -1, 1 ; Conexiones izq y derecha ID 0 | + | DB -1, 1 ; Conexiones izq y derecha ID 0 |
- | DB FONDO_BALDOSAS | + | DB FONDO_BALDOSAS |
- | DW Pantalla_Salon | + | DW Pantalla_Salon |
- | DB 0, 2 ; Conexiones izq y derecha ID 1 | + | DB 0, 2 ; Conexiones izq y derecha ID 1 |
- | DB FONDO_PIEDRA | + | DB FONDO_PIEDRA |
- | DW Pantalla_Pasillo | + | DW Pantalla_Pasillo |
- | DB 1, 3 ; Conexiones izq y derecha ID 2 | + | DB 1, 3 ; Conexiones izq y derecha ID 2 |
- | DB FONDO_PIEDRA | + | DB FONDO_PIEDRA |
- | (...) | + | (...) |
</ | </ | ||
Línea 3286: | Línea 3296: | ||
| | ||
- | La rutina tendría que utilizar DrawSpriteMxN (ya que los fondos pueden tener cualquier tamaño) pero se recomienda que emplee rutinas específicas en los tamaños de fondo para los que tengamos rutina de impresión disponible. | + | La rutina tendría que utilizar |
De esta forma, rellenamos el área de juego con el fondo asociado a dicha pantalla y después llamamos a DrawMap para dibujar sobre este " | De esta forma, rellenamos el área de juego con el fondo asociado a dicha pantalla y después llamamos a DrawMap para dibujar sobre este " | ||
Línea 3300: | Línea 3310: | ||
===== Compresión de los datos de pantalla ===== | ===== Compresión de los datos de pantalla ===== | ||
- | Todavía | + | Como hemos comentado antes, todavía |
\\ | \\ | ||
Línea 3311: | Línea 3321: | ||
<code z80> | <code z80> | ||
- | | + | |
</ | </ | ||
Línea 3317: | Línea 3327: | ||
<code z80> | <code z80> | ||
- | | + | |
- | DB 1, 2, 2, 2, 2, 2, 2, 3, 4 | + | DB 1, 2, 2, 2, 2, 2, 2, 3, 4 |
</ | </ | ||
Línea 3324: | Línea 3334: | ||
<code z80> | <code z80> | ||
- | | + | |
- | DB 1, 253, 6, 2, 3, 4 | + | DB 1, 253, 6, 2, 3, 4 |
</ | </ | ||
Línea 3333: | Línea 3343: | ||
En cualquier caso, para aplicar este tipo de técnica tendríamos que modificar el script codificador (en busca de valores idénticos consecutivos) y la rutina de impresión (en busca del código de control 253 y con un bucle para repetir N veces el valor del tile comprimido). | En cualquier caso, para aplicar este tipo de técnica tendríamos que modificar el script codificador (en busca de valores idénticos consecutivos) y la rutina de impresión (en busca del código de control 253 y con un bucle para repetir N veces el valor del tile comprimido). | ||
+ | |||
+ | Este tipo de algoritmo de compresión se denomina RLE y lo veremos en el siguiente capítulo. | ||
\\ | \\ | ||
Línea 3341: | Línea 3353: | ||
El sistema de compresión por patrones es el método que, probablemente, | El sistema de compresión por patrones es el método que, probablemente, | ||
- | + | ||
Se basa en identificar " | Se basa en identificar " | ||
Línea 3350: | Línea 3362: | ||
<code z80> | <code z80> | ||
Pantalla: | Pantalla: | ||
- | | + | |
</ | </ | ||
- | | + | |
| | ||
Línea 3378: | Línea 3390: | ||
Patron0: | Patron0: | ||
- | | + | |
Patron1: | Patron1: | ||
- | | + | |
Patron2: | Patron2: | ||
- | | + | |
- | + | ||
Patron3: | Patron3: | ||
- | | + | |
- | + | ||
Patron4: | Patron4: | ||
- | | + | |
</ | </ | ||
Línea 3397: | Línea 3409: | ||
<code z80> | <code z80> | ||
Tabla_Patrones: | Tabla_Patrones: | ||
- | | + | |
- | DW Patron1 | + | DW Patron1 |
- | DW Patron2 | + | DW Patron2 |
- | DW Patron3 | + | DW Patron3 |
- | DW Patron4 | + | DW Patron4 |
- | (...) | + | (...) |
</ | </ | ||
| | ||
- | + | ||
Si llamamos a estos patrones en el orden que los hemos visto, como A, B, C, D y E, obtenemos 1 patrón horizontal y 4 verticales: | Si llamamos a estos patrones en el orden que los hemos visto, como A, B, C, D y E, obtenemos 1 patrón horizontal y 4 verticales: | ||
Línea 3430: | Línea 3442: | ||
<code z80> | <code z80> | ||
Pantalla: | Pantalla: | ||
- | | + | |
- | DB 8, 2, 253, 0 | + | DB 8, 2, 253, 0 |
- | DB 1, 4, 253, 0 | + | DB 1, 4, 253, 0 |
- | DB 0, 6, 253, 0 | + | DB 0, 6, 253, 0 |
- | DB 7, 6, 253, 0 | + | DB 7, 6, 253, 0 |
- | DB 15, 0, 253, 1 | + | DB 15, 0, 253, 1 |
- | DB 19, 0, 253, 1 | + | DB 19, 0, 253, 1 |
- | DB 16, 0, 253, 2 | + | DB 16, 0, 253, 2 |
- | DB 20, 0, 253, 2 | + | DB 20, 0, 253, 2 |
- | DB 17, 0, 253, 3 | + | DB 17, 0, 253, 3 |
- | DB 18, 0, 253, 4 | + | DB 18, 0, 253, 4 |
- | DB 17, 5, 9, 9, 255 | + | DB 17, 5, 9, 9, 255 |
- | DB 17, 6, 9, 9, 255 | + | DB 17, 6, 9, 9, 255 |
</ | </ | ||
Línea 3454: | Línea 3466: | ||
\\ | \\ | ||
- | {{ : | + | {{ : |
\\ | \\ | ||
;#; | ;#; | ||
Línea 3481: | Línea 3493: | ||
\\ | \\ | ||
- | {{ : | + | {{ : |
\\ | \\ | ||
;#; | ;#; | ||
Línea 3493: | Línea 3505: | ||
\\ | \\ | ||
- | {{ : | + | {{ : |
\\ | \\ | ||
Línea 3511: | Línea 3523: | ||
;;; (etc...) | ;;; (etc...) | ||
Propiedades_Tiles: | Propiedades_Tiles: | ||
- | | + | |
- | DB %00000001 | + | DB %00000001 |
- | DB %00000010 | + | DB %00000010 |
- | DB %00000001 | + | DB %00000001 |
- | DB %00000101 | + | DB %00000101 |
</ | </ | ||
Línea 3547: | Línea 3559: | ||
| | ||
+ | * Tiled: https:// | ||
* Mappy: http:// | * Mappy: http:// | ||
* Mappy Linux : http:// | * Mappy Linux : http:// | ||
* Map Editor: http:// | * Map Editor: http:// | ||
- | Map Editor | + | Tiled es el editor más moderno de los 3, y soporta |
\\ | \\ | ||
Línea 3573: | Línea 3586: | ||
Esto implica la necesidad de 6912 bytes de memoria para evitar que el usuario vea la generación del mapa, por lo que no es normal utilizar esta técnica a menos que esté realmente justificado. | Esto implica la necesidad de 6912 bytes de memoria para evitar que el usuario vea la generación del mapa, por lo que no es normal utilizar esta técnica a menos que esté realmente justificado. | ||
- | Si utilizamos pantallas virtuales necesitaremos modificar todas las rutinas de impresión para que trabajen con una dirección destino diferente en lugar de sobre $4000. Para que las rutinas sigan pudiendo utilizar los trucos de composición de dirección en base a desplazamientos de bits que vimos en capítulos anteriores lo normal es que busquemos una dirección de memoria libre cuyos 3 bits más altos ya no sean " | + | Si utilizamos pantallas virtuales necesitaremos modificar todas las rutinas de impresión para que trabajen con una dirección destino diferente en lugar de sobre $4000. Para que las rutinas sigan pudiendo utilizar los trucos de composición de dirección en base a desplazamientos de bits que vimos en capítulos anteriores lo normal es que busquemos una dirección de memoria libre cuyos 3 bits más altos ya no sean " |
- | Por otra parte, si nos estamos planteando el usar una pantalla virtual simplemente para que no se vea el proceso de construcción de la pantalla, podemos ahorrarnos la pantalla virtual separando la rutina de impresión de pantalla en 2: una de impresión de gráficos y otra de impresión de atributos. Así, rellenamos el área de pantalla que aloja el mapa con atributos " | + | Por otra parte, si nos estamos planteando el usar una pantalla virtual simplemente para que no se vea el proceso de construcción de la pantalla, podemos ahorrarnos la pantalla virtual separando la rutina de impresión de pantalla en 2: una de impresión de gráficos y otra de impresión de atributos. Así, rellenamos el área de pantalla que aloja el mapa con atributos " |
Línea 3620: | Línea 3633: | ||
* [[http:// | * [[http:// | ||
* [[http:// | * [[http:// | ||
- | * [[http:// | ||
+ | \\ | ||
+ | **[ [[.: |