Dudas por una fuente la mar de misteriosa

Lugar donde se intentarán resolver problemas específicos
Responder
Avatar de Usuario
CUE
Administrador
Administrador
Mensajes: 5619
Registrado: 24 Ene 2011, 16:52

Mensaje por CUE » 30 Jul 2016, 15:28

Pues si es vectorial... Hay que ver la poca ayuda que te damos, vas a terminar odiándonos, pero te advierto que deberás ponerte en la cola, y es larga :twisted:

A simple vista se ven algunas cositas, pero no están comprobadas, además de no conocer cómo es la fuente.

A partir de 0x0028:
- paletas de 16 colores, 4 bytes por color

A partir de 0x0428:
- 4 bytes con el código del carácter
Al menos eso creo, pues muchos de esos códigos parecen SJIS, y al ser el juego japo he asociado ambas cosas.

A partir de 0x080C:
- 1 byte con el ancho
- 1 byte con el alto (a lo mejor es alto/ancho en vez de ancho/alto)
- 2 bytes con el tamaño de los datos (o solo uno seguido de un cero)
- 4 bytes con el offset relativo a los datos (hay que sumar 0xDEC4 a ese valor)
También está puesto a ojo, pero al ver los anchos/altos que inicialmente son de 10/20 (95 caracteres) y luego de 20/20 (un montón) da la impresión de ser el típico set ANSI seguido de uno SJIS. Al sumar el offset al tamaño da el valor del siguiente offset, así que eso sí debe estar bien.

A partir de 0xDEC4:
- los datos en sí
A mí me parece que están codificados de alguna forma, RLE o algo de eso.

Y hasta aquí hemos llegado, que no doy más de sí con los tropecientos mil grados que tenemos aquí (bendito invento el de las bebidas fresquitas).

Avatar de Usuario
SkyBladeCloud
Mensajes: 41
Registrado: 26 Ene 2011, 13:14
Ubicación: Sky´s Romhacking Nest

Mensaje por SkyBladeCloud » 01 Ago 2016, 01:50

Bueno... Veamos... Esto es lo que he podido observar hasta el momento...

0x00000000 -> Identificador de fichero (UFS, 4 bytes)
0x00000004 -> Número de caracteres almacenados (0x1ad7, 4 bytes)
0x00000008 -> Ni pajolera idea, no parece muy relevante (8 bytes)
0x00000010 -> Tamaño total de fichero (4 bytes)
0x00000014 -> Puntero al inicio de la tabla de caracteres (4 bytes)
0x00000018 -> Puntero al inicio de la tabla de metadatos de caracteres
0x0000001C -> Puntero al inicio de los datos de caracteres
0x00000020 -> Tampoco ni idea, apuesto a que constante (8 bytes)
0x00000028 -> 0x10 paletas de 0x10 colores cada una, ARGB8888 LE
0x00000428 -> Inicio de la tabla de caracteres (4 bytes por código de caracter)
0x0000080c -> Inicio de la tabla de metadatos; 8 bytes por cada entrada con el siguiente formato:
1 byte -> ancho del caracter
1 byte -> alto del caracter
2 bytes -> tamaño de los datos correspondientes a ese caracter
4 bytes -> offset (puntero relativo) a los datos del caracter (relativo al valor especificado en 0x0000001C)
0x0000dec4 -> Inicio de los datos de caracteres, en ese formato tan raro...

En realidad el formato en sí es un bitmap indexado de 4 bits (tal como sugieren las paletas), pero donde cada pixel ocupa siempre 8 bits (estando los primeros 4 bits siempre a cero).
Eso si... Todo codificado en lo que parece ser un RLE muy especialito. Usando memory breakpoints enseguida se encuentra la función de decodificación:

[spoil]

Código: Seleccionar todo

z_un_0885db24:

	addiu	sp,sp,-0x1040
	sw	fp,0x102C(sp)
	move	fp,a0
	lw	a0,0x1040(sp)
	sw	s0,0x100C(sp)
	lw	s0,0x1044(sp)
	sw	s1,0x1010(sp)
	lbu	s1,0x0(t3)
	sw	s6,0x1024(sp)
	lbu	s6,0x1(t3)
	lbu	a2,0xF(a0)
	sw	a1,0x1000(sp)
	sw	a3,0x1004(sp)
	sw	s2,0x1014(sp)
	li	t4,0x0
	andi	a2,a2,0x1
	sw	t0,0x1008(sp)
	move	s2,t1
	sw	s3,0x1018(sp)
	sw	s4,0x101C(sp)
	sw	s5,0x1020(sp)
	sw	s7,0x1028(sp)
	sw	ra,0x1030(sp)
	beq	a2,zero,pos_0885DB90
	move	s7,t2
	addiu	a0,a0,0x20
	lbu	t4,0x3(a0)

