cursos:ensamblador:gfx5_mapeados

Diferencias

Muestra las diferencias entre dos versiones de la página.

Enlace a la vista de comparación

Ambos lados, revisión anteriorRevisión previa
Próxima revisión
Revisión previa
cursos:ensamblador:gfx5_mapeados [03-01-2024 08:40] sromerocursos: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 "localidades" de juego en la memoria del Spectrum? + 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 "localidades" de juego en la memoria del Spectrum?
  
  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 "tiles" a dibujar. + 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 "tiles" a dibujar.
  
  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:
  
 \\  \\ 
-{{ :cursos:ensamblador:gfx5_sokobanl1.png | Pantalla 1 de Sokoban }}+{{ :cursos:ensamblador:gfx5_sokobanl1.png?640 | Pantalla 1 de Sokoban }}
 \\  \\ 
  
Línea 92: Línea 92:
  
 <code z80> <code z80>
-  DEFB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8+    DEFB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
 </code> </code>
  
Línea 98: Línea 98:
  
 <code z80> <code z80>
-  DEFB 8,8,8,8,8,8,2,3,1,4,8,8,8,8,8,8+    DEFB 8,8,8,8,8,8,2,3,1,4,8,8,8,8,8,8
 </code> </code>
- +
  Continuemos observando la pantalla del nivel 1 de Sokoban y el vector de datos que vamos generando: La tercera fila tiene 7 tiles: 3 consecutivos con formas de paredes (tiles nº 1, 2 y 3), luego 2 tiles "vacíos" de fondo (valor 0) y 2 tiles más de "paredes" (tiles nº 5 y 4). El resto de tiles son transparentes (valor 8):  Continuemos observando la pantalla del nivel 1 de Sokoban y el vector de datos que vamos generando: La tercera fila tiene 7 tiles: 3 consecutivos con formas de paredes (tiles nº 1, 2 y 3), luego 2 tiles "vacíos" de fondo (valor 0) y 2 tiles más de "paredes" (tiles nº 5 y 4). El resto de tiles son transparentes (valor 8):
  
 <code z80> <code z80>
-  DEFB 8,8,8,8,1,2,3,0,0,5,4,8,8,8,8,8+    DEFB 8,8,8,8,1,2,3,0,0,5,4,8,8,8,8,8
 </code> </code>
  
Línea 115: Línea 115:
  
 sokoban_LEVEL1_h: sokoban_LEVEL1_h:
-  DEFB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,+    DEFB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
-  DEFB 8,8,8,8,8,8,2,3,1,4,8,8,8,8,8,+    DEFB 8,8,8,8,8,8,2,3,1,4,8,8,8,8,8,
-  DEFB 8,8,8,8,1,2,3,0,0,5,4,8,8,8,8,+    DEFB 8,8,8,8,1,2,3,0,0,5,4,8,8,8,8,
-  DEFB 8,8,8,8,4,0,6,6,0,0,5,8,8,8,8,+    DEFB 8,8,8,8,4,0,6,6,0,0,5,8,8,8,8,
-  DEFB 8,8,8,8,5,0,0,6,0,0,4,8,8,8,8,+    DEFB 8,8,8,8,5,0,0,6,0,0,4,8,8,8,8,
-  DEFB 8,8,8,8,4,0,0,0,0,0,5,8,8,8,8,+    DEFB 8,8,8,8,4,0,0,0,0,0,5,8,8,8,8,
-  DEFB 8,8,8,8,5,2,3,0,0,2,3,8,8,8,8,+    DEFB 8,8,8,8,5,2,3,0,0,2,3,8,8,8,8,
-  DEFB 8,8,8,8,8,8,1,0,0,0,4,8,8,8,8,+    DEFB 8,8,8,8,8,8,1,0,0,0,4,8,8,8,8,
-  DEFB 8,8,8,8,8,8,4,7,7,7,5,8,8,8,8,+    DEFB 8,8,8,8,8,8,4,7,7,7,5,8,8,8,8,
-  DEFB 8,8,8,8,8,8,5,2,3,2,3,8,8,8,8,+    DEFB 8,8,8,8,8,8,5,2,3,2,3,8,8,8,8,
-  DEFB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,+    DEFB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
-  DEFB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8+    DEFB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
 </code> </code>
  
- 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 ''DEFB'' por cada fila horizontal, pero el aspecto real de los datos en memoria es totalmente lineal:
  
 <code z80> <code z80>
 sokoban_LEVEL1_h: sokoban_LEVEL1_h:
- DEFB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,2,3,1,4,(...),8,8,8,8+    DEFB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,2,3,1,4,(...),8,8,8,8
 </code> </code>
  
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, es decir, creando un vector que almacenara los identificadores de tile de cada **columna** de la pantalla. + En el anterior ejemplo hemos organizado el mapa en formato horizontal. También habría cabido la posibilidad de organizarlo verticalmente, es decir, creando un vector que almacenara los identificadores de tile de cada **columna** de la pantalla.
  
  Veamos de nuevo la pantalla inicial de Sokoban para codificarla verticalmente:  Veamos de nuevo la pantalla inicial de Sokoban para codificarla verticalmente:
  
 \\  \\ 
-{{ :cursos:ensamblador:gfx5_sokobanl1.png | Pantalla 1 de Sokoban }}+{{ :cursos:ensamblador:gfx5_sokobanl1.png?640 | Pantalla 1 de Sokoban }}
 \\  \\ 
  
Línea 155: Línea 155:
  
 <code z80> <code z80>
-  DEFB 8,8,8,8,8,8,8,8,8,8,8,+    DEFB 8,8,8,8,8,8,8,8,8,8,8,
-  DEFB 8,8,8,8,8,8,8,8,8,8,8,+    DEFB 8,8,8,8,8,8,8,8,8,8,8,
-  DEFB 8,8,8,8,8,8,8,8,8,8,8,+    DEFB 8,8,8,8,8,8,8,8,8,8,8,
-  DEFB 8,8,8,8,8,8,8,8,8,8,8,8+    DEFB 8,8,8,8,8,8,8,8,8,8,8,8
 </code> </code>
  
Línea 164: Línea 164:
  
 <code z80> <code z80>
-  DEFB 8,8,1,4,5,4,5,8,8,8,8,8+    DEFB 8,8,1,4,5,4,5,8,8,8,8,8
 </code> </code>
  
Línea 170: Línea 170:
  
 <code z80> <code z80>
-  DEFB 8,8,2,0,0,0,2,8,8,8,8,8+    DEFB 8,8,2,0,0,0,2,8,8,8,8,8
 </code> </code>
  
Línea 181: Línea 181:
  
 sokoban_LEVEL1_v: sokoban_LEVEL1_v:
-  DEFB 8,8,8,8,8,8,8,8,8,8,8,+    DEFB 8,8,8,8,8,8,8,8,8,8,8,
-  DEFB 8,8,8,8,8,8,8,8,8,8,8,+    DEFB 8,8,8,8,8,8,8,8,8,8,8,
-  DEFB 8,8,8,8,8,8,8,8,8,8,8,+    DEFB 8,8,8,8,8,8,8,8,8,8,8,
-  DEFB 8,8,8,8,8,8,8,8,8,8,8,+    DEFB 8,8,8,8,8,8,8,8,8,8,8,
-  DEFB 8,8,1,4,5,4,5,8,8,8,8,+    DEFB 8,8,1,4,5,4,5,8,8,8,8,
-  DEFB 8,8,2,0,0,0,2,8,8,8,8,+    DEFB 8,8,2,0,0,0,2,8,8,8,8,
-  DEFB 8,2,3,6,0,0,3,1,4,5,8,+    DEFB 8,2,3,6,0,0,3,1,4,5,8,
-  DEFB 8,3,0,6,6,0,0,0,7,2,8,+    DEFB 8,3,0,6,6,0,0,0,7,2,8,
-  DEFB 8,1,0,0,0,0,0,0,7,3,8,+    DEFB 8,1,0,0,0,0,0,0,7,3,8,
-  DEFB 8,4,5,0,0,0,2,0,7,2,8,+    DEFB 8,4,5,0,0,0,2,0,7,2,8,
-  DEFB 8,8,4,5,4,5,3,4,5,3,8,+    DEFB 8,8,4,5,4,5,3,4,5,3,8,
-  DEFB 8,8,8,8,8,8,8,8,8,8,8,+    DEFB 8,8,8,8,8,8,8,8,8,8,8,
-  DEFB 8,8,8,8,8,8,8,8,8,8,8,+    DEFB 8,8,8,8,8,8,8,8,8,8,8,
-  DEFB 8,8,8,8,8,8,8,8,8,8,8,+    DEFB 8,8,8,8,8,8,8,8,8,8,8,
-  DEFB 8,8,8,8,8,8,8,8,8,8,8,+    DEFB 8,8,8,8,8,8,8,8,8,8,8,
-  DEFB 8,8,8,8,8,8,8,8,8,8,8,8+    DEFB 8,8,8,8,8,8,8,8,8,8,8,8
 </code> </code>
  
- En este caso nuestros "DEFBs" son de 12 bytes cada uno, teniendo un total de 16 columnas de 12 bytes = los mismos 192 bytes de datos de pantalla.+ En este caso nuestros ''DEFB''son de 12 bytes cada uno, teniendo un total de 16 columnas de 12 bytes = los mismos 192 bytes de datos de pantalla.
  
  Según codifiquemos el mapa en formato horizontal o vertical tendremos que programar una rutina de impresión de pantalla u otra, ya que el orden de obtención de los datos desde el "vector de pantalla" es diferente.  Según codifiquemos el mapa en formato horizontal o vertical tendremos que programar una rutina de impresión de pantalla u otra, ya que el orden de obtención de los datos desde el "vector de pantalla" es diferente.
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,Y_INICIO), y está pensada para el trazado de una pantalla que no tiene scroll de ningún tipo y sobre la que después trabajaremos.+ 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'',''Y_INICIO''), y está pensada para el trazado de una pantalla que no tiene scroll de ningún tipo y sobre la que después trabajaremos.
  
  Ejemplos de juegos con este "formato" de pantalla son Manic Miner, Bubble Bobble, Sabre Wulf, Dynamite Dan, Sir Fred, etc.... La pantalla del mapa se dibuja una sóla vez y no se redibuja se o cambia de pantalla a menos que el personaje cruce los límites de la misma.  Ejemplos de juegos con este "formato" de pantalla son Manic Miner, Bubble Bobble, Sabre Wulf, Dynamite Dan, Sir Fred, etc.... La pantalla del mapa se dibuja una sóla vez y no se redibuja se o cambia de pantalla a menos que el personaje cruce los límites de la misma.
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:
-  FOR X=0 TO ANCHO_PANTALLA_EN_TILES: +    FOR X=0 TO ANCHO_PANTALLA_EN_TILES: 
-     TILE = PANTALLA[x][y] +       TILE = PANTALLA[x][y] 
-     XTILE = X_INICIAL + X*ANCHO_TILE +       XTILE = X_INICIAL + X*ANCHO_TILE 
-     YTILE = Y_INICIAL + Y*ALTO_TILE +       YTILE = Y_INICIAL + Y*ALTO_TILE 
-     CALL Draw_Sprite+       call Draw_Sprite
 </code> </code>
  
- 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.
  
  Además, la obtención de cada TILE implica un acceso a una matriz de 2 dimensiones X,Y, que en nuestro array de datos se corresponde con:  Además, la obtención de cada TILE implica un acceso a una matriz de 2 dimensiones X,Y, que en nuestro array de datos se corresponde con:
Línea 243: Línea 243:
  Veamos una aproximación mucho más óptima:  Veamos una aproximación mucho más óptima:
  
-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 (''DIR_PANTALLA'') para apuntar al siguiente dato.
  
-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 (''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.
  
  
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:
-  DIR_MEM = Posicion_Memoria( X_INICIAL, Y_INICIAL + Y*ALTO_BLOQUE ) +    DIR_MEM = Posicion_Memoria( X_INICIAL, Y_INICIAL + Y*ALTO_BLOQUE ) 
-  FOR X=0 TO ANCHO_PANTALLA: +    FOR X=0 TO ANCHO_PANTALLA: 
-     TILE = [DIR_PANTALLA] +        TILE = [DIR_PANTALLA] 
-     DIR_PANTALLA = DIR_PANTALLA + 1 +        DIR_PANTALLA = DIR_PANTALLA + 1 
-     PUSH DIR_MEM +        push DIR_MEM 
-     DIR_SPRITE = BASE_TILESET + (TILE*ANCHO_TILE*ALTO_TILE) +        DIR_SPRITE = BASE_TILESET + (TILE*ANCHO_TILE*ALTO_TILE) 
-     Dibujar Sprite desde DIR_SPRITE a DIR_MEM +        Dibujar Sprite desde DIR_SPRITE a DIR_MEM 
-     POP DIR_MEM +        pop DIR_MEM 
-     DIR_MEM = DIR_MEM + ANCHO_TILE+        DIR_MEM = DIR_MEM + ANCHO_TILE
 </code> </code>
  
- 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 ''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.
  
  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 (''DIR_PANTALLA'').
    * Utilizaremos el valor de tile 255 como un tile "especial" que la rutina no dibujará. Este tile será pues un tile transparente que dejará ver el fondo en contraposición al típico bloque "0" vacío que borra un tile de pantalla.    * Utilizaremos el valor de tile 255 como un tile "especial" que la rutina no dibujará. Este tile será pues un tile transparente que dejará ver el fondo en contraposición al típico bloque "0" vacío que borra un tile de pantalla.
  
Línea 288: Línea 288:
        bucle_anchura:        bucle_anchura:
           A = (IX)           A = (IX)
-          INC IX+          inc ix
  
-          Si A == 255 :  +          Si A == 255 : 
-             JR saltar_bloque+             jr saltar_bloque
  
-          PUSH HL+          push hl
           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)
-          PUSH HL+          push hl
           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
-          POP HL+          pop hl
  
        saltar_bloque:        saltar_bloque:
           HL = HL + ANCHO_TILE           HL = HL + ANCHO_TILE
-          DJNZ bucle_anchura+          djnz bucle_anchura
  
-  DJNZ bucle_altura+  djnz bucle_altura
 </code> </code>
  
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.
  
- Tamaños de 8x8 requerirían 768 bytes por pantalla y un tileset con gran cantidad de elementos para poder componer las pantallas. + Tamaños de 8x8 requerirían 768 bytes por pantalla y un tileset con gran cantidad de elementos para poder componer las pantallas.
  
  Tiles de mayores tamaños darían poca "resolución" para generar la pantalla, ya que serían demasiado grandes. Por ejemplo, tiles de 32x32 pixeles generarían pantallas de 8x6 tiles (poca "resolución" de mapa).  Tiles de mayores tamaños darían poca "resolución" para generar la pantalla, ya que serían demasiado grandes. Por ejemplo, tiles de 32x32 pixeles generarían pantallas de 8x6 tiles (poca "resolución" de mapa).
Línea 346: Línea 346:
 ;--------------------------------------------------------------- ;---------------------------------------------------------------
 DrawMap_16x16: DrawMap_16x16:
-  + 
-   ;;;;;; Impresion de la parte grafica de los tiles ;;;;;; +    ;;;;;; Impresion de la parte grafica de los tiles ;;;;;; 
-   LD IX, (DM_MAP)           ; IX apunta al mapa  +    ld ix, (DM_MAP)           ; IX apunta al mapa 
-   LD A, (DM_HEIGHT) +    ld a, (DM_HEIGHT) 
-   LD B                  ; B = ALTO_EN_TILES (para bucle altura)+    ld b                  ; 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)         ; A = ALTO_EN_TILES +    ld a, (DM_HEIGHT)         ; A = ALTO_EN_TILES 
-   SUB B                     ; A = ALTO - iteracion_bucle = Y actual +    sub b                     ; A = ALTO - iteracion_bucle = Y actual 
-   RLCA                      ; A = Y * 2+    rlca                      ; A = Y * 2
  
-   ;;; Calculamos la direccion destino en pantalla como +    ;;; Calculamos la direccion destino en pantalla como 
-   ;;; DIR_PANT = DIRECCION(X_INICIAL, Y_INICIAL + Y*2) +    ;;; DIR_PANT = DIRECCION(X_INICIAL, Y_INICIAL + Y*2) 
-   LD BC, (DM_COORD_X)       ; B = DB_COORD_Y y C = DB_COORD_X +    ld bc, (DM_COORD_X)       ; B = DB_COORD_Y y C = DB_COORD_X 
-   ADD AB +    add ab 
-   LD BA +    ld ba 
-   LD AB +    ld ab 
-   AND $18 +    and $18 
-   ADD A, $40 +    add a, $40 
-   LD HA +    ld ha 
-   LD AB +    ld ab 
-   AND +    and 
-   RRCA +    rrca 
-   RRCA +    rrca 
-   RRCA +    rrca 
-   ADD AC +    add ac 
-   LD L                  ; HL = DIR_PANTALLA(X_INICIAL,Y_INICIAL+Y*2)+    ld l                  ; HL = DIR_PANTALLA(X_INICIAL,Y_INICIAL+Y*2)
  
-   LD A, (DM_WIDTH) +    ld a, (DM_WIDTH) 
-   LD B                  ; B = ANCHO_EN_TILES+    ld b                  ; 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 +    cp 255                    ; Bloque especial a saltar: no se dibuja 
-   JP Z, drawm16_next+    jp z, drawm16_next
  
-   LD BA +    ld ba 
-   EX AFAF               ; Nos guardamos una copia del bloque en A' +    ex afaf               ; Nos guardamos una copia del bloque en A' 
-   LD AB+    ld ab
  
-   ;;; Calcular posicion origen (array sprites) en HL como: +    ;;; Calcular posicion origen (array sprites) en HL como: 
-   ;;;     direccion = base_sprites + (NUM_SPRITE*32) +    ;;;     direccion = base_sprites + (NUM_SPRITE*32) 
-   EX DEHL                 ; Intercambiamos DE y HL (DE=destino) +    ex dehl                 ; 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 HA +    ld ha 
-   ADD HLBC                ; HL = BC + HL = DS_SPRITES + (DS_NUMSPR * 32) +    add hlbc                ; HL = BC + HL = DS_SPRITES + (DS_NUMSPR * 32) 
-   EX DEHL                 ; Intercambiamos DE y HL (DE=origen, HL=destino)+    ex dehl                 ; 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 +    ;;; 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),                ; Copiamos dato a pantalla +    ld (hl),                ; 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),                ; Copiamos dato a pantalla +    ld (hl),                ; 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 +    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) +    ; 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 +    ; desde el septimo scanline de la fila Y+1 al primero de la Y+2 
-   LD AL +    ld al 
-   ADD A, 31 +    add a, 31 
-   LD LA +    ld la 
-   JR C, drawm16_nofix_abajop +    jr c, drawm16_nofix_abajop 
-   LD AH +    ld ah 
-   SUB +    sub 
-   LD HA+    ld ha
 drawm16_nofix_abajop: drawm16_nofix_abajop:
-  + 
-   ;;; Impresion de los segundos 2 bloques horizontales: +    ;;; 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),                ; Copiamos dato a pantalla +    ld (hl),                ; 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),                ; Copiamos dato a pantalla +    ld (hl),                ; 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+    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                    Recuperar puntero a inicio de tile
  
-   ;;;;;; Impresion de la parte de atributos del tile ;;;;;;+    ;;; Calcular posicion destino en area de atributos en DE. 
 +    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                    Recuperar puntero inicio de tile+    ld hl, (DM_ATTRIBS) 
 +    ex af, af'                Recuperamos el bloque del mapa desde A' 
 +    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 de atributo
  
-   ;;; Calcular posicion destino en area de atributos en DE. +    ldi 
-   LD A, H                   ; Codigo de Get_Attr_Offset_From_Image +    ldi                       Imprimimos la primeras fila de atributos
-   RRCA +
-   RRCA +
-   RRCA +
-   AND 3 +
-   OR $58 +
-   LD D, A +
-   LD E, L                   ; DE tiene el offset del attr de HL+
  
-   LD HL, (DM_ATTRIBS) +    ;;; Avance diferencial a la siguiente linea de atributos 
-   EX AF, AF'                ; Recuperamos el bloque del mapa desde A' +    ld a                  ; A = E 
-   LD C, A +    add a, 30                 ; Sumamos A = A + 30 mas los 2 INCs de ldi
-   LD B, 0 +    ld e                  ; 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 +
-   LDI                       ; Imprimimos la primeras fila de atributos +
-  +
-   ;;; Avance diferencial a la siguiente linea de atributos +
-   LD A                  ; A = E +
-   ADD A, 30                 ; Sumamos A = A + 30 mas los 2 INCs de LDI+
-   LD E                  ; 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+    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) +    ;;; 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
 </code> </code>
  
