Página 3 de 4

Re: Solucionado - Problemas compresión de mapas al pasar a 128K

Publicado: Mar, 11 Mar 2014, 08:26
por na_th_an
La idea es dejar el mapa comprimido en la RAM extra, y modificar el procedimiento de obtener una pantalla para que la pille directamente de ahí.

Se me ocurre que hagas lo siguiente:

1.- El mapa comprimido tal y como sale de las utilidades de Antonio no lo puedes comprimir más, además, como bien él dice, sería mala idea.
2.- Ahora bien, ese .bin lo puedes colocar en la lista de archivos que colocar en RAM extra, utilizando el librarian.
3.- Con esto consigues que el binario del mapa comprimido con las utilidades de Antonio esté en una página de RAM y una dirección fija. Estos valores los puedes sacar directamente de la estructura que se crea en librarian.h: la página será resources [res].ramPage y la dirección de inicio será resources [res].ramOffset.
4.- Cada vez que queramos obtener una nueva pantalla, habría que:
a) desactivar las interrupciones.
b) Cambiar a la página resources [res].ramPage
c) Descomprimir la pantalla.
d) Poner la página 0 de nuevo
e) habilitar las interrupciones.

5.- Efectivamente, habría que quitar
$this->bbcode_second_pass_code('', '.map BINARY "mapa_comprimido.bin" <--- y esta otra')

