Sigo por donde lo dejé..
A partir de la segunda imagen, el algoritmo debería ser:
- Por cada fila del mapa en pantalla: (5 o 6)
- Por cada tile de la fila en pantalla: (10 o 11)
- Por cada fila del tile: (entre 4 y 1)
- Por cada caracter de la fila (entre 4 y 1)
- Dibujar el caracter en la posición de pantalla correspondiente. (1)
Eso son 4 bucles anidados, y, enmedio, hay muchos punteros a calcular, variables que mantener, y condiciones que comprobar (bordes).
El objetivo tiene que ser, simplificar en lo posible ese bucle.Todo lo que haya dentro, va a impactar exponencialmente el tiempo de pintado. Lo ideal es dejarlo en bucle muy simple, parecido al que mostraba i03862 en su ejemplo.
En el código de i03862 , a partir de ciertos puntos fijos en la pantalla, indexando con X, se muestra un caracter de una lista, indexada por Y.
En el caso de los tiles, la idea es exactamente la misma.
Los puntos en pantalla a "fijar", son las posiciones donde empieza cada tile.En la imagen 1, los puntos de pantalla, serían:
1024 --> comienzo del tile 0
1028 --> comienzo del tile 1
....
1184 --> comienzo del tile 20
Esos son los puntos de "destino".Los puntos de "fuente", están en la memoria de tiles:
$2000 --> comienzo del tile 0
$2010 --> comienzo del tile 1
....
$2140 --> comienzo del tile 20
Entonces, lo que sería ideal sería un código del tipo:
LDA $2000,X ; Leemos del tile 0
STA 1024,Y ; Escribimos en la posicion de pantalla donde va a estar el tile 0
LDA $2010,X ; Leemos del tile 1
STA 1028,Y ; Escribimos en la posicion de pantalla donde va a estar el tile 1
...
X se debe incrementar hasta que llegue a 16. Cada 4 incrementos de X, Y se debe incrementar en 36, para pasar a la linea inferior de la pantalla.
Así, estamos pintando más de 1 tile a la vez. Mi código dibuja una fila completa de tiles (10 u 11) en el bucle.Por lo que el bucle se ejecuta tantas veces como filas de tiles hay (5 o 6).
Y de esta forma tenemos un bucle muy simple, que es la idea inicial.
Para llegar a ese tipo de bucle, sólo tenemos que precalcular los puntos de inicio en pantalla, los puntos de inicio de los tiles, y almacenar estos punteros SOBRE el propio bucle (modificando el código), antes de saltar a él.
Pero esto supone que el mapa está 100% alineado...Qué ocurre si no lo está?
Lo que se me ocurrió, es aplicar un par de ideas.
El problema del alineamiento se trata diferente en X y en Y.
Primero, cómo tratar el problema en Y
Lo que no quería, era convertir la primera y ultima linea, en casos "especiales", que me llevaran a introducir comprobaciones dentro del bucle.
Se hace "al revés".
Mirando la imagen 2 del post anterior, para el tile 0, mi código calcula una posición de pantalla de (1024-40-1) = 983. Es decir, va a generar un código del tipo:
LDA $2000,X
STA 983, Y
Y lo que va a hacer, es cambiar el offset inicial, haciendo que cuando entra por primera vez en el bucle, X se ha cargado con un 6, e Y con un 41, por lo que empieza a pintar en la posición correcta.
Que la primera linea se dibuje así, viene muy bien.Los punteros de pantalla a la fila siguiente, se calculan sumando 160 (4*40) a los punteros de la fila anterior.Si la primera fila no se calculara así, no se podría simplemente sumar para calcular los siguientes.Sería un caso especial, y eso significa condiciones que gastan ciclos.
Eso gestiona el offset en Y. Ahora toca gestionar el offset en X
Si el offset en X es 1, como en la imagen 2, lo que significa es que si estamos pintando la posición 0,4,8 o 12 del tile, hay que pintar en el ULTIMO tile. Y en el resto de los casos, pintar en el primero.
Esto se hace, de nuevo, almacenando el offset en X , SOBRE el programa.Después de cada dibujar cada linea de caracteres, y cuando se suma 36 al registro Y para pintar en la siguiente linea, además, se suma 4 a esa posición del programa donde se almacena el offset.
Es decir, al pintar una fila de tiles, se van a dibujar 4 lineas de caracteres.Al dibujar la primera linea, en el caso de la imagen 2, la condición que existe en el programa, es:
dbucle CPX #$00 ; Este 00, será sobreescrito por el offset en X, en este caso , '1' : CPX #$01
BCS tilecp0 ; Si es igual o mayor, se dibuja el tile 0
tilecp10 LDA PT_CURTILELO,Y ; Si no, se dibuja el tile 10.
STA $0400,X
JMP tilecp1 ; Y se salta al tile 1
tilecp0 LDA PT_CURTILELO,Y ; Dibujado del tile 0
STA $0400,X
tilecp1 LDA PT_CURTILELO,Y
STA $0400,X
En este trozo de código, que es parte del bucle principal,se ve que las posiciones de origen y destino de todos los tiles, son las mismas.. porque en realidad, cuando se vaya a ejecutar el bucle, se habrán sobreescrito con los punteros precalculados.
Cuando se termina de dibujar una linea completa de caracteres, se suma 36 a X, para pasar a la siguiente linea, y se incrementa en 4 el contenido de dbucle+1, con lo que el CMP se hará sobre '5'.
Y esto explica más o menos en qué consiste el nucleo del código. El resto es principalmente precálculo de los punteros.