Línea 514: Línea 514:
  
 \\  \\ 
-1.- Eliminar el **INC L** tras el **DJNZ drawm16_loop1**.+1.- Eliminar el ''inc l'' tras el ''djnz drawm16_loop1''.
  
-2.- Eliminar los **INC DE****INC H** **DEC L** antes del **DJNZ drawm16_loop2**.+2.- Eliminar los ''inc de''''inc h'' ''dec l'' antes del ''djnz drawm16_loop2''.
 \\  \\ 
  
Línea 529: Línea 529:
  
 <code z80> <code z80>
-  ; Ejemplo impresion mapa de 16x16 +; Ejemplo impresion mapa de 16x16 
-  ORG 32768+    ORG 35000
  
-  CALL ClearScreen_Pattern        ; Imprimimos patron de fondo+    call ClearScreen_Pattern        ; Imprimimos patron de fondo
  
-  LD HL, sokoban1_gfx +    ld hl, sokoban1_gfx 
-  LD (DM_SPRITES), HL +    ld (DM_SPRITES), hl 
-  LD HL, sokoban1_attr +    ld hl, sokoban1_attr 
-  LD (DM_ATTRIBS), HL +    ld (DM_ATTRIBS), hl 
-  LD HL, sokoban_LEVEL1 +    ld hl, sokoban_LEVEL1 
-  LD (DM_MAP), HL +    ld (DM_MAP), hl 
-  LD A, 16 +    ld a, 16 
-  LD (DM_WIDTH),                ; ANCHO +    ld (DM_WIDTH),                ; ANCHO 
-  LD A, 12 +    ld a, 12 
-  LD (DM_HEIGHT),               ; ALTO +    ld (DM_HEIGHT),               ; ALTO 
-  XOR A +    xor a 
-  LD (DM_COORD_X),              ; X = Y = 0 +    ld (DM_COORD_X),              ; X = Y = 0 
-  LD (DM_COORD_Y),              ; Establecemos valores llamada +    ld (DM_COORD_Y),              ; Establecemos valores llamada
-   +
-  CALL DrawMap_16x16              ; Imprimir pantalla de mapa+
  
-loop: +    call DrawMap_16x16              ; Imprimir pantalla de mapa
-  JR loop+
  
 +loop:
 +    jr loop
  
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 ClearScreen_Pattern:              ; Rutina para incluir: ClearScreen_Pattern:              ; Rutina para incluir:
-   (...)                          ; Rellenado de fondo con un patron +    (...)                          ; Rellenado de fondo con un patron 
-   RET                            ; (del capitulo de Sprites Lowres) +    ret                            ; (del capitulo de Sprites Lowres)
-   +
  
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
-DM_SPRITES  EQU  50020 +DM_SPRITES  DEFW   0 
-DM_ATTRIBS  EQU  50022 +DM_ATTRIBS  DEFW   0 
-DM_MAP      EQU  50024 +DM_MAP      DEFW   0 
-DM_COORD_X  EQU  50026 +DM_COORD_X  DEFB   0 
-DM_COORD_Y  EQU  50027 +DM_COORD_Y  DEFB   0 
-DM_WIDTH    EQU  50028 +DM_WIDTH    DEFB   0 
-DM_HEIGHT   EQU  50029 +DM_HEIGHT   DEFB   0
  
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 ; Level 1 from Sokoban: ; Level 1 from Sokoban:
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
-sokoban_LEVEL1:  +sokoban_LEVEL1: 
-  DEFB 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 +    DEFB 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 
-  DEFB 255,255,255,255,255,255,2,3,1,4,255,255,255,255,255,255 +    DEFB 255,255,255,255,255,255,2,3,1,4,255,255,255,255,255,255 
-  DEFB 255,255,255,255,1,2,3,0,0,5,4,255,255,255,255,255 +    DEFB 255,255,255,255,1,2,3,0,0,5,4,255,255,255,255,255 
-  DEFB 255,255,255,255,4,0,6,6,0,0,5,255,255,255,255,255 +    DEFB 255,255,255,255,4,0,6,6,0,0,5,255,255,255,255,255 
-  DEFB 255,255,255,255,5,0,0,6,0,0,4,255,255,255,255,255 +    DEFB 255,255,255,255,5,0,0,6,0,0,4,255,255,255,255,255 
-  DEFB 255,255,255,255,4,0,0,0,0,0,5,255,255,255,255,255 +    DEFB 255,255,255,255,4,0,0,0,0,0,5,255,255,255,255,255 
-  DEFB 255,255,255,255,5,2,3,0,0,2,3,255,255,255,255,255 +    DEFB 255,255,255,255,5,2,3,0,0,2,3,255,255,255,255,255 
-  DEFB 255,255,255,255,255,255,1,0,0,0,4,255,255,255,255,255 +    DEFB 255,255,255,255,255,255,1,0,0,0,4,255,255,255,255,255 
-  DEFB 255,255,255,255,255,255,4,7,7,7,5,255,255,255,255,255 +    DEFB 255,255,255,255,255,255,4,7,7,7,5,255,255,255,255,255 
-  DEFB 255,255,255,255,255,255,5,2,3,2,3,255,255,255,255,255 +    DEFB 255,255,255,255,255,255,5,2,3,2,3,255,255,255,255,255 
-  DEFB 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 +    DEFB 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 
-  DEFB 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 +    DEFB 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,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:        2,  16) ; Pixel Size:      ( 16, 128) -   Char Size:        2,  16)
Línea 597: Línea 593:
  
 sokoban1_gfx: sokoban1_gfx:
-  DEFB   0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0 +    DEFB   0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0 
-  DEFB   0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0 +    DEFB   0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0 
-  DEFB 127,252,193, 86,152,  2,180,170, 173, 86,153,254,194,170,255,254 +    DEFB 127,252,193, 86,152,  2,180,170, 173, 86,153,254,194,170,255,254 
-  DEFB   0,  0,102,102, 51, 50,153,152, 204,204,102,102, 51, 50,  0,  0 +    DEFB   0,  0,102,102, 51, 50,153,152, 204,204,102,102, 51, 50,  0,  0 
-  DEFB 127,102,205, 76,151, 24,205, 50, 151,102,205, 76,151, 24,205, 50 +    DEFB 127,102,205, 76,151, 24,205, 50, 151,102,205, 76,151, 24,205, 50 
-  DEFB 131,102,153, 76,173, 24,181, 50, 153,102,195, 76,127, 24,  0,  0 +    DEFB 131,102,153, 76,173, 24,181, 50, 153,102,195, 76,127, 24,  0,  0 
-  DEFB 255,252,255,134,255, 50,255, 90, 255,106,255, 50,255,134,255,254 +    DEFB 255,252,255,134,255, 50,255, 90, 255,106,255, 50,255,134,255,254 
-  DEFB 255,254,255,254,255,254,255,250, 255,242,253,166,255,252,  0,  0 +    DEFB 255,254,255,254,255,254,255,250, 255,242,253,166,255,252,  0,  0 
-  DEFB 127,252,205,134,151, 50,205,106, 151, 90,205, 50,151,134,205,254 +    DEFB 127,252,205,134,151, 50,205,106, 151, 90,205, 50,151,134,205,254 
-  DEFB 195,254,153,254,173,254,181,250, 153,242,195,166,127,252,  0,  0 +    DEFB 195,254,153,254,173,254,181,250, 153,242,195,166,127,252,  0,  0 
-  DEFB 255,254,255,254,255,254,255,254, 255,254,255,254,191,254,255,254 +    DEFB 255,254,255,254,255,254,255,254, 255,254,255,254,191,254,255,254 
-  DEFB 255,134,191, 50,255,106,191, 90, 159, 50,207,134,127,252,  0,  0 +    DEFB 255,134,191, 50,255,106,191, 90, 159, 50,207,134,127,252,  0,  0 
-  DEFB   0,  0,127,254, 95,250, 96,  6, 111,182,111,118, 96,230,109,214 +    DEFB   0,  0,127,254, 95,250, 96,  6, 111,182,111,118, 96,230,109,214 
-  DEFB 107,182,103,  6,110,246,109,246,  96,  6, 95,250,127,254,  0,  0 +    DEFB 107,182,103,  6,110,246,109,246,  96,  6, 95,250,127,254,  0,  0 
-  DEFB   0,  0,123,222,123,222, 96,  6,  96,  6,  0,  0, 96,  6, 96,  6 +    DEFB   0,  0,123,222,123,222, 96,  6,  96,  6,  0,  0, 96,  6, 96,  6 
-  DEFB  96,  6, 96,  6,  0,  0, 96,  6,  96,  6,123,222,123,222,  0,  0+    DEFB  96,  6, 96,  6,  0,  0, 96,  6,  96,  6,123,222,123,222,  0,  0
  
 sokoban1_attr: sokoban1_attr:
-  DEFB   0,  0,  0,  0,  5,  5, 70, 70, 5, 70,  5, 70, 69, 71, 69, 71 +    DEFB   0,  0,  0,  0,  5,  5, 70, 70, 5, 70,  5, 70, 69, 71, 69, 71 
-  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
 </code> </code>
  
Línea 622: Línea 620:
  
 \\  \\ 
-{{ :cursos:ensamblador:gfx5_sokoban1.png | Programa de ejemplo impresion pantalla 16x16}}+{{ :cursos:ensamblador:gfx5_sokoban1.png?640 | Programa de ejemplo impresion pantalla 16x16}}
 \\  \\ 
  
- Nótese que las pantallas de mapa no tienen por qué tener el tamaño exacto de 256x192 de la pantalla de TV. Nuestra pantalla anterior ocupa más memoria de la estrictamente necesaria, ya que gran parte de la información alrededor del "área de juego real" son bloques transparentes. + Nótese que las pantallas de mapa no tienen por qué tener el tamaño exacto de 256x192 de la pantalla de TV. Nuestra pantalla anterior ocupa más memoria de la estrictamente necesaria, ya que gran parte de la información alrededor del "área de juego real" son bloques transparentes.
  
  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,255,  2,  3,  4,  1,255 +    DEFB 255,255,  2,  3,  4,  1,255 
-  DEFB   4,  2,  3,  0,  0,  5,  1 +    DEFB   4,  2,  3,  0,  0,  5,  1 
-  DEFB   1,  0,  6,  6,  0,  0,  5 +    DEFB   1,  0,  6,  6,  0,  0,  5 
-  DEFB   5,  0,  0,  6,  0,  0,  1 +    DEFB   5,  0,  0,  6,  0,  0,  1 
-  DEFB   1,  0,  0,  0,  0,  0,  5 +    DEFB   1,  0,  0,  0,  0,  0,  5 
-  DEFB   5,  2,  3,  0,  0,  2,  3 +    DEFB   5,  2,  3,  0,  0,  2,  3 
-  DEFB 255,255,  4,  0,  0,  0,  1 +    DEFB 255,255,  4,  0,  0,  0,  1 
-  DEFB 255,255,  1,  7,  7,  7,  5 +    DEFB 255,255,  1,  7,  7,  7,  5 
-  DEFB 255,255,  5,  2,  3,  2,  3+    DEFB 255,255,  5,  2,  3,  2,  3
 </code> </code>
  
Línea 648: Línea 646:
  
 <code z80> <code z80>
-  LD HL, sokoban1_gfx +    ld hl, sokoban1_gfx 
-  LD (DM_SPRITES), HL +    ld (DM_SPRITES), hl 
-  LD HL, sokoban1_attr +    ld hl, sokoban1_attr 
-  LD (DM_ATTRIBS), HL +    ld (DM_ATTRIBS), hl 
-  LD HL, sokoban_LEVEL1 +    ld hl, sokoban_LEVEL1 
-  LD (DM_MAP), HL +    ld (DM_MAP), hl 
-  LD A, 7 +    ld a, 7 
-  LD (DM_WIDTH),                ; ANCHO +    ld (DM_WIDTH),                ; ANCHO 
-  LD A, 9 +    ld a, 9 
-  LD (DM_HEIGHT),               ; ALTO +    ld (DM_HEIGHT),               ; ALTO 
-  LD A, 8 +    ld a, 8 
-  LD (DM_COORD_X),              ; X_INICIAL +    ld (DM_COORD_X),              ; X_INICIaL 
-  LD A, 3 +    ld a, 3 
-  LD (DM_COORD_Y),              ; Y_INICIAL +    ld (DM_COORD_Y),              ; Y_INICIaL 
-  CALL DrawMap_16x16              ; Imprimir pantalla de mapa+    call DrawMap_16x16              ; Imprimir pantalla de mapa
 </code> </code>
  
- 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 "tamaños y posiciones" para establecer los parámetros de entrada a DrawMap_16x16 y dibujar la pantalla en su posición correcta.+ 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'' ''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 "tamaños y posiciones" para establecer los parámetros de entrada a ''DrawMap_16x16'' y dibujar la pantalla en su posición correcta.
  
  Esto puede valer para juegos como Sokoban (donde cada pantalla puede tener un tamaño diferente) pero no para juegos tipo plataformas/aventuras/arcade donde todas las pantallas tienen un tamaño fijo. En ese caso basta con usar nuestra rutina con unos valores fijos para todas ellas.  Esto puede valer para juegos como Sokoban (donde cada pantalla puede tener un tamaño diferente) pero no para juegos tipo plataformas/aventuras/arcade donde todas las pantallas tienen un tamaño fijo. En ese caso basta con usar nuestra rutina con unos valores fijos para todas ellas.
Línea 680: Línea 678:
 ;--------------------------------------------------------------- ;---------------------------------------------------------------
 DrawMap_8x8: DrawMap_8x8:
-  + 
-   ;;;;;; Impresion de la parte grafica de los tiles ;;;;;; +    ;;;;;; Impresion de la parte grafica de los tiles ;;;;;; 
-   LD IX, (DM_MAP)           ; IX apunta al mapa  +    ld ix, (DM_MAP)           ; IX apunta al mapa 
-   LD A, (DM_HEIGHT) +    ld a, (DM_HEIGHT) 
-   LD B                  ; B = ALTO_EN_TILES (para bucle altura)+    ld b                  ; 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)         ; A = ALTO_EN_TILES +    ld a, (DM_HEIGHT)         ; A = ALTO_EN_TILES 
-   SUB B                     ; A = ALTO - iteracion_bucle = Y actual +    sub b                     ; A = ALTO - iteracion_bucle = Y actual 
-                             ;;; NUEVO: Eliminamos RLCA (no multiplicar Y*2)+                              ;;; NUEVO: Eliminamos rlca (no multiplicar Y*2)
  
-   ;;; Calculamos la direccion destino en pantalla como +    ;;; Calculamos la direccion destino en pantalla como 
-   ;;; DIR_PANT = DIRECCION(X_INICIAL, Y_INICIAL + Y) +    ;;; DIR_PANT = DIRECCION(X_INICIAL, Y_INICIAL + Y) 
-   LD BC, (DM_COORD_X)       ; B = DB_COORD_Y y C = DB_COORD_X +    ld bc, (DM_COORD_X)       ; B = DB_COORD_Y y C = DB_COORD_X 
-   ADD AB +    add ab 
-   LD BA +    ld ba 
-   LD AB +    ld ab 
-   AND $18 +    and $18 
-   ADD A, $40 +    add a, $40 
-   LD HA +    ld ha 
-   LD AB +    ld ab 
-   AND +    and 
-   RRCA +    rrca 
-   RRCA +    rrca 
-   RRCA +    rrca 
-   ADD AC +    add ac 
-   LD L                  ; HL = DIR_PANTALLA(X_INICIAL,Y_INICIAL+Y*2)+    ld l                  ; HL = DIR_PANTALLA(X_INICIAL,Y_INICIAL+Y*2)
  
-   LD A, (DM_WIDTH) +    ld a, (DM_WIDTH) 
-   LD B                  ; B = ANCHO_EN_TILES+    ld b                  ; 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)              ; Leemos un byte del mapa 
 +    inc ix                    ; Apuntamos al siguiente byte del mapa
  
-   LD A(IX+0)              ; Leemos un byte del mapa    +    cp 255                    ; Bloque especial a saltar: no se dibuja 
-   INC IX                    ; Apuntamos al siguiente byte del mapa+    jp zdrawm8_next
  
-   CP 255                    Bloque especial a saltar: no se dibuja +    ld b, a 
-   JP Zdrawm8_next+    ex af, af'                Nos guardamos una copia del bloque en A' 
 +    ld ab
  
-   LD BA +    ;;; Calcular posicion origen (array sprites) en HL como: 
-   EX AFAF'                ; Nos guardamos una copia del bloque en A' +    ;;;     direccion = base_sprites + (NUM_SPRITE*8) 
-   LD AB+    ex dehl                 ; 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=origenHL=destino)
  
-   ;;; Calcular posicion origen (array sprites) en HL como: +    push hl                   Guardamos el puntero a pantalla recien calculado 
-   ;;;     direccion = base_sprites + (NUM_SPRITE*8) +    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 +    ;;; Impresion de los primeros 2 bloques horizontales del tile 
-   PUSH HL+    ld b, 8
  
-   ;;; Impresion de los primeros 2 bloques horizontales del tile +drawm8_loop:                  ;;; NUEVO: Bucle de impresion de 1 solo bloque 
-   LD B8+    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:                 ;;; NUEVO: Bucle de impresion de 1 solo bloque +    ;;; En este punto, los 8 scanlines del tile estan dibujados.
-   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 ;;;;;; +    ;;;;;; 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. +    ;;; Calcular posicion destino en area de atributos en DE. 
-   LD A                  ; Codigo de Get_Attr_Offset_From_Image +    ld a                  ; Codigo de Get_Attr_Offset_From_Image 
-   RRCA +    rrca 
-   RRCA +    rrca 
-   RRCA +    rrca 
-   AND +    and 
-   OR $58 +    or $58 
-   LD DA +    ld da 
-   LD E                  ; DE tiene el offset del attr de HL+    ld e                  ; DE tiene el offset del attr de HL
  
-   LD HL, (DM_ATTRIBS) +    ld hl, (DM_ATTRIBS) 
-   EX AFAF               ; Recuperamos el bloque del mapa desde A' +    ex afaf               ; Recuperamos el bloque del mapa desde A' 
-   LD CA +    ld ca 
-   LD B, 0                   ;;; NUEVO: HL = HL+DM_NUMSPR (NO *4) +    ld b, 0                   ;;; NUEVO: HL = HL+DM_NUMSPR (NO *4) 
-   ADD HLBC                ; HL = HL+DM_NUMSPR = Origen de atributo+    add hlbc                ; HL = HL+DM_NUMSPR = Origen de atributo
  
-   LD A, (HL+    ld a, (hl
-   LD (DE),                ;;; NUEVO: Impresion de un unico atributo. +    ld (de),                ;;; 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) +    ;;; 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
 </code> </code>
  
Línea 812: Línea 810:
  
  Hay 2 posibilidades de agrupación de las pantallas: como un **array de pantallas**, o como una **matriz global de mapeado**.  Hay 2 posibilidades de agrupación de las pantallas: como un **array de pantallas**, o como una **matriz global de mapeado**.
- +
 \\  \\ 
 ==== 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:
-  DB 0, 0, 0, 3, (...) +    DB 0, 0, 0, 3, (...) 
-  +
 Pantalla_Salon: Pantalla_Salon:
-  DB 1, 2, 3, 4, (...) +    DB 1, 2, 3, 4, (...) 
-  +
 Pantalla_Pasillo: Pantalla_Pasillo:
-  DB 2, 2, 2, 2, (...) +    DB 2, 2, 2, 2, (...) 
-  +
 Pantalla_Escalera: Pantalla_Escalera:
-  DB 4, 4, 5, 1, (...)+    DB 4, 4, 5, 1, (...)
  
 (...) (...)
Línea 840: Línea 838:
 <code z80> <code z80>
 Mapa: Mapa:
-  DW Pantalla_Inicio         ; Pantalla 0 +    DW Pantalla_Inicio         ; Pantalla 0 
-  DW Pantalla_Salon          ; Pantalla 1 +    DW Pantalla_Salon          ; Pantalla 1 
-  DW Pantalla_Pasillo        ; Pantalla 2 +    DW Pantalla_Pasillo        ; Pantalla 2 
-  DW Pantalla_Escalera       ; Pantalla 3 +    DW Pantalla_Escalera       ; Pantalla 3 
-  (...)                      ; (etc...) +    (...)                      ; (etc...) 
-  DW 0000                    ; Fin de pantalla+    DW 0000                    ; Fin de pantalla
 </code> </code>
  
Línea 863: Línea 861:
  
 <code z80> <code z80>
-  ;;; Calculamos la posicion de "pantalla_actual" en al tabla +    ;;; Calculamos la posicion de "pantalla_actual" en al tabla 
-  LD BC, Mapa                     ; BC = Inicio de la tabla Mapa +    ld bc, Mapa                     ; BC = Inicio de la tabla Mapa 
-  LD A, (pantalla_actual)         ; A = Pantalla actual +    ld a, (pantalla_actual)         ; A = Pantalla actual 
-  LD LA +    ld la 
-  LD H, 0                         ; HL = Pantalla actual +    ld h, 0                         ; HL = Pantalla actual 
-  SLA L +    sla l 
-  RL  H                           ; HL = Pantalla actual * 2 +    rl                            ; HL = Pantalla actual * 2 
-  ADD HLBC                      ; HL = Mapa + (Pantalla actual * 2) +    add hlbc                      ; 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 LA +    ld la 
-  LD (DM_MAP), HL                 ; Almacenamos el mapa a imprimir +    ld (DM_MAP), hl                 ; Almacenamos el mapa a imprimir 
-  CALL DrawMap_16x16              ; Imprimimos el mapa+    call DrawMap_16x16              ; Imprimimos el mapa
 </code> </code>
  
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:
-  DW Pantalla_Inicio            ; ID = 0 +    DW Pantalla_Inicio            ; ID = 0 
-  DB -1, 1                      ; Conexiones izq y derecha ID 0 +    DB -1, 1                      ; Conexiones izq y derecha ID 0 
-  DW Pantalla_Salon             ; ID = 1  +    DW Pantalla_Salon             ; ID = 1 
-  DB 0, 2                       ; Conexiones izq y derecha ID 1 +    DB 0, 2                       ; Conexiones izq y derecha ID 1 
-  DW Pantalla_Pasillo           ; ID = 2 +    DW Pantalla_Pasillo           ; ID = 2 
-  DB 1, 3                       ; Conexiones izq y derecha ID 2 +    DB 1, 3                       ; Conexiones izq y derecha ID 2 
-  DW Pantalla_Escalera          ; ID = 3 +    DW Pantalla_Escalera          ; ID = 3 
-  DB 3, -1                      ; Conexiones izq y derecha ID 3 +    DB 3, -1                      ; Conexiones izq y derecha ID 3 
-  (...)+    (...)
 </code> </code>
  
Línea 926: Línea 924:
 <code z80> <code z80>
 BYTES_POR_PANTALLA     EQU   4 BYTES_POR_PANTALLA     EQU   4
-RUTINA_ROM_HL_POR_DE   EQU   $30A9+RUTINA_ROM_HL_POR_DE   EQU   $30a9
  
 ;------------------------------------------------------------ ;------------------------------------------------------------
 ; 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                        ; HL = PANTALLA +    ld d                        ; HL = PANTALLA 
-  LD E, BYTES_POR_PANTALLA        ; DE = BYTES POR PANTALLA +    ld e, BYTES_POR_PANTALLA        ; DE = BYTES POR PANTALLA 
-  CALL RUTINA_ROM_HL_POR_DE       ; HL = HL * DE +    call RUTINA_ROM_HL_POR_DE       ; HL = HL * DE 
-  ADD HLBC                      ; Lo sumamos al inicio del MAPA +    add hlbc                      ; Lo sumamos al inicio del MAPA 
-  RET                             ; HL = MAPA + (PANTALLA*BYTES)+    ret                             ; HL = MAPA + (PANTALLA*BYTES)
 </code> </code>
  
  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.
  
- Podríamos haber realizado la multiplicación por 4 mediante desplazamientos, pero utilizando una rutina de multiplicación nos aseguramos que Get_Screen_Pointer pueda ser utilizado para mapas que definan más conexiones.+ Podríamos haber realizado la multiplicación por 4 mediante desplazamientos, pero utilizando una rutina de multiplicación nos aseguramos que ''Get_Screen_Pointer'' pueda ser utilizado para mapas que definan más conexiones.
  
  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>
-  ;;; En el inicio del programa... +    ;;; En el inicio del programa... 
-  LD HL, sokoban1_gfx +    ld hl, sokoban1_gfx 
-  LD (DM_SPRITES), HL +    ld (DM_SPRITES), hl 
-  LD HL, sokoban1_attr +    ld hl, sokoban1_attr 
-  LD (DM_ATTRIBS), HL +    ld (DM_ATTRIBS), hl 
-  LD A, 16 +    ld a, 16 
-  LD (DM_WIDTH),                ; ANCHO +    ld (DM_WIDTH),                ; ANCHO 
-  LD A, 12 +    ld a, 12 
-  LD (DM_HEIGHT),               ; ALTO +    ld (DM_HEIGHT),               ; ALTO 
-  XOR A +    xor a 
-  LD (DM_COORD_X),              ; X = Y = 0 +    ld (DM_COORD_X),              ; X = Y = 0 
-  LD (DM_COORD_Y),              ; Establecemos valores llamada+    ld (DM_COORD_Y),              ; Establecemos valores llamada
  
-  (...) +    (...) 
-   + 
-  ;;; 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 LA +    ld la 
-  CALL Get_Screen_Pointer         ; HL = Datos de la pantalla +    call Get_Screen_Pointer         ; HL = Datos de la pantalla 
-  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 LA +    ld la 
-  LD (DM_MAP), HL                 ; Almacenamos el mapa a imprimir +    ld (DM_MAP), hl                 ; Almacenamos el mapa a imprimir 
-  CALL DrawMap_16x16              ; Imprimimos el mapa+    call DrawMap_16x16              ; Imprimimos el mapa
  
-  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 
-  LD (con_izquierda),           ; la almacenamos +    ld (con_izquierda),           ; la almacenamos 
-  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 
-  LD (con_derecha),             ; la almacenamos+    ld (con_derecha),             ; la almacenamos
 </code> </code>
  
Línea 996: Línea 994:
 <code z80> <code z80>
 Mapa: Mapa:
-  DW Pantalla_Inicio            ; ID = 0 +    DW Pantalla_Inicio            ; ID = 0 
-  DW Pantalla_Salon             ; ID = 1  +    DW Pantalla_Salon             ; ID = 1 
-  DW Pantalla_Pasillo           ; ID = 2 +    DW Pantalla_Pasillo           ; ID = 2 
-  DW Pantalla_Escalera          ; ID = 3 +    DW Pantalla_Escalera          ; ID = 3 
-  (...) +    (...) 
-  +
 Conexiones: Conexiones:
-  DB -1, 1                      ; Conexiones izq y derecha ID 0 +    DB -1, 1                      ; Conexiones izq y derecha ID 0 
-  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 
-  (...)+    (...)
  
 </code> </code>
Línea 1031: Línea 1029:
 <code z80> <code z80>
 Mapa: Mapa:
-  DW Pantalla_Inicio            ; ID = 0 +    DW Pantalla_Inicio            ; ID = 0 
-  DW -1, 1                      ; Conexiones izq y derecha ID 0+    DW -1, 1                      ; Conexiones izq y derecha ID 0
 </code> </code>
  
Línea 1042: Línea 1040:
 ;;; Vector de direcciones de pantalla. ;;; Vector de direcciones de pantalla.
 Mapa: Mapa:
-  DW Pantalla_Inicio            ; ID = 0 +    DW Pantalla_Inicio            ; ID = 0 
-  DB -1, 1                      ; Conexiones izq y derecha ID 0 +    DB -1, 1                      ; Conexiones izq y derecha ID 0 
-  DW titulo_inicio              ; Direccion de la cadena de titulo +    DW titulo_inicio              ; Direccion de la cadena de titulo 
-  DW Pantalla_Salon             ; ID = 1  +    DW Pantalla_Salon             ; ID = 1 
-  DB 0, 2                       ; Conexiones izq y derecha ID 1 +    DB 0, 2                       ; Conexiones izq y derecha ID 1 
-  DW titulo_salon               ; Direccion de la cadena de titulo +    DW titulo_salon               ; Direccion de la cadena de titulo 
-  DW Pantalla_Pasillo           ; ID = 2 +    DW Pantalla_Pasillo           ; ID = 2 
-  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          ; ID = 3 +    DW Pantalla_Escalera          ; ID = 3 
-  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   DB "La pantalla de inicio", 0 titulo_inicio   DB "La pantalla de inicio", 0
Línea 1086: Línea 1084:
 <code z80> <code z80>
 Mapa: Mapa:
-  DW Pantalla_Inicio            ; ID = 0 +    DW Pantalla_Inicio            ; ID = 0 
-  DB -1, 1                      ; Conexiones izq y derecha ID 0 +    DB -1, 1                      ; Conexiones izq y derecha ID 0 
-  DW Pantalla_Salon             ; ID = 1  +    DW Pantalla_Salon             ; ID = 1 
-  DB 0, 2                       ; Conexiones izq y derecha ID 1 +    DB 0, 2                       ; Conexiones izq y derecha ID 1 
-  DW Pantalla_Pasillo           ; ID = 2 +    DW Pantalla_Pasillo           ; ID = 2 
-  DB 1, 3                       ; Conexiones izq y derecha ID 2 +    DB 1, 3                       ; Conexiones izq y derecha ID 2 
-  DW Pantalla_Pasillo           ; ID = 3 +    DW Pantalla_Pasillo           ; ID = 3 
-  DB 2, 4                       ; Conexiones izq y derecha ID 3 +    DB 2, 4                       ; Conexiones izq y derecha ID 3 
-  DW Pantalla_Pasillo           ; ID = 4 +    DW Pantalla_Pasillo           ; ID = 4 
-  DB 3, 5                       ; Conexiones izq y derecha ID 4 +    DB 3, 5                       ; Conexiones izq y derecha ID 4 
-  DW Pantalla_Escalera          ; ID = 5 +    DW Pantalla_Escalera          ; ID = 5 
-  DB 4, -1                      ; Conexiones izq y derecha ID 5 +    DB 4, -1                      ; Conexiones izq y derecha ID 5 
-  (...)+    (...)
 </code> </code>
  
Línea 1136: Línea 1134:
  
 Mapa Mapa
- DB A,A,A,A,A,A,A,A,B,B,B,B,B,B,B,+    DB A,A,A,A,A,A,A,A,B,B,B,B,B,B,B,
- DB A,A,A,A,A,A,A,A,B,B,B,B,B,B,B,+    DB A,A,A,A,A,A,A,A,B,B,B,B,B,B,B,
- DB A,A,A,A,A,A,A,A,B,B,B,B,B,B,B,+    DB A,A,A,A,A,A,A,A,B,B,B,B,B,B,B,
- DB A,A,A,A,A,A,A,A,B,B,B,B,B,B,B,+    DB A,A,A,A,A,A,A,A,B,B,B,B,B,B,B,
- DB A,A,A,A,A,A,A,A,B,B,B,B,B,B,B,+    DB A,A,A,A,A,A,A,A,B,B,B,B,B,B,B,
- DB A,A,A,A,A,A,A,A,B,B,B,B,B,B,B,+    DB A,A,A,A,A,A,A,A,B,B,B,B,B,B,B,
- DB A,A,A,A,A,A,A,A,B,B,B,B,B,B,B,+    DB A,A,A,A,A,A,A,A,B,B,B,B,B,B,B,
- DB A,A,A,A,A,A,A,A,B,B,B,B,B,B,B,+    DB A,A,A,A,A,A,A,A,B,B,B,B,B,B,B,
- DB C,C,C,C,C,C,C,C,D,D,D,D,D,D,D,+    DB C,C,C,C,C,C,C,C,D,D,D,D,D,D,D,
- DB C,C,C,C,C,C,C,C,D,D,D,D,D,D,D,+    DB C,C,C,C,C,C,C,C,D,D,D,D,D,D,D,
- DB C,C,C,C,C,C,C,C,D,D,D,D,D,D,D,+    DB C,C,C,C,C,C,C,C,D,D,D,D,D,D,D,
- DB C,C,C,C,C,C,C,C,D,D,D,D,D,D,D,+    DB C,C,C,C,C,C,C,C,D,D,D,D,D,D,D,
- DB C,C,C,C,C,C,C,C,D,D,D,D,D,D,D,+    DB C,C,C,C,C,C,C,C,D,D,D,D,D,D,D,
- DB C,C,C,C,C,C,C,C,D,D,D,D,D,D,D,+    DB C,C,C,C,C,C,C,C,D,D,D,D,D,D,D,
- DB C,C,C,C,C,C,C,C,D,D,D,D,D,D,D,+    DB C,C,C,C,C,C,C,C,D,D,D,D,D,D,D,
- DB C,C,C,C,C,C,C,C,D,D,D,D,D,D,D,D+    DB C,C,C,C,C,C,C,C,D,D,D,D,D,D,D,D
 </code> </code>
  
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 "A" del ejemplo. Para avanzar hacia la derecha basta con incrementar el puntero "xmapa" con lo que la siguiente impresión de la pantalla mostrará 7 columnas "A" y una columna "B" en el extremo derecho de la pantalla.  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 "A" del ejemplo. Para avanzar hacia la derecha basta con incrementar el puntero "xmapa" con lo que la siguiente impresión de la pantalla mostrará 7 columnas "A" y una columna "B" en el extremo derecho de la pantalla.
  
- 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), pero modificada en los siguientes términos:+ 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''), pero modificada en los siguientes términos:
  
 \\  \\ 
-  * 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 ''Mapa + (ymapa * ANCHO_MAPA) + xmapa''
-  * 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 ''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).
 \\  \\ 
  
Línea 1171: Línea 1169:
 <code z80> <code z80>
 DrawMap_16x16_Map: DrawMap_16x16_Map:
-  
-   LD IX, (DM_MAP)           ; IX apunta al mapa  
  
-   ;;; NUEVO: Posicionamos el puntero de mapa en posicion inicial. +    ld ix, (DM_MAP)           ; IX apunta al mapa 
-   LD HL, (DM_MAPY) + 
-   LD DE, ANCHO_MAPA_TILES +    ;;; NUEVO: Posicionamos el puntero de mapa en posicion inicial. 
-   CALL MULT_HL_POR_DE       ; HL = (ANCHO_MAPA * MAPA_Y) +    ld hl, (DM_MAPY) 
-   LD BC, (DM_MAPX) +    ld de, ANCHO_MAPA_TILES 
-   ADD HLBC                ; HL = MAPA_X + (ANCHO_MAPA * MAPA_Y) +    call MULT_HL_POR_DE       ; HL = (ANCHO_MAPA * MAPA_Y) 
-   EX DEHL +    ld bc, (DM_MAPX) 
-   ADD IXDE                ; IX = Inicio_Mapa + HL +    add hlbc                ; HL = MAPA_X + (ANCHO_MAPA * MAPA_Y) 
-   ;;; FIN NUEVO+    ex dehl 
 +    add ixde                ; IX = Inicio_Mapa + HL 
 +    ;;; FIN NUEVO
 </code> </code>
  
Línea 1188: Línea 1186:
  
 <code z80> <code z80>
-   ;;; NUEVO: Incrementar puntero de mapa a siguiente linea +    ;;; NUEVO: Incrementar puntero de mapa a siguiente linea 
-   LD BC, ANCHO_MAPA_TILES - ANCHO_PANTALLA +    ld bc, ANCHO_MAPA_TILES - ANCHO_PANTALLA 
-   ADD IXBC +    add ixbc 
-   ;;; FIN NUEVO+    ;;; FIN NUEVO
  
-   ;;; En este punto, hemos dibujado ANCHO tiles en pantalla (1 fila) +    ;;; 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> </code>
  
Línea 1205: Línea 1203:
 <code z80> <code z80>
 ;------------------------------------------------------------- ;-------------------------------------------------------------
-DM_SPRITES  EQU  50020 +DM_SPRITES  DEFW   0 
-DM_ATTRIBS  EQU  50022 +DM_ATTRIBS  DEFW   0 
-DM_MAP      EQU  50024 +DM_MAP      DEFW   0 
-DM_COORD_X  EQU  50026 +DM_COORD_X  DEFB   0 
-DM_COORD_Y  EQU  50027 +DM_COORD_Y  DEFB   0 
-DM_WIDTH    EQU  50028 +DM_WIDTH    DEFB   0 
-DM_HEIGHT   EQU  50029 +DM_HEIGHT   DEFB   0 
-DM_MAPX     EQU  50030 +DM_MAPX     DEFW   0 
-DM_MAPY     EQU  50032+DM_MAPY     DEFW   0
  
 ;------------------------------------------------------------- ;-------------------------------------------------------------
Línea 1224: Línea 1222:
 ALTO_PANTALLA          EQU   11 ALTO_PANTALLA          EQU   11
  
-;;; 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         EQU   $30A9 +MULT_HL_POR_DE         EQU   $30a9
  
 ;--------------------------------------------------------------- ;---------------------------------------------------------------
Línea 1247: Línea 1244:
 ;--------------------------------------------------------------- ;---------------------------------------------------------------
 DrawMap_16x16_Map: DrawMap_16x16_Map:
-  
-   LD IX, (DM_MAP)           ; IX apunta al mapa  
  
-   ;;; NUEVO: Posicionamos el puntero de mapa en posicion inicial. +    ld ix, (DM_MAP          ; IX apunta al mapa
-   LD HL, (DM_MAPY) +
-   LD DE, ANCHO_MAPA_TILES +
-   CALL MULT_HL_POR_DE       HL = (ANCHO_MAPA * MAPA_Y) +
-   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) +    ;;; NUEVO: Posicionamos el puntero de mapa en posicion inicial. 
-   LD B                  ; B = ALTO_EN_TILES (para bucle altura)+    ld hl, (DM_MAPY) 
 +    ld de, ANCHO_MAPA_TILES 
 +    call MULT_HL_POR_DE       ; HL = (ANCHO_MAPA * MAPA_Y) 
 +    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                  ; 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)         ; A = ALTO_EN_TILES +    ld a, (DM_HEIGHT)         ; A = ALTO_EN_TILES 
-   SUB B                     ; A = ALTO - iteracion_bucle = Y actual +    sub b                     ; A = ALTO - iteracion_bucle = Y actual 
-   RLCA                      ; A = Y * 2+    rlca                      ; A = Y * 2
  
-   ;;; Calculamos la direccion destino en pantalla como +    ;;; Calculamos la direccion destino en pantalla como 
-   ;;; DIR_PANT = DIRECCION(X_INICIAL, Y_INICIAL + Y*2) +    ;;; DIR_PANT = DIRECCION(X_INICIAL, Y_INICIAL + Y*2) 
-   LD BC, (DM_COORD_X)       ; B = DB_COORD_Y y C = DB_COORD_X +    ld bc, (DM_COORD_X)       ; B = DB_COORD_Y y C = DB_COORD_X 
-   ADD AB +    add ab 
-   LD BA +    ld ba 
-   LD AB +    ld ab 
-   AND $18 +    and $18 
-   ADD A, $40 +    add a, $40 
-   LD HA +    ld ha 
-   LD AB +    ld ab 
-   AND +    and 
-   RRCA +    rrca 
-   RRCA +    rrca 
-   RRCA +    rrca 
-   ADD AC +    add ac 
-   LD L                  ; HL = DIR_PANTALLA(X_INICIAL,Y_INICIAL+Y*2)+    ld l                  ; HL = DIR_PANTALLA(X_INICIAL,Y_INICIAL+Y*2)
  
-   LD A, (DM_WIDTH) +    ld a, (DM_WIDTH) 
-   LD B                  ; B = ANCHO_EN_TILES+    ld b                  ; 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 +    cp 255                    ; Bloque especial a saltar: no se dibuja 
-   JP Z, drawmg16_next+    jp z, drawmg16_next
  
-   LD BA +    ld ba 
-   EX AFAF               ; Nos guardamos una copia del bloque en A' +    ex afaf               ; Nos guardamos una copia del bloque en A' 
-   LD AB+    ld ab
  
-   ;;; Calcular posicion origen (array sprites) en HL como: +    ;;; Calcular posicion origen (array sprites) en HL como: 
-   ;;;     direccion = base_sprites + (NUM_SPRITE*32) +    ;;;     direccion = base_sprites + (NUM_SPRITE*32) 
-   EX DEHL                 ; Intercambiamos DE y HL (DE=destino) +    ex dehl                 ; 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 HA +    ld ha 
-   ADD HLBC                ; HL = BC + HL = DM_SPRITES + (DM_NUMSPR * 32) +    add hlbc                ; HL = BC + HL = DM_SPRITES + (DM_NUMSPR * 32) 
-   EX DEHL                 ; Intercambiamos DE y HL (DE=origen, HL=destino)+    ex dehl                 ; 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+    ;;; 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),                ; Copiamos dato a pantalla +    ld (hl),                ; 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),                ; Copiamos dato a pantalla +    ld (hl),                ; 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 +    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) +    ; 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 +    ; desde el septimo scanline de la fila Y+1 al primero de la Y+2 
-   LD AL +    ld al 
-   ADD A, 31 +    add a, 31 
-   LD LA +    ld la 
-   JR C, drawmg16_nofix_abajop +    jr c, drawmg16_nofix_abajop 
-   LD AH +    ld ah 
-   SUB +    sub 
-   LD HA+    ld ha
 drawmg16_nofix_abajop: drawmg16_nofix_abajop:
-  + 
-   ;;; Impresion de los segundos 2 bloques horizontales: +    ;;; 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),                ; Copiamos dato a pantalla +    ld (hl),                ; 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),                ; Copiamos dato a pantalla +    ld (hl),                ; 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+    djnz drawmg16_loop2
  
-   ;;; En este punto, los 16 scanlines del tile estan dibujados.+    ;;; En este punto, los 16 scanlines del tile estan dibujados.
  
-   ;;;;;; Impresion de la parte de atributos del tile ;;;;;;+    ;;;;;; 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. +    ;;; Calcular posicion destino en area de atributos en DE. 
-   LD A                  ; Codigo de Get_Attr_Offset_From_Image +    ld a                  ; Codigo de Get_Attr_Offset_From_Image 
-   RRCA +    rrca 
-   RRCA +    rrca 
-   RRCA +    rrca 
-   AND +    and 
-   OR $58 +    or $58 
-   LD DA +    ld da 
-   LD E                  ; DE tiene el offset del attr de HL+    ld e                  ; DE tiene el offset del attr de HL
  
-   LD HL, (DM_ATTRIBS) +    ld hl, (DM_ATTRIBS) 
-   EX AFAF               ; Recuperamos el bloque del mapa desde A' +    ex afaf               ; Recuperamos el bloque del mapa desde A' 
-   LD CA +    ld ca 
-   LD B, 0 +    ld b, 0 
-   ADD HLBC +    add hlbc 
-   ADD HLBC +    add hlbc 
-   ADD HLBC +    add hlbc 
-   ADD HLBC                ; HL = HL+HL=(DM_NUMSPR*4) = Origen de atributo +    add hlbc                ; HL = HL+HL=(DM_NUMSPR*4) = Origen de atributo 
-  + 
-   LDI +    ldi 
-   LDI                       ; Imprimimos la primeras fila de atributos +    ldi                       ; Imprimimos la primeras fila de atributos 
-  + 
-   ;;; Avance diferencial a la siguiente linea de atributos +    ;;; Avance diferencial a la siguiente linea de atributos 
-   LD A                  ; A = E +    ld a                  ; 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                  ; Guardamos en E (E = E+30 + 2 por LDI=E+32) +    ld e                  ; 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+    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 +    ;;; NUEVO: Incrementar puntero de mapa a siguiente linea 
-   LD BC, ANCHO_MAPA_TILES - ANCHO_PANTALLA +    ld bc, ANCHO_MAPA_TILES - ANCHO_PANTALLA 
-   ADD IXBC +    add ixbc 
-   ;;; FIN NUEVO+    ;;; FIN NUEVO
  
-   ;;; En este punto, hemos dibujado ANCHO tiles en pantalla (1 fila) +    ;;; 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> </code>
  
- Además es necesario realizar rutinas adicionales que gestionen el movimiento por pantalla alterando DM_MAPX y DM_MAPY sin permitir incrementarlos más allá de (Ancho_Mapa-Ancho_Pantalla) y (Alto_Mapa-Alto_Pantalla) o decrementarlos por debajo de cero:+ Además es necesario realizar rutinas adicionales que gestionen el movimiento por pantalla alterando ''DM_MAPX'' ''DM_MAPY'' sin permitir incrementarlos más allá de (''ANCHO_MAPA ANCHO_PANTALLA'') y (''ALTO_MAPA ALTO_PANTALLA'') o decrementarlos por debajo de cero:
  
 <code z80> <code z80>
Línea 1431: Línea 1428:
 ;------------------------------------------------------------- ;-------------------------------------------------------------
 Map_Inc_X: Map_Inc_X:
-  LD HL, (DM_MAPX)+    ld hl, (DM_MAPX)
  
-  ;;; Comparacion 16 bits de HL y (ANCHO_MAPA-ANCHO_PANTALLA) +    ;;; Comparacion 16 bits de HL y (ANCHO_MAPA-ANCHO_PANTALLA) 
-  LD AH +    ld ah 
-  CP (ANCHO_MAPA_TILES-ANCHO_PANTALLA) / 256 +    CP (ANCHO_MAPA_TILES-ANCHO_PANTALLA) / 256 
-  RET NZ +    ret nz 
-  LD AL +    ld al 
-  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. 
-  LD (DM_MAPX), HL +    ld (DM_MAPX), hl 
-  RET+    ret
  
 ;------------------------------------------------------------- ;-------------------------------------------------------------
Línea 1449: Línea 1446:
 ;------------------------------------------------------------- ;-------------------------------------------------------------
 Map_Inc_Y: Map_Inc_Y:
-  LD HL, (DM_MAPY)+    ld hl, (DM_MAPY)
  
-  ;;; Comparacion 16 bits de HL y (ALTO_MAPA-ALTO_PANTALLA) +    ;;; Comparacion 16 bits de HL y (ALTO_MAPA-ALTO_PANTALLA) 
-  LD AH +    ld ah 
-  CP (ALTO_MAPA_TILES-ALTO_PANTALLA) / 256 +    CP (ALTO_MAPA_TILES-ALTO_PANTALLA) / 256 
-  RET NZ +    ret nz 
-  LD AL +    ld al 
-  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. 
-  LD (DM_MAPY), HL +    ld (DM_MAPY), hl 
-  RET+    ret
  
 ;------------------------------------------------------------- ;-------------------------------------------------------------
Línea 1467: Línea 1464:
 ;------------------------------------------------------------- ;-------------------------------------------------------------
 Map_Dec_X: Map_Dec_X:
-  LD HL, (DM_MAPX) +    ld hl, (DM_MAPX) 
-  LD AH +    ld ah 
-  AND A +    and a 
-  JR NZ, mapdecx_doit        ; Verificamos que DM_MAPX no sea 0 +    jr nz, mapdecx_doit        ; Verificamos que DM_MAPX no sea 0 
-  LD AL +    ld al 
-  AND A +    and a 
-  RET Z +    ret z 
-mapdecx_doit: +    mapdecx_doit: 
-  DEC HL +    dec hl 
-  LD (DM_MAPX), HL           ; No es cero, podemos decrementar +    ld (DM_MAPX), hl           ; No es cero, podemos decrementar 
-  RET+    ret
  
 ;------------------------------------------------------------- ;-------------------------------------------------------------
Línea 1483: Línea 1480:
 ;------------------------------------------------------------- ;-------------------------------------------------------------
 Map_Dec_Y: Map_Dec_Y:
-  LD HL, (DM_MAPY) +    ld hl, (DM_MAPY) 
-  LD AH +    ld ah 
-  AND A +    and a 
-  JR NZ, mapdecy_doit        ; Verificamos que DM_MAPX no sea 0 +    jr nz, mapdecy_doit        ; Verificamos que DM_MAPX no sea 0 
-  LD AL +    ld al 
-  AND A +    and a 
-  RET Z +    ret z 
-mapdecy_doit: +    mapdecy_doit: 
-  DEC HL +    dec hl 
-  LD (DM_MAPY), HL           ; No es cero, podemos decrementar +    ld (DM_MAPY), hl           ; No es cero, podemos decrementar 
-  RET+    ret
 </code> </code>
  
- 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 ''DM_MAPX'' ''DM_MAPY'' requiere verificar que ninguna de las 2 variables excede ''ANCHO_MAPA - ANCHO_PANTALLA'' ''ALTO_MAPA - ALTO_PANTALLA'' respectivamente. Sus decrementos requieren comprobar que el valor actual de estas variables no es cero.
  
  Utilicemos las anteriores rutinas en un programa de ejemplo en el que podemos mover una ventana de 14x11 bloques a través de un mapa de 32x24 tiles usando las teclas O, P, Q y A:  Utilicemos las anteriores rutinas en un programa de ejemplo en el que podemos mover una ventana de 14x11 bloques a través de un mapa de 32x24 tiles usando las teclas O, P, Q y A:
  
 <code z80> <code z80>
-  ; Ejemplo impresion mapa de 16x16 desde array global +; Ejemplo impresion mapa de 16x16 desde array global 
-  ORG 32768+    ORG 35000
  
-  LD HL, sokoban1_gfx +    ld hl, sokoban1_gfx 
-  LD (DM_SPRITES), HL +    ld (DM_SPRITES), hl 
-  LD HL, sokoban1_attr +    ld hl, sokoban1_attr 
-  LD (DM_ATTRIBS), HL +    ld (DM_ATTRIBS), hl 
-  LD HL, mapa_ejemplo +    ld hl, mapa_ejemplo 
-  LD (DM_MAP), HL +    ld (DM_MAP), hl 
-  LD A, ANCHO_PANTALLA +    ld a, ANCHO_PANTALLA 
-  LD (DM_WIDTH), A +    ld (DM_WIDTH), a 
-  LD A, ALTO_PANTALLA +    ld a, ALTO_PANTALLA 
-  LD (DM_HEIGHT), A +    ld (DM_HEIGHT), a 
-  XOR A +    xor a 
-  LD (DM_COORD_X), A +    ld (DM_COORD_X), a 
-  LD (DM_COORD_Y), A    +    ld (DM_COORD_Y), a 
-  LD (DM_MAPX),            ; Establecemos MAPXMAPY iniciales = 0 +    ld (DM_MAPX),            ; Establecemos MaPXMaPY iniciales = 0 
-  LD (DM_MAPY), A+    ld (DM_MAPY), a
  
 redraw: redraw:
-  CALL DrawMap_16x16_Map     ; Imprimir pantalla de mapa+    call DrawMap_16x16_Map     ; Imprimir pantalla de mapa
  
 bucle: bucle:
-  CALL LEER_TECLADO          ; Leemos el estado de O, P, Q, A+    call LEER_TECLADO          ; Leemos el estado de O, P, Q, A
  
-  BIT 0,                   ; Modificamos MAPX y MAPY segun OPQA +    bit 0,                   ; Modificamos MAPX y MAPY segun OPQA 
-  JR Z, nopulsada_q +    jr z, nopulsada_q 
-  CALL Map_Dec_Y +    call Map_Dec_Y 
-  JR redraw+    jr redraw
 nopulsada_q: nopulsada_q:
-  BIT 1, A +    bit 1, a 
-  JR Z, nopulsada_a +    jr z, nopulsada_a 
-  CALL Map_Inc_Y +    call Map_Inc_Y 
-  JR redraw+    jr redraw
 nopulsada_a: nopulsada_a:
-  BIT 2, A +    bit 2, a 
-  JR Z, nopulsada_p +    jr z, nopulsada_p 
-  CALL Map_Inc_X +    call Map_Inc_X 
-  JR redraw+    jr redraw
 nopulsada_p: nopulsada_p:
-  BIT 3, A +    bit 3, a 
-  JR Z, nopulsada_o +    jr z, nopulsada_o 
-  CALL Map_Dec_X +    call Map_Dec_X 
-  JR redraw+    jr redraw
 nopulsada_o: nopulsada_o:
-  JR bucle+    jr bucle
  
 loop: loop:
-  JR loop+  jr 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
-  BIT 0,                   ; Leemos la tecla Q +    bit 0,                   ; Leemos la tecla Q 
-  JR NZ, Control_no_up       ; No pulsada, no cambiamos nada en D +    jr nz, Control_no_up       ; No pulsada, no cambiamos nada en D 
-  SET 0,                   ; Pulsada, ponemos a 1 el bit 0+    set 0,                   ; Pulsada, ponemos a 1 el bit 0
 Control_no_up: Control_no_up:
-  + 
-  LD BC, $FDFE +    ld bc, $fdfe 
-  IN A, (C+    in a, (c
-  BIT 0,                   ; Leemos la tecla A +    bit 0,                   ; Leemos la tecla A 
-  JR NZ, Control_no_down     ; No pulsada, no cambianos nada en D +    jr nz, Control_no_down     ; No pulsada, no cambianos nada en D 
-  SET 1,                   ; Pulsada, ponemos a 1 el bit 1+    set 1,                   ; Pulsada, ponemos a 1 el bit 1
 Control_no_down: Control_no_down:
-  + 
-  LD BC, $DFFE +    ld bc, $dffe 
-  IN A, (C+    in a, (c
-  BIT 0,                   ; Leemos la tecla P +    bit 0,                   ; Leemos la tecla P 
-  JR NZ, Control_no_right    ; No pulsada +    jr nz, Control_no_right    ; No pulsada 
-  SET 2,                   ; Pulsada, ponemos a 1 el bit 2+    set 2,                   ; Pulsada, ponemos a 1 el bit 2 
 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) 
-  BIT 1,                   ; Tecla O +    bit 1,                   ; Tecla O 
-  JR NZ, Control_no_left +    jr nz, Control_no_left 
-  SET 3, D+    set 3, d
 Control_no_left: Control_no_left:
-  + 
-  LD A                   ; Devolvemos en A el estado de las teclas +    ld a                   ; Devolvemos en A el estado de las teclas 
-  RET+    ret
  
 ;------------------------------------------------------------- ;-------------------------------------------------------------
-DM_SPRITES  EQU  50020 +DM_SPRITES  DEFW   0 
-DM_ATTRIBS  EQU  50022 +DM_ATTRIBS  DEFW   0 
-DM_MAP      EQU  50024 +DM_MAP      DEFW   0 
-DM_COORD_X  EQU  50026 +DM_COORD_X  DEFB   0 
-DM_COORD_Y  EQU  50027 +DM_COORD_Y  DEFB   0 
-DM_WIDTH    EQU  50028 +DM_WIDTH    DEFB   0 
-DM_HEIGHT   EQU  50029 +DM_HEIGHT   DEFB   0 
-DM_MAPX     EQU  50030 +DM_MAPX     DEFW   0 
-DM_MAPY     EQU  50032+DM_MAPY     DEFW   0
  
 ;------------------------------------------------------------- ;-------------------------------------------------------------
Línea 1610: Línea 1608:
 ALTO_PANTALLA          EQU   11 ALTO_PANTALLA          EQU   11
  
-;;; 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         EQU   $30A9+MULT_HL_POR_DE         EQU   $30a9
  
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 ;;; Nuestra pantalla de ejemplo de 32x24 bloques: ;;; Nuestra pantalla de ejemplo de 32x24 bloques:
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
-mapa_ejemplo:  +mapa_ejemplo: 
-  DEFB 1,2,1,1,2,1,2,1,2,1,1,2,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,+    DEFB 1,2,1,1,2,1,2,1,2,1,1,2,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  DEFB 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,+    DEFB 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  DEFB 1,0,0,0,0,0,0,0,0,0,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,+    DEFB 1,0,0,0,0,0,0,0,0,0,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  DEFB 1,0,0,0,0,0,0,0,0,2,3,2,3,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,+    DEFB 1,0,0,0,0,0,0,0,0,2,3,2,3,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,
-  DEFB 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,+    DEFB 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,
-  DEFB 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,0,0,0,+    DEFB 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,7,7,0,0,0,
-  DEFB 1,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,0,0,+    DEFB 1,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,0,0,
-  DEFB 1,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,5,0,0,0,0,0,0,2,3,2,3,2,0,+    DEFB 1,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,5,0,0,0,0,0,0,2,3,2,3,2,0,
-  DEFB 1,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,4,0,0,0,0,0,0,0,0,0,0,0,0,+    DEFB 1,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,4,0,0,0,0,0,0,0,0,0,0,0,0,
-  DEFB 1,5,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,5,0,0,0,0,0,0,0,0,0,0,0,0,+    DEFB 1,5,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,5,0,0,0,0,0,0,0,0,0,0,0,0,
-  DEFB 1,4,2,3,2,3,0,0,0,0,2,3,2,3,2,3,2,3,4,2,3,2,0,0,0,0,0,0,0,0,0,+    DEFB 1,4,2,3,2,3,0,0,0,0,2,3,2,3,2,3,2,3,4,2,3,2,0,0,0,0,0,0,0,0,0,
-  DEFB 1,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,+    DEFB 1,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  DEFB 1,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,+    DEFB 1,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  DEFB 1,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,+    DEFB 1,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  DEFB 1,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,2,3,2,3,0,0,0,0,0,0,0,0,0,0,+    DEFB 1,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,2,3,2,3,0,0,0,0,0,0,0,0,0,0,
-  DEFB 1,0,0,0,6,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,+    DEFB 1,0,0,0,6,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  DEFB 1,0,0,6,6,6,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,+    DEFB 1,0,0,6,6,6,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  DEFB 1,0,2,3,2,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,+    DEFB 1,0,2,3,2,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,
-  DEFB 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,0,0,0,0,0,+    DEFB 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,0,0,0,0,0,
-  DEFB 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,6,6,0,0,0,0,+    DEFB 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,6,6,0,0,0,0,
-  DEFB 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,6,6,6,6,0,0,0,+    DEFB 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,6,6,6,6,0,0,0,
-  DEFB 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,2,3,2,3,2,3,2,3,0,0,+    DEFB 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,2,3,2,3,2,3,2,3,0,0,
-  DEFB 1,0,2,3,2,2,2,3,2,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,+    DEFB 1,0,2,3,2,2,2,3,2,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  DEFB 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1+    DEFB 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 
 + 
 +    END 35000
 </code> </code>
  
Línea 1647: Línea 1647:
  
 \\  \\ 
-{{ :cursos:ensamblador:gfx5_maparray.png | Moviendose por un mapa en array global }}+{{ :cursos:ensamblador:gfx5_maparray.png?640 | Moviendose por un mapa en array global }}
 \\  \\ 
  
  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 "entra" en el área de visión del jugador.  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 "entra" en el área de visión del jugador.
  
- Para esta implementación serían necesarias 4 rutinas de scroll de una porción de videomemoria, según el tipo de movimiento, y la impresión en la primera/última fila/columna de visión del dato de la pantalla entrante. Sigue siendo necesario modificar DM_MAPX y DM_MAPY.+ Para esta implementación serían necesarias 4 rutinas de scroll de una porción de videomemoria, según el tipo de movimiento, y la impresión en la primera/última fila/columna de visión del dato de la pantalla entrante. Sigue siendo necesario modificar ''DM_MAPX'' ''DM_MAPY''.
  
- El scroll mediante instrucciones de transferencia de N-1 FILAS o N-1 COLUMNAS de pantalla  gráfica y de atributos resultará bastante más rápido y eficiente que la rutina de impresión de sprites integrada en DrawMap, al no tener que realizar apenas cálculos.+ El scroll mediante instrucciones de transferencia de N-1 FILAS o N-1 COLUMNAS de pantalla  gráfica y de atributos resultará bastante más rápido y eficiente que la rutina de impresión de sprites integrada en ''DrawMap'', al no tener que realizar apenas cálculos.
  
  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 "agrupación" o "compresión" que veremos a continuación.  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 "agrupación" o "compresión" que veremos a continuación.
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 de ellos, la **compresión** con algoritmos conocidos (como RLE o ZX0): podemos tomar todo el bloque de datos con información sobre las pantallas y lo comprimirlo antes de salvarlo a cinta. Después, tendremos 2 opciones: o bien descomprimirlo durante el proceso de carga en su ubicación definitiva en memoria (con lo cual ahorremos tiempo de carga desde cinta, pero no memoria) o bien guardarlo en memoria comprimido (ahorrando espacio) y descomprimirlo al vuelo en algún buffer temporal antes de su uso (por ejemplo, al principio de cada nivel), lo que sí que supondría un ahorro de memoria incluso pese a necesitar ese buffer para la descompresión.  
 + 
 + 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, y es muy probable que gracias a sencillos algoritmos de compresión básicos (RLE ym sobre todo, ZX0), sea suficiente para nuestras necesidades.
  
- Uno de ellos podría basarse en la compresión por diferentes algoritmos del mapeado considerado globalmente: si tomamos todo el bloque de datos con información sobre las pantallas y lo comprimimos antes de salvarlo a cintar y lo descomprimimos al vuelo durante su carga reducimos la ocupación del binario resultante en cinta pero no de la ocupación de datos en memoria.+ Pero no siempre la compresión es la solución a todos los problemas y a veces hay que dar un paso atrás, mirar el conjunto de datos y fijarnos si podemos reducir lo que ocupa de alguna forma más inteligente mediante la **codificación**.
  
- Por estolo mejor es codificar o "comprimir" cada pantalla en sí misma que la rutina de impresión la desempaquete al vuelo.+ Este segundo métodola **codificación**, consiste en encontrar patrones repetidos en las pantallas codificarlos de una forma inteligente. Es una especie de compresión, pero muy sencilla y visual, y se puede "desempaquetar" al vuelo cuando estamos imprimiendo las pantallas.
  
- La técnica que vamos a ver no es una compresión en sí misma sino que se basa en no almacenar en el vector de datos de la pantalla los datos en blanco/transparentes. Los datos de la pantalla incluirán sólo los tiles que deben de ser dibujados.+ La técnica que vamos a ver se basa en no almacenar el total de datos de la pantalla, sino que ignoraremos los datos en blanco/transparentes. Los datos de la pantalla incluirán sólo los tiles que deben de ser dibujados, asumiendo que el resto de la pantalla es "fondo", "transparente" o "suelo".
  
  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". A continuación veremos diferentes formas de codificar los datos de los tiles "reales" y descartar los tiles "vacíos".  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". A continuación veremos diferentes formas de codificar los datos de los tiles "reales" y descartar los tiles "vacíos".
Línea 1712: Línea 1716:
 <code z80> <code z80>
 sokoban_LEVEL1: sokoban_LEVEL1:
-  DEFB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,+    DEFB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  DEFB 0,0,0,0,0,0,2,3,1,4,0,0,0,0,0,+    DEFB 0,0,0,0,0,0,2,3,1,4,0,0,0,0,0,
-  DEFB 0,0,0,0,1,2,3,0,0,5,4,0,0,0,0,+    DEFB 0,0,0,0,1,2,3,0,0,5,4,0,0,0,0,
-  DEFB 0,0,0,0,4,0,6,6,0,0,5,0,0,0,0,+    DEFB 0,0,0,0,4,0,6,6,0,0,5,0,0,0,0,
-  DEFB 0,0,0,0,5,0,0,6,0,0,4,0,0,0,0,+    DEFB 0,0,0,0,5,0,0,6,0,0,4,0,0,0,0,
-  DEFB 0,0,0,0,4,0,0,0,0,0,5,0,0,0,0,+    DEFB 0,0,0,0,4,0,0,0,0,0,5,0,0,0,0,
-  DEFB 0,0,0,0,5,2,3,0,0,2,3,0,0,0,0,+    DEFB 0,0,0,0,5,2,3,0,0,2,3,0,0,0,0,
-  DEFB 0,0,0,0,0,0,1,0,0,0,4,0,0,0,0,+    DEFB 0,0,0,0,0,0,1,0,0,0,4,0,0,0,0,
-  DEFB 0,0,0,0,0,0,4,7,7,7,5,0,0,0,0,+    DEFB 0,0,0,0,0,0,4,7,7,7,5,0,0,0,0,
-  DEFB 0,0,0,0,0,0,5,2,3,2,3,0,0,0,0,+    DEFB 0,0,0,0,0,0,5,2,3,2,3,0,0,0,0,
-  DEFB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,+    DEFB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  DEFB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0+    DEFB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
 </code> </code>
  
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 ",", str(valor)          print ",", str(valor)
          CONTADOR_DB = -1          CONTADOR_DB = -1
Línea 1942: Línea 1946:
 if __name__ == '__main__': if __name__ == '__main__':
  
-   # Variables que utilizaremos +   # Variables que utilizaremos
    pantalla = []    pantalla = []
    COORD_X = 0    COORD_X = 0
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.
  
- Veamos a continuación una sencilla rutina que permitiría imprimir un mapa con este tipo de codificación. La rutina se basa en recorrer el array de datos de pantalla obtenido el valor X, Y y de TILE y llamando a DrawSprite16x16 para la impresión de cada tile:+ Veamos a continuación una sencilla rutina que permitiría imprimir un mapa con este tipo de codificación. La rutina se basa en recorrer el array de datos de pantalla obtenido el valor X, Y y de TILE y llamando a ''DrawSprite16x16'' para la impresión de cada tile:
  
 <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), HL       ; Establecer tileset (graficos) +    ld (DS_SPRITES), hl       ; Establecer tileset (graficos) 
-   LD HL, (DM_ATTRIBS) +    ld hl, (DM_ATTRIBS) 
-   LD (DS_ATTRIBS), HL       ; Establecer tileset (atributos) +    ld (DS_ATTRIBS), hl       ; Establecer tileset (atributos) 
-   LD BC, (DM_COORD_X)       ; B = Y_INICIO, C = X_INICIO +    ld bc, (DM_COORD_X)       ; B = Y_INICIO, C = X_INICIO 
-   LD DE, (DM_MAP)           ; DE apunta al mapa +    ld de, (DM_MAP)           ; DE apunta al mapa
  
 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 +    cp 255                    ; Bloque especial fin de pantalla 
-   RET Z                     ; En ese caso, salir+    ret z                     ; En ese caso, salir
  
-   ADD A                 ; A = (X_INICIO + COORD_X_TILE) +    add a                 ; A = (X_INICIO + COORD_X_TILE) 
-   RLCA                      ; A = (X_INICIO + COORD_X_TILE) * 2 +    rlca                      ; A = (X_INICIO + COORD_X_TILE) * 2 
-   LD (DS_COORD_X),        ; Establecemos COORD_X a imprimir tile+    ld (DS_COORD_X),        ; 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                 ; A = (X_INICIO + COORD_X_TILE) +    add a                 ; A = (X_INICIO + COORD_X_TILE) 
-   RLCA                      ; A = (Y_INICIO + COORD_Y_TILE) +    rlca                      ; A = (Y_INICIO + COORD_Y_TILE) 
-   LD (DS_COORD_Y),        ; Establecemos COORD_Y a imprimir tile+    ld (DS_COORD_Y),        ; Establecemos COORD_Y a imprimir tile
  
-   LD A, (DE)                ; Leemos el valor del TILE +    ld a, (de)                ; Leemos el valor del TILE 
-   INC DE +    inc de 
-   LD (DS_NUMSPR),         ; Establecemos el TILE +    ld (DS_NUMSPR),         ; Establecemos el TILE
-    +
-   EXX                       ; Preservar todos los registros en shadows +
-   CALL DrawSprite_16x16_LD  ; Imprimir el tile con los parametros +
-   EXX                       ; Recuperar valores de los registros+
  
-   JR drawm16cb_loop         ; Repetimos hasta encontrar el 255+    exx                       ; Preservar todos los registros en shadows 
 +    call DrawSprite_16x16_LD  ; Imprimir el tile con los parametros 
 +    exx                       ; Recuperar valores de los registros 
 + 
 +    jr drawm16cb_loop         ; Repetimos hasta encontrar el 255
 </code> </code>
  
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 "bloques vacíos" borrando inicialmente la pantalla antes de realizar la impresión de los "bloques con datos".  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 "bloques vacíos" borrando inicialmente la pantalla antes de realizar la impresión de los "bloques con datos".
  
- 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 "vacías" se dibujen mediante transferencia y no mediante operaciones lógicas. Recordemos que si hemos borrado mediante atributos en negro estas áreas están vacías de color pero no de contenido gráfico y la impresión con OR haría aparecer el antiguo contenido gráfico de la pantalla. En el caso de impresión de sprites con OR sobre el área "vacía" del mapa sería necesario realizar el borrado previo a la impresión del mapa no como borrado de atributos sino como borrado de zona gráfica y de atributos.+ 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 "vacías" se dibujen mediante transferencia y no mediante operaciones lógicas. Recordemos que si hemos borrado mediante atributos en negro estas áreas están vacías de color pero no de contenido gráfico y la impresión con or haría aparecer el antiguo contenido gráfico de la pantalla. En el caso de impresión de sprites con OR sobre el área "vacía" del mapa sería necesario realizar el borrado previo a la impresión del mapa no como borrado de atributos sino como borrado de zona gráfica y de atributos.
  
  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 +; Ejemplo impresion mapa de 16x16 codificacion basica 
-  ORG 32768+    ORG 35000
  
-  ;;; Borramos la pantalla (graficos y atributos) +    ;;; Borramos la pantalla (graficos y atributos) 
-  XOR A +    xor a 
-  CALL ClearScreen +    call ClearScreen 
-  XOR A +    xor a 
-  CALL ClearAttributes+    call ClearAttributes
  
-  ;;; Establecer valores de llamada: +    ;;; Establecer valores de llamada: 
-  LD HL, sokoban1_gfx +    ld hl, sokoban1_gfx 
-  LD (DM_SPRITES), HL +    ld (DM_SPRITES), hl 
-  LD HL, sokoban1_attr +    ld hl, sokoban1_attr 
-  LD (DM_ATTRIBS), HL +    ld (DM_ATTRIBS), hl 
-  LD HL, sokoban_LEVEL1_codif_basica +    ld hl, sokoban_LEVEL1_codif_basica 
-  LD (DM_MAP), HL +    ld (DM_MAP), hl 
-  LD A, 16 +    ld a, 16 
-  LD (DM_WIDTH), A +    ld (DM_WIDTH), a 
-  LD A, 12 +    ld a, 12 
-  LD (DM_HEIGHT), A +    ld (DM_HEIGHT), a 
-  XOR A +    xor a 
-  LD (DM_COORD_X), A +    ld (DM_COORD_X), a 
-  LD (DM_COORD_Y), A+    ld (DM_COORD_Y), a
  
-  ;;; Impresion de pantalla por codificacion basica +    ;;; Impresion de pantalla por codificacion basica 
-  CALL DrawMap_16x16_Cod_Basica+    call DrawMap_16x16_Cod_Basica
  
 loop: loop:
-  JR loop +    jr loop 
-   + 
-DM_SPRITES  EQU  50020 +DM_SPRITES  DEFW   0 
-DM_ATTRIBS  EQU  50022 +DM_ATTRIBS  DEFW   0 
-DM_MAP      EQU  50024 +DM_MAP      DEFW   0 
-DM_COORD_X  EQU  50026 +DM_COORD_X  DEFB   0 
-DM_COORD_Y  EQU  50027 +DM_COORD_Y  DEFB   0 
-DM_WIDTH    EQU  50028 +DM_WIDTH    DEFB   0 
-DM_HEIGHT   EQU  50029+DM_HEIGHT   DEFB   0 
 +DM_MAPX     DEFW   0 
 +DM_MAPY     DEFW   0 
 + 
 +DS_SPRITES  DEFW   0 
 +DS_ATTRIBS  DEFW   0 
 +DS_COORD_X  DEFB   0 
 +DS_COORD_Y  DEFB   0 
 +DS_NUMSPR   DEFB   0
  
-DS_SPRITES  EQU  50000 +    END 35000
-DS_ATTRIBS  EQU  50002 +
-DS_COORD_X  EQU  50004 +
-DS_COORD_Y  EQU  50005 +
-DS_NUMSPR   EQU  50006+
 </code> </code>
  
Línea 2153: Línea 2161:
  
 \\  \\ 
-{{ :cursos:ensamblador:gfx5_codifb.png | Codificación básica }}+{{ :cursos:ensamblador:gfx5_codifb.png?640 | Codificación básica }}
 \\  \\ 
  
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  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 solución es codificar tiles "consecutivos" de forma que sólo haya que indicar una coordenada X e Y iniciales para cada "fila" o "columna" de tiles gráficos. De esta forma, 4 tiles gráficos consecutivos se codificarían como:  La solución es codificar tiles "consecutivos" de forma que sólo haya que indicar una coordenada X e Y iniciales para cada "fila" o "columna" de tiles gráficos. De esta forma, 4 tiles gráficos consecutivos se codificarían como:
  
 <code z80> <code z80>
-  DB coordenada_x_primer_tile, coordenada_y_primer_tile, +    DB coordenada_x_primer_tile, coordenada_y_primer_tile, 
-  DB tile1, tile2, tile3, tile4, 255 +    DB tile1, tile2, tile3, tile4, 255 
-  ; (255 = byte de fin de "scanline")+    ; (255 = byte de fin de "scanline")
 </code> </code>
  
Línea 2186: Línea 2194:
  
 <code z80> <code z80>
-$ ./codificar_pantalla.py -h pantalla.dat +$ ./codificar_pantalla.py -h pantalla.dat
  ; Flag codificacion: -h  ; Flag codificacion: -h
  ; 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), HL       ; Establecer tileset (graficos) 
-   LD HL, (DM_ATTRIBS) 
-   LD (DS_ATTRIBS), HL       ; Establecer tileset (atributos) 
-   LD BC, (DM_COORD_X)       ; B = Y_INICIO, C = X_INICIO 
-   LD DE, (DM_MAP)           ; DE apunta al mapa  
  
-   LD HL, DS_COORD_X+    ld hl, (DM_SPRITES) 
 +    ld (DS_SPRITES), hl       ; Establecer tileset (graficos) 
 +    ld hl, (DM_ATTRIBS) 
 +    ld (DS_ATTRIBS), hl       ; Establecer tileset (atributos) 
 +    ld bc, (DM_COORD_X)       ; B = Y_INICIO, C = X_INICIO 
 +    ld de, (DM_MAP)           ; DE apunta al mapa 
 + 
 +    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 +    cp 255                    ; Bloque especial fin de pantalla 
-   RET Z                     ; En ese caso, salir+    ret z                     ; En ese caso, salir
  
-   ADD A                 ; A = (X_INICIO + COORD_X_TILE) +    add a                 ; A = (X_INICIO + COORD_X_TILE) 
-   RLCA                      ; A = (X_INICIO + COORD_X_TILE) * 2 +    rlca                      ; A = (X_INICIO + COORD_X_TILE) * 2 
-   LD (HL),                ; Establecemos COORD_X a imprimir tile+    ld (hl),                ; 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                 ; A = (Y_INICIO + COORD_Y_TILE) +    add a                 ; A = (Y_INICIO + COORD_Y_TILE) 
-   RLCA                      ; A = (Y_INICIO + COORD_Y_TILE) +    rlca                      ; A = (Y_INICIO + COORD_Y_TILE) 
-   LD (DS_COORD_Y),        ; Establecemos COORD_Y a imprimir tile+    ld (DS_COORD_Y),        ; Establecemos COORD_Y a imprimir tile 
 + 
 +    ;;; 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      ; Si es fin de tile codificado, fin bucle
  
-   CP 255 +    ld (DS_NUMSPR)a         Establecemos el TILE
-   JR Zdrawm16ch_read      Si es fin de tile codificado, fin bucle+
  
-   LD (DS_NUMSPR), A         ; Establecemos el TILE +    exx                       ; Preservar todos los registros en shadows 
-    +    call DrawSprite_16x16_LD  ; Imprimir el tile con los parametros 
-   EXX                       ; Preservar todos los registros en shadows +    exx                       ; Recuperar valores de los registros
-   CALL DrawSprite_16x16_LD  ; Imprimir el tile con los parametros +
-   EXX                       ; Recuperar valores de los registros+
  
-   INC (HL)                  ; Avanzamos al siguiente tile +    inc (hl)                  ; Avanzamos al siguiente tile 
-   INC (HL)                  ; COORD_X = COORD_X + 2+    inc (hl)                  ; COORD_X = COORD_X + 2
  
-   JR drawm16ch_tileloop     ; Repetimos hasta encontrar el 255+    jr drawm16ch_tileloop     ; Repetimos hasta encontrar el 255
 </code> </code>
  
Línea 2276: Línea 2284:
  Según el tipo de pantalla que estemos codificando, es posible que existan más agrupaciones de bloques en "scanlines verticales" (columnas de bloques) que horizontales (filas de bloques). En ese caso, puede convenirmos codificar los bloques por scanlines verticales.  Según el tipo de pantalla que estemos codificando, es posible que existan más agrupaciones de bloques en "scanlines verticales" (columnas de bloques) que horizontales (filas de bloques). En ese caso, puede convenirmos codificar los bloques por scanlines verticales.
  
- 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 ''-v'' sobre la pantalla de ejemplo, obtenemos la siguiente pantalla codificada:
  
 <code z80> <code z80>
-$ ./codificar_pantalla.py -v pantalla.dat +$ ./codificar_pantalla.py -v pantalla.dat
  ; Flag codificacion: -v  :  ; Flag codificacion: -v  :
  ; 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), HL       ; Establecer tileset (graficos) 
-   LD HL, (DM_ATTRIBS) 
-   LD (DS_ATTRIBS), HL       ; Establecer tileset (atributos) 
-   LD BC, (DM_COORD_X)       ; B = Y_INICIO, C = X_INICIO 
-   LD DE, (DM_MAP)           ; DE apunta al mapa  
  
-   LD HL, DS_COORD_Y         ; CAMBIO: Ahora HL apunta a la variable Y+    ld hl, (DM_SPRITES) 
 +    ld (DS_SPRITES), hl       ; Establecer tileset (graficos) 
 +    ld hl, (DM_ATTRIBS) 
 +    ld (DS_ATTRIBS), hl       ; Establecer tileset (atributos) 
 +    ld bc, (DM_COORD_X)       ; B = Y_INICIO, C = X_INICIO 
 +    ld de, (DM_MAP)           ; DE apunta al mapa 
 + 
 +    ld hl, DS_COORD_Y         ; CAMBIO: Ahora HL apunta a la variable 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 +    cp 255                    ; Bloque especial fin de pantalla 
-   RET Z                     ; En ese caso, salir+    ret z                     ; En ese caso, salir
  
-   ADD A                 ; A = (X_INICIO + COORD_X_TILE) +    add a                 ; A = (X_INICIO + COORD_X_TILE) 
-   RLCA                      ; A = (X_INICIO + COORD_X_TILE) * 2 +    rlca                      ; A = (X_INICIO + COORD_X_TILE) * 2 
-   LD (DS_COORD_X),        ; CAMBIO: Establecemos COORD_X a imprimir tile+    ld (DS_COORD_X),        ; CaMBIO: 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                 ; A = (Y_INICIO + COORD_Y_TILE) +    add a                 ; A = (Y_INICIO + COORD_Y_TILE) 
-   RLCA                      ; A = (Y_INICIO + COORD_Y_TILE) +    rlca                      ; A = (Y_INICIO + COORD_Y_TILE) 
-   LD (HL),                ; CAMBIO: Establecemos COORD_Y a imprimir tile+    ld (hl),                ; CAMBIO: Establecemos COORD_Y a imprimir tile
  
-   ;;; Bucle impresion de todos los tiles del scanline (aunque sea 1 solo)+    ;;; 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      ; Si es fin de tile codificado, fin bucle 
 + 
 +    ld (DS_NUMSPR), a         ; Establecemos el TILE
  
-   CP 255 +    exx                       ; Preservar todos los registros en shadows 
-   JR Z, drawm16cv_read      ; Si es fin de tile codificado, fin bucle +    call DrawSprite_16x16_LD  ; Imprimir el tile con los parametros 
-    +    exx                       ; Recuperar valores de los registros
-   LD (DS_NUMSPR), A         ; Establecemos el TILE +
-    +
-   EXX                       ; Preservar todos los registros en shadows +
-   CALL DrawSprite_16x16_LD  ; Imprimir el tile con los parametros +
-   EXX                       ; Recuperar valores de los registros+
  
-   INC (HL+    inc (hl
-   INC (HL)                  ; COORD_Y = COORD_Y + 2+    inc (hl)                  ; COORD_Y = COORD_Y + 2
  
-   JR drawm16cv_tileloop     ; Repetimos hasta encontrar el 255+    jr drawm16cv_tileloop     ; Repetimos hasta encontrar el 255
 </code> </code>
  
Línea 2367: Línea 2375:
 \\  \\ 
  
- Finalmente, cabe la posibilidad de que en una misma pantalla nos encontremos "filas" de tiles y "columnas" de tiles que convenga codificar con un método u otro. + Finalmente, cabe la posibilidad de que en una misma pantalla nos encontremos "filas" de tiles y "columnas" de tiles que convenga codificar con un método u otro.
  
  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 "agrupación"+ 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 "agrupación".
  
  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).
  
- Nuestro script de conversión en Python, con el flag "**-m**", calcula todas las posibilidades de codificación de cada tile y los procesa en orden de mayor a menor cantidad de tiles agrupados para codificar toda la pantalla en un formato mixto donde cada ristra de datos de la pantalla tendría el siguiente aspecto:+ Nuestro script de conversión en Python, con el flag ''-m'', calcula todas las posibilidades de codificación de cada tile y los procesa en orden de mayor a menor cantidad de tiles agrupados para codificar toda la pantalla en un formato mixto donde cada ristra de datos de la pantalla tendría el siguiente aspecto:
  
 <code z80> <code z80>
 Pantalla: Pantalla:
-  DB coordenada_x_primer_tile_horiz, coordenada_y_primer_tile_horiz, +    DB coordenada_x_primer_tile_horiz, coordenada_y_primer_tile_horiz, 
-  DB tile1, tile2, (...), tileN, 255 +    DB tile1, tile2, (...), tileN, 255 
-  DB coordenada_x_primer_tile_horiz, coordenada_y_primer_tile_horiz, +    DB coordenada_x_primer_tile_horiz, coordenada_y_primer_tile_horiz, 
-  DB tile1, tile2, (...), tileN, 254 +    DB tile1, tile2, (...), tileN, 254 
-  DB coordenada_x_primer_tile_vert, coordenada_y_primer_tile_vert, +    DB coordenada_x_primer_tile_vert, coordenada_y_primer_tile_vert, 
-  DB tile1, tile2, (...), tileN, 255 +    DB tile1, tile2, (...), tileN, 255 
-  DB coordenada_x_primer_tile_vert, coordenada_y_primer_tile_vert, +    DB coordenada_x_primer_tile_vert, coordenada_y_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 "scanline" +    ; 255 a final de scanline = byte de fin de "scanline" 
-  ; 254 a final de scanline = cambio de codificacion de horizontal a vertical+    ; 254 a final de scanline = cambio de codificacion de horizontal a vertical
 </code> </code>
  
Línea 2402: Línea 2410:
  
 <code z80> <code z80>
-$ ./codificar_pantalla.py -m pantalla.dat +$ ./codificar_pantalla.py -m pantalla.dat
  ; Flag codificacion: -m  ; Flag codificacion: -m
  ; 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
 </code> </code>
- +
  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, la vertical).  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, la vertical).
  
Línea 2423: Línea 2431:
  Concretamente, tomamos como base la rutina de impresión de scanlines horizontales y utilizamos un sencillo truco para convertirla en la rutina de impresión de scanlines verticales. Lo haremos mediante **código automodificable** (self-modifying code).  Concretamente, tomamos como base la rutina de impresión de scanlines horizontales y utilizamos un sencillo truco para convertirla en la rutina de impresión de scanlines verticales. Lo haremos mediante **código automodificable** (self-modifying code).
  
- Primero, cargamos en HL la dirección de la variable COORD_X y en DE la dirección de la variable COORD_Y:+ Primero, cargamos en HL la dirección de la variable ''COORD_X'' y en DE la dirección de la variable ''COORD_Y'':
  
 <code z80> <code z80>
-   LD DE, DS_COORD_Y         ; DE apunta a la coordenada Y +    ld de, DS_COORD_Y         ; DE apunta a la coordenada Y 
-   LD HL, DS_COORD_X         ; HL apunta a la coordenada X+    ld hl, DS_COORD_X         ; HL apunta a la coordenada X
 </code> </code>
  
- Despues, incluímos 2 instrucciones **NOP** (de 1 byte, con opcode 0), antes y después de los **INC (HL)** que producen el incremento de la coordenada apuntada por HL (COORD_X). Además, establecemos 2 etiquetas del programa ensamblador en las posiciones de los 2 NOPs para poder referenciar la dirección de memoria donde se han ensamblado estos NOPs en el código:+ Despues, incluímos 2 instrucciones ''NOP'' (de 1 byte, con opcode 0), antes y después de los ''inc (hl)'' que producen el incremento de la coordenada apuntada por HL (''COORD_X''). Además, establecemos 2 etiquetas del programa ensamblador en las posiciones de los 2 NOPs para poder referenciar la dirección de memoria donde se han ensamblado estos NOPs en el código:
  
 <code z80> <code z80>
 drawm16cm_dir1: drawm16cm_dir1:
-   NOP +    nop 
-   INC (HL+    inc (hl
-   INC (HL)                  ; COORD = COORD + 2+    inc (hl)                  ; COORD = COORD + 2
 drawm16cm_dir2: drawm16cm_dir2:
-   NOP+    nop
 </code> </code>
  
- Cuando entramos por primera vez en la rutina, y comenzamos a procesar "scanlines", sabemos que son todos horizontales hasta que encontremos el valor "254" (cambio de horizontales a verticales), por lo que nuestra rutina de impresión de tiles en bucle horizontal funciona adecuadamente: se ejecuta un NOP (que no tiene ningún efecto salvo el consumo de 4 ciclos de reloj), después los 2 INC (HL) y luego otro NOP, lo que produce el incremento de COORD_X en 2 unidades (HL apunta a COORD_X).+ Cuando entramos por primera vez en la rutina, y comenzamos a procesar "scanlines", sabemos que son todos horizontales hasta que encontremos el valor "254" (cambio de horizontales a verticales), por lo que nuestra rutina de impresión de tiles en bucle horizontal funciona adecuadamente: se ejecuta un nop (que no tiene ningún efecto salvo el consumo de 4 ciclos de reloj), después los 2 ''inc (hl)'' y luego otro ''NOP'', lo que produce el incremento de ''COORD_X'' en 2 unidades (HL apunta a ''COORD_X'').
  
  Cuando la rutina encuentra un valor 254 como "fin de scanline" debe de cambiar al modo de impresión vertical, por lo que dentro del bucle de procesado del scanline añadimos el siguiente código:  Cuando la rutina encuentra un valor 254 como "fin de scanline" debe de cambiar al modo de impresión vertical, por lo que dentro del bucle de procesado del scanline añadimos el siguiente código:
Línea 2448: Línea 2456:
 drawm16cm_tileloop: drawm16cm_tileloop:
  
-   (...) +    (...) 
-    + 
-   CP 254 +    cp 254 
-   JR Z, drawm16cm_switch    ; Codigo 254 -> cambiar a codif. vertical +    jr z, drawm16cm_switch    ; Codigo 254 -> cambiar a codif. vertical 
-    + 
-   (...)+    (...)
  
 drawm16cm_switch: drawm16cm_switch:
-   ;;; Cambio de codificacion de horizontal a vertical: +    ;;; Cambio de codificacion de horizontal a vertical: 
-   LD A, $EB                 ; Opcode de EX DEHL +    ld a, $eb                 ; Opcode de ex dehl 
-   LD (drawm16cm_dir1),    ; Lo escribimos sobre los NOPs +    ld (drawm16cm_dir1),    ; Lo escribimos sobre los NOPs 
-   LD (drawm16cm_dir2), A +    ld (drawm16cm_dir2), a 
-   JR drawm16cm_read+    jr drawm16cm_read
 </code> </code>
  
- Es decir, cuando se encuentra un valor 254 como fin de scanline saltamos a drawm16cm_switch, la cual escribe un valor **$EB** (EX DEHL) en las posiciones de memoria donde antes había un NOP, cambiando la porción de código que habíamos visto antes por:+ Es decir, cuando se encuentra un valor 254 como fin de scanline saltamos a drawm16cm_switch, la cual escribe un valor **$eb** (''ex dehl'') en las posiciones de memoria donde antes había un nop, cambiando la porción de código que habíamos visto antes por:
  
 <code z80> <code z80>
 drawm16cm_dir1: drawm16cm_dir1:
-   EX DEHL +    ex dehl 
-   INC (HL+    inc (hl
-   INC (HL)                  ; COORD = COORD + 2+    inc (hl)                  ; COORD = COORD + 2
 drawm16cm_dir2: drawm16cm_dir2:
-   EX DEHL+    ex dehl
 </code> </code>
  
- 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 DEHL) 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 ''COORD_Y'' (debido al ''ex dehl'') en lugar de ''COORD_X'', convirtiendo la rutina en un sistema de impresión de scanlines horizontales.
  
- Cuando salimos de la rutina, esta se queda con los valores de "EX DEHL" en memoria, por lo que la siguiente vez que sea llamada tenemos que asegurarnos de que vuelven a estar los NOPs en su lugar, porque las pantallas siempre empiezan por scanlines horizontales. Para lograr esto, nuestra rutina debe empezar por la colocación del "NOPen las direcciones apuntadas por las etiquetas:+ Cuando salimos de la rutina, esta se queda con los valores de ''ex dehl'' en memoria, por lo que la siguiente vez que sea llamada tenemos que asegurarnos de que vuelven a estar los NOPs en su lugar, porque las pantallas siempre empiezan por scanlines horizontales. Para lograr esto, nuestra rutina debe empezar por la colocación del ''NOP'' en las direcciones apuntadas por las etiquetas:
  
 <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),    ; Almacenar en la posicion de las labels +    ld (drawm16cm_dir1),    ; almacenar en la posicion de las labels 
-   LD (drawm16cm_dir2), A+    ld (drawm16cm_dir2), a
 </code> </code>
  
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),    ; Almacenar en la posicion de labels +    ld (drawm16cm_dir1),    ; almacenar en la posicion de labels 
-   LD (drawm16cm_dir2), A+    ld (drawm16cm_dir2), a
  
-   LD HL, (DM_SPRITES) +    ld hl, (DM_SPRITES) 
-   LD (DS_SPRITES), HL       ; Establecer tileset (graficos) +    ld (DS_SPRITES), hl       ; Establecer tileset (graficos) 
-   LD HL, (DM_ATTRIBS) +    ld hl, (DM_ATTRIBS) 
-   LD (DS_ATTRIBS), HL       ; Establecer tileset (atributos) +    ld (DS_ATTRIBS), hl       ; Establecer tileset (atributos) 
-   LD BC, (DM_COORD_X)       ; B = Y_INICIO, C = X_INICIO +    ld bc, (DM_COORD_X)       ; B = Y_INICIO, C = X_INICIO 
-   LD IX, (DM_MAP)           ; DE apunta al mapa +    ld ix, (DM_MAP)           ; DE apunta al mapa
  
-   LD DE, DS_COORD_Y         ; DE apunta a la coordenada Y +    ld de, DS_COORD_Y         ; DE apunta a la coordenada Y 
-   LD HL, DS_COORD_X         ; HL apunta a la coordenada X+    ld hl, DS_COORD_X         ; HL apunta a la coordenada 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 +    cp 255                    ; Bloque especial fin de pantalla 
-   RET Z                     ; En ese caso, salir+    ret z                     ; En ese caso, salir
  
-   ADD A                 ; A = (X_INICIO + COORD_X_TILE) +    add a                 ; A = (X_INICIO + COORD_X_TILE) 
-   RLCA                      ; A = (X_INICIO + COORD_X_TILE) * 2 +    rlca                      ; A = (X_INICIO + COORD_X_TILE) * 2 
-   LD (HL),                ; Establecemos COORD_X a imprimir tile+    ld (hl),                ; 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                 ; A = (Y_INICIO + COORD_Y_TILE) +    add a                 ; A = (Y_INICIO + COORD_Y_TILE) 
-   RLCA                      ; A = (Y_INICIO + COORD_Y_TILE) +    rlca                      ; A = (Y_INICIO + COORD_Y_TILE) 
-   LD (DE),                ; Establecemos COORD_Y a imprimir tile+    ld (de),                ; Establecemos COORD_Y a imprimir tile
  
-   ;;; Bucle impresion vertical de los N tiles del scanline+    ;;; 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      ; Si es fin de tile codificado, fin bucle
  
-   CP 255 +    cp 254 
-   JR Zdrawm16cm_read      Si es fin de tile codificado, fin bucle+    jr zdrawm16cm_switch    Codigo 254 -> cambiar a codif. vertical
  
-   CP 254 +    ld (DS_NUMSPR), a         ; Establecemos el TILE 
-   JR Z, drawm16cm_switch    ; Codigo 254 -> cambiar a codif. vertical+    exx                       ; Preservar todos los registros en shadows 
 +    call DrawSprite_16x16_LD  Imprimir el tile con los parametros 
 +    exx                       ; Recuperar valores de los registros
  
-   LD (DS_NUMSPR), A         Establecemos el TILE +drawm16cm_dir1:               Etiqueta con la direccion del nop 
-   EXX                       ; Preservar todos los registros en shadows +    nop                       ; nop->inc cOORD_X,  ex de,hl->inc cOORD_Y
-   CALL DrawSprite_16x16_LD  ; Imprimir el tile con los parametros +
-   EXX                       ; Recuperar valores de los registros+
  
-drawm16cm_dir1:              ; Etiqueta con la direccion del NOP +    inc (hl
-   NOP                       ; NOP->INC COORD_X,  EX DE,HL->INC COORD_Y +    inc (hl)                  ; COORD = COORD + 2
-    +
-   INC (HL+
-   INC (HL)                  ; COORD = COORD + 2+
  
-drawm16cm_dir2:              ; Etiqueta con la direccion del NOP +drawm16cm_dir2:               ; Etiqueta con la direccion del nop 
-   NOP                       ; NOP->INC COORD_X,  EX DE,HL->INC COORD_Y+    nop                       ; nop->inc cOORD_X,  ex de,hl->inc cOORD_Y
  
-   JR drawm16cm_tileloop     ; Repetimos hasta encontrar el 255+    jr drawm16cm_tileloop     ; Repetimos hasta encontrar el 255
  
 drawm16cm_switch: drawm16cm_switch:
-   ;;; Cambio de codificacion de horizontal a vertical: +    ;;; Cambio de codificacion de horizontal a vertical: 
-   LD A, $EB                 ; Opcode de EX DEHL +    ld a, $eb                 ; Opcode de ex dehl 
-   LD (drawm16cm_dir1),    ; Ahora se hace el EX DEHL y por lo tanto +    ld (drawm16cm_dir1),    ; ahora se hace el ex dehl y por lo tanto 
-   LD (drawm16cm_dir2),    ; INC (HL) incrementa COORD_Y en vez de X +    ld (drawm16cm_dir2),    ; inc (hl) incrementa COORD_Y en vez de X 
-   JR drawm16cm_read         ; Volvemos al bucle de lectura+    jr drawm16cm_read         ; Volvemos al bucle de lectura
 </code> </code>
  
- Con el sistema de "automodificación de código" nos ahorramos el disponer de 2 porciones de código para realizar una misma tarea en la que cambia algún salto o alguna instrucción específica. + Con el sistema de "automodificación de código" nos ahorramos el disponer de 2 porciones de código para realizar una misma tarea en la que cambia algún salto o alguna instrucción específica.
  
  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( X ) 
-  mapa_codificado.append( Y )+mapa_codificado.append( Y )
 </code> </code>
  
Línea 2602: Línea 2610:
  
 <code z80> <code z80>
-  mapa_codificado.append( (X * 16) + Y )+mapa_codificado.append( (X * 16) + Y )
 </code> </code>
  
- Aunque hemos dicho que el tamaño máximo del mapa será de 16x16, la realidad es que puede ser como máximo de 16x14, ya que si ambas coordenadas X e Y valen 15 ($F), el byte resultante compuesto sería $FF que es el código de final de pantalla. De la misma forma, si X vale 15 e Y vale 14, el valor resultante, $FE, sería confundido por la rutina mixta con el código especial de cambio de scanlines horizontales a verticales.+ Aunque hemos dicho que el tamaño máximo del mapa será de 16x16, la realidad es que puede ser como máximo de 16x14, ya que si ambas coordenadas X e Y valen 15 ($f), el byte resultante compuesto sería $fF que es el código de final de pantalla. De la misma forma, si X vale 15 e Y vale 14, el valor resultante, $fE, sería confundido por la rutina mixta con el código especial de cambio de scanlines horizontales a verticales.
  
  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:
Línea 2617: 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 ''COORD_X'' ''COORD_Y'' en 2 valores diferentes, lo que supone un pequeño tiempo adicional de procesado por cada scanline.
  
- Nuestra pantalla de pruebas es de 16x12, por lo que podemos perfectamente codificarla con esta técnica, utilizando el flag **-a**, además del tipo de codificación:+ Nuestra pantalla de pruebas es de 16x12, por lo que podemos perfectamente codificarla con esta técnica, utilizando el flag ''-a'', además del tipo de codificación:
  
 <code z80> <code z80>
-$ ./codificar_pantalla.py -m -a pantalla.dat +$ ./codificar_pantalla.py -m -a pantalla.dat
  ; Flag codificacion: -m -a  ; Flag codificacion: -m -a
  ; Resultado: 60 Bytes  ; Resultado: 60 Bytes
Línea 2639: Línea 2647:
  
 <code z80> <code z80>
-   ;;; (venimos del LD A, (IX+0) / INC IX de la coordenada X) +    ;;; (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) +
-   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 +    ;;; Sumamos la coordenada X recogida y obtenemos desde el mapa la Y: 
-   INC IX +    add a, c                  ; = (X_INICIO + COORD_X_TILE) 
-   ADD A                 ; 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),                ; Establecemos COORD_Y a imprimir tile+ 
 +    ld a, (ix+0)              ; Leemos el valor de COORD_Y_TILE 
 +    inc ix 
 +    add a                 ; A = (Y_INICIO + COORD_Y_TILE) 
 +    rlca                      ; A = (Y_INICIO + COORD_Y_TILE) 
 +    ld (de),                ; Establecemos COORD_Y a imprimir tile
 </code> </code>
  
Línea 2656: Línea 2664:
  
 <code z80> <code z80>
-   PUSH AF +    push af 
-   AND %11110000             ; Nos quedamos con la parte alta (COORD_X) +    and %11110000             ; Nos quedamos con la parte alta (COORD_X) 
-   RRCA                      ; Pasamos parte alta a parte baja +    rrca                      ; Pasamos parte alta a parte baja 
-   RRCA                      ; con 4 desplazamientos +    rrca                      ; con 4 desplazamientos 
-   RRCA +    rrca 
-   RRCA                      ; Ya podemos sumar: +    rrca                      ; Ya podemos sumar: 
-   ADD A                 ; A = (X_INICIO + COORD_X_TILE) +    add a                 ; A = (X_INICIO + COORD_X_TILE) 
-   RLCA                      ; A = (X_INICIO + COORD_X_TILE) * 2 +    rlca                      ; A = (X_INICIO + COORD_X_TILE) * 2 
-   LD (HL),                ; Establecemos COORD_X a imprimir tile+    ld (hl),                ; Establecemos COORD_X a imprimir tile
  
-   POP AF +    pop af 
-   AND %00001111             ; Nos quedamos con la parte baja (COORD_Y)+    and %00001111             ; Nos quedamos con la parte baja (COORD_Y)
  
-   ADD A                 ; A = (Y_INICIO + COORD_Y_TILE) +    add a                 ; A = (Y_INICIO + COORD_Y_TILE) 
-   RLCA                      ; A = (Y_INICIO + COORD_Y_TILE) +    rlca                      ; A = (Y_INICIO + COORD_Y_TILE) 
-   LD (DE),                ; Establecemos COORD_Y a imprimir tile+    ld (de),                ; Establecemos COORD_Y a imprimir tile
 </code> </code>
  
- De la rutina original hemos eliminado las instrucciones "**LD A, (IX+0)**" "**INC IX**" (29 ciclos de reloj menos) y hemos añadido PUSH/POP AF e instrucciones AND y RLCA (51 ciclos de reloj más) resultando en una rutina que es 22 ciclos de reloj más lenta por scanline. Pero a cambio de estos 22 ciclos de reloj se pueden producir grandes ahorros en las pantallas resultantes.+ De la rutina original hemos eliminado las instrucciones ''ld a, (ix+0)'' ''inc ix'' (29 ciclos de reloj menos) y hemos añadido ''push af''/''pop af'' e instrucciones ''AND'' ''RLCA'' (51 ciclos de reloj más) resultando en una rutina que es 22 ciclos de reloj más lenta por scanline. Pero a cambio de estos 22 ciclos de reloj se pueden producir grandes ahorros en las pantallas resultantes.
  
  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 2691: 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),  ; Almacenar en la posicion de las labels +    ld (drawm16cmxy_dir1),  ; almacenar en la posicion de las labels 
-   LD (drawm16cmxy_dir2), A +    ld (drawm16cmxy_dir2), a 
-   LD HL, (DM_SPRITES) +    ld hl, (DM_SPRITES) 
-   LD (DS_SPRITES), HL       ; Establecer tileset (graficos) +    ld (DS_SPRITES), hl       ; Establecer tileset (graficos) 
-   LD HL, (DM_ATTRIBS) +    ld hl, (DM_ATTRIBS) 
-   LD (DS_ATTRIBS), HL       ; Establecer tileset (atributos) +    ld (DS_ATTRIBS), hl       ; Establecer tileset (atributos) 
-   LD BC, (DM_COORD_X)       ; B = Y_INICIO, C = X_INICIO +    ld bc, (DM_COORD_X)       ; B = Y_INICIO, C = X_INICIO 
-   LD IX, (DM_MAP)           ; DE apunta al mapa +    ld ix, (DM_MAP)           ; DE apunta al mapa
  
-   LD DE, DS_COORD_Y         ; DE apunta a la coordenada Y +    ld de, DS_COORD_Y         ; DE apunta a la coordenada Y 
-   LD HL, DS_COORD_X         ; HL apunta a la coordenada X+    ld hl, DS_COORD_X         ; HL apunta a la coordenada 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 +    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             ; Nos quedamos con la parte alta (COORD_X) +    and %11110000             ; Nos quedamos con la parte alta (COORD_X) 
-   RRCA                      ; Pasamos parte alta a parte baja +    rrca                      ; Pasamos parte alta a parte baja 
-   RRCA                      ; con 4 desplazamientos +    rrca                      ; con 4 desplazamientos 
-   RRCA +    rrca 
-   RRCA                      ; Ya podemos sumar +    rrca                      ; Ya podemos sumar 
-   ADD A                 ; A = (X_INICIO + COORD_X_TILE) +    add a                 ; A = (X_INICIO + COORD_X_TILE) 
-   RLCA                      ; A = (X_INICIO + COORD_X_TILE) * 2 +    rlca                      ; A = (X_INICIO + COORD_X_TILE) * 2 
-   LD (HL),                ; Establecemos COORD_X a imprimir tile +    ld (hl),                ; Establecemos COORD_X a imprimir tile 
-   POP AF +    pop af 
-   AND %00001111             ; Nos quedamos con la parte baja (COORD_Y) +    and %00001111             ; Nos quedamos con la parte baja (COORD_Y) 
-   ADD A                 ; A = (Y_INICIO + COORD_Y_TILE) +    add a                 ; A = (Y_INICIO + COORD_Y_TILE) 
-   RLCA                      ; A = (Y_INICIO + COORD_Y_TILE) +    rlca                      ; A = (Y_INICIO + COORD_Y_TILE) 
-   LD (DE),                ; Establecemos COORD_Y a imprimir tile+    ld (de),                ; 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 +    cp 255 
-   JR Z, drawm16cmxy_read    ; Si es fin de tile codificado, fin bucle +    jr z, drawm16cmxy_read    ; Si es fin de tile codificado, fin bucle 
-   CP 254 +    cp 254 
-   JR Z, drawm16cmxy_switch  ; Codigo 254 -> cambiar a codif. vertical+    jr z, drawm16cmxy_switch  ; Codigo 254 -> cambiar a codif. vertical
  
-   LD (DS_NUMSPR),         ; Establecemos el TILE +    ld (DS_NUMSPR),         ; Establecemos el TILE 
-   EXX                       ; Preservar todos los registros en shadows +    exx                       ; Preservar todos los registros en shadows 
-   CALL DrawSprite_16x16_LD  ; Imprimir el tile con los parametros +    call DrawSprite_16x16_LD  ; Imprimir el tile con los parametros 
-   EXX                       ; Recuperar valores de los registros+    exx                       ; Recuperar valores de los registros
  
-drawm16cmxy_dir1:            ; Etiqueta con la direccion del NOP +drawm16cmxy_dir1:            ; Etiqueta con la direccion del nop 
-   NOP                       ; NOP->INC COORD_X,  EX DE,HL->INC COORD_Y +    nop                       ; nop->inc cOORD_X,  ex de,hl->inc cOORD_Y 
-   INC (HL+    inc (hl
-   INC (HL)                  ; COORD = COORD + 2 +    inc (hl)                  ; COORD = COORD + 2 
-drawm16cmxy_dir2:            ; Etiqueta con la direccion del NOP +drawm16cmxy_dir2:            ; Etiqueta con la direccion del nop 
-   NOP                       ; NOP->INC COORD_X,  EX DE,HL->INC COORD_Y +    nop                       ; nop->inc cOORD_X,  ex de,hl->inc cOORD_Y 
-   JR drawm16cmxy_tileloop   ; Repetimos hasta encontrar el 255+    jr drawm16cmxy_tileloop   ; Repetimos hasta encontrar el 255
  
 drawm16cmxy_switch: drawm16cmxy_switch:
-   ;;; Cambio de codificacion de horizontal a vertical: +    ;;; Cambio de codificacion de horizontal a vertical: 
-   LD A, $EB                 ; Opcode de EX DEHL +    ld a, $eb                 ; Opcode de ex dehl 
-   LD (drawm16cmxy_dir1),    ; Ahora se hace el EX DEHL y por lo tanto +    ld (drawm16cmxy_dir1),    ; ahora se hace el ex dehl y por lo tanto 
-   LD (drawm16cmxy_dir2),    ; INC (HL) incrementa COORD_Y en vez de X +    ld (drawm16cmxy_dir2),    ; inc (hl) incrementa COORD_Y en vez de X 
-   JR drawm16cmxy_read+    jr drawm16cmxy_read
 </code> </code>
  
Línea 2780: 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 "wrapper" (o "envoltorio") de impresión de pantalla obtendría del mapa la dirección de la pantalla en HL o DE, leería el tipo de codificación utilizado (primer byte de la pantalla), incrementaría HL o DE, almacenaría el valor resultante en (DM_MAP) y llamaría a la función de impresión adecuada según el tipo de codificación que acabamos de leer.+ Una rutina "wrapper" (o "envoltorio") de impresión de pantalla obtendría del mapa la dirección de la pantalla en HL o DE, leería el tipo de codificación utilizado (primer byte de la pantalla), incrementaría HL o DE, almacenaría el valor resultante en (''DM_MAP'') y llamaría a la función de impresión adecuada según el tipo de codificación que acabamos de leer.
  
  Como ID de codificación se podría utilizar, por ejemplo:  Como ID de codificación se podría utilizar, por ejemplo:
Línea 2792: Línea 2800:
 </code> </code>
  
- Es difícil que la codificación básica sea más óptima que ninguna de las anteriores a menos que apenas haya bloques "transparentes" o "vacíos", pero aún así se ha contemplado su uso en la rutina. Hemos incluído también la posibilidad de utilizar una pantalla sin agrupación indicando MAP_CODIF_NONE al inicio de la misma.+ Es difícil que la codificación básica sea más óptima que ninguna de las anteriores a menos que apenas haya bloques "transparentes" o "vacíos", pero aún así se ha contemplado su uso en la rutina. Hemos incluído también la posibilidad de utilizar una pantalla sin agrupación indicando ''MAP_CODIF_NONE'' al inicio de la misma.
  
 <code z80> <code z80>
Línea 2800: Línea 2808:
 ;--------------------------------------------------------------- ;---------------------------------------------------------------
 DrawMap_16x16_Codificada: DrawMap_16x16_Codificada:
-   LD HL, (DM_MAP)            ; HL apunta al mapa  +    ld hl, (DM_MAP)            ; HL apunta al mapa 
-   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), HL            ; Guardamos el valor en DM_MAP +    ld (DM_MAP), hl            ; Guardamos el valor en DM_MAP 
-    + 
-   AND A                      ; Es A == 0? (MAP_CODIF_NONE) +    and a                      ; Es A == 0? (MAP_CODIF_NONE) 
-   JR NZ, dm16c_nocero        ; No +    jr nz, dm16c_nocero        ; No 
-   CALL DrawMap_16x16 +    call DrawMap_16x16 
-   RET+    ret
  
 dm16c_nocero: dm16c_nocero:
-   CP MAP_CODIF_HORIZ         ; Es A == MAP_CODIF_HORIZ? +    CP MAP_CODIF_HORIZ         ; Es A == MAP_CODIF_HORIZ? 
-   JR NZ, dm16c_nohoriz       ; No, saltar +    jr nz, dm16c_nohoriz       ; No, saltar 
-   CALL DrawMap_16x16_Cod_Horiz +    call DrawMap_16x16_Cod_Horiz 
-   RET+    ret
  
 dm16c_nohoriz: dm16c_nohoriz:
-   CP MAP_CODIF_VERT          ; Es A == MAP_CODIF_VERT? +    CP MAP_CODIF_VERT          ; Es A == MAP_CODIF_VERT? 
-   JR NZ, dm16c_novert        ; No, saltar +    jr nz, dm16c_novert        ; No, saltar 
-   CALL DrawMap_16x16_Cod_Vert +    call DrawMap_16x16_Cod_Vert 
-   RET+    ret
  
 dm16c_novert: dm16c_novert:
-   CP MAP_CODIF_MIXTA         ; Es A == MAP_CODIF_MIXTA? +    CP MAP_CODIF_MIXTA         ; Es A == MAP_CODIF_MIXTA? 
-   JR NZ, dm16c_nomixta       ; No, saltar +    jr nz, dm16c_nomixta       ; No, saltar 
-   CALL DrawMap_16x16_Cod_Mixta +    call DrawMap_16x16_Cod_Mixta 
-   RET+    ret
  
 dm16c_nomixta:                ; Entonces es basica. dm16c_nomixta:                ; Entonces es basica.
-   CALL DrawMap_16x16_Cod_Basica +    call DrawMap_16x16_Cod_Basica 
-   RET+    ret
 </code> </code>
  
Línea 2847: 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 "bloque no dibujable".  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 "bloque no dibujable".
  
- Lo bueno de las técnicas de codificación por scanlines horizontales, verticales o mixtos es que los bloques vacíos o los transparentes (según nos interese en el juego) se pueden codificar junto a los bloques normales, modificando las variables IGNORE_VALUES y BLANK del script de codificación en python.+ Lo bueno de las técnicas de codificación por scanlines horizontales, verticales o mixtos es que los bloques vacíos o los transparentes (según nos interese en el juego) se pueden codificar junto a los bloques normales, modificando las variables ''IGNORE_VALUES'' ''BLANK'' del script de codificación en python.
  
  Concretamente, tenemos que establecer ambas variables con el identificador de tile que queremos  "ignorar" (y por lo tanto no codificar).  Concretamente, tenemos que establecer ambas variables con el identificador de tile que queremos  "ignorar" (y por lo tanto no codificar).
Línea 2856: Línea 2864:
  
 <code z80> <code z80>
-$ grep -E "^(IGNORE_VALUES|BLANK)" codificar_pantalla.py +$ grep -E "^(IGNORE_VALUES|BLANK)" codificar_pantalla.py
 IGNORE_VALUES = 255 IGNORE_VALUES = 255
 BLANK = 255 BLANK = 255
Línea 2871: Línea 2879:
 </code> </code>
  
- En este caso, los bloques "0" (fondo negro) se han codificado junto a los demás bloques normales (mejorando la "compresión") y los bloques 255 (transparentes) no, por lo que si en los ejemplos anteriores eliminamos el ClearScreen() y lanzamos el DrawMap correspondiente, obtenemos la siguiente pantalla:+ En este caso, los bloques "0" (fondo negro) se han codificado junto a los demás bloques normales (mejorando la "compresión") y los bloques 255 (transparentes) no, por lo que si en los ejemplos anteriores eliminamos el ClearScreen() y lanzamos el ''DrawMap'' correspondiente, obtenemos la siguiente pantalla:
  
 \\  \\ 
-{{ :cursos:ensamblador:gfx5_transp.png | Codificando los blancos pero no las transparencias }}+{{ :cursos:ensamblador:gfx5_transp.png?640 | Codificando los blancos pero no las transparencias }}
 \\  \\ 
  
- No hay colisión entre el 255 "transparente" y el 255 "fin de scanline" porque el codificador lo que ha hecho es, precisamente, no codificar los bloques 255 con lo que estos no aparecen en la pantalla resultante. Por contra, sí que es necesario incluir los bloques 0 ya que pretendemos que sean dibujados para "tapar" el fondo (por eso se ha cambiando BLANK e IGNORE_VALUES en el script codificador, cambiando 0 por 255).+ No hay colisión entre el 255 "transparente" y el 255 "fin de scanline" porque el codificador lo que ha hecho es, precisamente, no codificar los bloques 255 con lo que estos no aparecen en la pantalla resultante. Por contra, sí que es necesario incluir los bloques 0 ya que pretendemos que sean dibujados para "tapar" el fondo (por eso se ha cambiando ''BLANK'' ''IGNORE_VALUES'' en el script codificador, cambiando 0 por 255).
  
  
Línea 2886: Línea 2894:
 \\  \\ 
  
- Otro efecto interesante para mejorar la riqueza gráfica de un juego es generar una "sombra" para aquellos tiles que estén cercanos a otros tiles definidos como "fondo"+ Otro efecto interesante para mejorar la riqueza gráfica de un juego es generar una "sombra" para aquellos tiles que estén cercanos a otros tiles definidos como "fondo".
  
  Por ejemplo, la siguiente captura de pantalla de un juego de los //Mojon Twins// muestra cómo los muros verticales rojos cercanos a la "bellota" proyectan hacia la derecha, sobre el suelo "morado", una sombra generada durante el proceso de trazado de la pantalla. Esta sombra hace que los tiles de suelo cercanos al muro sean diferentes del resto de tiles de suelo, sin necesidad de haber definido un tile específico para ello.  Por ejemplo, la siguiente captura de pantalla de un juego de los //Mojon Twins// muestra cómo los muros verticales rojos cercanos a la "bellota" proyectan hacia la derecha, sobre el suelo "morado", una sombra generada durante el proceso de trazado de la pantalla. Esta sombra hace que los tiles de suelo cercanos al muro sean diferentes del resto de tiles de suelo, sin necesidad de haber definido un tile específico para ello.
  
 \\  \\ 
-{{ :cursos:ensamblador:gfx5_cotbss08.png | Sombreados sobre tiles }}+{{ :cursos:ensamblador:gfx5_cotbss08.png?544 | Sombreados sobre tiles }}
 \\  \\ 
  
Línea 2914: Línea 2922:
  Siendo (x, y) la posición de nuestro tile de fondo (a nivel de tiles):  Siendo (x, y) la posición de nuestro tile de fondo (a nivel de tiles):
  
-- 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 2976: Línea 2984:
 </code> </code>
  
- Es decir, para codificar las 3 líneas originales hemos generado 1 ristra de bytes verticales, y ahora 4 horizontales, con sus bytes de X, Y y FIN DE CODIFICACION (255) para los 5 scanlines. + Es decir, para codificar las 3 líneas originales hemos generado 1 ristra de bytes verticales, y ahora 4 horizontales, con sus bytes de X, Y y FIN DE CODIFICACION (255) para los 5 scanlines.
  
  Sin embargo, hubiera sido mejor codificar primero los scanlines horizontales, aunque fueran de menor longitud de que el vertical:  Sin embargo, hubiera sido mejor codificar primero los scanlines horizontales, aunque fueran de menor longitud de que el vertical:
Línea 2983: Línea 2991:
 0001234000   --> 0000000000 0001234000   --> 0000000000
 0000010000   --> 0000010000 0000010000   --> 0000010000
-0000010000   --> 0000010000 +0000010000   --> 0000010000
 0000010000   --> 0000010000 0000010000   --> 0000010000
 0000010000   --> 0000010000 0000010000   --> 0000010000
Línea 2994: Línea 3002:
  
 <code z80> <code z80>
-$ ./codificar_pantalla.py -h pantalla3.dat +$ ./codificar_pantalla.py -h pantalla3.dat
  ; Flag codificacion: -h  ; Flag codificacion: -h
  ; Resultado: 31 Bytes  ; Resultado: 31 Bytes
Línea 3001: Línea 3009:
  DB 5 , 1 , 2 , 3 , 4 , 255 , 255  DB 5 , 1 , 2 , 3 , 4 , 255 , 255
  
-$ ./codificar_pantalla.py -v pantalla3.dat +$ ./codificar_pantalla.py -v pantalla3.dat
  ; Flag codificacion: -v  ; Flag codificacion: -v
  ; Resultado: 34 Bytes  ; Resultado: 34 Bytes
Línea 3008: 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
  
-$ ./codificar_pantalla.py -m pantalla3.dat +$ ./codificar_pantalla.py -m pantalla3.dat
  ; Flag codificacion: -m  ; Flag codificacion: -m
  ; Resultado: 28 Bytes  ; Resultado: 28 Bytes
Línea 3054: Línea 3062:
 </code> </code>
  
- Si la separación entre 2 scanlines la forma 1 bloque "transparente" , añadimos 1 byte "252" pero eliminamos el "255" del primer scanline y el COORD_X y COORD_Y del segundo, por lo que sumamos 1 bytes pero restamos 3, ahorrando 2 bytes.+ Si la separación entre 2 scanlines la forma 1 bloque "transparente" , añadimos 1 byte "252" pero eliminamos el "255" del primer scanline y el ''COORD_X'' ''COORD_Y'' del segundo, por lo que sumamos 1 bytes pero restamos 3, ahorrando 2 bytes.
  
- Si la separación entre 2 scanlines la forman 2 bloques "transparentes" , añadimos 2 bytes "252" pero eliminamos el "255" del primer scanline y el COORD_X y COORD_Y del segundo, por lo que sumamos 2 bytes pero restamos 3, ahorrando 1 byte.+ Si la separación entre 2 scanlines la forman 2 bloques "transparentes" , añadimos 2 bytes "252" pero eliminamos el "255" del primer scanline y el ''COORD_X'' ''COORD_Y'' del segundo, por lo que sumamos 2 bytes pero restamos 3, ahorrando 1 byte.
  
  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 3072: Línea 3080:
 <code z80> <code z80>
 Tabla_IDs_Tilesets: Tabla_IDs_Tilesets:
-  DW dir_tileset_gfx_1 +    DW dir_tileset_gfx_1 
-  DW dir_tileset_attrib_1 +    DW dir_tileset_attrib_1 
-  DB ancho_tiles_tileset1, alto_tiles_tileset1 +    DB ancho_tiles_tileset1, alto_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, alto_tiles_tileset2 +    DB ancho_tiles_tileset2, alto_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, alto_tiles_tileset3+    DB ancho_tiles_tileset3, alto_tiles_tileset3
 </code> </code>
  
Línea 3087: 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 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 (...) 
-   DB 255 (fin de pantalla)+    DB 255 (fin de pantalla)
 </code> </code>
  
Línea 3105: Línea 3113:
 ==== Mapeados de tiles de cualquier tamaño de bloque ==== ==== Mapeados de tiles de cualquier tamaño de bloque ====
  
- Además de la posibilidad de disponer de mapeados basados en diferentes tilesets, podemos componer las pantallas de nuestro juego a partir de todo tipo de gráficos y tiles de tamaños diversos, pertenezcan o no a tilesets. + Además de la posibilidad de disponer de mapeados basados en diferentes tilesets, podemos componer las pantallas de nuestro juego a partir de todo tipo de gráficos y tiles de tamaños diversos, pertenezcan o no a tilesets.
  
  Para eso, debemos dejar de pensar en las pantallas como matrices de tiles y visualizarlas y definirlas como "listas de sprites a dibujar" (sean tiles o no).  Para eso, debemos dejar de pensar en las pantallas como matrices de tiles y visualizarlas y definirlas como "listas de sprites a dibujar" (sean tiles o no).
Línea 3113: Línea 3121:
 <code z80> <code z80>
 Tabla_Tiles: Tabla_Tiles:
-   DW tileset_1_gfx+(0*32)             ; Cada tile ocupa 8*4=32 bytes en el tileset 16x16 +    DW tileset_1_gfx+(0*32)             ; Cada tile ocupa 8*4=32 bytes en el tileset 16x16 
-   DW tileset_1_attr+(0*4)             ; Cada tile ocupa 4 atributos en el tileset 16x16 +    DW tileset_1_attr+(0*4)             ; Cada tile ocupa 4 atributos en el tileset 16x16 
-   DB 16, 16 +    DB 16, 16 
-   DW tileset_1_gfx+(1*32)             ; Apuntamos a datos del tile 1 del tileset +    DW tileset_1_gfx+(1*32)             ; Apuntamos a datos del tile 1 del tileset 
-   DW tileset_1_attr+(1*4) +    DW tileset_1_attr+(1*4) 
-   DB 16, 16 +    DB 16, 16 
-   DW tileset_1_gfx+(2*32) +    DW tileset_1_gfx+(2*32) 
-   DW tileset_1_attr+(2*4) +    DW tileset_1_attr+(2*4) 
-   DB 16, 16 +    DB 16, 16 
-   DW tileset_2_gfx+(0*8)              ; Cada tile ocupa 8 bytes en el tileset 8x8 +    DW tileset_2_gfx+(0*8)              ; Cada tile ocupa 8 bytes en el tileset 8x8 
-   DW tileset_2_attr+(0*1)             ; Cada tile ocupa 1 atributo en el tileset 8x8 +    DW tileset_2_attr+(0*1)             ; Cada tile ocupa 1 atributo en el tileset 8x8 
-   DB 8, 8 +    DB 8, 8 
-   DW tileset_2_gfx+(1*8) +    DW tileset_2_gfx+(1*8) 
-   DW tileset_2_attr+(1*0) +    DW tileset_2_attr+(1*0) 
-   DB 8, 8 +    DB 8, 8 
-   DW logotipo_gfx +    DW logotipo_gfx 
-   DW logotipo_attr +    DW logotipo_attr 
-   DB 32, 16 +    DB 32, 16 
-   DW piedra_gfx +    DW piedra_gfx 
-   DW piedra_attr +    DW piedra_attr 
-   DB 32, 32 +    DB 32, 32 
-   DW muro_grande_gfx +    DW muro_grande_gfx 
-   DW muro_grande_attr +    DW muro_grande_attr 
-   DB 64, 64 +    DB 64, 64 
-   DW grafico_escalera_gfx +    DW grafico_escalera_gfx 
-   DW grafico_escalera_attr +    DW grafico_escalera_attr 
-   DB 16, 32+    DB 16, 32
 </code> </code>
  
Línea 3151: 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.
  
- Nuestra rutina de impresión puede acceder a los datos del tile mediante multiplicación de ID_EN_TABLA_TILE por 2+2+2 e imprimir el sprite gfx/attr/ancho/alto leído desde la tabla.+ Nuestra rutina de impresión puede acceder a los datos del tile mediante multiplicación de ''ID_EN_TABLA_TILE'' por 2+2+2 e imprimir el sprite gfx/attr/ancho/alto leído desde la tabla.
  
  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 3162: Línea 3170:
 DrawSprite_MxN_LD_extendida: DrawSprite_MxN_LD_extendida:
  
-   LD A, (DS_HEIGHT) +    ld a, (DS_HEIGHT) 
-   LD BA +    ld ba 
-   LD A, (DS_WIDTH) +    ld a, (DS_WIDTH) 
-   LD C                  ; Obtenemos datos del sprite +    ld c                  ; Obtenemos datos del sprite 
-    + 
-   ;;; B = ALTO de Sprite +    ;;; B = ALTO de Sprite 
-   ;;; C = ANCHO de Sprite +    ;;; C = ANCHO de Sprite 
-    + 
-   LD A                  ; A = ANCHO +    ld a                  ; A = ANCHO 
-   CP 16                     ; Comparar ancho +    cp 16                     ; Comparar ancho 
-   JR NZ, dspMN_no16         ; ¿es 16?+    jr nz, dspMN_no16         ; ¿es 16?
  
-   SUB B                     ; A = Ancho - alto +    sub b                     ; A = Ancho - alto 
-   JR NZ, dspMN_generica     ; Si no es cero, rutina generica +    jr nz, dspMN_generica     ; Si no es cero, rutina generica 
-                             ; Es cero, imprimir 16x16:                  +                                ; Es cero, imprimir 16x16: 
-   CALL DrawSprite16x16      ; Imprimir via especifica 16x16 +    call DrawSprite16x16      ; Imprimir via especifica 16x16 
-   RET+    ret
  
 dspMN_no16: dspMN_no16:
-   LD A                  ; Recuperamos ancho +    ld a                  ; Recuperamos ancho 
-   CP 8                      ; ¿es 8? +    cp 8                      ; ¿es 8? 
-   JR NZ, dspMN_generica     ; Si no es 8, ni 16, generica +    jr nz, dspMN_generica     ; Si no es 8, ni 16, generica 
-   SUB B                     ; A = Ancho - alto +    sub b                     ; A = Ancho - alto 
-   JR NZ, dspMN_generica     ; Si no es cero, rutina generica+    jr nz, dspMN_generica     ; Si no es cero, rutina generica
  
-   CALL DrawSprite_8x8       ; Imprimir via especifica 8x8 +    call DrawSprite_8x8       ; Imprimir via especifica 8x8 
-   RET+    ret
  
 dspMN_generica: dspMN_generica:
-   ;;; (resto rutina generica) +    ;;; (resto rutina generica) 
-   RET+    ret
 </code> </code>
  
Línea 3209: Línea 3217:
 <code z80> <code z80>
 Tiles_Extendidos: Tiles_Extendidos:
-   DW logotipo_gfx +    DW logotipo_gfx 
-   DW logotipo_attr +    DW logotipo_attr 
-   DB 32, 16 +    DB 32, 16 
-   DW piedra_gfx +    DW piedra_gfx 
-   DW piedra_attr +    DW piedra_attr 
-   DB 32, 32 +    DB 32, 32 
-   DW muro_grande_gfx +    DW muro_grande_gfx 
-   DW muro_grande_attr +    DW muro_grande_attr 
-   DB 64, 64 +    DB 64, 64 
-   DW grafico_escalera_gfx +    DW grafico_escalera_gfx 
-   DW grafico_escalera_attr +    DW grafico_escalera_attr 
-   DB 16, 32+    DB 16, 32
 </code> </code>
  
Línea 3241: 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 "ignoramos" los bloques de fondo sino que ahora hay que dibujarlos para trazar ese nuevo fondo gráfico). Con esto, se esfuma nuestro ahorro de memoria.  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 "ignoramos" los bloques de fondo sino que ahora hay que dibujarlos para trazar ese nuevo fondo gráfico). Con esto, se esfuma nuestro ahorro de memoria.
  
- Podemos utilizar una sencilla solución basada en tabla para disponer de fondos en las pantallas y continuar ahorrando memoria con la codificación. La tabla alojará la dirección + Podemos utilizar una sencilla solución basada en tabla para disponer de fondos en las pantallas y continuar ahorrando memoria con la codificación. La tabla alojará la dirección
  
 <code z80> <code z80>
Línea 3249: Línea 3257:
  
 Fondos: Fondos:
-   DW fondo_piedra_gfx +    DW fondo_piedra_gfx 
-   DW fondo_piedra_attr +    DW fondo_piedra_attr 
-   DB 16, 16 +    DB 16, 16 
-   DW fondo_baldosas_gfx +    DW fondo_baldosas_gfx 
-   DW fondo_baldosas_attr +    DW fondo_baldosas_attr 
-   DB 64, 64 +    DB 64, 64 
-   DW fondo_hierba_gfx +    DW fondo_hierba_gfx 
-   DW fondo_hierba_attr +    DW fondo_hierba_attr 
-   DB 32, 32+    DB 32, 32
 </code> </code>
  
Línea 3270: Línea 3278:
 <code z80> <code z80>
 Mapa: Mapa:
-  DW Pantalla_Inicio            ; ID = 0 +    DW Pantalla_Inicio            ; ID = 0 
-  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             ; ID = 1  +    DW Pantalla_Salon             ; ID = 1 
-  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           ; ID = 2 +    DW Pantalla_Pasillo           ; ID = 2 
-  DB 1, 3                       ; Conexiones izq y derecha ID 2 +    DB 1, 3                       ; Conexiones izq y derecha ID 2 
-  DB FONDO_PIEDRA +    DB FONDO_PIEDRA 
-  (...)+    (...)
 </code> </code>
  
Línea 3288: Línea 3296:
  Finalmente, en lugar de realizar un borrado del área de pantalla donde vamos a imprimir el mapa sería necesario programar una rutina que utilice el sprite Fondo (mediante su ID y la tabla de Fondos). La rutina deberá "rellenar" vía impresión por repetición el área de juego con el fondo seleccionado. Para simplificar la rutina es recomendable que todos los tamaños de los tiles de fondo sean dividores exactos del tamaño de la pantalla, de forma que la rutina no tenga que calcular si la impresión del último tile que quepa en la misma ha de ser dibujado total o parcialmente. Si el área de juego es de 256 píxeles, podremos utilizar tiles de ancho 8 (32 repeticiones), 16 (16 repeticiones), 32 (8 repeticiones), 64 (4 repeticiones), 128 (2 repeticiones) o incluso de 256 (1 repetición). Lo mismo ocurriría para la altura.  Finalmente, en lugar de realizar un borrado del área de pantalla donde vamos a imprimir el mapa sería necesario programar una rutina que utilice el sprite Fondo (mediante su ID y la tabla de Fondos). La rutina deberá "rellenar" vía impresión por repetición el área de juego con el fondo seleccionado. Para simplificar la rutina es recomendable que todos los tamaños de los tiles de fondo sean dividores exactos del tamaño de la pantalla, de forma que la rutina no tenga que calcular si la impresión del último tile que quepa en la misma ha de ser dibujado total o parcialmente. Si el área de juego es de 256 píxeles, podremos utilizar tiles de ancho 8 (32 repeticiones), 16 (16 repeticiones), 32 (8 repeticiones), 64 (4 repeticiones), 128 (2 repeticiones) o incluso de 256 (1 repetición). Lo mismo ocurriría para la altura.
  
- 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 ''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.
  
  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 "fondo" los tiles reales.  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 "fondo" los tiles reales.
Línea 3302: Línea 3310:
 ===== Compresión de los datos de pantalla ===== ===== Compresión de los datos de pantalla =====
  
- Todavía podríamos arañar algunos bytes adicionales a las pantallas utilizando técnicas de compresión.+ Como hemos comentado antes, todavía podríamos arañar algunos bytes adicionales a las pantallas utilizando técnicas de compresión básicas.
  
 \\  \\ 
Línea 3313: Línea 3321:
  
 <code z80> <code z80>
-  DB 253, NUMERO_REPETICIONES, TILE_A_REPETIR+    DB 253, NUMERO_REPETICIONES, TILE_A_REPETIR
 </code> </code>
  
Línea 3319: Línea 3327:
  
 <code z80> <code z80>
-  ; 9 bytes +    ; 9 bytes 
-  DB 1, 2, 2, 2, 2, 2, 2, 3, 4+    DB 1, 2, 2, 2, 2, 2, 2, 3, 4
 </code> </code>
  
Línea 3326: Línea 3334:
  
 <code z80> <code z80>
-  ; 6 bytes +    ; 6 bytes 
-  DB 1, 253, 6, 2, 3, 4+    DB 1, 253, 6, 2, 3, 4
 </code> </code>
  
Línea 3335: 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 3343: Línea 3353:
  
  El sistema de compresión por patrones es el método que, probablemente, producirá los mejores resultados de reducción de tamaño de las pantallas en la mayoría de juegos.  El sistema de compresión por patrones es el método que, probablemente, producirá los mejores resultados de reducción de tamaño de las pantallas en la mayoría de juegos.
- +
  Se basa en identificar "conjuntos de tiles" (no tienen por qué tener todos ellos el mismo valor) que se repitan a lo largo de la pantalla y de otras pantallas. Estos patrones se almacenan en memoria y se referencian por medio de una tabla que relaciona un "identificador de patrón" con la dirección donde está almacenado el patrón, finalizado en 255.  Se basa en identificar "conjuntos de tiles" (no tienen por qué tener todos ellos el mismo valor) que se repitan a lo largo de la pantalla y de otras pantallas. Estos patrones se almacenan en memoria y se referencian por medio de una tabla que relaciona un "identificador de patrón" con la dirección donde está almacenado el patrón, finalizado en 255.
  
Línea 3352: Línea 3362:
 <code z80> <code z80>
 Pantalla: Pantalla:
-  DB X_TILE, Y_TILE, 253, ID_PATRON+    DB X_TILE, Y_TILE, 253, ID_PATRON
 </code> </code>
  
- (También podemos agrupar X_TILE e Y_TILE en un mismo byte como hicimos en el script codificador).+ (También podemos agrupar ''X_TILE'' ''Y_TILE'' en un mismo byte como hicimos en el script codificador).
  
  Supongamos la siguiente pantalla ilustrativa:  Supongamos la siguiente pantalla ilustrativa:
Línea 3380: Línea 3390:
  
 Patron0: Patron0:
-  DB CODIF_HORIZONTAL, 1, 2, 3, 2, 4, 255+    DB CODIF_HORIZONTAL, 1, 2, 3, 2, 4, 255
  
 Patron1: Patron1:
-  DB CODIF_VERTICAL, 8, 8, 8, 8, 8, 8, 8, 255+    DB CODIF_VERTICAL, 8, 8, 8, 8, 8, 8, 8, 255
  
 Patron2: Patron2:
-  DB CODIF_VERTICAL, 7, 7, 7, 7, 7, 7, 7, 255 +    DB CODIF_VERTICAL, 7, 7, 7, 7, 7, 7, 7, 255 
-  +
 Patron3: Patron3:
-  DB CODIF_VERTICAL, 7, 7, 7, 7, 7, 255 +    DB CODIF_VERTICAL, 7, 7, 7, 7, 7, 255 
-  +
 Patron4: Patron4:
-  DB CODIF_VERTICAL, 8, 8, 8, 8, 8, 255+    DB CODIF_VERTICAL, 8, 8, 8, 8, 8, 255
 </code> </code>
  
Línea 3399: Línea 3409:
 <code z80> <code z80>
 Tabla_Patrones: Tabla_Patrones:
-  DW Patron0 +    DW Patron0 
-  DW Patron1 +    DW Patron1 
-  DW Patron2 +    DW Patron2 
-  DW Patron3 +    DW Patron3 
-  DW Patron4 +    DW Patron4 
-  (...)+    (...)
 </code> </code>
  
  Mediante esta tabla podemos acceder a los datos de cualquier patrón como **Tabla_Patrones + ID_PATRON*2**.  Mediante esta tabla podemos acceder a los datos de cualquier patrón como **Tabla_Patrones + ID_PATRON*2**.
- +
  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 3432: Línea 3442:
 <code z80> <code z80>
 Pantalla: Pantalla:
-  DB 2, 1, 253, 0 +    DB 2, 1, 253, 0 
-  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
 </code> </code>
  
Línea 3456: Línea 3466:
  
 \\  \\ 
-{{ :cursos:ensamblador:gfx5_tresluces.png | Tres luces de Glaurung }}+{{ :cursos:ensamblador:gfx5_tresluces.png?1018 | Tres luces de Glaurung }}
 \\  \\ 
 ;#; ;#;
Línea 3483: Línea 3493:
  
 \\  \\ 
-{{ :cursos:ensamblador:gfx5_blinky.gif | Atravesando tiles }}+{{ :cursos:ensamblador:gfx5_blinky.gif?512 | Atravesando tiles }}
 \\  \\ 
 ;#; ;#;
Línea 3495: Línea 3505:
  
 \\  \\ 
-{{ :cursos:ensamblador:gfx5_turrican.gif | Turrican }}+{{ :cursos:ensamblador:gfx5_turrican.gif?512 | Turrican }}
 \\  \\ 
  
Línea 3513: Línea 3523:
 ;;; (etc...) ;;; (etc...)
 Propiedades_Tiles: Propiedades_Tiles:
-  DB %00000000        ; Propiedades tile 0 (tile vacio) +    DB %00000000        ; Propiedades tile 0 (tile vacio) 
-  DB %00000001        ; Propiedades tile 1 (bloque) +    DB %00000001        ; Propiedades tile 1 (bloque) 
-  DB %00000010        ; Propiedades tile 2 (suelo que se rompe) +    DB %00000010        ; Propiedades tile 2 (suelo que se rompe) 
-  DB %00000001        ; Propiedades tile 3 (otro bloque) +    DB %00000001        ; Propiedades tile 3 (otro bloque) 
-  DB %00000101        ; Propiedades tile 4 ("pinchos")+    DB %00000101        ; Propiedades tile 4 ("pinchos")
 </code> </code>
  
Línea 3549: Línea 3559:
  Alguno de los programas más conocidos para este tipo de tareas son:  Alguno de los programas más conocidos para este tipo de tareas son:
  
 +  * Tiled: https://www.mapeditor.org/
   * Mappy: http://www.tilemap.co.uk/mappy.php   * Mappy: http://www.tilemap.co.uk/mappy.php
   * Mappy Linux : http://membres.multimania.fr/edorul/Mappy-1.0.tar.gz   * Mappy Linux : http://membres.multimania.fr/edorul/Mappy-1.0.tar.gz
   * Map Editor: http://www.mapeditor.org/   * Map Editor: http://www.mapeditor.org/
  
- Map Editor es el editor más moderno de los 3, y soporta exportación del mapa a formato XML lo que puede facilitar la creación del script de conversión a formato ASM. Además, es una herramienta Free Software, por lo que disponemos tanto del código fuente como del permiso para modificarlo y adaptarlo a nuestras necesidades.+ Tiled es el editor más moderno de los 3, y soporta múltiples opciones de exportación del mapalo que puede facilitar la creación del script de conversión a formato ASM. Además, es una herramienta Free Software, por lo que disponemos tanto del código fuente como del permiso para modificarlo y adaptarlo a nuestras necesidades.
  
 \\  \\ 
Línea 3575: 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 "010b" (caso de la videoram -> $4000 -> 0100000000000000b) sino, por ejemplo "110" ($C000). De esta forma se pueden alterar las rutinas fácilmente para trabajar sobre un área de 7KB equivalente a la videoram pero comenzando en $C000.+ 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 "010b" (caso de la videoram -> $4000 -> 0100000000000000b) sino, por ejemplo "110" ($c000). De esta forma se pueden alterar las rutinas fácilmente para trabajar sobre un área de 7KB equivalente a la videoram pero comenzando en $c000.
  
- 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 "cero" (negro), trazamos los datos gráficos (que no podrá ver el usuario) y después trazamos los atributos. Estos atributos podemos trazarlos directamente en pantalla tras un HALT, o en una "tabla de atributos virtual" de 768 que después copiaremos sobre el área de atributos. De esta forma utilizamos una pantalla virtual de 768 bytes en lugar de requerir 6912.+ 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 "cero" (negro), trazamos los datos gráficos (que no podrá ver el usuario) y después trazamos los atributos. Estos atributos podemos trazarlos directamente en pantalla tras un halt, o en una "tabla de atributos virtual" de 768 que después copiaremos sobre el área de atributos. De esta forma utilizamos una pantalla virtual de 768 bytes en lugar de requerir 6912.
  
  
Línea 3622: Línea 3633:
   * [[http://www.worldofspectrum.org/faq/reference/z80reference.htm|Z80 Reference de WOS]].   * [[http://www.worldofspectrum.org/faq/reference/z80reference.htm|Z80 Reference de WOS]].
   * [[http://www.speccy.org/trastero/cosas/Fichas/fichas.htm|Microfichas de CM de MicroHobby]].   * [[http://www.speccy.org/trastero/cosas/Fichas/fichas.htm|Microfichas de CM de MicroHobby]].
-  * [[http://www.arrakis.es/~ninsesabe/pasmo/|PASMO]]. 
  
 +\\ 
 +**[ [[.:indice|⬉]] | [[.:gfx4_fuentes|⬅]] | [[.:compresion_rle|➡]] ]**
  • cursos/ensamblador/gfx5_mapeados.1704271225.txt.gz
  • Última modificación: 03-01-2024 08:40
  • por sromero