pos_0885DB90:

	move	a0,sp
	move	a1,t4
	jal	memset_jak
	li	a2,0x1000
	lbu	t2,0x0(s0)
	li	t1,0x0
	li	t5,0x0
	li	t4,0x0
	li	t6,-0x9
	li	s5,0x7
	li	s4,0x6
	li	s3,0x5
	li	ra,0x4
	li	t9,0x3
	li	t8,0x2
	li	t7,0x1
	move	v1,sp

pos_0885DBD4:

	bne	t4,zero,pos_0885DBF8
	andi	a3,t2,0xF
	sra	a0,t2,0x4
	andi	a3,a0,0xFF
	and	a1,a3,t6
	move	t4,t7
	andi	a3,a3,0x8
	b	pos_0885DC10
	andi	a1,a1,0xFF

pos_0885DBF8:

	addiu	s0,s0,0x1
	and	a1,a3,t6
	li	t4,0x0
	lbu	t2,0x0(s0)
	andi	a3,a3,0x8
	andi	a1,a1,0xFF

pos_0885DC10:

	beq	a1,s5,pos_0885DC50
	li	t3,0xF
	beq	a1,s4,pos_0885DC4C
	li	a0,0xD
	beq	a1,s3,pos_0885DC4C
	li	a0,0xA
	beq	a1,ra,pos_0885DC4C
	move	a0,s5
	beq	a1,t9,pos_0885DC4C
	move	a0,s3
	beq	a1,t8,pos_0885DC4C
	move	a0,ra
	li	a0,0x0
	beql	a1,t7,pos_0885DC4C
	move	a0,t8

pos_0885DC4C:

	move	t3,a0

pos_0885DC50:

	beq	a3,zero,pos_0885DD04
	addu	a0,v1,t1
	li	a1,0x0
	li	a3,0x0
	li	a0,0x8

pos_0885DC64:

	bne	t4,zero,pos_0885DC88
	andi	a2,t2,0xF
	sra	a2,t2,0x4
	andi	a2,a2,0xFF
	sllv	a2,a2,a0
	addu	t0,a1,a2
	andi	t0,t0,0xFFFF
	b	pos_0885DCA0
	move	t4,t7

pos_0885DC88:

	sllv	a2,a2,a0
	addiu	s0,s0,0x1
	addu	t0,a1,a2
	li	t4,0x0
	andi	t0,t0,0xFFFF
	lbu	t2,0x0(s0)

pos_0885DCA0:

	addiu	a3,a3,0x1
	addiu	a0,a0,-0x4
	slti	a2,a3,0x3
	bne	a2,zero,pos_0885DC64
	move	a1,t0
	li	a0,0x0
	slt	a1,a0,t0
	beql	a1,zero,pos_0885DD28
	slt	a0,t5,s6
	addu	a1,v1,t1

pos_0885DCC8:

	addiu	t1,t1,0x1
	sb	t3,0x0(a1)
	slt	a1,t1,s1
	bnel	a1,zero,pos_0885DCEC
	addiu	a0,a0,0x1
	addiu	t5,t5,0x1
	addiu	v1,v1,0x40
	li	t1,0x0
	addiu	a0,a0,0x1

pos_0885DCEC:

	slt	a1,a0,t0
	bne	a1,zero,pos_0885DCC8
	addu	a1,v1,t1
	b	pos_0885DD28
	slt	a0,t5,s6
	addu	a0,v1,t1

pos_0885DD04:

	addiu	t1,t1,0x1
	sb	t3,0x0(a0)
	slt	a0,t1,s1
	bne	a0,zero,pos_0885DD28
	slt	a0,t5,s6
	addiu	t5,t5,0x1
	addiu	v1,v1,0x40
	li	t1,0x0
	slt	a0,t5,s6

pos_0885DD28:

	beq	a0,zero,pos_0885DD40
	slti	a0,t5,0x40
	beql	a0,zero,pos_0885DD44
	lw	a0,0x1008(sp)
	b	pos_0885DBD4
	lbu	t2,0x0(s0)