6.- Pero te conviene tener esto:
$this->bbcode_second_pass_code('', 'extern unsigned int map_address [0];
extern unsigned int map_fin [0];
#asm
._map_address defw 0
._map_fin defw 0
#endasm')

7.- Y cambiar el descompresor para que mire ahí la dirección:
Esto:
$this->bbcode_second_pass_code('', 'ld de, map <----- Esta línea
ld hl, fin-1')

Cambiarlo por esto (atención, la puedo estar cagando):
$this->bbcode_second_pass_code('', 'ld hl, (_map_address)
ex de, hl
ld hl, (_map_fin)')

8.- Y antes de empezar el nivel, hay que establecer el valor de esas dos variables. La primera dice el principio del mapa compilado, y la segunda dice donde acaba. Necesitamos siempre que haya un recurso más después del mapa para poder calcularlo así:
$this->bbcode_second_pass_code('', 'map_address [0] = resources [n].ramOffset;
map_fin [0] = resources [n + 1].ramOffset - 1;')

donde n es el número de recurso donde está el mapa.

9.- Así, antes de llamar al descompresor para obtener la pantalla actual, como dijimos antes, haríamos:

$this->bbcode_second_pass_code('', 'asm_number [0] = resources [n].ramPage
#asm
; Deshabilitar interrupciones
di
; Cambiar de página
ld a, (_asm_number)
ld b, a
call SetRAMBank
#endasm

// AQUÍ LLAMARÍAMOS AL DESCOMPRESOR

#asm
; Poner RAM 0 de nuevo
ld b, 0
call SetRAMBank
; Habilitar interrupciones
ei
#endasm')

Más o menos esta es la idea (es posible que haya metido alguna gamba ;) ). Supongo que Antonio nos podrá ayudar más.

Re: Solucionado - Problemas compresión de mapas al pasar a 128K

Publicado: Mar, 11 Mar 2014, 10:58
por elborra
Pues en cuanto pueda le hecho un vistazo a todo esto.

Lo de comprimir 2 veces ya se que es contraproducente. Pretendía ir paso a paso y lo primero era conseguir cambiar la rutina de antonio para que "buscara" el mapa en una determinada dirección de memoria; por lo que de momento me daba igual recomprimir el fichero con apack para las pruebas, más adelante me dedicaría a evitar apack, aunque sorprendentemente el fichero recomprimido con apack ocupaba 17 bytes menos o_O. Aún así no es mi intención dejar esa doble compresión.

Gracias una vez más. Os ire comentando los progresos.

Re: Solucionado - Problemas compresión de mapas al pasar a 128K

Publicado: Mar, 11 Mar 2014, 13:58
por elborra
Ummm. hay un par de cosas que no acabo de entender muy bien. A ver si antonio se pasa y comenta. Recordar que de ensamblador poquito entiendo...

Por lo que yo entiendo la función de antonio de descomprimir mapa necesitaba 2 cosas:
    - la pantalla que se quiere descomprimir
    - el binario comprimido
aparte dentro de la propia función usa
    - dirección del inicio del mapa comprimido
    - dirección final del mapa comprimido

La descompresión, por lo que entiendo, se hace de atrás hacia alante. Estas dos direcciones antonio las resuelve con ¿etiquetas? ya que el propio mapa binario se incluye dentro de la funcion descomprimir_map. Pego la función completa (que bien vendría un tag spoiler en el foro para no saturar el post :P)
$this->bbcode_second_pass_code('', 'void __FASTCALL__ descomprimir_map ( unsigned char pantalla) {
#asm
ld a, l
and a
ld b, h
ld c, h
ld de, map ; elborra: dirección final? o al revés
ld hl, fin-1 ; elborra: dirección inicio? o al revés
desc1: sbc hl, bc
ex de, hl
ld c, (hl)
ex de, hl
inc de
dec a
jp p, desc1
ld de, DMAP_BUFFER+SCR_W*SCR_H-1
ld b, $80 ; marker bit
desc2: ld a, 256 / 2^DMAP_BITSYMB
desc3: call gbit3 ; load DMAP_BITSYMB bits (literal)
jr nc, desc3
#if (DMAP_BITHALF==1)
#if (DMAP_BITSYMB==1)
rrca
jr nc, desc4
xor a
call gbit3
inc a
#else
rrca ; half bit implementation (ie 48 tiles)
call c, gbit1
#endif
#else
and a
#endif
desc4: ld (de), a ; write literal
desc5: dec e ; test end of file (map is always 150 bytes)
ret z
call gbit3 ; read one bit
rra
jr nc, desc2 ; test if literal or sequence
push de ; if sequence put de in stack
ld a, 1 ; determine number of bits used for length
desc6: call nc, gbit3 ; (Elias gamma coding)
and a
call gbit3
rra
jr nc, desc6 ; check end marker
inc a ; adjust length
ld c, a ; save lenth to c
xor a
ld de, SCR_W
call gbit3 ; get two bits
call gbit3
jr z, desc9 ; 00 = 1
dec a
call gbit3
jr z, descb ; 010 = 15
bit 2, a
jr nz, desc7
#if (SCR_W>15)
call gbit3 ; [011, 100, 101] xx = from 2 to 13
dec a
call gbit3
jr desca
desc7: call gbit3 ; [110, 111] xxxxxx = from 14-15, 17-142
jr nc, desc7
cp SCR_W-14
sbc a, -14
#else
#if (SCR_W==15)
add a, $7c ; [011, 100, 101] xx = from 2 to 13
dec e
desc7: dec e ; [110, 111] xxxxxx = 14 and from 16 to 142
desc8: call gbit3
jr nc, desc8
jr z, descb
add a, e
#else
call gbit3 ; [011, 100, 101] xx = from 2 to 11 and from 13 to 14
call gbit3
cp SCR_W+2
sbc a, 2
jr desc9
desc7: call gbit3 ; [110, 111] xxxxxx = from 15 to 142
jr nc, desc7
add a, 14
#endif
#endif
desc9: inc a
desca: ld e, a
descb: ld a, b ; save b (byte reading) on a
ld b, d ; b= 0 because lddr moves bc bytes
ex (sp), hl ; store source, restore destination
ex de, hl ; HL = destination + offset + 1
add hl, de ; DE = destination
lddr
pop hl ; restore source address (compressed data)
ld b, a ; restore b register
inc e ; prepare test of end of file
jr desc5 ; jump to main loop
#if (DMAP_BITHALF==1 && DMAP_BITSYMB>1)
gbit1: sub $80 - (2^(DMAP_BITSYMB-2))
defb $da ; second part of half bit implementation
#endif
gbit2: ld b, (hl) ; load another group of 8 bits
dec hl
gbit3: rl b ; get next bit
jr z, gbit2 ; no more bits left?
adc a, a ; put bit in a
ret
.map BINARY "mapa_comprimido.bin" ;<-- elborra: etiqueta?
.fin ;<-- el borra: etiqueta?
#endasm
}')Por lo que entiendo con .map BINARY "mapa_comprimido.bin" lo que sucede es que "por donde vaya el compilador" crea una referencia (etiqueta?) llamada map y "copia" el binario del mapa_comprimido. A continuación crea otra referencia llamada fin que identificará el siguiente byte después del mapa binario. Así cuando mete en el registro DE la dirección de map y en HL la dirección de fin-1 (es decir el último byte del mapa) ya lo tiene todo listo para la descompresión.

$this->bbcode_second_pass_quote('na_th_an', '4').- Cada vez que queramos obtener una nueva pantalla, habría que:
a) desactivar las interrupciones.
b) Cambiar a la página resources [res].ramPage
c) Descomprimir la pantalla.
d) Poner la página 0 de nuevo
e) habilitar las interrupciones.
Yo lo que pretendo es que el mapa en memoria extra se copie y mantenga en memoria principal (en una estructura reservada) hasta que se cambie de nivel. No necesito (ni debería) estar copiando el mapa continuamente a cada pantalla.

Por un momento olvidaros que el mapa está comprimido previamente con tmxcompress y lo único que quiero hacer es copiar un recurso que esta en memoria extra a memoria principal donde yo quiera, lo cual, sino me equivoco es precisamente lo que hace get_resource, que a fin de cuentas es usar unpack_RAMn con los datos de librarian.h. Así si mi recurso es el 27 y quiero descomprimirlo a partir del byte 32000 del binario principal sólo tendría que hacer:$this->bbcode_second_pass_code('', 'get_resource(27, 32000)')Está claro que yo no quiero descomprimirlo en 32000 sino en esa estructura que habiamos reservado anteriormente. Así si en alguna parte del código hemos escrito por ejemplo$this->bbcode_second_pass_code('', 'unsigned char mimapa[2000]')al poner$this->bbcode_second_pass_code('', 'get_resource(27, (unsigned int) (mimapa))')tendría teóricamente el mapa donde quiero.

Así lo único que quedaría es como referenciar en la utilidad de antonio las direcciones map y fin-1 con las nuevas direcciones que hagan referencia al inicio de mimapa[] y su final (que esto si se haría más o menos como me explicas) Yo es que me confundo en asm con los
.algo
._algo
(algo)
(_algo)
y las correspondencias en c.

Sorry por el tocho post

Re: Solucionado - Problemas compresión de mapas al pasar a 128K

Publicado: Mar, 11 Mar 2014, 17:32
por antoniovillena
A ver, la rutina sólo recibe como parámetro de entrada el registro A con el que le indicamos la pantalla que vamos a descomprimir, el resto de direcciones/parámetros están dentro de la rutina.

El algoritmo de descompresión va hacia atrás pero las longitudes de los streams comprimidos (1 byte cada una) están al comienzo, por eso es necesario esa referencia doble (al comienzo y al final del bloque de datos).

Imagínate que tienes un mapa de 5x5 pantallas. En total serían 25 streams comprimidos (de longitud variable) que se descomprimen en 25 pantallas de longitud fija (150 bytes). Cada vez que llamamos a la rutina sólo vamos a descomprimir uno de esos 25 streams, así que un primer paso es calcular donde empieza ese stream.

Como el primer stream ya sabemos donde empieza (al final del bloque, o sea en fin-1) debemos almacenar 24 longitudes variables, que como nunca van a superar los 150 bytes (normalmente ocupan menos de la mitad de eso) con un byte por longitud nos sobra. Así que los primeros 24 bytes almacenan las longitudes, en orden ascendente, de nuestras 24 últimas pantallas.

Básicamente lo que se hace es un sumatorio (como vamos para atrás restamos) de las longitudes de las pantallas hasta llegar a la que queramos para poder calcular la dirección de comienzo del stream comprimido. Este cálculo se hace muy rápido, por eso opté por un algoritmo de complejidad lineal (sumatorio). Otra opción más rápida sería poner directamente un array de punteros (complejidad constante), pero requiere 2 bytes por pantalla en lugar de 1 byte.

Re: Solucionado - Problemas compresión de mapas al pasar a 128K

Publicado: Sab, 15 Mar 2014, 11:54
por elborra
Bueno, tras unos pocos días liados, daros de nuevo las gracias a los 2.

Na_th_an, al principio no entendía muy bien lo que me proponias, despues de darle unas cuantas vueltas al asunto y empaparme un poco más sobre la memoria extendida he conseguido llegar a la solución deseada ^_^

antonio, gracias por la última explicación, más o menos tenía los conceptos claros pero con alguna cosa pendiente, ahora entiendo como funciona 100% la rutina.

Peeeero.. siempre hay un pero. (Y esto no tiene nada que ver, que yo sepa, con memoria extendida o incluso con el mapa comprimido) Os explico, antes siquiera de pasar a 128K, en pruebas trabajando con los mapas comprimidos de antonio llegue a hacer algun mapa con más de 100 pantallas (con todos los tiles a 0 para que con la compresión no hubiera ningún problema con el espacio). El caso es que al ejecutar el juego petaba; con el tiempo y con el primer "mapa final" (de 54 pantallas) este problema no surgía (independientemente de que este mapa comprimido ocupara más que el de 100 pantallas vacias). Obviamente el binario del juego no se acerca siquiera al máximo permitido.

Ahora, quiero volver a ampliarlo, y me estan surgiendo los mismos problemas. El juego me peta al poner un número elevado de pantallas. He estado buceando por el código buscando que variable podía estar desbordando, ya que en un principio me imagino que no se concibió la churrera para tal número de pantallas, pero aún así teóricamente la unidad más pequeña seria el byte lo cual debería ser suficiente.
- He estado mirando si es por el array de scripts y no parece
- tampoco de las definiciones de MAP_W y MAP_H
- en combinaciones de MAP_W*MAP_H tampoco encontré nada que pudiese provocar el fallo

