// SPDX-License-Identifier: MIT // // Copyright (c) 2009-2014 Cesar Rincon "NightFox" // // NightFox LIB - Funciones de Fondos con tiles // http://www.nightfoxandco.com/ // Version 20140413 // Includes devKitPro #include // Includes C #include #include #include // Includes propios #include "nf_basic.h" #include "nf_2d.h" #include "nf_tiledbg.h" // Define los bancos de Mapas y Tiles u8 NF_BANKS_TILES[2]; // (1 banks = 16kb) Cada banco de tiles puede alvergar 8 bancos de Mapas u8 NF_BANKS_MAPS[2]; // (1 bank = 2kb) Usar multiplos de 8. Cada set de 8 bancos consume 1 banco de tiles // Define los Buffers para almacenar los fondos char* NF_BUFFER_BGTILES[NF_SLOTS_TBG]; char* NF_BUFFER_BGMAP[NF_SLOTS_TBG]; char* NF_BUFFER_BGPAL[NF_SLOTS_TBG]; // Define la estructura de propiedades de los fondos NF_TYPE_TBG_INFO NF_TILEDBG[NF_SLOTS_TBG]; // Info de los fondos cargados en RAM NF_TYPE_TBGLAYERS_INFO NF_TILEDBG_LAYERS[2][4]; // Info de los fondos en pantalla // Define la estructura para las paletas extendidas NF_TYPE_EXBGPAL_INFO NF_EXBGPAL[NF_SLOTS_EXBGPAL]; // Datos de las paletas extendidas // Define el array de bloques libres u8 NF_TILEBLOCKS[2][NF_MAX_BANKS_TILES]; u8 NF_MAPBLOCKS[2][NF_MAX_BANKS_MAPS]; // Funcion NF_InitTiledBgBuffers(); void NF_InitTiledBgBuffers(void) { u8 n = 0; // Buffers de fondos tileados for (n = 0; n < NF_SLOTS_TBG; n ++) { // Inicializa todos los slots NF_BUFFER_BGTILES[n] = NULL; // Buffer para los tiles NF_BUFFER_BGMAP[n] = NULL; // Buffer para el map NF_BUFFER_BGPAL[n] = NULL; // Buffer para la paleta snprintf(NF_TILEDBG[n].name, sizeof(NF_TILEDBG[n].name), "xxxNONAMExxx"); NF_TILEDBG[n].tilesize = 0; // Tamaño del Tileset NF_TILEDBG[n].mapsize = 0; // Tamaño del Mapa NF_TILEDBG[n].palsize = 0; // Tamaño de la Paleta NF_TILEDBG[n].width = 0; // Ancho del Mapa NF_TILEDBG[n].height = 0; // Alto del Mapa NF_TILEDBG[n].available = true; // Disponibilidad } // Buffers de paletas extendidas for (n = 0; n < NF_SLOTS_EXBGPAL; n ++) { NF_EXBGPAL[n].buffer = NULL; NF_EXBGPAL[n].palsize = 0; NF_EXBGPAL[n].inuse = false; } } // Funcion NF_ResetTiledBgBuffers(); void NF_ResetTiledBgBuffers(void) { u8 n = 0; for (n = 0; n < NF_SLOTS_TBG; n ++) { // Inicializa todos los slots free(NF_BUFFER_BGTILES[n]); // Vacia el Buffer para los tiles free(NF_BUFFER_BGMAP[n]); // Vacia Buffer para el map free(NF_BUFFER_BGPAL[n]); // Vacia Buffer para la paleta } for (n = 0; n < NF_SLOTS_EXBGPAL; n ++) { NF_EXBGPAL[n].buffer = NULL; } NF_InitTiledBgBuffers(); // Reinicia el resto de variables } // Funcion NF_InitTiledBgSys(); void NF_InitTiledBgSys(u8 screen) { // Variables u8 n = 0; // Define el numero de bancos de Mapas y Tiles NF_BANKS_TILES[screen] = 8; // (1 banks = 16kb) Cada banco de tiles puede alvergar 8 bancos de Mapas NF_BANKS_MAPS[screen] = 16; // (1 bank = 2kb) Usar multiplos de 8. Cada set de 8 bancos consume 1 banco de tiles // Por defecto Tiles = 8, Mapas = 16 // Esto nos deja 6 bancos de 16kb para tiles // y 16 bancos de 2kb para mapas // Inicializa el array de bloques libres de Tiles for (n = 0; n < NF_BANKS_TILES[screen]; n ++) { NF_TILEBLOCKS[screen][n] = 0; } // Inicializa el array de bloques libres de Mapas for (n = 0; n < NF_BANKS_MAPS[screen]; n ++) { NF_MAPBLOCKS[screen][n] = 0; } // Inicializa el array de informacion de fondos en pantalla for (n = 0; n < 4; n ++) { NF_TILEDBG_LAYERS[screen][n].tilebase = 0; // Base del Tileset NF_TILEDBG_LAYERS[screen][n].tileblocks = 0; // Bloques usados por el Tileset NF_TILEDBG_LAYERS[screen][n].mapbase = 0; // Base del Map NF_TILEDBG_LAYERS[screen][n].mapblocks = 0; // Bloques usados por el Map NF_TILEDBG_LAYERS[screen][n].bgwidth = 0; // Ancho del fondo NF_TILEDBG_LAYERS[screen][n].bgheight = 0; // Altura del fondo NF_TILEDBG_LAYERS[screen][n].mapwidth = 0; // Ancho del mapa NF_TILEDBG_LAYERS[screen][n].mapheight = 0; // Altura del mapa NF_TILEDBG_LAYERS[screen][n].bgtype = 0; // Tipo de mapa NF_TILEDBG_LAYERS[screen][n].bgslot = 0; // Buffer de graficos usado NF_TILEDBG_LAYERS[screen][n].blockx = 0; // Bloque de mapa actual (horizontal) NF_TILEDBG_LAYERS[screen][n].blocky = 0; // Bloque de mapa actual (vertical) NF_TILEDBG_LAYERS[screen][n].created = false; // Esta creado ? } // Ahora reserva los bancos necesarios de VRAM para mapas // Cada bloque de 16kb (1 banco de tiles) permite 8 bancos de mapas (de 2kb cada uno) u8 r_banks; r_banks = ((NF_BANKS_MAPS[screen] - 1) >> 3) + 1; // Calcula los bancos de Tiles a reservar para Maps for (n = 0; n < r_banks; n ++) { NF_TILEBLOCKS[screen][n] = 128; // Marca que bancos de VRAM son para MAPS } if (screen == 0) { // Si es la pantalla 0 (Superior, Main engine) REG_DISPCNT |= (DISPLAY_BG_EXT_PALETTE); // Activa las paletas extendidas vramSetBankA(VRAM_A_MAIN_BG); // Banco A de la VRAM para fondos (128kb) memset((void*)0x06000000, 0, 131072); // Borra el contenido del banco A vramSetBankE(VRAM_E_LCD); // Reserva el banco E de la VRAM para Paletas Extendidas (0-3) (32kb de 64kb) memset((void*)0x06880000, 0, 32768); // Borra el contenido del banco E for (n = 0; n < 4; n ++) { // Oculta todas las 4 capas NF_HideBg(0, n); } } else { // Si es la pantalla 1 (Inferior, Sub engine) REG_DISPCNT_SUB |= (DISPLAY_BG_EXT_PALETTE); // Activa las paletas extendidas vramSetBankC(VRAM_C_SUB_BG); // Banco C de la VRAM para fondos (128kb) memset((void*)0x06200000, 0, 131072); // Borra el contenido del banco C vramSetBankH(VRAM_H_LCD); // Reserva el banco H de la VRAM para Paletas Extendidas (0-3) (32kb) memset((void*)0x06898000, 0, 32768); // Borra el contenido del banco H for (n = 0; n < 4; n ++) { // Oculta todas las 4 capas NF_HideBg(1, n); } } } // Funcion NF_LoadTiledBg(); void NF_LoadTiledBg(const char* file, const char* name, u16 width, u16 height) { // Variable temporal del tamaño de la paleta u32 pal_size = 0; // Busca un slot libre u8 n = 0; u8 slot = 255; for (n = 0; n < NF_SLOTS_TBG; n ++) { // Busca en todos los slots if (NF_TILEDBG[n].available) { // Si esta libre NF_TILEDBG[n].available = false; // Marcalo como en uso slot = n; // Guarda el slot a usar n = NF_SLOTS_TBG; // Deja de buscar } } // Si no hay ningun slot libre, error if (slot == 255) { NF_Error(103, "Tiled Bg", NF_SLOTS_TBG); } // Verifica que el fondo sea multiplo de 256px (32 tiles) if (((width % 256) != 0) || ((height % 256) != 0)) { NF_Error(115, file, 0); } // Vacia los buffers que se usaran free(NF_BUFFER_BGMAP[slot]); // Buffer para los mapas NF_BUFFER_BGMAP[slot] = NULL; free(NF_BUFFER_BGTILES[slot]); // Buffer para los tiles NF_BUFFER_BGTILES[slot] = NULL; free(NF_BUFFER_BGPAL[slot]); // Buffer para los paletas NF_BUFFER_BGPAL[slot] = NULL; // Declara los punteros a los ficheros FILE* file_id; // Variable para almacenar el path al archivo char filename[256]; // Carga el archivo .IMG snprintf(filename, sizeof(filename), "%s/%s.img", NF_ROOTFOLDER, file); file_id = fopen(filename, "rb"); if (file_id) { // Si el archivo existe... // Obten el tamaño del archivo fseek(file_id, 0, SEEK_END); NF_TILEDBG[slot].tilesize = ftell(file_id); rewind(file_id); // Reserva el espacio en RAM NF_BUFFER_BGTILES[slot] = (char*) calloc (NF_TILEDBG[slot].tilesize, sizeof(char)); if (NF_BUFFER_BGTILES[slot] == NULL) { // Si no hay suficiente RAM libre NF_Error(102, NULL, NF_TILEDBG[slot].tilesize); } // Lee el archivo y ponlo en la RAM fread(NF_BUFFER_BGTILES[slot], 1, NF_TILEDBG[slot].tilesize, file_id); } else { // Si el archivo no existe... NF_Error(101, filename, 0); } fclose(file_id); // Cierra el archivo // Carga el archivo .MAP snprintf(filename, sizeof(filename), "%s/%s.map", NF_ROOTFOLDER, file); file_id = fopen(filename, "rb"); if (file_id) { // Si el archivo existe... // Obten el tamaño del archivo fseek(file_id, 0, SEEK_END); NF_TILEDBG[slot].mapsize = ((((ftell(file_id) - 1) >> 11) + 1) << 11); // Ajusta el tamaño a bloques de 2kb rewind(file_id); // Reserva el espacio en RAM NF_BUFFER_BGMAP[slot] = (char*) calloc (NF_TILEDBG[slot].mapsize, sizeof(char)); if (NF_BUFFER_BGMAP[slot] == NULL) { // Si no hay suficiente RAM libre NF_Error(102, NULL, NF_TILEDBG[slot].mapsize); } // Lee el archivo y ponlo en la RAM fread(NF_BUFFER_BGMAP[slot], 1, NF_TILEDBG[slot].mapsize, file_id); } else { // Si el archivo no existe... NF_Error(101, filename, 0); } fclose(file_id); // Cierra el archivo // Carga el archivo .PAL snprintf(filename, sizeof(filename), "%s/%s.pal", NF_ROOTFOLDER, file); file_id = fopen(filename, "rb"); if (file_id) { // Si el archivo existe... // Obten el tamaño del archivo fseek(file_id, 0, SEEK_END); pal_size = ftell(file_id); NF_TILEDBG[slot].palsize = pal_size; rewind(file_id); // Si el tamaño es inferior a 512 bytes, ajustalo if (NF_TILEDBG[slot].palsize < 512) NF_TILEDBG[slot].palsize = 512; // Reserva el espacio en RAM NF_BUFFER_BGPAL[slot] = (char*) calloc (NF_TILEDBG[slot].palsize, sizeof(char)); if (NF_BUFFER_BGPAL[slot] == NULL) { // Si no hay suficiente RAM libre NF_Error(102, NULL, NF_TILEDBG[slot].palsize); } // Lee el archivo y ponlo en la RAM fread(NF_BUFFER_BGPAL[slot], 1, pal_size, file_id); } else { // Si el archivo no existe... NF_Error(101, filename, 0); } fclose(file_id); // Cierra el archivo // Guarda el nombre del Fondo snprintf(NF_TILEDBG[slot].name, sizeof(NF_TILEDBG[slot].name), "%s", name); // Y las medidas NF_TILEDBG[slot].width = width; NF_TILEDBG[slot].height = height; } // Funcion NF_LoadTilesForBg(); void NF_LoadTilesForBg(const char* file, const char* name, u16 width, u16 height, u16 tile_start, u16 tile_end) { // Variable temporal del tamaño de los datos u32 tile_size = 0; u32 pal_size = 0; // Busca un slot libre u8 n = 0; u8 slot = 255; for (n = 0; n < NF_SLOTS_TBG; n ++) { // Busca en todos los slots if (NF_TILEDBG[n].available) { // Si esta libre NF_TILEDBG[n].available = false; // Marcalo como en uso slot = n; // Guarda el slot a usar n = NF_SLOTS_TBG; // Deja de buscar } } // Si no hay ningun slot libre, error if (slot == 255) { NF_Error(103, "Tiled Bg", NF_SLOTS_TBG); } // Verifica que el fondo sea multiplo de 256px (32 tiles) if (((width % 256) != 0) || ((height % 256) != 0)) { NF_Error(115, file, 0); } // Vacia los buffers que se usaran free(NF_BUFFER_BGMAP[slot]); // Buffer para los mapas NF_BUFFER_BGMAP[slot] = NULL; free(NF_BUFFER_BGTILES[slot]); // Buffer para los tiles NF_BUFFER_BGTILES[slot] = NULL; free(NF_BUFFER_BGPAL[slot]); // Buffer para los paletas NF_BUFFER_BGPAL[slot] = NULL; // Declara los punteros a los ficheros FILE* file_id; // Variable para almacenar el path al archivo char filename[256]; // Carga el archivo .IMG snprintf(filename, sizeof(filename), "%s/%s.img", NF_ROOTFOLDER, file); file_id = fopen(filename, "rb"); if (file_id) { // Si el archivo existe... // Obten el tamaño del archivo fseek(file_id, 0, SEEK_END); tile_size = ftell(file_id); rewind(file_id); // Calcula el tamaño del tilesize a cargar NF_TILEDBG[slot].tilesize = (((tile_end - tile_start) + 1) << 6); // nº de tiles x 64 bytes // Si el tamaño del Tilesed solicitado excede del tamaño de archivo, error if ((u32)((tile_end + 1) << 6) > tile_size) { NF_Error(106, "Tilenumber", (tile_size >> 6)); } // Reserva el espacio en RAM NF_BUFFER_BGTILES[slot] = (char*) calloc (NF_TILEDBG[slot].tilesize, sizeof(char)); if (NF_BUFFER_BGTILES[slot] == NULL) { // Si no hay suficiente RAM libre NF_Error(102, NULL, NF_TILEDBG[slot].tilesize); } // Posicionate en la posicion donde esta el primer tile a cargar fseek(file_id, (tile_start << 6), SEEK_SET); // ahora lee el archivo y ponlo en la RAM fread(NF_BUFFER_BGTILES[slot], 1, NF_TILEDBG[slot].tilesize, file_id); } else { // Si el archivo no existe... NF_Error(101, filename, 0); } fclose(file_id); // Cierra el archivo // Crea un archivo .MAP vacio en RAM // ((ancho / 8) * (alto / 8)) * 2 NF_TILEDBG[slot].mapsize = (((width >> 3) * (height >> 3)) << 1); // Reserva el espacio en RAM NF_BUFFER_BGMAP[slot] = (char*) calloc (NF_TILEDBG[slot].mapsize, sizeof(char)); if (NF_BUFFER_BGMAP[slot] == NULL) { // Si no hay suficiente RAM libre NF_Error(102, NULL, NF_TILEDBG[slot].mapsize); } // Y ponlo a 0 memset(NF_BUFFER_BGMAP[slot], 0, NF_TILEDBG[slot].mapsize); // Carga el archivo .PAL snprintf(filename, sizeof(filename), "%s/%s.pal", NF_ROOTFOLDER, file); file_id = fopen(filename, "rb"); if (file_id) { // Si el archivo existe... // Obten el tamaño del archivo fseek(file_id, 0, SEEK_END); pal_size = ftell(file_id); NF_TILEDBG[slot].palsize = pal_size; rewind(file_id); // Si el tamaño es inferior a 512 bytes, ajustalo if (NF_TILEDBG[slot].palsize < 512) NF_TILEDBG[slot].palsize = 512; // Reserva el espacio en RAM NF_BUFFER_BGPAL[slot] = (char*) calloc (NF_TILEDBG[slot].palsize, sizeof(char)); if (NF_BUFFER_BGPAL[slot] == NULL) { // Si no hay suficiente RAM libre NF_Error(102, NULL, NF_TILEDBG[slot].palsize); } // Lee el archivo y ponlo en la RAM fread(NF_BUFFER_BGPAL[slot], 1, pal_size, file_id); } else { // Si el archivo no existe... NF_Error(101, filename, 0); } fclose(file_id); // Cierra el archivo // Guarda el nombre del Fondo snprintf(NF_TILEDBG[slot].name, sizeof(NF_TILEDBG[slot].name), "%s", name); // Y las medidas NF_TILEDBG[slot].width = width; NF_TILEDBG[slot].height = height; } // Funcion NF_UnloadTiledBg(); void NF_UnloadTiledBg(const char* name) { // Busca el fondo solicitado u16 n = 0; // Bucle u8 slot = 255; // Slot seleccionado char bg[32]; // Nombre // Busca el fondo solicitado snprintf(bg, sizeof(bg), "%s", name); // Obten el nombre del fondo a buscar for (n = 0; n < NF_SLOTS_TBG; n ++) { // Busca en todos los slots if (strcmp(bg, NF_TILEDBG[n].name) == 0) { // Si lo encuentras slot = n; // Guarda el slot a usar n = NF_SLOTS_TBG; // Deja de buscar } } // Si no se encuentra, error if (slot == 255) { NF_Error(104, name, 0); } // Vacia los buffers que se usaran free(NF_BUFFER_BGMAP[slot]); // Buffer para los mapas NF_BUFFER_BGMAP[slot] = NULL; free(NF_BUFFER_BGTILES[slot]); // Buffer para los tiles NF_BUFFER_BGTILES[slot] = NULL; free(NF_BUFFER_BGPAL[slot]); // Buffer para los paletas NF_BUFFER_BGPAL[slot] = NULL; // Resetea las variables para ese fondo snprintf(NF_TILEDBG[slot].name, sizeof(NF_TILEDBG[slot].name), "xxxNONAMExxx"); NF_TILEDBG[slot].tilesize = 0; // Tamaño del Tileset NF_TILEDBG[slot].mapsize = 0; // Tamaño del Mapa NF_TILEDBG[slot].palsize = 0; // Tamaño de la Paleta NF_TILEDBG[slot].width = 0; // Ancho del Mapa NF_TILEDBG[slot].height = 0; // Alto del Mapa NF_TILEDBG[slot].available = true; // Disponibilidad } // Funcion NF_CreateTiledBg(); void NF_CreateTiledBg(u8 screen, u8 layer, const char* name) { // Variables u8 n = 0; // Bucle u8 slot = 255; // Slot seleccionado char bg[32]; // Nombre // Busca el fondo solicitado snprintf(bg, sizeof(bg), "%s", name); // Obten el nombre del fondo a buscar for (n = 0; n < NF_SLOTS_TBG; n ++) { // Busca en todos los slots if (strcmp(bg, NF_TILEDBG[n].name) == 0) { // Si lo encuentras slot = n; // Guarda el slot a usar n = NF_SLOTS_TBG; // Deja de buscar } } // Si no se encuentra, error if (slot == 255) { NF_Error(104, name, 0); } // Si ya hay un fondo existente en esta pantalla y capa, borralo antes if (NF_TILEDBG_LAYERS[screen][layer].created) { NF_DeleteTiledBg(screen, layer); } // Variables de control de Tiles u8 counter = 0; u8 start = 255; u8 tilesblocks = 0; u8 basetiles = 0; // Transfiere el tamaño del fondo NF_TILEDBG_LAYERS[screen][layer].bgwidth = NF_TILEDBG[slot].width; // Ancho del fondo NF_TILEDBG_LAYERS[screen][layer].bgheight = NF_TILEDBG[slot].height; // Altura del fondo NF_TILEDBG_LAYERS[screen][layer].mapwidth = NF_TILEDBG[slot].width; // Ancho del mapa NF_TILEDBG_LAYERS[screen][layer].mapheight = NF_TILEDBG[slot].height; // Altura del mapa NF_TILEDBG_LAYERS[screen][layer].bgtype = 0; // Tipo de fondo NF_TILEDBG_LAYERS[screen][layer].bgslot = slot; // Buffer de graficos usado // Calcula el tipo y tamaño del mapa si es Infinito ( >512 ) // ( >512 x n ) if ((NF_TILEDBG[slot].width >= 512) && (NF_TILEDBG[slot].height <= 256)) { NF_TILEDBG_LAYERS[screen][layer].mapwidth = 512; NF_TILEDBG_LAYERS[screen][layer].mapheight = NF_TILEDBG[slot].height; NF_TILEDBG_LAYERS[screen][layer].bgtype = 1; } // ( n x >512 ) if ((NF_TILEDBG[slot].width <= 256) && (NF_TILEDBG[slot].height >= 512)) { NF_TILEDBG_LAYERS[screen][layer].mapwidth = NF_TILEDBG[slot].width; NF_TILEDBG_LAYERS[screen][layer].mapheight = 512; NF_TILEDBG_LAYERS[screen][layer].bgtype = 2; } // ( >512 x >512 ) if ((NF_TILEDBG[slot].width >= 512) && (NF_TILEDBG[slot].height >= 512)) { NF_TILEDBG_LAYERS[screen][layer].mapwidth = 512; NF_TILEDBG_LAYERS[screen][layer].mapheight = 512; NF_TILEDBG_LAYERS[screen][layer].bgtype = 3; } // Busca un los bloques libres para almacenar los Tiles en VRAM tilesblocks = ((NF_TILEDBG[slot].tilesize - 1) >> 14) + 1; // Bloques necesarios para el Tileset for (n = 0; n < NF_BANKS_TILES[screen]; n ++) { if (NF_TILEBLOCKS[screen][n] == 0) { // Si esta libre if (counter == 0) { // Y el contador esta a 0 start = n; // Marca la posicion de inicio } counter ++; if (counter == tilesblocks) { // Si ya tienes suficientes bloques libres n = NF_BANKS_TILES[screen]; // Termina de buscar } } else { // Si el bloque no esta libre start = 255; // Borra el marcador counter = 0; // Y resetea el contador } } // Si no se han encontrado bloques libres if ((start == 255) || (counter < tilesblocks)) { NF_Error(107, name, tilesblocks); } else { basetiles = start; // Guarda donde empiezan los bloques libres } // Marca los bancos de Tiles usados por este fondo for (n = basetiles; n < (basetiles + tilesblocks); n ++) { NF_TILEBLOCKS[screen][n] = 255; // Marca los bloques usados por tiles } // Variables de control de Maps u8 mapblocks = 0; u8 basemap = 0; counter = 0; start = 255; u16 mapsize = 0; // Busca un los bloques libres para almacenar los Mapas en VRAM if (NF_TILEDBG_LAYERS[screen][layer].bgtype == 0) { // Si el mapa es normal =<512 mapblocks = ((NF_TILEDBG[slot].mapsize - 1) >> 11) + 1; } else { // Si el mapa es infinito >512 mapsize = (((NF_TILEDBG_LAYERS[screen][layer].mapwidth >> 3) * (NF_TILEDBG_LAYERS[screen][layer].mapheight >> 3)) << 1); mapblocks = ((mapsize - 1) >> 11) + 1; } for (n = 0; n < NF_BANKS_MAPS[screen]; n ++) { if (NF_MAPBLOCKS[screen][n] == 0) { // Si esta libre if (counter == 0) { // Y el contador esta a 0 start = n; // Marca la posicion de inicio } counter ++; if (counter == mapblocks) { // Si ya tienes suficientes bloques libres n = NF_BANKS_MAPS[screen]; // Termina de buscar } } else { // Si el bloque no esta libre start = 255; // Borra el marcador counter = 0; // Y resetea el contador } } // Si no se han encontrado bloques libres if ((start == 255) || (counter < mapblocks)) { NF_Error(108, name, mapblocks); } else { basemap = start; // Guarda donde empiezan los bloques libres } // Marca los bancos de Mapa usados por este fondo for (n = basemap; n < (basemap + mapblocks); n ++) { NF_MAPBLOCKS[screen][n] = 255; // Marca los bloques usados por mapas } // Obten el tamaño del fondo u32 bg_size = 0; // 256x256 if ((NF_TILEDBG_LAYERS[screen][layer].mapwidth == 256) && (NF_TILEDBG_LAYERS[screen][layer].mapheight == 256)) { bg_size = BG_32x32; } // 512x256 if ((NF_TILEDBG_LAYERS[screen][layer].mapwidth == 512) && (NF_TILEDBG_LAYERS[screen][layer].mapheight == 256)) { bg_size = BG_64x32; } // 256x512 if ((NF_TILEDBG_LAYERS[screen][layer].mapwidth == 256) && (NF_TILEDBG_LAYERS[screen][layer].mapheight == 512)) { bg_size = BG_32x64; } // 512x512 if ((NF_TILEDBG_LAYERS[screen][layer].mapwidth == 512) && (NF_TILEDBG_LAYERS[screen][layer].mapheight == 512)) { bg_size = BG_64x64; } // Crea el fondo segun la pantalla, capa y demas caracteristicas dadas // REG_BG0CNT <- Carracteristicas del fondo // REG_BG0HOFS <- Posicion X // REG_BG0VOFS <- Posicion Y if (screen == 0) { switch (layer) { case 0: REG_BG0CNT = BgType_Text8bpp | bg_size | BG_PRIORITY_0 | BG_PALETTE_SLOT0 | BG_COLOR_256 | BG_TILE_BASE(basetiles) | BG_MAP_BASE(basemap); break; case 1: REG_BG1CNT = BgType_Text8bpp | bg_size | BG_PRIORITY_1 | BG_PALETTE_SLOT1 | BG_COLOR_256 | BG_TILE_BASE(basetiles) | BG_MAP_BASE(basemap); break; case 2: REG_BG2CNT = BgType_Text8bpp | bg_size | BG_PRIORITY_2 | BG_COLOR_256 | BG_TILE_BASE(basetiles) | BG_MAP_BASE(basemap); break; case 3: REG_BG3CNT = BgType_Text8bpp | bg_size | BG_PRIORITY_3 | BG_COLOR_256 | BG_TILE_BASE(basetiles) | BG_MAP_BASE(basemap); break; } } else { switch (layer) { case 0: REG_BG0CNT_SUB = BgType_Text8bpp | bg_size | BG_PRIORITY_0 | BG_PALETTE_SLOT0 | BG_COLOR_256 | BG_TILE_BASE(basetiles) | BG_MAP_BASE(basemap); break; case 1: REG_BG1CNT_SUB = BgType_Text8bpp | bg_size | BG_PRIORITY_1 | BG_PALETTE_SLOT1 | BG_COLOR_256 | BG_TILE_BASE(basetiles) | BG_MAP_BASE(basemap); break; case 2: REG_BG2CNT_SUB = BgType_Text8bpp | bg_size | BG_PRIORITY_2 | BG_COLOR_256 | BG_TILE_BASE(basetiles) | BG_MAP_BASE(basemap); break; case 3: REG_BG3CNT_SUB = BgType_Text8bpp | bg_size | BG_PRIORITY_3 | BG_COLOR_256 | BG_TILE_BASE(basetiles) | BG_MAP_BASE(basemap); break; } } u32 address; // Variable de direccion de VRAM; // Transfiere el Tileset a VRAM if (screen == 0) { // (VRAM_A) address = (0x6000000) + (basetiles << 14); } else { // (VRAM_C) address = (0x6200000) + (basetiles << 14); } NF_DmaMemCopy((void*)address, NF_BUFFER_BGTILES[slot], NF_TILEDBG[slot].tilesize); // Transfiere el Mapa a VRAM if (screen == 0) { // (VRAM_A) address = (0x6000000) + (basemap << 11); } else { // (VRAM_C) address = (0x6200000) + (basemap << 11); } if (NF_TILEDBG_LAYERS[screen][layer].bgtype == 0) { // Si el mapa es normal NF_DmaMemCopy((void*)address, NF_BUFFER_BGMAP[slot], NF_TILEDBG[slot].mapsize); } else { // Segun el tipo de mapa infinito switch (NF_TILEDBG_LAYERS[screen][layer].bgtype) { case 1: // >512x256 // Bloque A y B (32x32) + (32x32) (2kb x 2 = 4kb) NF_DmaMemCopy((void*)address, NF_BUFFER_BGMAP[slot], 4096); break; case 2: // 256x>512 // Bloque A (32x64) (2kb x 2 = 4kb) NF_DmaMemCopy((void*)address, NF_BUFFER_BGMAP[slot], 4096); break; case 3: // >512x>512 // Bloque A y B (32x32) + (32x32) (2kb x 2 = 4kb) NF_DmaMemCopy((void*)address, NF_BUFFER_BGMAP[slot], 4096); // Bloque (+4096) C y D (32x32) + (32x32) (2kb x 2 = 4kb) u16 nextrow = 0; // Desplazamiento para cargar la fila inferior nextrow = ((((NF_TILEDBG_LAYERS[screen][layer].bgwidth - 1) >> 8) + 1) << 11); NF_DmaMemCopy((void*)(address + 4096), (NF_BUFFER_BGMAP[slot] + nextrow), 4096); break; } } // Tranfiere la Paleta a VRAM if (screen == 0) { vramSetBankE(VRAM_E_LCD); address = (0x06880000) + (layer << 13); NF_DmaMemCopy((void*)address, NF_BUFFER_BGPAL[slot], NF_TILEDBG[slot].palsize); vramSetBankE(VRAM_E_BG_EXT_PALETTE); } else { // Paletas de la pantalla 1 (VRAM_H) vramSetBankH(VRAM_H_LCD); address = (0x06898000) + (layer << 13); NF_DmaMemCopy((void*)address, NF_BUFFER_BGPAL[slot], NF_TILEDBG[slot].palsize); vramSetBankH(VRAM_H_SUB_BG_EXT_PALETTE); } // Registra los datos del fondos en pantalla NF_TILEDBG_LAYERS[screen][layer].tilebase = basetiles; // Base del Tileset NF_TILEDBG_LAYERS[screen][layer].tileblocks = tilesblocks; // Bloques usados por el Tileset NF_TILEDBG_LAYERS[screen][layer].mapbase = basemap; // Base del Map NF_TILEDBG_LAYERS[screen][layer].mapblocks = mapblocks; // Bloques usados por el Map NF_TILEDBG_LAYERS[screen][layer].created = true; // Esta creado ? // Posiciona el fondo en las coordenadas 0,0 NF_ScrollBg(screen, layer, 0, 0); // Haz visible el fondo creado NF_ShowBg(screen, layer); } // Funcion NF_DeleteTiledBg(); void NF_DeleteTiledBg(u8 screen, u8 layer) { // Verifica que el fondo esta creado if (!NF_TILEDBG_LAYERS[screen][layer].created) { char text[32]; snprintf(text, sizeof(text), "%d", screen); NF_Error(105, text, layer); // Si no existe, error } // Esconde el fondo creado NF_HideBg(screen, layer); // Variables de uso general u32 address; // Direccion de VRAM; u8 n; // Uso general u16 basetiles = 0; // Base del Tileset u16 basemap = 0; // Base del Map u16 tilesize = 0; // Tamaño del Tileset u16 mapsize = 0; // Tamaño del Map // Borra el Tileset de la VRAM basetiles = NF_TILEDBG_LAYERS[screen][layer].tilebase; tilesize = (NF_TILEDBG_LAYERS[screen][layer].tileblocks << 14); if (screen == 0) { // (VRAM_A) address = (0x6000000) + (basetiles << 14); } else { // (VRAM_C) address = (0x6200000) + (basetiles << 14); } memset((void*)address, 0, tilesize); // Pon a 0 todos los bytes de la area de VRAM // Borra el Mapa de la VRAM basemap = NF_TILEDBG_LAYERS[screen][layer].mapbase; mapsize = (NF_TILEDBG_LAYERS[screen][layer].mapblocks << 11); if (screen == 0) { // (VRAM_A) address = (0x6000000) + (basemap << 11); } else { // (VRAM_C) address = (0x6200000) + (basemap << 11); } memset((void*)address, 0, mapsize); // Pon a 0 todos los bytes de la area de VRAM // Borra la Paleta a VRAM if (screen == 0) { vramSetBankE(VRAM_E_LCD); address = (0x06880000) + (layer << 13); memset((void*)address, 0, 8192); vramSetBankE(VRAM_E_BG_EXT_PALETTE); } else { // Paletas de la pantalla 1 (VRAM_H) vramSetBankH(VRAM_H_LCD); address = (0x06898000) + (layer << 13); memset((void*)address, 0, 8192); vramSetBankH(VRAM_H_SUB_BG_EXT_PALETTE); } // Marca como libres los bancos de Tiles usados por este fondo tilesize = (basetiles + NF_TILEDBG_LAYERS[screen][layer].tileblocks); for (n = basetiles; n < tilesize; n ++) { NF_TILEBLOCKS[screen][n] = 0; } // Marca como libres los bancos de Mapa usados por este fondo mapsize = (basemap + NF_TILEDBG_LAYERS[screen][layer].mapblocks); for (n = basemap; n < mapsize; n ++) { NF_MAPBLOCKS[screen][n] = 0; } // Borra los datos del fondos en pantalla NF_TILEDBG_LAYERS[screen][layer].tilebase = 0; // Base del Tileset NF_TILEDBG_LAYERS[screen][layer].tileblocks = 0; // Bloques usados por el Tileset NF_TILEDBG_LAYERS[screen][layer].mapbase = 0; // Base del Map NF_TILEDBG_LAYERS[screen][layer].mapblocks = 0; // Bloques usados por el Map NF_TILEDBG_LAYERS[screen][layer].bgwidth = 0; // Ancho del fondo NF_TILEDBG_LAYERS[screen][layer].bgheight = 0; // Altura del fondo NF_TILEDBG_LAYERS[screen][layer].mapwidth = 0; // Ancho del mapa NF_TILEDBG_LAYERS[screen][layer].mapheight = 0; // Altura del mapa NF_TILEDBG_LAYERS[screen][layer].bgtype = 0; // Tipo de mapa NF_TILEDBG_LAYERS[screen][layer].bgslot = 0; // Buffer de graficos usado NF_TILEDBG_LAYERS[screen][layer].blockx = 0; // Bloque de mapa actual (horizontal) NF_TILEDBG_LAYERS[screen][layer].blocky = 0; // Bloque de mapa actual (vertical) NF_TILEDBG_LAYERS[screen][layer].created = false; // Esta creado ? } // Funcion NF_GetTileMapAddress(); u32 NF_GetTileMapAddress(u8 screen, u8 layer, u16 tile_x, u16 tile_y) { // Verifica que el fondo esta creado if (!NF_TILEDBG_LAYERS[screen][layer].created) { char text[32]; snprintf(text, sizeof(text), "%d", screen); NF_Error(105, text, layer); // Si no existe, error } // Obtiene las medidas en tiles del mapa u16 size_x = (NF_TILEDBG_LAYERS[screen][layer].bgwidth >> 3); // Tiles de ancho u16 size_y = (NF_TILEDBG_LAYERS[screen][layer].bgheight >> 3); // Tiles de alto u16 block_x = (tile_x >> 5); // nº de pantalla (X) u16 block_y = (tile_y >> 5); // nº de pantalla (Y) u32 row_size = ((size_x >> 5) << 11); // Tamaño en bytes de una fila de pantallas // Protegete de los fuera de rango if (tile_x > size_x) NF_Error(106, "Tile X", size_x); if (tile_y > size_y) NF_Error(106, "Tile Y", size_y); // Calcula la posicion de memoria que deberas leer // El mapa esta ordenado en bloques de 32x32 tiles, en filas. u32 scr_y = (block_y * row_size); // Desplazamiento en memoria, bloques de pantallas (32x32) sobre Y u32 scr_x = (block_x << 11); // Desplazamiento en memoria, bloques de pantallas (32x32) sobre X u32 tls_y = ((tile_y - (block_y << 5)) << 5); // Desplazamiento en memoria, tiles sobre X u32 tls_x = (tile_x - (block_x << 5)); // Desplazamiento en memoria, tiles sobre Y u32 address = scr_y + scr_x + ((tls_y + tls_x) << 1); // Devuelve el la direccion en el buffer del Tile return address; } // Funcion NF_GetTileOfMap(); u16 NF_GetTileOfMap(u8 screen, u8 layer, u16 tile_x, u16 tile_y) { // Obten la direccion en el buffer del Tile u32 address = NF_GetTileMapAddress(screen, layer, tile_x, tile_y); // Obten los bytes u8 lobyte = *(NF_BUFFER_BGMAP[NF_TILEDBG_LAYERS[screen][layer].bgslot] + address); u8 hibyte = *(NF_BUFFER_BGMAP[NF_TILEDBG_LAYERS[screen][layer].bgslot] + (address + 1)); // Devuelve el valor del tile return ((hibyte << 8) | lobyte); } // Funcion NF_SetTileOfMap(); void NF_SetTileOfMap(u8 screen, u8 layer, u16 tile_x, u16 tile_y, u16 tile) { // Obten la direccion en el buffer del Tile u32 address = NF_GetTileMapAddress(screen, layer, tile_x, tile_y); // Calcula los valores para el HI-Byte y el LO-Byte u8 hibyte = ((tile >> 8) & 0xff); u8 lobyte = (tile & 0xff); // Graba los bytes *(NF_BUFFER_BGMAP[NF_TILEDBG_LAYERS[screen][layer].bgslot] + address) = lobyte; *(NF_BUFFER_BGMAP[NF_TILEDBG_LAYERS[screen][layer].bgslot] + (address + 1)) = hibyte; } // Funcion NF_UpdateVramMap(); void NF_UpdateVramMap(u8 screen, u8 layer) { // Verifica que el fondo esta creado if (!NF_TILEDBG_LAYERS[screen][layer].created) { char text[32]; snprintf(text, sizeof(text), "%d", screen); NF_Error(105, text, layer); // Si no existe, error } // Variables u32 address = 0; // Direccion de destino u32 mov_x = 0; // Desplazamiento X u32 mov_y = 0; // Desplazamiento Y u32 rowsize = 0; // Tamaño de la fila de pantallas // Calcula la direccion base del mapa if (screen == 0) { // (VRAM_A) address = (0x6000000) + (NF_TILEDBG_LAYERS[screen][layer].mapbase << 11); } else { // (VRAM_C) address = (0x6200000) + (NF_TILEDBG_LAYERS[screen][layer].mapbase << 11); } // Segun el tipo de mapa switch (NF_TILEDBG_LAYERS[screen][layer].bgtype) { case 0: // 256x256 - Bloque A (32x32) (2kb) // Copias el Bloque A (32x32) (2kb) NF_DmaMemCopy((void*)address, NF_BUFFER_BGMAP[NF_TILEDBG_LAYERS[screen][layer].bgslot], 2048); break; case 1: // 512x256 - Bloque A y B (32x32) + (32x32) (2kb x 2 = 4kb) // Calcula el desplazamiento de datos mov_x = (NF_TILEDBG_LAYERS[screen][layer].blockx << 11); // Copias los Bloques A y B (32x32) + (32x32) (2kb x 2 = 4kb) NF_DmaMemCopy((void*)address, (NF_BUFFER_BGMAP[NF_TILEDBG_LAYERS[screen][layer].bgslot] + mov_x), 4096); break; case 2: // 256x512 - Bloque A (32x64) (2kb x 2 = 4kb) // Calcula el desplazamiento de datos mov_y = (NF_TILEDBG_LAYERS[screen][layer].blocky << 11); // Copias los Bloques A y B (32x32) + (32x32) (2kb x 2 = 4kb) NF_DmaMemCopy((void*)address, (NF_BUFFER_BGMAP[NF_TILEDBG_LAYERS[screen][layer].bgslot] + mov_y), 4096); break; case 3: // >512x>512 // Calcula el Rowsize rowsize = (((((NF_TILEDBG_LAYERS[screen][layer].bgwidth - 1) >> 8)) + 1) << 11); // Y el desplazamiento de datos mov_x = (NF_TILEDBG_LAYERS[screen][layer].blocky * rowsize) + (NF_TILEDBG_LAYERS[screen][layer].blockx << 11); mov_y = mov_x + rowsize; // Bloque A y B (32x32) + (32x32) (2kb x 2 = 4kb) NF_DmaMemCopy((void*)address, (NF_BUFFER_BGMAP[NF_TILEDBG_LAYERS[screen][layer].bgslot] + mov_x), 4096); // Bloque (+4096) C y D (32x32) + (32x32) (2kb x 2 = 4kb) NF_DmaMemCopy((void*)(address + 4096), (NF_BUFFER_BGMAP[NF_TILEDBG_LAYERS[screen][layer].bgslot] + mov_y), 4096); break; } } // Funcion NF_BgSetPalColor(); void NF_BgSetPalColor(u8 screen, u8 layer, u8 number, u8 r, u8 g, u8 b) { // Verifica que el fondo esta creado if (!NF_TILEDBG_LAYERS[screen][layer].created) { char text[32]; snprintf(text, sizeof(text), "%d", screen); NF_Error(105, text, layer); // Si no existe, error } // Calcula el valor RGB u16 rgb = ((r)|((g) << 5)|((b) << 10)); // Direccion en VRAM u32 address = 0; // Modifica la paleta if (screen == 0) { vramSetBankE(VRAM_E_LCD); address = (0x06880000) + (layer << 13) + (number << 1); *((u16*)address) = rgb; vramSetBankE(VRAM_E_BG_EXT_PALETTE); } else { // Paletas de la pantalla 1 (VRAM_H) vramSetBankH(VRAM_H_LCD); address = (0x06898000) + (layer << 13) + (number << 1); *((u16*)address) = rgb; vramSetBankH(VRAM_H_SUB_BG_EXT_PALETTE); } } // Funcion NF_BgEditPalColor(); void NF_BgEditPalColor(u8 screen, u8 layer, u8 number, u8 r, u8 g, u8 b) { // Verifica que el fondo esta creado if (!NF_TILEDBG_LAYERS[screen][layer].created) { char text[32]; snprintf(text, sizeof(text), "%d", screen); NF_Error(105, text, layer); // Si no existe, error } // Calcula el valor RGB u16 rgb = ((r)|((g) << 5)|((b) << 10)); // Calcula los valores para el HI-Byte y el LO-Byte u8 hibyte = ((rgb >> 8) & 0xff); u8 lobyte = (rgb & 0xff); // Graba los bytes *(NF_BUFFER_BGPAL[NF_TILEDBG_LAYERS[screen][layer].bgslot] + (number << 1)) = lobyte; *(NF_BUFFER_BGPAL[NF_TILEDBG_LAYERS[screen][layer].bgslot] + ((number << 1) + 1)) = hibyte; } // Funcion NF_BgUpdatePalette(); void NF_BgUpdatePalette(u8 screen, u8 layer) { // Verifica que el fondo esta creado if (!NF_TILEDBG_LAYERS[screen][layer].created) { char text[32]; snprintf(text, sizeof(text), "%d", screen); NF_Error(105, text, layer); // Si no existe, error } // Direccion en VRAM u32 address = 0; // Obten el slot donde esta la paleta en RAM u8 slot = NF_TILEDBG_LAYERS[screen][layer].bgslot; // Tranfiere la Paleta a VRAM if (screen == 0) { vramSetBankE(VRAM_E_LCD); address = (0x06880000) + (layer << 13); NF_DmaMemCopy((void*)address, NF_BUFFER_BGPAL[slot], NF_TILEDBG[slot].palsize); vramSetBankE(VRAM_E_BG_EXT_PALETTE); } else { // Paletas de la pantalla 1 (VRAM_H) vramSetBankH(VRAM_H_LCD); address = (0x06898000) + (layer << 13); NF_DmaMemCopy((void*)address, NF_BUFFER_BGPAL[slot], NF_TILEDBG[slot].palsize); vramSetBankH(VRAM_H_SUB_BG_EXT_PALETTE); } } // Funcion NF_BgGetPalColor(); void NF_BgGetPalColor(u8 screen, u8 layer, u8 number, u8* r, u8* g, u8* b) { // Verifica que el fondo esta creado if (!NF_TILEDBG_LAYERS[screen][layer].created) { char text[32]; snprintf(text, sizeof(text), "%d", screen); NF_Error(105, text, layer); // Si no existe, error } // Obten los bytes u8 lobyte = *(NF_BUFFER_BGPAL[NF_TILEDBG_LAYERS[screen][layer].bgslot] + (number << 1)); u8 hibyte = *(NF_BUFFER_BGPAL[NF_TILEDBG_LAYERS[screen][layer].bgslot] + ((number << 1) + 1)); // Calcula el RGB (compuesto) u16 rgb = ((hibyte << 8) | lobyte); // Calcula los RGB *r = (rgb & 0x1F); *g = ((rgb >> 5) & 0x1F); *b = ((rgb >> 10) & 0x1F); } // Funcion NF_GetTilePal(); u8 NF_GetTilePal(u8 screen, u8 layer, u16 tile_x, u16 tile_y) { // Obten la direccion en el buffer del Tile u32 address = NF_GetTileMapAddress(screen, layer, tile_x, tile_y); // Obten los bytes u8 hibyte = *(NF_BUFFER_BGMAP[NF_TILEDBG_LAYERS[screen][layer].bgslot] + (address + 1)); // Devuelve el nº de la paleta (4 ultimos bits del HI-Byte) return ((hibyte >> 4) & 0x0F); } // Funcion NF_SetTilePal(); void NF_SetTilePal(u8 screen, u8 layer, u16 tile_x, u16 tile_y, u8 pal) { // Obten la direccion en el buffer del Tile u32 address = NF_GetTileMapAddress(screen, layer, tile_x, tile_y); // Obten el valor actual del HI-Byte u8 hibyte = *(NF_BUFFER_BGMAP[NF_TILEDBG_LAYERS[screen][layer].bgslot] + (address + 1)); // Y determina el valor del resto de datos del byte, excluyendo la paleta u8 data = (hibyte & 0x0F); // Graba los bytes *(NF_BUFFER_BGMAP[NF_TILEDBG_LAYERS[screen][layer].bgslot] + (address + 1)) = ((pal << 4) | data); } // Funcion NF_LoadExBgPal(); void NF_LoadExBgPal(const char* file, u8 slot) { // Verifica el rango de Id's de Gfx if (slot > (NF_SLOTS_EXBGPAL - 1)) { NF_Error(106, "ExBgPal", (NF_SLOTS_EXBGPAL - 1)); } // Variable temporal del tamaño de la paleta u32 pal_size = 0; // Vacia el buffer free(NF_EXBGPAL[slot].buffer); NF_EXBGPAL[slot].buffer = NULL; // Declara los punteros a los ficheros FILE* file_id; // Variable para almacenar el path al archivo char filename[256]; // Carga el archivo .PAL snprintf(filename, sizeof(filename), "%s/%s.pal", NF_ROOTFOLDER, file); file_id = fopen(filename, "rb"); if (file_id) { // Si el archivo existe... // Obten el tamaño del archivo fseek(file_id, 0, SEEK_END); pal_size = ftell(file_id); NF_EXBGPAL[slot].palsize = pal_size; rewind(file_id); // Si el tamaño es inferior a 512 bytes, ajustalo if (NF_EXBGPAL[slot].palsize < 512) NF_EXBGPAL[slot].palsize = 512; // Reserva el espacio en RAM NF_EXBGPAL[slot].buffer = (char*) calloc (NF_EXBGPAL[slot].palsize, sizeof(char)); if (NF_EXBGPAL[slot].buffer == NULL) { // Si no hay suficiente RAM libre NF_Error(102, NULL, NF_EXBGPAL[slot].palsize); } // Lee el archivo y ponlo en la RAM fread(NF_EXBGPAL[slot].buffer, 1, pal_size, file_id); } else { // Si el archivo no existe... NF_Error(101, filename, 0); } fclose(file_id); // Cierra el archivo // Guarda el estado del slot NF_EXBGPAL[slot].inuse = true; } // Funcion NF_UnloadExBgPal(); void NF_UnloadExBgPal(u8 slot) { // Verifica el rango de Id's de Gfx if (slot > (NF_SLOTS_EXBGPAL - 1)) { NF_Error(106, "ExBgPal", (NF_SLOTS_EXBGPAL - 1)); } // Verifica si la Id esta cargada if (!NF_EXBGPAL[slot].inuse) { NF_Error(110, "ExBgPal", slot); } // Vacia el buffer free(NF_EXBGPAL[slot].buffer); NF_EXBGPAL[slot].buffer = NULL; // Tamaño de la paleta a 0 NF_EXBGPAL[slot].palsize = 0; // Guarda el estado del slot NF_EXBGPAL[slot].inuse = false; } // Funcion NF_VramExBgPal(); void NF_VramExBgPal(u8 screen, u8 layer, u8 id, u8 slot) { // Verifica el rango de Id's de Gfx if (slot > (NF_SLOTS_EXBGPAL - 1)) { NF_Error(106, "ExBgPal", (NF_SLOTS_EXBGPAL - 1)); } // Verifica si la Id esta cargada if (!NF_EXBGPAL[slot].inuse) { NF_Error(110, "ExBgPal", slot); } // Tranfiere la Paleta a VRAM u32 address = 0; if (screen == 0) { vramSetBankE(VRAM_E_LCD); address = (0x06880000) + (layer << 13) + (slot << 9); NF_DmaMemCopy((void*)address, NF_EXBGPAL[id].buffer, NF_EXBGPAL[id].palsize); vramSetBankE(VRAM_E_BG_EXT_PALETTE); } else { // Paletas de la pantalla 1 (VRAM_H) vramSetBankH(VRAM_H_LCD); address = (0x06898000) + (layer << 13) + (slot << 9); NF_DmaMemCopy((void*)address, NF_EXBGPAL[id].buffer, NF_EXBGPAL[id].palsize); vramSetBankH(VRAM_H_SUB_BG_EXT_PALETTE); } } // Funcion NF_SetExBgPal(); void NF_SetExBgPal(u8 screen, u8 layer, u8 pal) { // Verifica el rango de Id's de Gfx if (pal > 15) { NF_Error(106, "ExBgPal", (NF_SLOTS_EXBGPAL - 1)); } // Verifica que el fondo esta creado if (!NF_TILEDBG_LAYERS[screen][layer].created) { char text[32]; snprintf(text, sizeof(text), "%d", screen); NF_Error(105, text, layer); // Si no existe, error } // Tamaño del buffer u32 mapsize = NF_TILEDBG[NF_TILEDBG_LAYERS[screen][layer].bgslot].mapsize; // Variables comunes u32 pos = 0; u16 hibyte = 0; u8 data = 0; for (pos = 0; pos < mapsize; pos += 2) { // Obten el valor actual del HI-Byte hibyte = *(NF_BUFFER_BGMAP[NF_TILEDBG_LAYERS[screen][layer].bgslot] + (pos + 1)); // Y determina el valor del resto de datos del byte, excluyendo la paleta data = (hibyte & 0x0F); // Graba los bytes *(NF_BUFFER_BGMAP[NF_TILEDBG_LAYERS[screen][layer].bgslot] + (pos + 1)) = ((pal << 4) | data); } // Actualiza el mapa en la VRAM NF_UpdateVramMap(screen, layer); } // Funcion NF_SetTileHflip(); void NF_SetTileHflip(u8 screen, u8 layer, u16 tile_x, u16 tile_y) { // Obten la direccion en el buffer del Tile u32 address = NF_GetTileMapAddress(screen, layer, tile_x, tile_y); // Obten el valor actual del HI-Byte u8 hibyte = *(NF_BUFFER_BGMAP[NF_TILEDBG_LAYERS[screen][layer].bgslot] + (address + 1)); // Invierte el BIT correspondiente a FLIP horizontal del tile (BIT 3) hibyte ^= 0x04; // Graba el valor actualizado *(NF_BUFFER_BGMAP[NF_TILEDBG_LAYERS[screen][layer].bgslot] + (address + 1)) = hibyte; } // Funcion NF_SetTileVflip(); void NF_SetTileVflip(u8 screen, u8 layer, u16 tile_x, u16 tile_y) { // Obten la direccion en el buffer del Tile u32 address = NF_GetTileMapAddress(screen, layer, tile_x, tile_y); // Obten el valor actual del HI-Byte u8 hibyte = *(NF_BUFFER_BGMAP[NF_TILEDBG_LAYERS[screen][layer].bgslot] + (address + 1)); // Invierte el BIT correspondiente a FLIP vertical del tile (BIT 4) hibyte ^= 0x08; // Graba el valor actualizado *(NF_BUFFER_BGMAP[NF_TILEDBG_LAYERS[screen][layer].bgslot] + (address + 1)) = hibyte; } // Funcion NF_RotateTileGfx(); void NF_RotateTileGfx(u8 slot, u16 tile, u8 rotation) { // Buffers temporales char* character_a; character_a = NULL; character_a = (char*) calloc (64, sizeof(char)); if (character_a == NULL) { // Si no hay suficiente RAM libre NF_Error(102, NULL, 64); } char* character_b; character_b = NULL; character_b = (char*) calloc (64, sizeof(char)); if (character_b == NULL) { // Si no hay suficiente RAM libre NF_Error(102, NULL, 64); } // Variables locales s16 xa = 0; s16 xb = 0; s16 pos_a = 0; s16 ya = 0; s16 yb = 0; s16 pos_b = 0; // Copia el tile al buffer temporal A memcpy(character_a, (NF_BUFFER_BGTILES[slot] + (tile << 6)), 64); switch (rotation) { case 1: // 90º a la derecha xb = 7; yb = 0; for (ya = 0; ya < 8; ya ++) { for (xa = 0; xa < 8; xa ++) { pos_a = ((ya << 3) + xa); pos_b = ((yb << 3) + xb); character_b[pos_b] = character_a[pos_a]; yb ++; if (yb > 7) { yb = 0; xb --; } } } break; case 2: // 90º a la izquierda xb = 0; yb = 7; for (ya = 0; ya < 8; ya ++) { for (xa = 0; xa < 8; xa ++) { pos_a = ((ya << 3) + xa); pos_b = ((yb << 3) + xb); character_b[pos_b] = character_a[pos_a]; yb --; if (yb < 0) { yb = 7; xb ++; } } } break; case 3: // 180 º xb = 7; yb = 7; for (ya = 0; ya < 8; ya ++) { for (xa = 0; xa < 8; xa ++) { pos_a = ((ya << 3) + xa); pos_b = ((yb << 3) + xb); character_b[pos_b] = character_a[pos_a]; xb --; if (xb < 0) { xb = 0; yb --; } } } break; default: break; } // Copia el tile desde buffer temporal B memcpy((NF_BUFFER_BGTILES[slot] + (tile << 6)), character_b, 64); // Libera los buffers temporales free (character_a); free (character_b); }