pos_0885DD40:

	lw	a0,0x1008(sp)

pos_0885DD44:

	lw	t1,0x1000(sp)
	mult	t1,a0
	lw	a0,0x1004(sp)
	sra	a1,a0,0x1
	srl	a1,a1,0x1F
	addu	a0,a0,a1
	mflo	a1
	sra	a2,a1,0x1
	srl	a2,a2,0x1F
	addu	a1,a1,a2
	sra	a1,a1,0x1
	sra	a0,a0,0x1
	addu	a1,a1,a0
	li	a0,0x0
	slt	a3,a0,s7
	beq	a3,zero,pos_0885DDEC
	li	a2,0x0
	sra	a3,t1,0x1
	srl	a3,a3,0x1F
	addu	t0,t1,a3
	sra	t0,t0,0x1
	move	a3,sp

pos_0885DD9C:

	li	t1,0x0
	slt	t2,t1,s2
	beq	t2,zero,pos_0885DDD8
	addu	t2,a2,a1
	addu	t2,t2,fp

pos_0885DDB0:

	addu	t3,a3,t1
	lbu	v0,0x1(t3)
	lbu	t3,0x0(t3)
	sll	v0,v0,0x4
	or	t3,t3,v0
	sb	t3,0x0(t2)
	addiu	t1,t1,0x2
	slt	t3,t1,s2
	bne	t3,zero,pos_0885DDB0
	addiu	t2,t2,0x1

pos_0885DDD8:

	addiu	a0,a0,0x1
	addu	a2,a2,t0
	slt	t1,a0,s7
	bne	t1,zero,pos_0885DD9C
	addiu	a3,a3,0x40

pos_0885DDEC:

	li	v0,0
	lw	s0,0x100C(sp)
	lw	s1,0x1010(sp)
	lw	s2,0x1014(sp)
	lw	s3,0x1018(sp)
	lw	s4,0x101C(sp)
	lw	s5,0x1020(sp)
	lw	s6,0x1024(sp)
	lw	s7,0x1028(sp)
	lw	fp,0x102C(sp)
	lw	ra,0x1030(sp)
	jr	ra
	addiu	sp,sp,0x1040
[/spoil]

La parte interesante empieza en el bloque etiquetado como "pos_0885DB90". En este punto, el registro "s0" contiene un puntero a los datos comprimidos del caracter. El registro "v1" ocntiene la dirección de memoria donde están los metadatos del caracter a descomprimir, y el registro "v0" el buffer de salida (examinándolo tras la ejecución de la función veo el bitmap en el formato que describo arriba).

De todos modos, y tras descomprimir el bitmap, el programa del juego lo copia nibble a nibble (convirtiéndolo a un verdadero 4bpp) a una textura que incluye todos los caracteres usados en la escena actual. Esta es la textura que se usará para renderizar el texto. Así, contiene únicamente los caracteres usados en esa escena, y en orden de necesidad (y además así se evita descomprimir más de una vez un mismo caracter en una misma escena). Esta "fuente generada según el texto" me recuerda bastante a las "fuentes locales" de Valkyrie Profile, o Final Fantasy I (el de PSP), aunque aquí es más sencillo ya que el texto viene como shift-jis, en lugar de usar índices a los caracteres de la fuente.

Un posible plan? Bueno... Yo empezaría por reimplementar la función arriba posteada para descomprimir todos los caracteres, de modo que puedan editarse... Nada de complicaciones, simplemente declarar una variable por cada registro y una línea de C por cada una de ensamblador (si, si, ya lo sé... Pero a estas alturas nadie va a venir a calificarme el código y ponerme un cero XDDDD)...
Seguidamente me fijaría en qué flag indica datos literales para recodificar los datos editados usando fake compression. Finalmente recompondría el fichero para reinsertarlo en el juego...

Claro, siempre se puede hacer una herramienta que implemente la descompresión en las 4 líneas de C que seguramente lleve, y que recomprima como es debido, pero el resultado en el juego sería exactamente el mismo y esto último puede llevar mucho más trabajo...

Bueno... Creo que de momento eso es todo lo que tengo que comentar, tampoco creo que quede demasiado asi que... Manos a la obra... No? :)

~Sky

Avatar de Usuario
Davoker
Mensajes: 884
Registrado: 18 Ago 2011, 04:38

Mensaje por Davoker » 05 Ago 2016, 06:13

