[ASM] Mostrar Imágenes a Pantalla Completa
A continuación aprenderemos como mostrar imágenes a pantalla completa (240x160) por medio de ASM en Fire Red y Rojo Fuego.
Las características de la rutina son:
- BG en Modo 0, por lo que se puede seguir haciendo uso de los demás BG y OBJ
- Uso del BG0 para mostrar la imágen
- Tamaño de la imágen de 1x1 hasta 240x160 (pantalla completa)
- Tabla con estructura [Imágen][RAW][Paleta]
- Uso de variable para controlar el índice de la Tabla
- Imágen y RAW comprimidas en LZ77 para ahorrar espacio
- Paleta de 16 colores
- Borrar la imágen de forma segura con la misma rutina sin necesidad de refrescar la pantalla
- O borrar mediante otra rutina (RECOMENDADO)
Herramientas a usar:
- GraphicsGale DESCARGAR
- Nameless Tilemap Editor (NTME) DESCARGAR
- Sphere DESCARGAR
- Compilador THUMB ASM DESCARGAR
- HxD DESCARGAR
- GBA Graphics Editor DESCARGA
Ya con todo a la mano podemos empezar
Primero busquemos la imágen que deseamos mostrar, máximo de 240x160 e indexada a 16 colores incluido el primer color que es usado como transparencia. Si tienes problema con ello, pásate por este post donde explico como redimensionar e indexar.
Yo usaré esta:
Ahora abrimos GraphicsGale y creamos un nuevo documento (Ctrl+N) de 256x160 a 4bits
Luego con GraphicsGale también abrimos nuestra imágen, la seleccionamos toda (Ctrl+A) y la copiamos (Ctrl+C). Ahora volvemos al lienzo creado anteriormente (la imágen de 256x160) e importamos la paleta de la siguiente manera:
Presionando la flecha hacia abajo que aparece debajo de la paleta de colores y seleccionando "Load Palette..."
Seleccionamos la opción File > Import From Clipboard para copiar la paleta de la imágen en el portapapeles. Seleccionamos All y OK.
Ahora pintamos toda la imágen con el color de transparencia, para ello seleccionamos el primer color y rellenamos con la herramienta Flood Fill . Luego vayan a las propiedades de la capa y selecciones el color de transparencia de la siguiente manera:
Esto se hace para que no se eliminen colores de la imágen al importar la que vamos a usar. Tambien basta simplemente con deseleccionar la opción de color de transparencia o Transparent Color. Ahora pegamos nuestra imágen y guardamos la imágen en formato PNG o BMP preferiblemente, nos debería quedar así:
Ahora abrimos el Editor de Sphere y seleccionamos importar imágen a mapa, seleccionamos la imágen y en la ventana Tile Dimensions colocamos 8 tanto en el alto como el ancho.
Presionamos OK y luego Sí para eliminar los tiles repetidos y finalmente aceptar.
Ahora abrimos el archivo recien creado por Sphere con la opcion File > Open > Map...
Hacemos una captura de pantalla y vamos a Pain, la pegamos y recortamos la imágen correspondiente al Tileset teniendo cuidado de no recortar pixeles del Tileset para ello pueden hacer uso del zoom, tengan en cuenta que las dimensiones deben de ser en múltiplos de 8px, el cual, es la base de cada Tile tanto horizontal como verticalmente. Una vez recortada la imágen correctamente, guardamos como imágen como Mapa de bits de 24bits y ya tendremos nuestro Tileset.
Ahora lo abrimos con GraphicsGale y reducimos la profundidad de color con la opción All Frames > Color Depth... y en Pixel Format seleccionamos 4bpp (16 Colors), presionamos OK y ya estárá indexada a 16 colores. Posiblemente el color de transparencia no quede en el primer lugar, para corregirlo sin usar CMP simplemente selecciona toda la imágen (Ctrl+A), córtala (Ctrl+X), haz clic y mantén presionado en el color de transparencia y arrástralo al primer lugar, luego pega la imágen (Ctrl+V) y ya tendrás el color de transparencia donde debería ir
Ya estando indexada correctamente la imágen nos queda un ultimo paso para tenminar con el Tileset, éste es colocar el Tile de tranparencia en la primera posición (créeme nos ahorrará muchos dolores de cabeza). Para ello activa la función de transparencia en la capa como vimos anteriormente y selecciona el primer color, ahora haz un zoom con el que puedas trabajar tranquilamente, luego haz clic en la opción Custom Grid y selecciona 8x8. Si no la trae por defecto puedes fácilmente ir a Custom Grid > Setup... > Add y añadirla.
Guardamos la imágen y tendremos finalmente el Tileset a insertar. Pasemos a crear el mapa o RAW. Para ello abrimos NTME, abrimos el Tileset con la opción File > Open TileSet y abrimos el TileMap con la opción File > Open TileMap > From Sphere RPM file. Nos quedará así:
Ahora vamos a Edit > Extra > Change All Palettes y seleccionamos Palette D [14], guardamos el TileMap y éste será el TileMap de nuestra imágen.
Ya teniendo el TileSet (imágen) con su Paleta y el TileMap (RAW), procedemos a insertarla con GBA Graphics Editor. Para ello abrimos GBA Graphics Editor y cargamos nuestra ROM Fire Red o Rojo Fuego y abrimos la ventana Image Control (Ctrl+I) en la pestaña Windows. Por defecto debería cargar una imágen comprimida por lo que no debemos hacer más nada que hacer clic en Import a bitmap, hacemos clic en Browse... y buscamos nuestro TileSet. Ahora en la sección Palette en Palette offset colocamos un offset con suficiente espacio vacío. Para ello podemos usar HxD para confirmar, por ser una ROM limpia usaré 0x800000 luego en la sección Graphics en Graphics offset colocamos el offset de la paleta más 0x20, es decir, 0x800020, ya que una paleta de 16 colores sin comprimir ocupa 0x20 tambien puedes insertar tanto la paleta como la imágen donde desees, lo importante es tener suficiente espacio para los datos nuevos y apuntar los offset para la Tabla. Finalmente deja el resto de las opciones como aparece la imágen para que no repuntee la imágen que usamos como referencia y que aborde la instrucción si no hay suficiente espacio disponible para insertar la imágen (así no dañaremos la ROM).
Presionamos OK y Finished. luego guardamos y abrimos la ROM con HxD vamos al offset donde insertamos la paleta 0x800000 en nuestro caso y buscamos (Ctrl+F) la secuencia FFFFFFFF a partir de ese offset, es decir, seleccionando la opción Adelante y verificamos que tengamos suficiente espacio libre. Yo ya lo he hecho y he encontrado el offset 0x800F50.
Volvemos a GraphicsGale y en la vetana Image Control hacemos clic en Load raw seleccionamos All files en los tipos de archivos y seleccionamos la RAW de nuestra imágen.
Presionamos OK y salvamos (Ctrl+S) y ya tendremos insertada nuestro TileMap. Ahora volvemos a HxD y volvemos a buscar espacio libre buscando la secuencia FFFFFFFF. He conseguido el offset 0x8012E8. Ten en cuenta que todos los archivos que insertemos en la ROM deben estar alineados en pasos de 4 bytes por lo que deben terminar en 0, 4, 8 o C para que no tengan problemas con la rutina THUMB, como el offset encontrado termina en 8 lo podemos usar de forma segura. Volvemos a GraphicsGale e insertamos el otro TileMap (la de borrar) en la dirección encontrada 8012E8. Ya tendremos lo necesario para armar nuestra Tabla y hacer funcionar nuestra rutina.
Buscamos nuevamente espacio disponible en nuestra ROM. Yo he conseguido el offset 0x801388 pero por razones de comodidad usaré el offset 0x801390. Para armar la tabla sólo debemos permutar los offsets donde insertamos la(s) imágen(es), la(s) paleta(s) y las RAW, recuerden que pueden insertar tantas imágenes deseen hasta un total de 255 más la de borrar. Simplemente asegúrense de que en los TileSet el primer Tile siempre sea el transparente, así no deberán insertar una raw para borrar cada imágen independientemente sino que la primera no servirá para borrarlas todas ¿Ya me entendíste cierto?. Ok permutando los offsets tenemos:
TileSet : 0x08800020 => 20 00 80 08
TileMap Imagen: 0x08800F50 => 50 0F 80 08
Paleta : 0x08800000 => 00 00 80 08
TileMap Borrar : 0x088012E8 => E8 12 80 08
Luego nuestra tabla tentrá la estructura [TileSet][TileMap][Paleta], es decir, [20 00 80 08][50 0F 80 08][00 00 80 08]. Por cuestión de orden en la tabla colocaré primero los datos de borrar y luego el de las imágenes (en mi caso la imágen) quedando de esta manera:
[20 00 80 08][E8 12 80 08][00 00 80 08][20 00 80 08][50 0F 80 08][00 00 80 08]
Una vez llenada la tabla procedemos a editar y compilar la rutina que Cargará las imágenes:
- En la línea ldr r0, =0x000040F2 colocamos la variable que deseemos usar
- En la línea ldr r4, =0x0806E455 colocamos el offset correspondiente a la rutina que desencripta las variables, 0x0806E454 = Fire Red o 0x0806E48C = Rojo Fuego se le agrega +1 para indicar al procesador que es una rutina THUMB
- En la línea TABLA: .word 0x08801390 colocamos el offset de la tabla
- En la línea PAL: .word 0x020375F8 + (0x20 * 0xD) reemplazamos 0xD por el slot de la paleta a usar. Recomiendo usar con total seguridad las paletas 0xD, 0xE y 0xF ya que corresponden a los textox y textbox y éstas se actualizan con sus valores originales cuando se llama cualquier diálogo o menú.
Para borrar la imágen tenemos 3 opciones:
1) Si hiciste el paso opcional con todas las imágenes, algo que daría un poco de pereza si se van a insertar muchas imágenes
En este caso se asume que el primer Tile está completamente relleno del color transparente, por lo que al rellenar toda la RAW con 00 00 le estamos indicando que rellene la pantalla con el Tile 0 (el primero) con la Paleta 0 y la imágen mostrada será completamente transparente. Para ello compilamos la siguiente rutina:
2) Si omitiste el paso opcional
En este caso como el primer Tile NO está completamente relleno del color transparente debemos borrar al menos el primer Tile a parte de borrar la RAW para que quede de la misma forma que la opción anterior. Para ello compilamos la siguiente rutina:
3) Si omitiste el paso opcional
Igual que en el caso anterior que el primer Tile NO está completamente relleno del color transparente debemos borrar el primer Tile a parte de borrar la RAW pero si queremos hacer un borrado más seguro, borramos completamente la RAW y el TileSet. Para ello compilamos la siguiente rutina:
Ahora descomprimimos el compilador THUMB y arrastramos la rutina ASM sobre el Archivo por lotes thumb. Si no contiene errores la rutina, creará un archivo binario con el mismo nombre que le hayamos dado a la rutina, hacemos lo mismo con la rutina de Borrar que mejor se adapte a nuestro trabajo y ¡listo!. Ya tenemos nuestras rutinas compliadas en hexadecimal.
Ahora abrimos los archivo .bin generado por el compilador con HxD, copiamos el código hexadecimal y buscamos nuevamente espacio libre en la ROM teniendo en cuenat que deben estar alineados a 4 bytes por lo que el offset debe terminar en 0, 4, 8 o C. Pegamos, guardamos y listo! ya hemos insertado correctamente nuestras rutinas.
Ahora sólo basta abrir la ROM con AdvanceMap y editar algún script para ejecutar la rutina. Recuerda que por ser en modo THUMB el offset de la rutina a llamar debe ser el offset donde se insertó +1, es decir, ejemplo s1 insertó en 0x800000, entonces para llamar la rutina lo hacemos con un callasm 0x800001
Aquí un ejemplo del script:
Y aquí el resultado final en Fire Red y Rojo Fuego respectivamente:
PD: Es mi primera rutina ASM y quizás estoy usando comandos de más o nombrando mal los términos, así que si alguién tiene alguna corrección me puede escribir por el perfil o por privado y lo corregiré a la brevedad.
Saludos!
Max.
Las características de la rutina son:
- BG en Modo 0, por lo que se puede seguir haciendo uso de los demás BG y OBJ
- Uso del BG0 para mostrar la imágen
- Tamaño de la imágen de 1x1 hasta 240x160 (pantalla completa)
- Tabla con estructura [Imágen][RAW][Paleta]
- Uso de variable para controlar el índice de la Tabla
- Imágen y RAW comprimidas en LZ77 para ahorrar espacio
- Paleta de 16 colores
- Borrar la imágen de forma segura con la misma rutina sin necesidad de refrescar la pantalla
- O borrar mediante otra rutina (RECOMENDADO)
Herramientas a usar:
- GraphicsGale DESCARGAR
- Nameless Tilemap Editor (NTME) DESCARGAR
- Sphere DESCARGAR
- Compilador THUMB ASM DESCARGAR
- HxD DESCARGAR
- GBA Graphics Editor DESCARGA
Ya con todo a la mano podemos empezar
Primero busquemos la imágen que deseamos mostrar, máximo de 240x160 e indexada a 16 colores incluido el primer color que es usado como transparencia. Si tienes problema con ello, pásate por este post donde explico como redimensionar e indexar.
Yo usaré esta:
Ahora abrimos GraphicsGale y creamos un nuevo documento (Ctrl+N) de 256x160 a 4bits
Luego con GraphicsGale también abrimos nuestra imágen, la seleccionamos toda (Ctrl+A) y la copiamos (Ctrl+C). Ahora volvemos al lienzo creado anteriormente (la imágen de 256x160) e importamos la paleta de la siguiente manera:
Presionando la flecha hacia abajo que aparece debajo de la paleta de colores y seleccionando "Load Palette..."
Seleccionamos la opción File > Import From Clipboard para copiar la paleta de la imágen en el portapapeles. Seleccionamos All y OK.
Ahora pintamos toda la imágen con el color de transparencia, para ello seleccionamos el primer color y rellenamos con la herramienta Flood Fill . Luego vayan a las propiedades de la capa y selecciones el color de transparencia de la siguiente manera:
Esto se hace para que no se eliminen colores de la imágen al importar la que vamos a usar. Tambien basta simplemente con deseleccionar la opción de color de transparencia o Transparent Color. Ahora pegamos nuestra imágen y guardamos la imágen en formato PNG o BMP preferiblemente, nos debería quedar así:
Ahora abrimos el Editor de Sphere y seleccionamos importar imágen a mapa, seleccionamos la imágen y en la ventana Tile Dimensions colocamos 8 tanto en el alto como el ancho.
Presionamos OK y luego Sí para eliminar los tiles repetidos y finalmente aceptar.
Ahora abrimos el archivo recien creado por Sphere con la opcion File > Open > Map...
Hacemos una captura de pantalla y vamos a Pain, la pegamos y recortamos la imágen correspondiente al Tileset teniendo cuidado de no recortar pixeles del Tileset para ello pueden hacer uso del zoom, tengan en cuenta que las dimensiones deben de ser en múltiplos de 8px, el cual, es la base de cada Tile tanto horizontal como verticalmente. Una vez recortada la imágen correctamente, guardamos como imágen como Mapa de bits de 24bits y ya tendremos nuestro Tileset.
Ahora lo abrimos con GraphicsGale y reducimos la profundidad de color con la opción All Frames > Color Depth... y en Pixel Format seleccionamos 4bpp (16 Colors), presionamos OK y ya estárá indexada a 16 colores. Posiblemente el color de transparencia no quede en el primer lugar, para corregirlo sin usar CMP simplemente selecciona toda la imágen (Ctrl+A), córtala (Ctrl+X), haz clic y mantén presionado en el color de transparencia y arrástralo al primer lugar, luego pega la imágen (Ctrl+V) y ya tendrás el color de transparencia donde debería ir
Ya estando indexada correctamente la imágen nos queda un ultimo paso para tenminar con el Tileset, éste es colocar el Tile de tranparencia en la primera posición (créeme nos ahorrará muchos dolores de cabeza). Para ello activa la función de transparencia en la capa como vimos anteriormente y selecciona el primer color, ahora haz un zoom con el que puedas trabajar tranquilamente, luego haz clic en la opción Custom Grid y selecciona 8x8. Si no la trae por defecto puedes fácilmente ir a Custom Grid > Setup... > Add y añadirla.
Ahora corta el primer Tile y pégalo donde está el Tile relleno con el color de transparencia, si seleccionaste correctamente y tildaste la opción de transparencia el primer Tile debería quedar con el primer color. Quedándo de ésta manera:
Guardamos la imágen y tendremos finalmente el Tileset a insertar. Pasemos a crear el mapa o RAW. Para ello abrimos NTME, abrimos el Tileset con la opción File > Open TileSet y abrimos el TileMap con la opción File > Open TileMap > From Sphere RPM file. Nos quedará así:
Como pueden ver la imágen contine ciertos "errores" y es que el Tileset cargado es diferente al original (recuerden que cambiamos el primer tile por el de transparencia). Para corregirlo solo basta buscar donde debería esta el tile de transparencia y rellenar dichos Tiles, finalmente rellenar los Tiles correspondientes con el Tile de transparencia, para saber donde van los Tiles de Transparencia NTME muestra una línea punteada al final de los 240px horizontales (esa es el área de la imágen que se muestra en pantalla), lo que esté despues de eso va de color transparente como la imágen que deseamos insertar al principio. Si hacemos todo bien nos quedará así:
Ahora vamos a Edit > Extra > Change All Palettes y seleccionamos Palette D [14], guardamos el TileMap y éste será el TileMap de nuestra imágen.
Guardamos la imágen y tendremos finalmente el Tileset a insertar. Pasemos a crear el mapa o RAW. Para ello abrimos NTME, abrimos el Tileset con la opción File > Open TileSet y abrimos el TileMap con la opción File > Open TileMap > From Sphere RPM file. Nos quedará así:
Como pueden ver la imágen contine ciertos "errores" y es que el Tileset cargado es diferente al original (recuerden que cambiamos el primer tile por el de transparencia). Para corregirlo solo basta buscar donde debería esta el tile de transparencia y rellenar dichos Tiles, finalmente rellenar los Tiles correspondientes con el Tile de transparencia, para saber donde van los Tiles de Transparencia NTME muestra una línea punteada al final de los 240px horizontales (esa es el área de la imágen que se muestra en pantalla), lo que esté despues de eso va de color transparente como la imágen que deseamos insertar al principio. Si hacemos todo bien nos quedará así:
Ahora vamos a Edit > Extra > Change All Palettes y seleccionamos Palette D [14], guardamos el TileMap y éste será el TileMap de nuestra imágen.
Guardamos la imágen y tendremos finalmente el Tileset a insertar. Pasemos a crear el mapa o RAW. Para ello abrimos NTME, abrimos el Tileset con la opción File > Open TileSet y abrimos el TileMap con la opción File > Open TileMap > From Sphere RPM file. Nos quedará así:
Ahora vamos a Edit > Extra > Change All Palettes y seleccionamos Palette D [14], guardamos el TileMap y éste será el TileMap de nuestra imágen.
Ya teniendo el TileSet (imágen) con su Paleta y el TileMap (RAW), procedemos a insertarla con GBA Graphics Editor. Para ello abrimos GBA Graphics Editor y cargamos nuestra ROM Fire Red o Rojo Fuego y abrimos la ventana Image Control (Ctrl+I) en la pestaña Windows. Por defecto debería cargar una imágen comprimida por lo que no debemos hacer más nada que hacer clic en Import a bitmap, hacemos clic en Browse... y buscamos nuestro TileSet. Ahora en la sección Palette en Palette offset colocamos un offset con suficiente espacio vacío. Para ello podemos usar HxD para confirmar, por ser una ROM limpia usaré 0x800000 luego en la sección Graphics en Graphics offset colocamos el offset de la paleta más 0x20, es decir, 0x800020, ya que una paleta de 16 colores sin comprimir ocupa 0x20 tambien puedes insertar tanto la paleta como la imágen donde desees, lo importante es tener suficiente espacio para los datos nuevos y apuntar los offset para la Tabla. Finalmente deja el resto de las opciones como aparece la imágen para que no repuntee la imágen que usamos como referencia y que aborde la instrucción si no hay suficiente espacio disponible para insertar la imágen (así no dañaremos la ROM).
Presionamos OK y Finished. luego guardamos y abrimos la ROM con HxD vamos al offset donde insertamos la paleta 0x800000 en nuestro caso y buscamos (Ctrl+F) la secuencia FFFFFFFF a partir de ese offset, es decir, seleccionando la opción Adelante y verificamos que tengamos suficiente espacio libre. Yo ya lo he hecho y he encontrado el offset 0x800F50.
Volvemos a GraphicsGale y en la vetana Image Control hacemos clic en Load raw seleccionamos All files en los tipos de archivos y seleccionamos la RAW de nuestra imágen.
Presionamos OK y salvamos (Ctrl+S) y ya tendremos insertada nuestro TileMap. Ahora volvemos a HxD y volvemos a buscar espacio libre buscando la secuencia FFFFFFFF. He conseguido el offset 0x8012E8. Ten en cuenta que todos los archivos que insertemos en la ROM deben estar alineados en pasos de 4 bytes por lo que deben terminar en 0, 4, 8 o C para que no tengan problemas con la rutina THUMB, como el offset encontrado termina en 8 lo podemos usar de forma segura. Volvemos a GraphicsGale e insertamos el otro TileMap (la de borrar) en la dirección encontrada 8012E8. Ya tendremos lo necesario para armar nuestra Tabla y hacer funcionar nuestra rutina.
Buscamos nuevamente espacio disponible en nuestra ROM. Yo he conseguido el offset 0x801388 pero por razones de comodidad usaré el offset 0x801390. Para armar la tabla sólo debemos permutar los offsets donde insertamos la(s) imágen(es), la(s) paleta(s) y las RAW, recuerden que pueden insertar tantas imágenes deseen hasta un total de 255 más la de borrar. Simplemente asegúrense de que en los TileSet el primer Tile siempre sea el transparente, así no deberán insertar una raw para borrar cada imágen independientemente sino que la primera no servirá para borrarlas todas ¿Ya me entendíste cierto?. Ok permutando los offsets tenemos:
TileSet : 0x08800020 => 20 00 80 08
TileMap Imagen: 0x08800F50 => 50 0F 80 08
Paleta : 0x08800000 => 00 00 80 08
TileMap Borrar : 0x088012E8 => E8 12 80 08
Luego nuestra tabla tentrá la estructura [TileSet][TileMap][Paleta], es decir, [20 00 80 08][50 0F 80 08][00 00 80 08]. Por cuestión de orden en la tabla colocaré primero los datos de borrar y luego el de las imágenes (en mi caso la imágen) quedando de esta manera:
[20 00 80 08][E8 12 80 08][00 00 80 08][20 00 80 08][50 0F 80 08][00 00 80 08]
Una vez llenada la tabla procedemos a editar y compilar la rutina que Cargará las imágenes:
Código:
.thumb
.align 2
push {r4,lr} @;Almacena el registro no dinámico y el registro de enlace
Valores_Iniciales:
ldr r0, =0x000040F2 @;Carga el offset de variable 0x40F2 la variable puede ir de 0x00 hasta 0xFF para un total de 256 imagenes
ldr r4, =(0x0806E454+1) @;Carga el offset de la rutina que la desencripta (el +1 indica que la rutina está en modo THUMB)
bl Ejecuta @;Y la manda a ejecutar, ésta devuelve en R0 el valor de la variable
ldrb r0, [r0] @;Carga el primer byte del Registro R0 (valor de la variable) en R0
ldr r2, TABLA @;Carga el offset de la Tabla
mov r3, #0xC @;Impone R3 como constante y le da el valor de 0xC (longitud de datos por entrada de la Tabla)
mul r3, r0 @;Multiplica el valor de la variable por 0xC para obtener el numero de entrada de la Tabla
add r3, r2, r3 @;Suma el offset de la Tabla al numero de entrada (multiplo de 0xC) para ir al indice de la entrada
Carga_Paleta:
mov r4, #0x8 @;Carga en R4 0x8
add r2, r3, r4 @;Desplaza el puntero 8 bytes para cargar la Paleta
ldr r0, [r2] @;Fuente: Puntero de la Paleta de la entrada de la Tabla
ldr r1, PAL @;Destino: Paleta (0xD)
mov r2, #0x10 @;Longitud/2: Paleta de 16 colores = 0x20 /2 = 0x10(Modo 16bits o THUMB)
swi 0xb @;Copia directamente a la memoria especificada en R1, lo que está en R0 con una longitud de 2*R2
Carga_Tile:
ldr r0, [r3] @;Fuente: Puntero del Tileset en la entrada de la Tabla
ldr r1, Char_Base @;Destino: 1er Tile BG0
swi 0x12 @;Descomprime el Tile que está en LZ77 de la fuente R0 al destino R1
push {r0-r3} @;Almacena los registros que se están usando
swi 0x5 @;VBlankIntrWait = Espera a que haya una interrupción por blanqueo vertical
Carga_RAW:
pop {r0-r3} @;Recupera los registros que se están usando
add r2, r3, #0x4 @;Desplazo el puntero 4 bytes para cargar la RAW
ldr r0, [r2] @;Fuente: Puntero de la RAW en la entrada de la Tabla
ldr r1, Map_Base @;Destino: 1er Mapa BG0
swi 0x12 @;Descomprime el Mapa que está en LZ77 de la fuente R0 al destino R1
pop {r4,pc} @;Carga el puntero a la instrucción siguiente al llamar la sub-rutina
Ejecuta:
bx r4 @;Ejecuta la rutina que se encuentra en el offset almacenado en R4
Map_Base: .word 0x0600F800 @;Offset donde empieza el Map Base del BG0
Char_Base: .word 0x06008000 @;Offset donde empieza el Tile Base del BG0
TABLA: .word 0x08B00000 @;Offset de la Tabla
PAL: .word 0x020375F8+(0x20*0xD) @;Slot de Paleta, en este caso 0xD
- En la línea ldr r4, =0x0806E455 colocamos el offset correspondiente a la rutina que desencripta las variables, 0x0806E454 = Fire Red o 0x0806E48C = Rojo Fuego se le agrega +1 para indicar al procesador que es una rutina THUMB
- En la línea TABLA: .word 0x08801390 colocamos el offset de la tabla
- En la línea PAL: .word 0x020375F8 + (0x20 * 0xD) reemplazamos 0xD por el slot de la paleta a usar. Recomiendo usar con total seguridad las paletas 0xD, 0xE y 0xF ya que corresponden a los textox y textbox y éstas se actualizan con sus valores originales cuando se llama cualquier diálogo o menú.
Para borrar la imágen tenemos 3 opciones:
1) Si hiciste el paso opcional con todas las imágenes, algo que daría un poco de pereza si se van a insertar muchas imágenes
En este caso se asume que el primer Tile está completamente relleno del color transparente, por lo que al rellenar toda la RAW con 00 00 le estamos indicando que rellene la pantalla con el Tile 0 (el primero) con la Paleta 0 y la imágen mostrada será completamente transparente. Para ello compilamos la siguiente rutina:
Código:
/*NOTA: Como la Map-Base va desde 0x0600F800 hasta 0x06010000 tiene una longitud de 0x800
y como cada vez que se ejecuta un STMIA R0!, {R1-R4} escribe en la Map-Base 16 bytes o 0x10 bytes
(4 bytes x 4 registros), entonces se debe hacer esa operación 80 veces (0x80 x 0x10 = 800) */
.thumb
.align 2
push {r4-r5,lr} @;Almacena en la pila el registro de enlace
ldr r0,Map_Base @;Destino: Map_Base
mov r1,#0 @;Fuente: Carga 0x00000000 en R1
mov r2,#0 @;Fuente: Carga 0x00000000 en R2
mov r3,#0 @;Fuente: Carga 0x00000000 en R3
mov r4,#0 @;Fuente: Carga 0x00000000 en R4
mov r5,#0 @;Reinicia R5 opara usarlo como contador
Borrar_Mapa:
stmia r0!, {r1-r4} @;Almacena el contenido de los registros R1-R4 a partir de la dirección especificada en R0,
@;incrementando las direcciones para cada palabra y escribe el valor actualizado de R0.
add r5,r5,#1 @;Aumenta el contador en 1
cmp r5,#0x80 @;Compara si se realizó la operación 0x80 veces
bne Borrar_Mapa @;Si no se culpe la comparación Sigue borrando el TileMap, si se cumple continúa a Fin y termina la rutina.
Fin:
pop {r4-r5,pc} @;Carga el puntero a la instrucción siguiente al llamar la sub-rutina
Map_Base: .word 0x0600F800 @;Offset donde empieza el Map Base del BG0
En este caso como el primer Tile NO está completamente relleno del color transparente debemos borrar al menos el primer Tile a parte de borrar la RAW para que quede de la misma forma que la opción anterior. Para ello compilamos la siguiente rutina:
Código:
/*NOTA: Como la Map-Base va desde 0x0600F800 hasta 0x06010000 tiene una longitud de 0x800
y como cada vez que se ejecuta un STMIA R0!, {R1-R4} escribe en la Map-Base 16 bytes o 0x10 bytes
(4 bytes x 4 registros), entonces se debe hacer esa operación 80 veces (0x80 x 0x10 = 800) */
/*NOTA2: Como cada tile tiene una longitud de 0x20 y como cada vez que se ejecuta un STMIA R0!, {R1-R4}
escribe en la Char-Base 16 bytes o 0x10 bytes (4 bytes x 4 registros), entonces para borrar el primer Tile
se debe hacer esa operación 2 veces (0x2 x 0x10 = 20) */
.thumb
.align 2
push {r4-r6,lr} @;Almacena en la pila el registro de enlace
ldr r0,Map_Base @;Destino: Map_Base
mov r1,#0 @;Fuente: Carga 0x00000000 en R1
mov r2,#0 @;Fuente: Carga 0x00000000 en R2
mov r3,#0 @;Fuente: Carga 0x00000000 en R3
mov r4,#0 @;Fuente: Carga 0x00000000 en R4
mov r5,#0 @;Reinicia R5 para usarlo como contador
mov r6,#0 @;Reinicia R6 para usarlo como contador
Borrar_Mapa:
stmia r0!, {r1-r4} @;Almacena el contenido de los registros R1-R4 a partir de la dirección especificada en R0,
@;incrementando las direcciones para cada palabra y escribe el valor actualizado de R0
add r5,r5,#1 @;Aumenta el contador en 1
cmp r5,#0x80 @;Compara si se realizó la operación 0x80 veces
bne Borrar_Mapa @;Si no se culpe la comparación Sigue borrando el TileMap, si se cumple continúa para borrar el TileSet
mov r5,#0 @;Reinicia R5 para usarlo como contador
ldr r0,Char_Base @;Destino: Char_Base
Borrar_Tile:
stmia r0!, {r1-r4} @;Almacena el contenido de los registros R1-R4 a partir de la dirección especificada en R0,
@;incrementando las direcciones para cada palabra y escribe el valor actualizado de R0
add r5,r5,#1 @;Aumenta el contador en 1
cmp r5,#0x2 @;Compara si se realizó la operación 0x2 veces
beq Fin @;Si se culpe la comparación va a Fin y termina la sub-rutina
b Borrar_Tile @;Si no sigue borrando el TileSet
Fin:
pop {r4-r6,pc} @;Carga el puntero a la instrucción siguiente al llamar la sub-rutina
Map_Base: .word 0x0600F800 @;Offset donde empieza el Map Base del BG0
Char_Base: .word 0x06008000 @;Offset donde empieza el Tile Base del BG0
Igual que en el caso anterior que el primer Tile NO está completamente relleno del color transparente debemos borrar el primer Tile a parte de borrar la RAW pero si queremos hacer un borrado más seguro, borramos completamente la RAW y el TileSet. Para ello compilamos la siguiente rutina:
Código:
/*NOTA: Como la Map-Base va desde 0x0600F800 hasta 0x06010000 tiene una longitud de 0x800
y como cada vez que se ejecuta un STMIA R0!, {R1-R4} escribe en la Map-Base 16 bytes o 0x10 bytes
(4 bytes x 4 registros), entonces se debe hacer esa operación 80 veces (0x80 x 0x10 = 800) */
/*NOTA2: Como la Char-Base de BG0 va desde 0x06008000 hasta 0x060E0000 tiene una longitud de 0x6000
y como cada vez que se ejecuta un STMIA R0!, {R1-R4} escribe en la Char-Base 16 bytes o 0x10 bytes
(4 bytes x 4 registros), entonces se debe hacer esa operación 600 veces (0x600 x 0x10 = 6000) */
.thumb
.align 2
push {r4-r6,lr} @;Almacena en la pila el registro de enlace
ldr r0,Map_Base @;Destino: Map_Base
mov r1,#0 @;Fuente: Carga 0x00000000 en R1
mov r2,#0 @;Fuente: Carga 0x00000000 en R2
mov r3,#0 @;Fuente: Carga 0x00000000 en R3
mov r4,#0 @;Fuente: Carga 0x00000000 en R4
mov r5,#0 @;Reinicia R5 para usarlo como contador
mov r6,#0 @;Reinicia R6 para usarlo como contador
Borrar_Mapa:
stmia r0!, {r1-r4} @;Almacena el contenido de los registros R1-R4 a partir de la dirección especificada en R0,
@;incrementando las direcciones para cada palabra y escribe el valor actualizado de R0
add r5,r5,#1 @;Aumenta el contador en 1
cmp r5,#0x80 @;Compara si se realizó la operación 0x80 veces
bne Borrar_Mapa @;Si no se culpe la comparación Sigue borrando el TileMap, si se cumple continúa para borrar el TileSet
mov r5,#0 @;Reinicia R5 para usarlo como contador
ldr r0,Char_Base @;Destino: Char_Base
Borrar_Tile:
stmia r0!, {r1-r4} @;Almacena el contenido de los registros R1-R4 a partir de la dirección especificada en R0,
@;incrementando las direcciones para cada palabra y escribe el valor actualizado de R0
add r5,r5,#1 @;Aumenta el contador en 1
cmp r5,#0x60 @;Compara si se realizó la operación 0x80 veces
beq Ciclo @;Si se culpe la comparación va a Ciclo y verifica si ya se borró todo el TileSet
b Borrar_Tile @;Si no sigue borrando el TileSet
Ciclo:
add r6,r6,#1 @;Aumenta el contador en 1
cmp r6,#0x10 @;Compara si se realizó la operación 0x10 veces para un total de 0x600 veces
beq Fin @;Si se culpe la comparación va a Fin y termina la sub-rutina
mov r5,#0 @;Sino reinicia en contador R5
b Borrar_Tile @;Y continúa borrando el TileSet
Fin:
nop @;NOP (No Opera) función que no hace nada excepto gastar un comando
@;se usa para alinear el código a comandos pares y pueda compilarse la sub-rutina
pop {r4-r6,pc} @;Carga el puntero a la instrucción siguiente al llamar la sub-rutina
Map_Base: .word 0x0600F800 @;Offset donde empieza el Map Base del BG0
Char_Base: .word 0x06008000 @;Offset donde empieza el Tile Base del BG0
Ahora abrimos los archivo .bin generado por el compilador con HxD, copiamos el código hexadecimal y buscamos nuevamente espacio libre en la ROM teniendo en cuenat que deben estar alineados a 4 bytes por lo que el offset debe terminar en 0, 4, 8 o C. Pegamos, guardamos y listo! ya hemos insertado correctamente nuestras rutinas.
Ahora sólo basta abrir la ROM con AdvanceMap y editar algún script para ejecutar la rutina. Recuerda que por ser en modo THUMB el offset de la rutina a llamar debe ser el offset donde se insertó +1, es decir, ejemplo s1 insertó en 0x800000, entonces para llamar la rutina lo hacemos con un callasm 0x800001
Aquí un ejemplo del script:
Código:
'---------------
#dynamic 0x900000
#org @Inicio
setvar 0x40F2 0x0 'selecciona la primera entrada de la tabla.
callasm 0x801391 'llama la rutina que Carga la imágen 0x801390+1
pause 0x50 'hace un pausa para visualizar la imágen
callasm 0x801421 'llama la rutina que Borra la imágen 0x801420+1
end 'fin del script
PD: Es mi primera rutina ASM y quizás estoy usando comandos de más o nombrando mal los términos, así que si alguién tiene alguna corrección me puede escribir por el perfil o por privado y lo corregiré a la brevedad.
Saludos!
Max.
Última edición por un moderador: