Registrarse

[FR] Estructura de los bloques de mapeado

Estado
Cerrado para nuevas respuestas.

Bugrhak

A long time ago I used to call myself "Subzero".
Buenas WAHeros, hoy me gustaria enseñarles una mini imbestigación/documentación que hice hoy al
amanecer. No tengo mucho que decir así que "aqui va el rollo". :V


¿De que va esto?
Esta imbestigación/documentacion trata sobre los bloques que utilizamos a diario para mapear,
al hacerlo me propongo "explicar de forma directa"el funcionamiento del bloque, y como está compuesto (su estructura).
Otro objetivo que para mi no es menor, es, que sepamos un poquito mas "el como de las cosas", es decir, con lo que lidiamos a diario, porque creo que un buen RomHacker es aquel que sabe lo que hace y de que manera hacerlo.

La documentación​

Estructura del bloque (De mapeo).

- La estructura no alberga los "comportamientos de byte" que se encuentran en el bloque.

- Cada bloque comprende una longitud de 0x10 es decir, "ocupa" unos 16 bytes (10 = 16 en decimal).

- Parte de esos 16 bytes conforman tanto la capa inferior, como la superior y a su vez, tambien estan incluidos los tiles que conforman la totalidad del bloque, al igual que los "Flips" ("Inversiones de derecha-izquierda") que puedan llegar a ser utilizados por los tiles del bloque.

- De los 16 bytes totales de la estructura, 8 de ellos comprenden cada fragmento de tile (de 8x8 pixeles cada uno), tanto de la capa inferior, como superior.

- Los otros 8 bytes restantes son destinados para los flips usados tanto para los fragmentos de tiles de la capa inferior como de la superior.

- El "físico" de la estructura es el siguiente: "Tile" - "flip" - "Tile" - "flip" y así sucecivamente hasta ocupar los 16 bytes correspondientes. Cabe aclarar que la estructura SIEMPRE comienza "enseñando" el tile, y finaliza con el flip.

- Como ya he dicho, el primer byte corresponde al "Tile". Esto significa que ese byte "almacena" el numero del tile dentro del tileset.

- Para cada variación de flip existente, un valor puntual que le identifica, he aqui los valores:

Código:
No usa flip: 00
Flip XY: 0C
Flip X: 04
Flip Y: 08
- Si por ejemplo, el numero de nuestro tile es de tres sifras (o superior), el valor del flip va a "mutar".
¿"Mutar"?
Si, eso, "muta", vamo a explicarlo:

Un byte esta compuesto de dos digitos, y el numero de nuestro tile tiene 3. Supongamos que tenemos el bloque 2C5 y tiene aplicado un flip X, esto ya en la estructura se veria así:

Código:
C5 06
C5 corresponde al numero del tile y 06 al flip X. Lo que ocurre aqui, es que como el byte del tile no puede almacenar todos los datos, tenemos que compartir datos con el byte del flip.
Podemos decir que aquí tambien ocurre una "suma" y una permuteción, veamos primero la "permutación:

Si vemos al nro del tile (0x25C)como "025C", estariamos "permutandolo y sumandolo de esta forma: 5C 06. Donde 5C como ya dige equivale al nro del tile y 06 es la suma del flip mas el numero "restante" que corresponde al nro del tile.
En caso de que el nro del tile use tres cifras (o mas)y este no use flip, simplemente ocupas el byte del flip con el numero proveniente del nro del tile (si, el que "nos quedó por fuera), si vemos el caso anterior pero ahora sin el uso de flip seria asi:
Código:
 C5 02 ...
Nota: Si se dirigen al editor de bloques, y seleccionan uno (bloque de mapeo) podrán ver un offset, dicho offset corresponde a la estructura del bloque.

----------------------------​

Muy bien waheros, espero que les haya gustado esta mini "imbestigación", un saludin :awesome:
Si hay algo que no se entiende por la forma en la que me expreso, o estoy en falta de información, por favor haganmelo saber en este mismo tema ;)


PD: Se que esto a la hora de romhackear parece no tener mucha importancia ya que es algo que hace una herramienta por nosotros, pero nunca está mal saber como funcionan las cosas (se que lo dige al principio del post :v)
 