Creo que ya te han respondido, otra cosa es que sepas interpretarlo, te vendría bien un traductor chino :lol:
51 75 65 20 62 75 73 63 61 72 61 73 20 61 71 75 69 20 6d 61 6c 61 6e 64 72 69 6e 2c 20 71 75 65 20 62 75 73 63 61 72 61 73 20 3d 29

Avatar de Usuario
CUE
Administrador
Administrador
Mensajes: 5619
Registrado: 24 Ene 2011, 16:52

Mensaje por CUE » 05 Ago 2016, 09:28

Yo he entendido que quería información. Más de eso no puedo dar por no saber nada del juego (imagino que es de 3DS o PSP) y porque no me da más de sí mi tiempo :(

Avatar de Usuario
CUE
Administrador
Administrador
Mensajes: 5619
Registrado: 24 Ene 2011, 16:52

Mensaje por CUE » 07 Ago 2016, 09:17

La fuente no es rara y no parece muy difícil. De hecho, a simple vista se veía que era una especie de RLE, pero la imposibilidad de poder hacer pruebas reales con el juego (no tengo ni consola y ahora mismo ni emuladores instalados) hace imposible que pueda seguir con ello. Con el código que ha puesto Sky, a ver si alguien se anima a hacer un poco más.

Avatar de Usuario
SkyBladeCloud
Mensajes: 41
Registrado: 26 Ene 2011, 13:14
Ubicación: Sky´s Romhacking Nest

Mensaje por SkyBladeCloud » 22 Ago 2016, 18:29

Pues ya que el foro vuelve a estar disponible, aprovecho y comento que hice todo lo que posteaba en mi anterior comentario, con lo que los caracteres de la fuente salen en fila india.
Ya sólo por las risas los puse todos en una única imagen, y eso que son unos cuantos... más que nada porque me mola verlos así todos TAL CUAL salen en el juego. Si que tiene buen ojo CUE al ver que había un RLE por ahí... xD

[img]https://s10.postimg.io/zdptlwxjb/DLFont0.png[/img]

Y aquí el mismo gráfico pero con otra de las paletas (caracteres sólidos sin outline)

[img]https://s13.postimg.io/5spfap3it/DLFont7.png[/img]

Un saludo:

~Sky

Avatar de Usuario
CUE
Administrador
Administrador
Mensajes: 5619
Registrado: 24 Ene 2011, 16:52

Mensaje por CUE » 22 Ago 2016, 21:46

No es buen ojo, es mucho tiempo viendo ficheros, y al final se te pega algo. quieras o no. También, como ya se sabe, además de muy, muy, muy guapo (tres veces), soy también muy listo :ic_crazy:

Yo la duda que tengo, que no he visto ni una sola imagen del juego, es si los caracteres son o no de ancho variable. Eso añadiría un "problema" más.

Avatar de Usuario
SkyBladeCloud
Mensajes: 41
Registrado: 26 Ene 2011, 13:14
Ubicación: Sky´s Romhacking Nest

Mensaje por SkyBladeCloud » 22 Ago 2016, 23:54

Justo eso estábamos comentando ahora con Saku.

El juego sí que tiene una tabla de anchos pero no funciona como la mayoría. En lugar de almacenar el ancho que ocupa cada caracter, almacena la resolución del caracter; así pues no es posible editarlo directamente para "acercar" unos caracteres a otros (ya que se descolocarían los píxeles, lo típico al decodificar una imagen con la resolución incorrecta). Esto tiene cierto sentido ya que cada caracter se almacena comprimido individualmente. Puesto que al descomprimir un caracter, éste se añade a la "fuente temporal" es necesario conocer la resolución del caracter para poder añadir sus píxeles a esta fuente, la cual luego actúa de textura para dibujar el texto en pantalla.

En teoría sí que es posible cambiar los anchos, siempre y cuando el grafiquito correspondiente se recorte para que su resolución coincina con la reflejada en la tabla de anchos. Claro que esto no lo he probado, aunque no debería dar ningún problema. He visto que el juego tiene caracteres de 10 y 20 píxeles, aunque luego durante el gameplay nunca he visto uno de 10 usado...

Supongo que la solución ideal para editarlo es coger los caracteres de 20 píxeles y recortarlos, actualizando la tabla de anchos de forma coherente, para que luego no de ese típico efecto de "tabla cuadriculada de texto". El caso es que se me han acabado las vacaciones así que a ver de dónde saco tiempo para darle a este tema xDD

Un saludo:

~Sky

Responder