¿sabriaís decirme si existe alguna limitación, a nivel de variables, del número de pantallas del mapa y todo lo que eso conlleva?
¿antonio, podría ser algo del propio compresor? yo diría que no, pero me pierdo en el código

Seguiré revisando a ver si me he dejado algo chorra por ahí (me he releido chorrocientas veces config.h y el make.bat para comprobar que estan bien los valores por si quedaba alguna duda). Si no hubiera nada estaré metiendo la pataza en algún lado :(

Edito: Mmmmm, ¿podrian ser los enemigos? he generado el fichero de enems.h (con las pantallas correctas -no, esto no lo habia hecho xD-) y ahora el problema es que me genera errores al compilar, y casualmente de desbordamiento..

Re: Solucionado - Problemas compresión de mapas al pasar a 128K

Publicado: Sab, 15 Mar 2014, 12:13
por na_th_an
No sé por qué petará, pero te digo desde ya que el valor 99 se utiliza como "pantalla no válida" o "pantalla no definida" y cosas por el estilo por todo el motor. Jamás pensé que a alguien se le ocurriese hacer un mapa tan grande.

Aparte de esto, la verdad es que no tengo ni idea de por qué fallará. 99 * 150 = 14850, que está en el rango de los números enteros, así que no debería haber ningún problema.

No sé, seguramente se irá algún puntero a tomar por culo. Tampoco puedo decirte nada sin "verlo". Describe el cuelgue y a lo mejor se me ocurre algo. ¿Desde el principio? ¿Al navegar por el mapa?

Además, si estás utilizando las rutinas de Antonio, creo que ni siquiera se toman en cuenta las multiplicaciones que hago yo en mi parte del código.

Ayudaría mucho que describieses mejor los cuelgues.

Re: Solucionado - Problemas compresión de mapas al pasar a 128K

Publicado: Sab, 15 Mar 2014, 12:15
por na_th_an
Hay una forma chusca de saber exactamente donde se te cuelga, que a mí me ha servido de la hostia en el pasado. Se trata de ir colocando en el código un sp_Border (2);.

Ejecutas. Si se pone el borde en rojo antes de colgarse, lo mueves más adelante. Así vas moviéndolo hasta que se cuelgue sin ponerse el borde rojo, y sabes que la instrucción justo anterior es la que jode la marrana.

Re: Solucionado - Problemas compresión de mapas al pasar a 128K

Publicado: Sab, 15 Mar 2014, 12:21
por elborra
$this->bbcode_second_pass_quote('na_th_an', 'H')ay una forma chusca de saber exactamente donde se te cuelga, que a mí me ha servido de la hostia en el pasado. Se trata de ir colocando en el código un sp_Border (2);.

Ejecutas. Si se pone el borde en rojo antes de colgarse, lo mueves más adelante. Así vas moviéndolo hasta que se cuelgue sin ponerse el borde rojo, y sabes que la instrucción justo anterior es la que jode la marrana.

Jajaja ya ves!!

De todas formas, tal como he editado en mi post de arriba. Recorde nada más escribirlo que no habia generado el fichero enems.h adecuado para el tamaño. Una vez generado ahora lo que tengo son (2) mensajes de desbordamiento al compilar: un par de defb fuera de rango.

Edito1: he visto que enoffs y enoffmasi eran de tipo char y he cambiado a int por$this->bbcode_second_pass_code('', 'enoffs = n_pant * 3;')Aún así me sigue dando el mismo error de compilación. ¿el cambio es correcto, ¿verdad? sigo comprobando a ver que más cosas puede haber.
Edito2: Estoy hoy tonto editando mis post, estoy autocitandome continuamente en lugar de editando.

Re: Solucionado - Problemas compresión de mapas al pasar a 128K

Publicado: Sab, 15 Mar 2014, 13:19
por na_th_an
Dime qué error de compilación te da y te podré ayudar más :D

Re: Solucionado - Problemas compresión de mapas al pasar a 128K

Publicado: Sab, 15 Mar 2014, 15:25
por elborra
Te lo dejo aquí, pero no se si es viable saber de donde proviene el error más allá de que es un desbordamiento.
$this->bbcode_second_pass_code('', 'C:\Utilidades\Spectrum\juego\dev>make juego
Error at file 'C:\Users\Borra\AppData\Local\Temp\smis_.opt' line 8878: Integer '
6192449487634800' out of range
Error at file 'C:\Users\Borra\AppData\Local\Temp\smis_.opt' line 8925: Integer '
7318349394477632' out of range
2 errors occurred during assembly
Errors in source file retro.c:
Error at file 'C:\Users\Borra\AppData\Local\Temp\smis_.opt' line 8878: Integer '
6192449487634800' out of range
^ ---- defb 368
Error at file 'C:\Users\Borra\AppData\Local\Temp\smis_.opt' line 8925: Integer '
7318349394477632' out of range
^ ---- defb 576
')