Última edición:
M

Miembro eliminado 28262

Invitado
Asombroso! Me resulta fascinante que hayas podido hallar todo esto, es sencillamente genial!

Ya sabía algo de esto, pues cuando adquieres habilidad de scripting estas cosas suelen notarse por ejemplo haciendo un setmaptile. Pero tú has ido mucho más allá profundizando en el tema.

No puedo parar de flipar puesto que esta investigación también nos "muestra" cuanto podría llegar a pesar un mapa en la ROM dependiendo de que tan grande o pequeño lo hagamos.

Sin duda el creador de A-map o MEH, se tubieron que comer el tarro bastante para lograr hacer esos editores de mapas usando esta lógica.

Mientras leía la investigación no podía dejar de pensr en algo que cierto usuario dijo hace poco "Es que Gamefreak tiene un código fuente, nosotros solo un montón de números". No podía estar más en lo correcto.

Espero que progreses y nos traigas más aportes chulos como estos que, aunque realmente no sirvan para mucho, nos enseñan bastante y resultan genial!

Saludos y Buenas vibras homie!
Bless!

#ÉliteSeich
 

Fran Agustín

Si el sol besa tus ojos, ni cuenta te das.
Miembro insignia
Desde el momento en que el Excelentísimo Señor Doctor Licenciado Profesor @Subzero me comentó de esta investigación (sí, la vi antes que ustedes simples mortales, son las ventajas de ser ayudante de cátedra) me interesó mucho.

Sin embargo, lo que más llamó mi atención, no sé si a alguien más le pasó lo mismo, fue que se sume el valor del flip con el primer byte del "número de tile" cuando éste tiene 3 dígitos.

Así que vengo hoy a ampliar la investigación exponiendo no solo mis descubrimientos, sino también todo el proceso lógico que seguí para hallarlos.

¿Cómo haría luego para recuperar los valores por separado? Supongamos que restara, ¿cómo sabría cuál número restar (4, 8 o C)?
Inmediatamente noté que los tres posibles valores de flip son divisibles por 4, lo que quiere decir que su desarrollo en el sistema binario termina con 2 números cero (0).
Más precisamente:

Código:
4 = 0b01[U]00[/U]
8 = 0b10[U]00[/U]
C = 0b11[U]00[/U]
Además, los "números de tile" como los ha llamado Sub, pueden tener como máximo valor el 0x3FF. Es decir, pueden tener hasta 3 dígitos y, ese último solo puede ser menor o igual a 3.

¿Qué pensé?
Si damos un vistazo a los valores que podría tener ese byte que se suma al flip:

Código:
1 = 0b01
2 = 0b10
3 = 0b11
¿Notan algo?
¡Los tres pueden expresarse usando tan solo 2 dígitos en binario!
Mi siguiente idea fue clara, al sumar el flip con el dígito que sobra del número de tile, obtenemos 4 bits (o dígitos binarios) que, al separarlos y, en el primer caso agregarles 2 ceros detrás y en el segundo quitando los 2 primeros dígitos, obtenemos el valor de flip o dígito de tile respectivamente.

¿Qué sigue?
Para mi era claro, GameFreak nos complica la vida y hace un ldrb y luego mediante logical shifts, agrega los ceros o quita los dígitos.
Me puse, entonces, a investigarlo buscando las rutinas ingame para verificar mi teoría. Lo que encontré, sin embargo, fueron rutinas que simplemente tomaban la información como estaba y la copiaban en distintos lugares de la RAM.

¿Era ese el fin?
Claro que no, yo estaba convencido de que algo más leía esa información de la RAM y hacía lo que yo creía.
Seguí buscando, sin demasiado éxito pues la rutina que encontré copiaba la información a otro lugar de la RAM...

Además, descubrí que en algunos tiles delante del número del flip aparecía otro número... Por ejemplo, encontré un "16 51" y lo cambié a "16 59". El número del tile era "116", le sumé "8" de flip horizontal. Pero, ¿y ese 5? Mirando un poquito llegué a la conclusión de que era el número de paleta.

¿Qué pasó luego?
Viendo las rutinas en la base de datos de knizz con el IDA PRO, descubrí que eran las que cargaban la imagen en el mode 4 de la GBA. Entonces busqué en la vieja y confiable GBA TEK, encontré esto:
GBA TEK dijo:
BG Mode 4,5 (Bitmap based Modes)

06000000-06009FFF 40 KBytes Frame 0 buffer (only 37.5K used in Mode 4)
0600A000-06013FFF 40 KBytes Frame 1 buffer (only 37.5K used in Mode 4)
06014000-06017FFF 16 KBytes OBJ Tiles
GBA TEK dijo:
Text BG Screen (2 bytes per entry)
Specifies the tile number and attributes. Note that BG tile numbers are always specified in steps of 1 (unlike OBJ tile numbers which are using steps of two in 256 color/1 palette mode).

Bit Expl.
0-9 Tile Number (0-1023) (a bit less in 256 color mode, because
there'd be otherwise no room for the bg map)
10 Horizontal Flip (0=Normal, 1=Mirrored)
11 Vertical Flip (0=Normal, 1=Mirrored)
12-15 Palette Number (0-15) (Not used in 256 color/1 palette mode)
En resumen, lo que vemos en pantalla empieza en la posición $06000000 y son tiles expresados, como Sub dijo, con 2 bytes: 0x"XX XX".

Ahora a la segunda parte, no podríamos decir que el primer byte corresponde al número de tile y el segundo al flip.
Siguiendo lo que dice allí sobre la estructura, tomemos el número "XX YY" permutémoslo: "YYXX".

Ahora lo pasamos a binario y tendremos 16 bits:
0bBBBBBBBBBBBBBBBB​
Que dividiremos de la siguiente manera:
0bPPPPVHTTTTTTTTTT
Donde P es la paleta, V el flip veritcal, H el flip horizontal y T el número de tile.
Tenemos, entonces, 10 bits para el número de tile; 1 para cada flip y 4 para el número de paleta.

Si pasamos esta estructura al editor hexadecimal, sabemos que de los dos bytes "XX YY" los primeros 2 dígitos (XX) son los 8 bits traseros del número de tile (las 8 últimas "T"); la primer Y son los 4 del número de paleta (es decir, medio byte de paleta) y la segunda Y contiene 2 bits de flip y 2 bits de número de tile (es decir que tiene 1/4 byte de flip y 1/4 byte de tile).


Con eso doy por finalizada la investigación sobre la estructura, aunque creo que sería bonito ver las funciones de la GBA que leen los gráficos y saber cómo se comportan en este caso. Lo dejo pendiente por ahora.
 

cosarara97

Dejad de cambiar de nick
Miembro de honor
Sin duda el creador de A-map o MEH, se tubieron que comer el tarro bastante para lograr hacer esos editores de mapas usando esta lógica.

Nadie piensa en mi T_T
https://github.com/cosarara97/blue-spider/blob/954d4e91d8c548948cf28dba4549c7f2cb19e4f4/bluespider/mapped.py#L462

o resumido:

Código:
    offset = part*2
    byte1 = layer_mem[offset]
    byte2 = layer_mem[offset+1]
    tile_num = byte1 | ((byte2 & 0b11) << 8)

    palette_num = byte2 >> 4
    flips = (byte2 & 0xC) >> 2
    if flips & 1:
        part_img = part_img.transpose(Image.FLIP_LEFT_RIGHT)
    if flips & 2:
        part_img = part_img.transpose(Image.FLIP_TOP_BOTTOM)
Cosa que concuerda con la investigación:
Un byte, con los 2 bits menores del otro, nos dan el número de tile.
De los 6 bits que nos quedan, los 4 de más a la izquierda son el número de paleta, y los otros dos son el flip vertical y el horizontal.

Me parece una excelente investigación y razonamiento. Aún así, me hace rabia pensar que todo esto ya estaba más que resuelto: solo hacía falta preguntar (o leer el código*, que siempre es más fácil que el ensamblador).

* AM es el único de código cerrado, el código de Blue Spider es público, así como también el de MEH y EliteMap.
 
Estado
Cerrado para nuevas respuestas.
Arriba