examples: docs: Add example of NFlib and NE integration

https://github.com/knightfox75/nds_nflib
This commit is contained in:
Antonio Niño Díaz 2022-11-09 01:41:57 +00:00
parent 72dca60154
commit bb04ea86a5
58 changed files with 10259 additions and 1 deletions

View File

@ -0,0 +1,222 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/ds_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# INCLUDES is a list of directories containing extra header files
# DATA is a list of directories containing binary files embedded using bin2o
# GRAPHICS is a list of directories containing image files to be converted with grit
# AUDIO is a list of directories containing audio to be converted by maxmod
# ICON is the image used to create the game icon, leave blank to use default rule
# NITRO is a directory that will be accessible via NitroFS
#---------------------------------------------------------------------------------
TARGET := $(shell basename $(CURDIR))
BUILD := build
SOURCES := source
INCLUDES := include
DATA := data
GRAPHICS :=
AUDIO :=
ICON :=
# specify a directory which contains the nitro filesystem
# this is relative to the Makefile
NITRO := nitrofiles
# These set the information text in the nds file
GAME_TITLE := Nitro Engine example
GAME_SUBTITLE1 := built with devkitARM
GAME_SUBTITLE2 := http://devitpro.org
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -marm -mthumb-interwork -march=armv5te -mtune=arm946e-s
CFLAGS := -g -Wall -O3\
$(ARCH) $(INCLUDE) -DARM9
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project (order is important)
#---------------------------------------------------------------------------------
LIBS := -lNE -lnflib
# automatigically add libraries for NitroFS
ifneq ($(strip $(NITRO)),)
LIBS := $(LIBS) -lfilesystem -lfat
endif
# automagically add maxmod library
ifneq ($(strip $(AUDIO)),)
LIBS := $(LIBS) -lmm9
endif
LIBS := $(LIBS) -lnds9
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(LIBNDS) $(PORTLIBS) $(DEVKITPRO)/nitro-engine $(CURDIR)/nflib
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export VPATH := $(CURDIR)/$(subst /,,$(dir $(ICON)))\
$(foreach dir,$(SOURCES),$(CURDIR)/$(dir))\
$(foreach dir,$(DATA),$(CURDIR)/$(dir))\
$(foreach dir,$(GRAPHICS),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
PNGFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.png)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
# prepare NitroFS directory
ifneq ($(strip $(NITRO)),)
export NITRO_FILES := $(CURDIR)/$(NITRO)
endif
# get audio list for maxmod
ifneq ($(strip $(AUDIO)),)
export MODFILES := $(foreach dir,$(notdir $(wildcard $(AUDIO)/*.*)),$(CURDIR)/$(AUDIO)/$(dir))
# place the soundbank file in NitroFS if using it
ifneq ($(strip $(NITRO)),)
export SOUNDBANK := $(NITRO_FILES)/soundbank.bin
# otherwise, needs to be loaded from memory
else
export SOUNDBANK := soundbank.bin
BINFILES += $(SOUNDBANK)
endif
endif
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
export OFILES_SOURCES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export OFILES := $(PNGFILES:.png=.o) $(OFILES_BIN) $(OFILES_SOURCES)
export HFILES := $(PNGFILES:.png=.h) $(addsuffix .h,$(subst .,_,$(BINFILES)))
export INCLUDE := $(foreach dir,$(INCLUDES),-iquote $(CURDIR)/$(dir))\
$(foreach dir,$(LIBDIRS),-I$(dir)/include)\
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
ifeq ($(strip $(ICON)),)
icons := $(wildcard *.bmp)
ifneq (,$(findstring $(TARGET).bmp,$(icons)))
export GAME_ICON := $(CURDIR)/$(TARGET).bmp
else
ifneq (,$(findstring icon.bmp,$(icons)))
export GAME_ICON := $(CURDIR)/icon.bmp
endif
endif
else
ifeq ($(suffix $(ICON)), .grf)
export GAME_ICON := $(CURDIR)/$(ICON)
else
export GAME_ICON := $(CURDIR)/$(BUILD)/$(notdir $(basename $(ICON))).grf
endif
endif
.PHONY: $(BUILD) clean
#---------------------------------------------------------------------------------
$(BUILD):
@mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(TARGET).elf $(TARGET).nds $(SOUNDBANK)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT).nds: $(OUTPUT).elf $(GAME_ICON)
$(OUTPUT).elf: $(OFILES)
# source files depend on generated headers
$(OFILES_SOURCES) : $(HFILES)
# need to build soundbank first
$(OFILES): $(SOUNDBANK)
#---------------------------------------------------------------------------------
# rule to build solution from music files
#---------------------------------------------------------------------------------
$(SOUNDBANK) : $(MODFILES)
#---------------------------------------------------------------------------------
mmutil $^ -d -o$@ -hsoundbank.h
#---------------------------------------------------------------------------------
%.bin.o %_bin.h : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
#---------------------------------------------------------------------------------
# This rule creates assembly source files using grit
# grit takes an image file and a .grit describing how the file is to be processed
# add additional rules like this for each image extension
# you use in the graphics folders
#---------------------------------------------------------------------------------
%.s %.h: %.png %.grit
#---------------------------------------------------------------------------------
grit $< -fts -o$*
#---------------------------------------------------------------------------------
# Convert non-GRF game icon to GRF if needed
#---------------------------------------------------------------------------------
$(GAME_ICON): $(notdir $(ICON))
#---------------------------------------------------------------------------------
@echo convert $(notdir $<)
@grit $< -g -gt -gB4 -gT FF00FF -m! -p -pe 16 -fh! -ftr
-include $(DEPSDIR)/*.d
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

View File

@ -0,0 +1,124 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/ds_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
#---------------------------------------------------------------------------------
TARGET := $(shell basename $(CURDIR))
BUILD := build
SOURCES := source
DATA := data
INCLUDES := include
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -mthumb -mthumb-interwork
CFLAGS := -g -Wall -O2\
-march=armv5te -mtune=arm946e-s \
-fomit-frame-pointer -ffast-math \
$(ARCH)
CFLAGS += $(INCLUDE) -DARM9
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := -g $(ARCH) -march=armv5te -mtune=arm946e-s
LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(LIBNDS)
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/lib/lib$(TARGET).a
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: $(BUILD)
lib:
@[ -d $@ ] || mkdir -p $@
$(BUILD): lib
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) lib
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT) : $(OFILES)
#---------------------------------------------------------------------------------
%.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

View File

@ -0,0 +1,139 @@
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __NF_2D_H__
#define __NF_2D_H__
// NightFox LIB - Include de funciones 2D comunes
// Requiere DevkitARM
// Codigo por Cesar Rincon "NightFox"
// http://www.nightfoxandco.com/
// Version 20140413
// Includes devKitPro
#include <nds.h>
// Funcion NF_Set2D();
void NF_Set2D(u8 screen, u8 mode);
// Inicia el modo 2D seleccionado en la pantalla deseada
// Funcion NF_ShowBg();
void NF_ShowBg(u8 screen, u8 layer);
// Haz visible el fondo de la capa y pantalla dados
// Funcion NF_HideBg();
void NF_HideBg(u8 screen, u8 layer);
// Oculta el fondo de la capa y pantalla dados
// Funcion NF_ScrollBg();
void NF_ScrollBg(u8 screen, u8 layer, s16 x, s16 y);
// Mueve el fondo a las coordenadas especificadas.
// Debes de indicar la pantalla, capa, y coordenadas X e Y
// Si el mapa es mayor de 512 en alguna medida, debes de mantener el fondo en RAM
// Funcion NF_MoveSprite();
void NF_MoveSprite(u8 screen, u8 id, s16 x, s16 y);
// Mueve el Sprite a las coordenadas especificadas
// Debes de indicar la pantalla, id de sprite y coordenadas
// Funcion NF_SpriteLayer();
void NF_SpriteLayer(u8 screen, u8 id, u8 layer);
// Define la capa sobre la que el sprite sera dibujado
// Debes de indicar la pantalla, id del sprite y capa
// Funcion NF_ShowSprite();
void NF_ShowSprite(u8 screen, u8 id, bool show);
// Muestra o oculta el sprite
// Debes especificar la pantalla, id del sprite y el estado (true, false)
// Funcion NF_HflipSprite();
void NF_HflipSprite(u8 screen, u8 id, bool hflip);
// Voltea el Sprite horizontalmente
// Debes especificar la pantalla, id del sprite y el estado (true, false)
// Funcion NF_GetSpriteHflip();
extern bool NF_GetSpriteHflip(u8 screen, u8 id);
// Devuelve el estado del volteado horizontal de un sprite
// Debes especificar la pantalla y la id del sprite
// Funcion NF_VflipSprite();
void NF_VflipSprite(u8 screen, u8 id, bool vflip);
// Voltea el Sprite verticalmente
// Debes especificar la pantalla, id del sprite y el estado (true, false)
// Funcion NF_GetSpriteVflip();
extern bool NF_GetSpriteVflip(u8 screen, u8 id);
// Devuelve el estado del volteado vertical de un sprite
// Debes especificar la pantalla y la id del sprite
// Funcion NF_SpriteFrame();
void NF_SpriteFrame(u8 screen, u8 id, u16 frame);
// Cambia el frame de un Sprite
// Debes especificar la pantalla, el Id del sprite y el frame
// Funcion NF_EnableSpriteRotScale();
void NF_EnableSpriteRotScale(u8 screen, u8 sprite, u8 id, bool doublesize);
// Habilita el sprite como rotable y escalable
// Debes especificar la pantalla, nº de sprite, id de rotacion y si
// tiene que activarse el doublesize (tamaño x2)
// Funcion NF_DisableSpriteRotScale();
void NF_DisableSpriteRotScale(u8 screen, u8 sprite);
// Deshabilita un sprite como rotable y escalable
// Debes especificar la pantalla y el nº de sprite
// Funcion NF_SpriteRotScale();
void NF_SpriteRotScale(u8 screen, u8 id, s16 angle, u16 sx, u16 sy);
// Define el angulo de rotacion y escala de los Sprites asociados a la Id.
// El rango del angulo es desde -512 a 512, siendo 0 el valor central
// El rango de escalado va de 0 a 512, siendo 256 el valor normal (100%)
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,50 @@
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __NF_3D_H__
#define __NF_3D_H__
// NightFox LIB - Include de funciones 3D
// Requiere DevkitARM
// Codigo por Cesar Rincon "NightFox"
// http://www.nightfoxandco.com/
// Version 20140413
// Includes devKitPro
#include <nds.h>
// Funcion NF_Set3D();
void NF_Set3D(u8 screen, u8 mode);
// Inicia el modo 3D seleccionado en la pantalla deseada
// Funcion NF_InitOpenGL();
void NF_InitOpenGL(void);
// Inicializa el OpenGL para la libreria
// Funcion NF_GetTextureSize();
extern u16 NF_GetTextureSize(u16 textel);
// Devuelve el tamaño del textel
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,106 @@
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __NF_AFFINEBG_H__
#define __NF_AFFINEBG_H__
// NightFox LIB - Includes de Fondos Affine
// Requiere DevkitARM
// Codigo por Cesar Rincon "NightFox"
// http://www.nightfoxandco.com/
// Version 20140413
// Includes devKitPro
#include <nds.h>
// Estructura para almacenar los parametros de los fondos Affine
typedef struct {
s32 x; // Posicion X
s32 y; // Posicion Y
s32 x_center; // Centro X
s32 y_center; // Centro Y
s32 x_scale; // Valor Zoom X (PA)
s32 y_scale; // Valor Zoom Y (PD)
s32 x_tilt; // Valor Inclinacion X (PB)
s32 y_tilt; // Valor Inclinacion Y (PC)
s32 angle; // Valor de la rotacion
} NF_TYPE_AFFINE_BG;
extern NF_TYPE_AFFINE_BG NF_AFFINE_BG[2][4];
// Funcion NF_InitTiledBgSys();
void NF_InitAffineBgSys(u8 screen);
// Inicializa el sistema de fondos Affine. Solo puede usarse en las capas 2 y 3, los fondos en
// la misma pantalla deben de compartir la paleta y no pueden tener mas de 256 tiles.
// Funcion NF_LoadAffineBg();
void NF_LoadAffineBg(const char* file, const char* name, u16 width, u16 height);
// Carga un fondo tileado desde FAT
// Debes de especificar el archivo que se cargara (sin extension) y el nombre
// que le quieres dar y las medidas en pixeles
// Los buffers para fondos tileados deben estar inicializados antes de usar esta funcion
// Funcion NF_UnloadAffineBg();
void NF_UnloadAffineBg(const char* name);
// Borra de la RAM el fondo affine especificado. Es una simple llamada a la funcion NF_UnloadTiledBg();
// Funcion NF_CreateAffineBg();
void NF_CreateAffineBg(u8 screen, u8 layer, const char* name, u8 wrap);
// Crea un fondo con los parametros dados, indicale la pantalla, capa, nombre y si se activa la opcion
// de WRAP arround (0 desactivado, 1 activado).
// Funcion NF_DeleteAffineBg();
void NF_DeleteAffineBg(u8 screen, u8 layer);
// Borra el fondo Affine especificado
// Funcion NF_AffineBgTransform();
void NF_AffineBgTransform(u8 screen, u8 layer, s32 x_scale, s32 y_scale, s32 x_tilt, s32 y_tilt);
// Modifica los parametros de la matriz de transformacion del fondo affine
// Funcion NF_AffineBgMove();
void NF_AffineBgMove(u8 screen, u8 layer, s32 x, s32 y, s32 angle);
// Desplaza el fondo affine y rotalo (-2048 a 2048)
// Funcion NF_AffineBgCenter();
void NF_AffineBgCenter(u8 screen, u8 layer, s32 x, s32 y);
// Define el centro de rotacion de un fondo affine
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,89 @@
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __NF_BASIC_H__
#define __NF_BASIC_H__
// NightFox LIB - Include de funciones basicas
// Requiere DevkitARM
// Codigo por Cesar Rincon "NightFox"
// http://www.nightfoxandco.com/
// Version 20140413
// Includes devKitPro
#include <nds.h>
// Define la variable global NF_ROOTFOLDER
extern char NF_ROOTFOLDER[32];
// Funcion NF_Error();
void NF_Error(u16 code, const char* text, u32 value);
// Errores para debug. Detiene el sistema e informa del error
// 101: Fichero no encontrado
// 102: Memoria insuficiente
// 103: No quedan Slots libres
// 104: Fondo no encontrado
// 105: Fondo no creado
// 106: Fuera de rango
// 107: Insuficientes bloques contiguos en VRAM (Tiles)
// 108: Insuficientes bloques contiguos en VRAM (Maps)
// 109: Id ocupada (ya esta en uso)
// 110: Id no cargada (en RAM)
// 111: Id no en VRAM
// 112: Sprite no creado
// 113: Memoria VRAM insuficiente
// 114: La capa de Texto no existe
// 115: Medidas del fondo no compatibles (no son multiplos de 256)
// 116: Archivo demasiado grande
// 117: Medidas del fondo affine incorrectas
// 118: Capa de creacion del fondo affine incorrecta
// Funcion NF_SetRootFolder();
void NF_SetRootFolder(const char* folder);
// Define el nombre de la carpeta que se usara como "root" si se usa la FAT
// Funcion NF_DmaMemCopy();
void NF_DmaMemCopy(void* destination, const void* source, u32 size);
// Copia un bloque de memoria usando DMA (canal 3, halfwords) y vaciando previamente
// el cache. Con pruebas de bloques grandes (64kb o 128kb) he observado que memcpy();
// sigue siendo mas rapida.
// Funcion NF_GetLanguage();
extern u8 NF_GetLanguage(void);
// Devuelve el ID del idioma del usuario
// 0 : Japanese
// 1 : English
// 2 : French
// 3 : German
// 4 : Italian
// 5 : Spanish
// 6 : Chinese
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,234 @@
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __NF_BITMAPBG_H__
#define __NF_BITMAPBG_H__
// NightFox LIB - Include de funciones de fondos en modo Bitmap
// Requiere DevkitARM
// Codigo por Cesar Rincon "NightFox"
// http://www.nightfoxandco.com/
// Version 20140413
// Includes devKitPro
#include <nds.h>
// Define los slots maximos para los fondos de 16 bits
#define NF_SLOTS_BG16B 16
// Define los slots maximos para los fondos de 8 bits
#define NF_SLOTS_BG8B 16
// Define los Buffers para almacenar datos de 16 bits
typedef struct {
u16* buffer; // Buffer de datos
u32 size; // Tamaño del buffer
u16 width; // Ancho de la imagen (256 max)
u16 height; // Altura de la imagen (256 max)
bool inuse; // Esta en uso el buffer?
} NF_TYPE_BG16B_INFO;
extern NF_TYPE_BG16B_INFO NF_BG16B[NF_SLOTS_BG16B]; // Fondos RAW de 16 bits
// BackBuffer de 16 bits de cada pantalla
extern u16* NF_16BITS_BACKBUFFER[2];
// Define los Buffers para almacenar datos de 8 bits
typedef struct {
u8* data; // Buffer de datos
u32 data_size; // Tamaño del buffer de datos
u16* pal; // Buffer para la paleta
u32 pal_size; // Tamaño de la paleta
bool inuse; // Esta en uso el buffer?
} NF_TYPE_BG8B_INFO;
extern NF_TYPE_BG8B_INFO NF_BG8B[NF_SLOTS_BG8B]; // Fondos indexados de 8 bits
// BackBuffer de 8 bits de cada pantalla
typedef struct {
u8* data;
u16* pal;
} NF_TYPE_BB8B_INFO;
extern NF_TYPE_BB8B_INFO NF_8BITS_BACKBUFFER[2];
// Funcion NF_Init16bitsBgBuffers();
void NF_Init16bitsBgBuffers(void);
// Inicia los buffers para almacenar fondos de BITMAP 16 bits
// Usalo UNA SOLA VEZ antes de usar los buffers
// Funcion NF_Reset16bitsBgBuffers();
void NF_Reset16bitsBgBuffers(void);
// Reinicia los buffers para almacenar fondos de BITMAP 16 bits,
// borrado su contenido
// Funcion NF_Init16bitsBackBuffer();
void NF_Init16bitsBackBuffer(u8 screen);
// Inicia el backbuffer de la pantalla dada.
// Usalo UNA SOLA VEZ antes de usar el backbuffer
// Funcion NF_Enable16bitsBackBuffer();
void NF_Enable16bitsBackBuffer(u8 screen);
// Habilita el backbuffer de la pantalla indicada.
// Si el buffer ya existe, la funcion borrara el contenido del mismo,
// poniendo a 0 todos los bytes del buffer.
// Funcion NF_Disble16bitsBackBuffer();
void NF_Disble16bitsBackBuffer(u8 screen);
// Deshabilita el backbuffer de la pantalla indicada, liberando de la
// RAM el espacio usado.
// Funcion NF_Flip16bitsBackBuffer();
void NF_Flip16bitsBackBuffer(u8 screen);
// Copia el contenido del backbuffer a la VRAM de la pantalla indicada.
// Funcion NF_InitBitmapBgSys();
void NF_InitBitmapBgSys(u8 screen, u8 mode);
// Inicia el modo BITMAP en la pantalla especificada, con la profundidad de color
// especificada. (0 -> 256 colores, 1 -> 16 bits)
// Funcion NF_Load16bitsBg();
void NF_Load16bitsBg(const char* file, u8 slot);
// Carga un Fondo BITMAP (en formato RAW) en el slot indicado,
// de un tamaño maximo de 256x256 pixeles.
// Debes especificar el nombre de archivo sin extension.
// El archivo debe ser un binario con extension .img
// Funcion NF_Load16bitsImage();
void NF_Load16bitsImage(const char* file, u8 slot, u16 size_x, u16 size_y);
// Carga una imagen BITMAP (en formato RAW) en el slot indicado,
// de un tamaño maximo de 256x256 pixeles.
// Debes especificar el nombre de archivo sin extension.
// El archivo debe ser un binario con extension .img
// Todos los pixeles Magenta de la imagen (0xFF00FF) seran transparentes.
// Funcion NF_Load16bImgData();
void NF_Load16bImgData(const char* file, u8 slot, u16 x, u16 y, u8 type);
// Funcion de uso interno, no documentar ni usar.
// Cargador generico de datos de imagen de 16 bits a la RAM.
// Funcion NF_Unload16bitsBg();
void NF_Unload16bitsBg(u8 slot);
// Borra de la RAM los datos del buffer especificado
// Funcion NF_Copy16bitsBuffer();
void NF_Copy16bitsBuffer(u8 screen, u8 destination, u8 slot);
// Copia los datos cargados en un Buffer de Bitmap a la VRAM o al BackBuffer
// destination: 0 -> VRAM, 1 -> BackBuffer
// Funcion NF_Draw16bitsImage();
void NF_Draw16bitsImage(u8 screen, u8 slot, s16 x, s16 y, bool alpha);
// Copia la imagen cargada en un Buffer de Bitmap al Backbuffer de la pantalla especificada
// Funcion NF_Init8bitsBgBuffers();
void NF_Init8bitsBgBuffers(void);
// Inicializa los buffers necesarios para la carda de fondos en modo BITMAP de 8 bits.
// Debes usar esta funcion antes de poder usar ninguno de los buffers.
// Funcion NF_Reset8bitsBgBuffers();
void NF_Reset8bitsBgBuffers(void);
// Reinicia los buffers de fondos de 8 bits, borrando todo el contenido de los buffers.
// Funcion NF_Load8bitsBg();
void NF_Load8bitsBg(const char* file, u8 slot);
// Carga los archivos necesarios de un fondo de 8 bits en el Slot indicado.
// Debes especificar el nombre de archivo sin extension.
// El archivo debe ser un binario con extension .img
// La paleta debe tener la extension .pal
// Funcion NF_Unload8bitsBg();
void NF_Unload8bitsBg(u8 slot);
// Borra de la RAM el fondo del slot indicado.
// Funcion NF_Copy8bitsBuffer();
void NF_Copy8bitsBuffer(u8 screen, u8 destination, u8 slot);
// Transfiere la imagen del buffer seleccionado a la pantalla y capas indicado o
// al backbuffer.
// Funcion NF_Init8bitsBackBuffer();
void NF_Init8bitsBackBuffer(u8 screen);
// Inicializa los buffers del backbuffer para la pantalla indicada.
// Debes usar esta funcion una vez antes de usar el backbuffer
// Funcion NF_Enable8bitsBackBuffer();
void NF_Enable8bitsBackBuffer(u8 screen);
// Habilita el backbuffer de la pantalla indicada.
// Si el buffer ya existe, la funcion borrara el contenido del mismo,
// poniendo a 0 todos los bytes del buffer.
// Funcion NF_Disble8bitsBackBuffer();
void NF_Disble8bitsBackBuffer(u8 screen);
// Deshabilita el backbuffer de la pantalla indicada, liberando de la
// RAM el espacio usado.
// Funcion NF_Flip8bitsBackBuffer();
void NF_Flip8bitsBackBuffer(u8 screen, u8 destination);
// Copia el contenido del backbuffer a la VRAM de la pantalla indicada.
// Debes especificar la capa de destino:
// 0 -> Capa 2
// 1 -> Capa 3
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,110 @@
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __NF_COLISION_H__
#define __NF_COLISION_H__
// NightFox LIB - Include de Colisiones
// Requiere DevkitARM
// Codigo por Cesar Rincon "NightFox"
// http://www.nightfoxandco.com/
// Version 20140413
// Includes devKitPro
#include <nds.h>
// Define los slots maximos para los mapas de colisiones
#define NF_SLOTS_CMAP 32
// Define la estructura de control de mapas de colisiones
typedef struct {
char* tiles; // Buffer para almacenar los tiles
char* map; // Buffer para almacenar el mapa
char* pal; // Buffer para almacenar la paleta
u32 tiles_size; // Tamaño de los archivos
u32 map_size;
u32 pal_size;
u16 width; // Ancho del mapa (en pixeles)
u16 height; // Alto del mapa (en pixeles)
bool inuse; // Esta en uso el slot?
} NF_TYPE_CMAP_INFO;
extern NF_TYPE_CMAP_INFO NF_CMAP[NF_SLOTS_CMAP]; // Datos de los mapas de colision
// Funcion NF_InitCmapBuffers();
void NF_InitCmapBuffers(void);
// Inicializa los buffers que almacenaran los mapas de colision
// Debes usar esta funcion una unica vez antes de cargar ningun mapa de colision
// Funcion NF_ResetCmapBuffers();
void NF_ResetCmapBuffers(void);
// Reinicia los buffers y variables de los mapas de colisiones.
// Funcion NF_LoadColisionMap();
void NF_LoadColisionMap(const char* file, u8 id, u16 width, u16 height);
// Carga un mapa de colisiones en el slot indicado.
// Funcion NF_UnloadColisionMap();
void NF_UnloadColisionMap(u8 id);
// Borra de la RAM el mapa de colisiones con el nº de slot indicado.
// Funcion NF_GetTile();
extern u16 NF_GetTile(u8 slot, s32 x, s32 y);
// Devuelve el numero de tile de la posicion especificada.
// Funcion NF_SetTile();
void NF_SetTile(u8 slot, s32 x, s32 y, u16 value);
// Cambia el valor del tile en la posicion especificada.
// Funcion NF_LoadColisionBg();
void NF_LoadColisionBg(const char* file, u8 id, u16 width, u16 height);
// Carga un fondo de colisiones para pixel perfect
// Funcion NF_UnloadColisionBg();
void NF_UnloadColisionBg(u8 id);
// Descarga un fondo de colisiones para pixel perfect
// Funcion NF_GetPoint();
extern u8 NF_GetPoint(u8 slot, s32 x, s32 y);
// Obten el color del pixel de las coordenadas dadas
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,79 @@
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __NF_DEFINES_H__
#define __NF_DEFINES_H__
// NightFox LIB - Definiciones General
// Requiere DevkitARM
// Codigo por Cesar Rincon "NightFox"
// http://www.nightfoxandco.com/
// Version 20140413
// Definicion de los datos del usuario
// Informacion obtenida de PALIB source code
// Referencias usadas de http://nds.metawiki.com/Firmware
/*
FW offset* RAM address Bytes Description
0x000020 2 user settings offset / 8 (default 0x7FC0 => 0x3FE00)
0x00002A 2 CRC16 (with initial value 0) of 0x2C with config length
0x00002C 2 config length (0x138)
0x000036 6 MAC address
0x00003C 4 enabled channels
0x000065 1 ?
0x000082 1 ?
0x000100 1 ?
0x000146 14 ?
0x000162 1 ?
0x03Fx00 0x023FFC80 1 version (5)
0x03Fx02 0x027FFC82 1 favorite color (0-15)
0x03Fx03 0x027FFC83 1 birthday month (1-12)
0x03Fx04 0x027FFC84 1 birthday day (1-31)
0x03Fx06 0x027FFC86 20 name, UTF-16
0x03Fx1A 0x027FFC9A 1/2 length of name in characters
0x03Fx1C 0x027FFC9C 52 message, UTF-16
0x03Fx50 0x027FFCD0 1/2 length of message in characters
0x03Fx52 0x027FFCD2 1 alarm hour
0x03Fx53 0x027FFCD3 1 alarm minute
0x03Fx56 0x027FFCD6 1 0x80=enable alarm, bit 0..6=enable?
0x027FFCD8 12 touch-screen calibration
0x027FFCE4 bit 0..2 language
0x027FFCE4 bit 3 GBA mode screen selection. 0=upper, 1=lower
0x027FFCE4 bit 6 auto/manual mode. 0=manual, 1=auto
WIFI power calibration
0x03Fx70 1/2 update counter (used to check latest)
0x03Fx72 CRC16 of 0x03FF00, 0x70 bytes
*/
#define NF_UDATA_COLOR *(u8*)(0x027FFC82)
#define NF_UDATA_BDAY_MONTH *(u8*)(0x027FFC83)
#define NF_UDATA_BDAY_DAY *(u8*)(0x027FFC84)
#define NF_UDATA_ALARM_HOUR *(u8*)(0x027FFCD2)
#define NF_UDATA_ALARM_MINUTE *(u8*)(0x027FFCD3)
#define NF_UDATA_NAME *(u8*)(0x027FFC86)
#define NF_UDATA_NAME_SIZE *(u8*)(0x027FFC9A)
#define NF_UDATA_MSG *(u8*)(0x027FFC9C)
#define NF_UDATA_MSG_SIZE *(u8*)(0x027FFCD0)
#define NF_UDATA_LANG *(u8*)(0x027FFCE4)
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,114 @@
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __NF_LIB_H__
#define __NF_LIB_H__
// NightFox LIB - Include General
// Requiere DevkitARM
// Codigo por Cesar Rincon "NightFox"
// http://www.nightfoxandco.com/
// Version 20140413
/*
Notas sobre BITSHIFT
(n >> x) Divide n / x
(n << x) Multiplica n * x
Valores de X
2 = 1
4 = 2
8 = 3
16 = 4
32 = 5
64 = 6
128 = 7
256 = 8
512 = 9
1024 = 10
2048 = 11
4096 = 12
8192 = 13
16384 = 14
32768 = 15
65536 = 16
Dado que la DS no tiene unidad de coma flotante, siempre que dividas o
multipliques por numeros de base 2, usa el bitshift
Por ejemplo:
a = (512 / 8);
seria equivalente a
a = (512 >> 3);
Multiplicando
b = (3 * 2048);
seria con bitshift
b = (3 << 11);
*/
// Definiciones comunes
#include "nf_defines.h"
// Libreria de funciones basicas y comunes
#include "nf_basic.h"
// Libreria de funciones 2D comunes
#include "nf_2d.h"
// Libreria de fondos con Tiles
#include "nf_tiledbg.h"
// Libreria de fondos Affine
#include "nf_affinebg.h"
// Libreria de fondos en modo Bitmap
#include "nf_bitmapbg.h"
// Libreria de fondos en modo mixto (Tiled / Bitmap 8 bits)
#include "nf_mixedbg.h"
// Libreria de sprites de 256 colores
#include "nf_sprite256.h"
// Libreria de textos
#include "nf_text.h"
// Libreria de textos de 16 pixeles
#include "nf_text16.h"
// Libreria de colisiones
#include "nf_colision.h"
// Libreria de sonido
#include "nf_sound.h"
// Libreria de archivos multimedia
#include "nf_media.h"
// Libreria 3D, funciones comunes
#include "nf_3d.h"
// Libreria 3D, Sprites
#include "nf_sprite3d.h"
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,41 @@
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __NF_MEDIA_H__
#define __NF_MEDIA_H__
// NightFox LIB - Include de funciones de carga de archivos multimedia
// Requiere DevkitARM
// Codigo por Cesar Rincon "NightFox"
// http://www.nightfoxandco.com/
// Version 20140413
// Includes devKitPro
#include <nds.h>
// Funcion NF_LoadBMP();
void NF_LoadBMP(const char* file, u8 slot);
// Carga un archivo BMP de 8, 16 o 24 bits en un slot de imagenes de 16 bits.
// Debes inicializar el modo 16 bits, el backbuffer y usar la funcion NF_Draw16bitsImage();
// para mostrarlo.
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,41 @@
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __NF_MIXEDBG_H__
#define __NF_MIXEDBG_H__
// NightFox LIB - Include de Fondos mixtos (Tiled / Bitmap 8 bits)
// Requiere DevkitARM
// Codigo por Cesar Rincon "NightFox"
// http://www.nightfoxandco.com/
// Version 20140413
// Includes devKitPro
#include <nds.h>
// Funcion NF_InitMixedBgSys();
void NF_InitMixedBgSys(u8 screen);
// Inicializa el modo mixto para fondo (Tiled BG + Bitmap 8 bits)
// Capas 0 a 2 - Tiled
// Capa 3 - Bitmap 8 bits
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,96 @@
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __NF_SOUND_H__
#define __NF_SOUND_H__
// NightFox LIB - Include de funciones de sonido
// Requiere DevkitARM
// Codigo por Cesar Rincon "NightFox"
// http://www.nightfoxandco.com/
// Version 20140413
// Includes devKitPro
#include <nds.h>
// Define los Slots para archivos de audio
#define NF_SLOTS_RAWSOUND 32
// Define los Buffers para almacenar los archivos de audio
extern char* NF_BUFFER_RAWSOUND[NF_SLOTS_RAWSOUND];
// Define la estructura de datos de los buffers (Audio)
typedef struct {
bool available; // Disponibilidat del Slot
u32 size; // Tamaño (en bytes) del sonido
u16 freq; // Frecuencia del sample
u8 format; // Formato del sample
} NF_TYPE_RAWSOUND_INFO;
extern NF_TYPE_RAWSOUND_INFO NF_RAWSOUND[NF_SLOTS_RAWSOUND]; // Datos de los sonidos cargado
// Funcion NF_InitRawSoundBuffers();
void NF_InitRawSoundBuffers(void);
// Iniciliaza los buffers y estructuras de datos para cargar sonidos en
// formato RAW. Debes de ejecutar esta funcion una vez antes de cargar
// ningun sonido en este formato
// Funcion NF_ResetRawSoundBuffers();
void NF_ResetRawSoundBuffers(void);
// Reinicia todos los buffers de sonido. Esta funcion es util para vaciar todos los datos
// en un cambio de pantalla, etc.
// Funcion NF_LoadRawSound();
void NF_LoadRawSound(const char* file, u16 id, u16 freq, u8 format);
// Carga un archivo RAW a la RAM desde la FAT o EFS
// Debes especificar el nombre del archivo sin extension, el slot
// donde lo guardaras (0 - 31), la frecuencia del sample (en Hz,
// por ejemplo 11050) y el formato de datos
// (0 - > 8 bits, 1 - > 16 bits, 2 -> ADPCM)
// Funcion UnloadRawSound();
void NF_UnloadRawSound(u8 id);
// Borra de la RAM el archivo cargado en el slot indicado.
// Debes especificar el slot a borrar (0 - 31)
// Funcion NF_PlayRawSound();
extern u8 NF_PlayRawSound(u8 id, u8 volume, u8 pan, bool loop, u16 loopfrom);
// Reproduce un archivo de sonido cargado en RAM.
// Debes especificar el slot donde se ha cargado el sonido, el volumen (0 - 127),
// el balance (0 Izquierda, 64 Centro, 127 Derecha), si se reproducira en bucle y
// de ser asi, a partir de que sample se producira este.
// Esta funcion devuelve el canal asignado a esta reproduccion
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,265 @@
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __NF_SPRITE256_H__
#define __NF_SPRITE256_H__
// NightFox LIB - Include de Sprites a 256 colores
// Requiere DevkitARM
// Codigo por Cesar Rincon "NightFox"
// http://www.nightfoxandco.com/
// Version 20140413
// Includes devKitPro
#include <nds.h>
// Define los Slots para sprites
#define NF_SLOTS_SPR256GFX 256 // Almacena los graficos
#define NF_SLOTS_SPR256PAL 64 // Almacena las paletas
// Define los Buffers para almacenar los Sprites
extern char* NF_BUFFER_SPR256GFX[NF_SLOTS_SPR256GFX];
extern char* NF_BUFFER_SPR256PAL[NF_SLOTS_SPR256PAL];
// Define la estructura de datos de los buffers (GFX)
typedef struct {
u32 size; // Tamaño (en bytes) del grafico (GFX)
u16 width; // Ancho del Gfx
u16 height; // Altura del Gfx
bool available; // Disponibilidat del Slot
} NF_TYPE_SPR256GFX_INFO;
extern NF_TYPE_SPR256GFX_INFO NF_SPR256GFX[NF_SLOTS_SPR256GFX]; // Buffers de Graficos
// Define la estructura de datos de los buffers (PAL)
typedef struct {
u32 size; // Tamaño (en bytes) de la paleta (PAL)
bool available; // Disponibilidat del Slot
} NF_TYPE_SPR256PAL_INFO;
extern NF_TYPE_SPR256PAL_INFO NF_SPR256PAL[NF_SLOTS_SPR256PAL]; // Buffers de Paletas
// Define la estructura de Gfx en VRAM
typedef struct {
u32 size; // Tamaño (en bytes) del Gfx
u16 width; // Ancho del Gfx
u16 height; // Altura del Gfx
u32 address; // Posicion en la VRAM
u16 ramid; // Numero de Slot en RAM del que provienes
u16 framesize; // Tamaño del frame (en bytes)
u16 lastframe; // Ultimo frame
bool keepframes; // Si es un Sprite animado, debes de mantener los frames en RAM ?
bool inuse; // Disponibilidat del Slot
} NF_TYPE_SPR256VRAM_INFO;
extern NF_TYPE_SPR256VRAM_INFO NF_SPR256VRAM[2][128];
// Datos de paletas de Sprites en VRAM (en uso, slot en ram, etc)
typedef struct {
bool inuse; // Slot en uso
u8 ramslot; // Paleta original en RAM
} NF_TYPE_SPRPALSLOT_INFO;
extern NF_TYPE_SPRPALSLOT_INFO NF_SPRPALSLOT[2][16];
// Define la estructura de datos del OAM (Sprites)
typedef struct {
u8 index; // Numero de Sprite
s16 x; // Coordenada X del Sprite
s16 y; // Coordenada Y del Sprite
u8 layer; // Prioridad en las capas
u8 pal; // Paleta que usaras
u32 size; // Tamaño del Sprite (macro)
u32 color; // Modo de color (macro)
u32* gfx; // Puntero al grafico usado
s8 rot; // Id de rotacion (-1 ninguno) (0 - 31 Id de rotacion)
bool doublesize; // Usar el "double size" al rotar ?
bool hide; // Ocultar el Sprite
bool vflip; // Volteado Vertical
bool hflip; // Volteado Horizontal
bool mosaic; // Mosaico
u16 gfxid; // Id de Gfx usado
u16 frame; // Frame actual
u16 framesize; // Tamaño del frame (en bytes)
u16 lastframe; // Ultimo frame
bool created; // Esta creado este sprite ?
} NF_TYPE_SPRITEOAM_INFO;
extern NF_TYPE_SPRITEOAM_INFO NF_SPRITEOAM[2][128]; // 2 pantallas, 128 sprites
// Define la esturctura de control de la VRAM para Sprites
typedef struct {
s32 free; // Memoria VRAM libre
u32 next; // Siguiente posicion libre
u32 last; // Ultima posicion usada
u32 pos[128]; // Posicion en VRAM para reusar despues de un borrado
u32 size[128]; // Tamaño del bloque libre para reusar
u16 deleted; // Numero de bloques borrados
s32 fragmented; // Memoria VRAM fragmentada
s32 inarow; // Memoria VRAM contigua
s32 max; // Maxima memoria VRAM direccionable
} NF_TYPE_SPRVRAM_INFO;
extern NF_TYPE_SPRVRAM_INFO NF_SPRVRAM[2]; // Informacion VRAM de Sprites en ambas pantallas
// Funcion NF_InitSpriteBuffers()
void NF_InitSpriteBuffers(void);
// Inicializa los buffers y estructuras de datos de los Buffers para almacenar Sprites
// Usala antes de cargar cualquier Sprites
// No uses esta funcion mas de una vez en tu codigo
// Funcion NF_ResetSpriteBuffers()
void NF_ResetSpriteBuffers(void);
// Reinicia los buffers y datos para almacenar Sprites
// Funcion NF_InitSpriteSys();
void NF_InitSpriteSys(int screen, ...);
// Inicializa las variables de control de Sprites y paletas
// Asigna 128kb de RAM para Sprites
// Activa el Soporte para Sprites
// Se debe especificar la pantalla (0 o 1)
// Funcion NF_LoadSpriteGfx();
void NF_LoadSpriteGfx(const char* file, u16 id, u16 width, u16 height);
// Carga un grafico para usarlo despues en la creacion de Sprites
// Especifica el archivo, ID exclusivo (0 - 255) y medidas del grafico
// Funcion NF_UnloadSpriteGfx();
void NF_UnloadSpriteGfx(u16 id);
// Borra de la RAM un Gfx cargado previamente con NF_LoadSpriteGfx();
// Especifica la Id exclusiva (0 - 255) de grafico a borrar.
// Funcion NF_LoadSpritePal();
void NF_LoadSpritePal(const char* file, u8 id);
// Carga una paleta para usarla despues en la creacion de Sprites
// Especifica el archivo y ID exclusivo (0 - 63)
// Funcion NF_UnloadSpritePal();
void NF_UnloadSpritePal(u8 id);
// Borra de la RAM una Paleta cargada previamente con NF_LoadSpritePal();
// Especifica la Id exclusiva (0 - 63) de la paleta a borrar.
// Funcion NF_VramSpriteGfx();
void NF_VramSpriteGfx(u8 screen, u16 ram, u16 vram, bool keepframes);
// Transfiere un Grafico cargado para Sprites a la VRAM
// Debes especificar la pantalla, el Id del Grafico en RAM (origen),
// la Id del grafico en VRAM (destino) y si, en caso de estar animado,
// debe de copiar a la VRAM todos los frames o solo el que este en uso
// Funcion NF_FreeSpriteGfx();
void NF_FreeSpriteGfx(u8 screen, u16 id);
// Borra de la VRAM el Grafico con la Id. especificada.
// Cualquier Sprite que este usando ese Gfx, quedara corrupto.
// Funcion NF_VramSpriteGfxDefrag();
void NF_VramSpriteGfxDefrag(u8 screen);
// Desfragmenta la VRAM de Sprites (Gfx) de la pantalla dada
// Esta se realiza automaticamente al borrar un Gfx de la VRAM
// si la memoria fragmentada es superior a la contigua libre.
// Puedes consultar estos valores con las siguientes variables
// NF_SPRVRAM[u8 screen].free <- Memoria VRAM de Sprites libre
// NF_SPRVRAM[u8 screen].fragmented <- Memoria VRAM de sprites libre fragmentada
// NF_SPRVRAM[u8 screen].inarow <- Memoria VRAM de sprites libre, ultimo bloque mas grande
// NF_SPRVRAM[u8 screen].lost <- Memoria VRAM libre no usable por fragmentacion
// Funcion NF_VramSpritePal();
void NF_VramSpritePal(u8 screen, u8 id, u8 slot);
// Transfiere una Paleta cargada para Sprites a la VRAM
// Debes especificar la pantalla, la Id de la Paleta a trasnferir
// y el slot de destino (0 - 15)
// Funcion NF_CreateSprite();
void NF_CreateSprite(u8 screen, u8 id, u16 gfx, u8 pal, s16 x, s16 y);
// Crea un sprite en la pantalla.
// Debes especificar la pantalla, la ID del Sprite (0 - 127),
// la ID del Grafico que usaras (0 - 255), el slot de paleta (0 - 15),
// y las coordenadas donde lo crearas.
// Funcion NF_DeleteSprite();
void NF_DeleteSprite(u8 screen, u8 id);
// Borra un sprite de la pantalla
// Debes especificar la pantalla y la Id del Sprite a borrar
// Funcion NF_SpriteOamSet();
void NF_SpriteOamSet(u8 screen);
// Copia los datos del array propio de OAM al OAM real
// Debes especificar la pantalla
// Funcion NF_SpriteSetPalColor();
void NF_SpriteSetPalColor(u8 screen, u8 pal, u8 number, u8 r, u8 g, u8 b);
// Cambia el valor de un color de la paleta de sprites especificada.
// Debes especificar la pantalla, slot de la paleta en VRAM, numero de color
// a cambiar dentro de la paleta y el nuevo valor a darle en formato RGB
// Funcion NF_SpriteEditPalColor();
void NF_SpriteEditPalColor(u8 screen, u8 pal, u8 number, u8 r, u8 g, u8 b);
// Modifica los valores de la paleta seleccionada. Las modificaciones se efectuan
// sobre la copia en RAM, por lo que los cambios no seran visibles hasta que se
// transfiera la paleta a la VRAM
// Funcion NF_SpriteUpdatePalette();
void NF_SpriteUpdatePalette(u8 screen, u8 pal);
// Actualiza la paleta en VRAM con la copia que se encuentra en la RAM
// Funcion NF_SpriteGetPalColor();
void NF_SpriteGetPalColor(u8 screen, u8 pal, u8 number, u8* r, u8* g, u8* b);
// Obtiene el valor de un color de la paleta que se encuentra en la RAM
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,243 @@
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __NF_SPRITE3D_H__
#define __NF_SPRITE3D_H__
// NightFox LIB - Include de funciones 3D
// Requiere DevkitARM
// Codigo por Cesar Rincon "NightFox"
// http://www.nightfoxandco.com/
// Version 20140413
// Includes devKitPro
#include <nds.h>
//////////////////////////////////
// Defines y variables globales //
//////////////////////////////////
// Numero maximo de sprites en pantalla
#define NF_3DSPRITES 256
// Estructura de control de los sprites 3d
typedef struct {
s16 x; // Coordenada X
s16 y; // Coordenada Y
s16 z; // Coordenada Z
s16 rx; // Rotacion Eje X (-512/0/512) << 6
s16 ry; // Rotacion Eje Y (-512/0/512) << 6
s16 rz; // Rotacion Eje Z (-512/0/512) << 6
bool rot; // Rotacion en uso
u16 sx; // Escala X (0/64/512) << 6
u16 sy; // Escala Y (0/64/512) << 6
bool scale; // Escalado en uso
s16 width; // Ancho del sprite
s16 height; // Alto del sprite
bool inuse; // Esta en uso?
bool show; // Debe mostrarse el sprite?
u32 gfx_tex_format; // Guarda el formato de la textura
u32 gfx; // Direccion donde esta almacenado el grafico en VRAM
u16 gfxid; // Id de Gfx usado
u16 frame; // Frame actual
u16 newframe; // Frame al que cambiar
u16 framesize; // Tamaño del frame (en bytes)
u16 lastframe; // Ultimo frame
u32 gfx_pal_format; // Guarda el formato de la paleta
u32 pal; // Direccion donde esta almacenada la paleta en VRAM
u16 palid; // Id de la paleta usada
u16 prio; // Prioridad de dibujado del sprite
u8 poly_id; // Identificador unico para el Alpha (0 por defecto, 63 prohibido)
u8 alpha; // Nivel de alpha (0 - 31) (31 por defecto)
} NF_TYPE_3DSPRITE_INFO;
extern NF_TYPE_3DSPRITE_INFO NF_3DSPRITE[NF_3DSPRITES];
// Estructura de control Texturas en VRAM
typedef struct {
u32 size; // Tamaño (en bytes) del Gfx
u16 width; // Ancho del Gfx
u16 height; // Altura del Gfx
u32 address; // Posicion en la VRAM
u16 ramid; // Numero de Slot en RAM del que provienes
u16 framesize; // Tamaño del frame (en bytes)
u16 lastframe; // Ultimo frame
bool keepframes; // Si es un Sprite animado, debes de mantener los frames en RAM ?
bool inuse; // Disponibilidat del Slot
} NF_TYPE_TEX256VRAM_INFO;
extern NF_TYPE_TEX256VRAM_INFO NF_TEX256VRAM[NF_3DSPRITES];
// Estructura de control de las paletas en VRAM
typedef struct {
bool inuse; // Slot en uso
u8 ramslot; // Paleta original en RAM
} NF_TYPE_3DSPRPALSLOT_INFO;
extern NF_TYPE_3DSPRPALSLOT_INFO NF_TEXPALSLOT[32];
// Define la esturctura de control de la VRAM para Sprites 3d
typedef struct {
s32 free; // Memoria VRAM libre
u32 next; // Siguiente posicion libre
u32 last; // Ultima posicion usada
u32 pos[NF_3DSPRITES]; // Posicion en VRAM para reusar despues de un borrado
u32 size[NF_3DSPRITES]; // Tamaño del bloque libre para reusar
u16 deleted; // Numero de bloques borrados
s32 fragmented; // Memoria VRAM fragmentada
s32 inarow; // Memoria VRAM contigua
} NF_TYPE_TEXVRAM_INFO;
extern NF_TYPE_TEXVRAM_INFO NF_TEXVRAM; // Informacion VRAM de texturas
// Define la estructura de control de los sprites 3d creados
typedef struct {
s16 total; // Numero de sprites creados
u16 id[NF_3DSPRITES]; // ID del Sprite
u16 bck[NF_3DSPRITES]; // Backup del ID
} NF_TYPE_CREATED_3DSPRITE_INFO;
extern NF_TYPE_CREATED_3DSPRITE_INFO NF_CREATED_3DSPRITE;
// Funcion NF_Init3dSpriteSys();
void NF_Init3dSpriteSys(void);
// Inicializa el sistema de Sprites en 3D
// Funcion NF_Vram3dSpriteGfx();
void NF_Vram3dSpriteGfx(u16 ram, u16 vram, bool keepframes);
// Transfiere un grafico de la RAM a la VRAM
// Funcion NF_Free3dSpriteGfx();
void NF_Free3dSpriteGfx(u16 id);
// Elimina de la VRAM un grafico de texturas y desfragmenta la VRAM si es necesario
// Funcion NF_Vram3dSpriteGfxDefrag();
void NF_Vram3dSpriteGfxDefrag(void);
// Desfragmenta la VRAM usada para texturas
// Funcion NF_Vram3dSpritePal();
void NF_Vram3dSpritePal(u8 id, u8 slot);
// Copia una paleta a la VRAM
// Funcion NF_Create3dSprite();
void NF_Create3dSprite(u16 id, u16 gfx, u16 pal, s16 x, s16 y);
// Crea un Sprite 3D en las coordenadas indicadas
// Funcion NF_Delete3dSprite();
void NF_Delete3dSprite(u16 id);
// Borra el Sprite con la ID indicada
// Funcion NF_Sort3dSprites();
void NF_Sort3dSprites(void);
// Reordena la cola de Sprites 3D creados de menor a mayor segun su ID
// Los Sprites con numeros mas bajos tienen prioridad.
// Funcion NF_Set3dSpritePriority();
void NF_Set3dSpritePriority(u16 id, u16 prio);
// Cambia la prioridad del Sprite
// Funcion NF_Swap3dSpritePriority();
void NF_Swap3dSpritePriority(u16 id_a, u16 id_b);
// Intercambia la prioridad de dos Sprites
// Funcion NF_Move3dSprite();
void NF_Move3dSprite(u16 id, s16 x, s16 y);
// Mueve el Sprite seleccionado a las coordenadas dadas
// Funcion NF_Show3dSprite();
void NF_Show3dSprite(u16 id, bool show);
// Muestra u oculta el sprite con la id indicada
// Funcion NF_Set3dSpriteFrame();
void NF_Set3dSpriteFrame(u16 id, u16 frame);
// Cambia el frame visible del sprite indicado
// Funcion NF_Draw3dSprites();
void NF_Draw3dSprites(void);
// Dibuja en pantalla todos los sprites creados
// Funcion NF_Update3dSpritesGfx();
void NF_Update3dSpritesGfx(void);
// Actualiza si es necesario las texturas de los sprites animados
// Funcion NF_Rotate3dSprite();
void NF_Rotate3dSprite(u16 id, s16 x, s16 y, s16 z);
// Rota el Sprite sobre los ejes indicados (-512/0/512)
// Funcion NF_Scale3dSprite();
void NF_Scale3dSprite(u16 id, u16 x, u16 y);
// Escala el sprite al tamaño indicado (0/64/512)
// Funcion NF_Blend3dSprite();
void NF_Blend3dSprite(u8 sprite, u8 poly_id, u8 alpha);
// Habilita y cambia el nivel de alpha de el sprite 3d indicado. Para que la transparencia
// sea efectiva entre Sprites, debes especificar un poly_id diferente para cada sprite
// (entre 1 y 62). El rango de alpha es de 0 a 31, siendo 31 opaco. Para eliminar la
// transparencia, selecciona un valor para alpha de 31 o especifica como poly_id el nº 0.
// Funcion NF_3dSpritesLayer();
void NF_3dSpritesLayer(u8 layer);
// Selecciona la capa en la que se dibujaran los Sprites 3D. (0 - 3)
// En realidad los Sprites 3D siempre se dibujan sobre la CAPA 0, esta funcion solo cambia
// la prioridad de esta capa sobre las demas.
// Funcion NF_3dSpriteEditPalColor();
void NF_3dSpriteEditPalColor(u8 pal, u8 number, u8 r, u8 g, u8 b);
// Modifica los valores de la paleta seleccionada. Las modificaciones se efectuan
// sobre la copia en RAM, por lo que los cambios no seran visibles hasta que se
// transfiera la paleta a la VRAM
// Funcion NF_3dSpriteUpdatePalette();
void NF_3dSpriteUpdatePalette(u8 pal);
// Actualiza la paleta en VRAM con la copia que se encuentra en la RAM
// Funcion NF_3dSpriteGetPalColor();
void NF_3dSpriteGetPalColor(u8 pal, u8 number, u8* r, u8* g, u8* b);
// Obtiene el valor de un color de la paleta que se encuentra en la RAM
// Funcion NF_3dSpriteSetDeep();
void NF_3dSpriteSetDeep(u8 id, s16 z);
// Cambia la profuncidad de dibujado (z) del sprite (-512/0/512),
// siendo -512 el punto mas cercano, 0 el centro por defecto
// y 512 el punto mas lejano.
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,124 @@
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __NF_TEXT_H__
#define __NF_TEXT_H__
// NightFox LIB - Include de Textos
// Requiere DevkitARM
// Codigo por Cesar Rincon "NightFox"
// http://www.nightfoxandco.com/
// Version 20140413
// Includes devKitPro
#include <nds.h>
// Define el nº de caracteres que tiene la fuente
#define NF_TEXT_FONT_CHARS 127
#define NF_TEXT_FONT_LAST_VALID_CHAR 113
// Define la estructura de control de textos
typedef struct {
u16 width; // Ultimo tile de la fila (0 - x) 32 tiles serian 0 - 31
u16 height; // Ultimo tile de la columna (0 - y)
u8 rotation; // Rotacion del texto
u8 slot; // Slot donde esta cargado el tileset de esta capa de texto
u8 pal; // Paleta que usara el texto (0 por defecto)
bool exist; // Existe la capa de texto?
bool update; // Tienes que actualizar la capa?
} NF_TYPE_TEXT_INFO;
extern NF_TYPE_TEXT_INFO NF_TEXT[2][4]; // Datos de las capas de texto
// Funcion NF_InitTextSys();
void NF_InitTextSys(u8 screen);
// Inicializa el sistema de Texto para la pantalla dada
// Funcion NF_LoadTextFont();
void NF_LoadTextFont(const char* file, const char* name, u16 width, u16 height, u8 rotation);
// Carga una fuente para usar como texto
// La fuente se cargara en un slot libre de fondos tileados
// Debes especificar el archivos sin extension y un nombre para referenciarla
// En caso de que la fuente tenga los sets de rotacion a izquierda y derecha,
// especificar 1 o 2 en el parametro "rot". 0 carga la fuente sin rotacion
// Funcion NF_UnloadTextFont();
void NF_UnloadTextFont(const char* name);
// Borra un fuente cargada en RAM
// Esta funcion simplemente llama a NF_UnloadTiledBg(); para su borrado
// Funcion NF_CreateTextLayer();
void NF_CreateTextLayer(u8 screen, u8 layer, u8 rotation, const char* name);
// Crea un fondo tileado para usarlo con texto
// Esta funcion simplemente llama a NF_CreateTiledBg(); para su creacion
// Funcion NF_DeleteTextLayer();
void NF_DeleteTextLayer(u8 screen, u8 layer);
// Borra un fondo usado como capa de texto y sus buffers y variables asociadas
// Funcion NF_WriteText();
void NF_WriteText(u8 screen, u8 layer, u16 x, u16 y, const char* text);
// Escribe un texto en el buffer de texto de la pantalla y capa seleccionada
// Funcion NF_UpdateTextLayers();
void NF_UpdateTextLayers(void);
// Copia el buffer de texto a la VRAM en las capas que sea necesario
// realizar una actualizacion
// Funcion NF_ClearTextLayer();
void NF_ClearTextLayer(u8 screen, u8 layer);
// Borra el contanido de la capa de texto seleccionada
// Funcion NF_DefineTextColor();
void NF_DefineTextColor(u8 screen, u8 layer, u8 color, u8 r, u8 g, u8 b);
// Define uno de los 16 colores disponibles para texto, en formato RGB
// Function NF_SetTextColor();
void NF_SetTextColor(u8 screen, u8 layer, u8 color);
// Selecciona con que color definido se escribira el texto (no cambia el color del texto ya escrito)
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,64 @@
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __NF_TEXT16_H__
#define __NF_TEXT16_H__
// NightFox LIB - Include de Textos de 16 pixels
// Requiere DevkitARM
// Codigo por Cesar Rincon "NightFox"
// http://www.nightfoxandco.com/
// Version 20140413
// Includes devKitPro
#include <nds.h>
// Define el nº de caracteres que tiene la fuente
#define NF_TEXT_FONT_CHARS_16 127
#define NF_TEXT_FONT_LAST_VALID_CHAR_16 113
// Funcion NF_LoadTextFont16();
void NF_LoadTextFont16(const char* file, const char* name, u16 width, u16 height, u8 rotation);
// Carga una fuente para texto de 16 pixeles de altura
// Funcion NF_CreateTextLayer16();
void NF_CreateTextLayer16(u8 screen, u8 layer, u8 rotation, const char* name);
// Crea una capa de texto para fuentes de 16 pixeles
// Funcion NF_WriteText16();
void NF_WriteText16(u8 screen, u8 layer, u16 x, u16 y, const char* text);
// Escribe un texto en la capa y pantalla especificados
// Funcion NF_ClearTextLayer16();
void NF_ClearTextLayer16(u8 screen, u8 layer);
// Limpia la capa de texto especificada
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,320 @@
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __NF_TILEDBG_H__
#define __NF_TILEDBG_H__
// NightFox LIB - Include de Fondos con tiles
// Requiere DevkitARM
// Codigo por Cesar Rincon "NightFox"
// http://www.nightfoxandco.com/
// Version 20140413
// Includes devKitPro
#include <nds.h>
// Define los slots maximos para los fondos
#define NF_SLOTS_TBG 64 // Datos de los fondos
#define NF_SLOTS_EXBGPAL 128 // Paletas extendidas (maximo 16 paletas por fondo)
// Define el numero maximo de bancos para tiles y mapas
#define NF_MAX_BANKS_TILES 8
#define NF_MAX_BANKS_MAPS 16
// Define el numero de bancos de Mapas y Tiles
extern u8 NF_BANKS_TILES[2]; // (1 banks = 16kb) Cada banco de tiles puede alvergar 8 bancos de Mapas
extern 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
extern char* NF_BUFFER_BGTILES[NF_SLOTS_TBG];
extern char* NF_BUFFER_BGMAP[NF_SLOTS_TBG];
extern char* NF_BUFFER_BGPAL[NF_SLOTS_TBG];
// Define estructura para almacenar la info de los fondos
typedef struct {
char name[32]; // Nombre del fondo
u32 tilesize; // Tamaño del Tileset
u32 mapsize; // Tamaño del Map
u32 palsize; // Tamaño de la Paleta
u16 width; // Ancho del fondo
u16 height; // Altura del fondo
bool available; // Disponibilidat del Slot
} NF_TYPE_TBG_INFO;
extern NF_TYPE_TBG_INFO NF_TILEDBG[NF_SLOTS_TBG]; // Datos de los fondos
// Define la estructura para almacenar la info y datos de las paletas extendidas
typedef struct {
char* buffer; // Buffer para almacenar la paleta
u32 palsize; // Tamaño de la paleta
bool inuse; // Slot libre o en uso
} NF_TYPE_EXBGPAL_INFO;
extern NF_TYPE_EXBGPAL_INFO NF_EXBGPAL[NF_SLOTS_EXBGPAL]; // Datos de las paletas extendidas
// Define estructura para almacenar la info de los fondos en pantalla
typedef struct {
u8 tilebase; // Bloque de inicio en VRAM del Tileset
u8 tileblocks; // Bloques usados por el Tileset
u8 mapbase; // Bloque de inicio en VRAM del Map
u8 mapblocks; // Bloques usados por el Map
u16 bgwidth; // Ancho del fondo
u16 bgheight; // Altura del fondo
u16 mapwidth; // Ancho del mapa
u16 mapheight; // Altura del mapa
u8 bgtype; // Tipo de mapa
u8 bgslot; // Buffer de graficos usado (NF_BUFFER_BGMAP)
u8 blockx; // Bloque de mapa (horizontal)
u8 blocky; // bloque de mapa (vertical)
bool created; // Flag de si esta creado
} NF_TYPE_TBGLAYERS_INFO;
// El hardware de la DS no permite mapas mayores de 512x512
// Asi que informaremos si nuestor mapa lo gestionara el hardware si es menor o
// igual a 512x512, o usaremos nuestro motor de Tile Swaping
// bgtype 0: Normal (maximo 512 x 512)
// bgtype 1: >512 x 256
// bgtype 2: 256 x >512
// bgtype 3: >512 x >512
extern NF_TYPE_TBGLAYERS_INFO NF_TILEDBG_LAYERS[2][4]; //[screen][layer]
// Define el array de bloques libres
extern u8 NF_TILEBLOCKS[2][NF_MAX_BANKS_TILES];
extern u8 NF_MAPBLOCKS[2][NF_MAX_BANKS_MAPS];
// Funcion NF_InitTiledBgBuffers();
void NF_InitTiledBgBuffers(void);
// Inicializa los buffers y estructuras de control para usar los fondos "tileados"
// Se debe usar antes de cargar o usar cualquier fondo
// No uses esta funcion mas de una vez en tu codigo
// Funcion NF_ResetTiledBgBuffers();
void NF_ResetTiledBgBuffers(void);
// Borra todos los buffers y reinicia las estructuras de fondos "tileados"
// Usala para los cambios de nivel y similares
// Funcion NF_InitTiledBgSys();
void NF_InitTiledBgSys(u8 screen);
// Inicializa las variables de control de tiles, mapas y paletas
// Asigna 128kb de RAM para fondos tileados
// Se debe especificar la pantalla (0 o 1)
// Funcion NF_LoadTiledBg();
void NF_LoadTiledBg(const char* file, const char* name, u16 width, u16 height);
// Carga un fondo tileado desde FAT
// Debes de especificar el archivo que se cargara (sin extension) y el nombre
// que le quieres dar y las medidas en pixeles
// Funcion NF_LoadTilesForBg();
void NF_LoadTilesForBg(const char* file, const char* name, u16 width, u16 height, u16 tile_start, u16 tile_end);
// Carga desde la FAT los tiles especificados y su paleta
// Ademas, crea un mapa vacio de la medida especificada
// Esta funcion es util para cargar varios tiles y despues generar fondos
// modificando el MAP desde cogido (Generador de escenarios, animaciones, etc)
// Funcion NF_UnloadTiledBg();
void NF_UnloadTiledBg(const char* name);
// Borra de la RAM un fondo cargado con NF_LoadTiledBg();
// Debes especificar el nombre que le diste al fondo
// Funcion NF_CreateTiledBg();
void NF_CreateTiledBg(u8 screen, u8 layer, const char* name);
// Crea un fondo con los parametros dados, indicale la pantalla, capa y nombre
// Funcion NF_DeleteTiledBg();
void NF_DeleteTiledBg(u8 screen, u8 layer);
// Borra un fondo de la memoria VRAM
// Debes especificar la pantalla y numero de capa
// Funcion NF_GetTileMapAddress();
extern u32 NF_GetTileMapAddress(u8 screen, u8 layer, u16 tile_x, u16 tile_y);
// Funcion de uso interno de la libreria
// Devuelve la direccion en el buffer de un tile concreto
// Funcion NF_GetTileOfMap();
extern u16 NF_GetTileOfMap(u8 screen, u8 layer, u16 tile_x, u16 tile_y);
// Obten el valor del tile del mapa indicado en las coordenadas (en tiles) indicadas.
// Funcion NF_SetTileOfMap();
void NF_SetTileOfMap(u8 screen, u8 layer, u16 tile_x, u16 tile_y, u16 tile);
// Cambia el valor del tile del mapa indicado en las coordenadas (en tiles) indicadas.
// Funcion NF_UpdateVramMap();
void NF_UpdateVramMap(u8 screen, u8 layer);
// Actualiza en VRAM el contenido del mapa seleccionado.
// Funcion NF_BgSetPalColor();
void NF_BgSetPalColor(u8 screen, u8 layer, u8 number, u8 r, u8 g, u8 b);
// Cambia al momento el valor de un color de la paleta
// Cuidado! Funcion Muy lenta, usar solo para 2 o 3 colores por ciclo
// Cambia el color directamente en la VRAM
// Funcion NF_BgEditPalColor();
void NF_BgEditPalColor(u8 screen, u8 layer, u8 number, u8 r, u8 g, u8 b);
// Edita un color de la paleta seleccionada.
// El color se edita en el buffer de RAM, para que sea efectivo,
// mandala a la VRAM con NF_UpdatePalette();
// Funcion NF_BgUpdatePalette();
void NF_BgUpdatePalette(u8 screen, u8 layer);
// Actualiza la paleta en VRAM con la que se encuentra en el buffer de RAM
// Funcion NF_BgGetPalColor();
void NF_BgGetPalColor(u8 screen, u8 layer, u8 number, u8* r, u8* g, u8* b);
// Obtiene el valor de un color de la paleta que se encuentra en la RAM
// Funcion NF_GetTilePal();
extern u8 NF_GetTilePal(u8 screen, u8 layer, u16 tile_x, u16 tile_y);
// Devuelve que numero de paleta (0 - 15) esta usando el tile del fondo especificado.
// Por defecto, todos los tiles usan la paleta del Slot nº0
// Los datos se obtienen de la compia en RAM del mapa del fondo.
// Funcion NF_SetTilePal();
void NF_SetTilePal(u8 screen, u8 layer, u16 tile_x, u16 tile_y, u8 pal);
// Cambia el numero de paleta (0 - 15) que usara el tile del fondo especificado.
// Por defecto, todos los tiles usan la paleta del Slot nº0
// Los datos se escriben de la compia en RAM del mapa del fondo, por lo que no seran
// visibles hasta que ejecutes la funcion NF_UpdateVramMap();
// Funcion NF_LoadExBgPal();
void NF_LoadExBgPal(const char* file, u8 slot);
// Carga en el buffer de RAM correspondiente una paleta de fondos, para poderla usar
// mas tarde como paleta extendida.
// Funcion NF_UnloadExBgPal();
void NF_UnloadExBgPal(u8 slot);
// Borra de la RAM la paleta del slot especificado.
// Funcion NF_VramExBgPal();
void NF_VramExBgPal(u8 screen, u8 layer, u8 id, u8 slot);
// Transfiere a la VRAM una paleta extendida en el slot de la pantalla y
// fondo especificados.
// Funcion NF_SetExBgPal();
void NF_SetExBgPal(u8 screen, u8 layer, u8 pal);
// Cambia la paleta extendida que usara un fondo.
// La paleta debe de estar transferida en la VRAM previamente
// Funcion NF_SetTileHflip();
void NF_SetTileHflip(u8 screen, u8 layer, u16 tile_x, u16 tile_y);
// Invierte horizontalmente el estado actual del tile seleccionado
// Los cambios no seran visibles hasta que actualices el mapa
// con la funcion NF_UpdateVramMap();
// Funcion NF_SetTileVflip();
void NF_SetTileVflip(u8 screen, u8 layer, u16 tile_x, u16 tile_y);
// Invierte verticalmente el estado actual del tile seleccionado
// Los cambios no seran visibles hasta que actualices el mapa
// con la funcion NF_UpdateVramMap();
// Funcion NF_RotateTileGfx();
void NF_RotateTileGfx(u8 slot, u16 tile, u8 rotation);
// Rota el grafico de un tile especificado. Rota el tile almacenado en un buffer de fondos
// que se encuentra en RAM. Debes especificar el SLOT del buffer, numero de tile en el buffer
// y el angulo de la rotacion.
// 1 - 90º a la derecha
// 2 - 90º a la izquierda
// 3 - 180º
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,511 @@
// NightFox LIB - Funciones 2D comunes
// Requiere DevkitARM
// Codigo por Cesar Rincon "NightFox"
// http://www.nightfoxandco.com/
// Version 20140413
// Includes devKitPro
#include <nds.h>
// Includes C
#include <stdio.h>
#include <string.h>
// Includes propios
#include "nf_basic.h"
#include "nf_2d.h"
#include "nf_tiledbg.h"
#include "nf_sprite256.h"
// Funcion NF_Set2D();
void NF_Set2D(u8 screen, u8 mode) {
if (screen == 0) { // Pantalla Superior
switch (mode) { // Selecciona modo
case 0:
videoSetMode(MODE_0_2D);
break;
case 2:
videoSetMode(MODE_2_2D);
break;
case 5:
videoSetMode(MODE_5_2D);
break;
}
} else { // Pantalla inferior
switch (mode) { // Seleccion modo
case 0:
videoSetModeSub(MODE_0_2D);
break;
case 2:
videoSetModeSub(MODE_2_2D);
break;
case 5:
videoSetModeSub(MODE_5_2D);
break;
}
}
}
// Funcion NF_ShowBg();
void NF_ShowBg(u8 screen, u8 layer) {
if (screen == 0) { // Pantalla Superior
switch (layer) { // Segun la capa
case 0:
REG_DISPCNT |= (DISPLAY_BG0_ACTIVE);
break;
case 1:
REG_DISPCNT |= (DISPLAY_BG1_ACTIVE);
break;
case 2:
REG_DISPCNT |= (DISPLAY_BG2_ACTIVE);
break;
case 3:
REG_DISPCNT |= (DISPLAY_BG3_ACTIVE);
break;
}
} else { // Pantalla Inferior
switch (layer) { // Segun la capa
case 0:
REG_DISPCNT_SUB |= (DISPLAY_BG0_ACTIVE);
break;
case 1:
REG_DISPCNT_SUB |= (DISPLAY_BG1_ACTIVE);
break;
case 2:
REG_DISPCNT_SUB |= (DISPLAY_BG2_ACTIVE);
break;
case 3:
REG_DISPCNT_SUB |= (DISPLAY_BG3_ACTIVE);
break;
}
}
}
// Funcion NF_HideBg();
void NF_HideBg(u8 screen, u8 layer) {
if (screen == 0) { // Pantalla Superior
switch (layer) { // Segun la capa
case 0:
REG_DISPCNT &= ~(DISPLAY_BG0_ACTIVE);
break;
case 1:
REG_DISPCNT &= ~(DISPLAY_BG1_ACTIVE);
break;
case 2:
REG_DISPCNT &= ~(DISPLAY_BG2_ACTIVE);
break;
case 3:
REG_DISPCNT &= ~(DISPLAY_BG3_ACTIVE);
break;
}
} else { // Pantalla Inferior
switch (layer) { // Segun la capa
case 0:
REG_DISPCNT_SUB &= ~(DISPLAY_BG0_ACTIVE);
break;
case 1:
REG_DISPCNT_SUB &= ~(DISPLAY_BG1_ACTIVE);
break;
case 2:
REG_DISPCNT_SUB &= ~(DISPLAY_BG2_ACTIVE);
break;
case 3:
REG_DISPCNT_SUB &= ~(DISPLAY_BG3_ACTIVE);
break;
}
}
}
// Funcion NF_ScrollBg();
void NF_ScrollBg(u8 screen, u8 layer, s16 x, s16 y) {
// Variables temporales
s16 sx = x;
s16 sy = y;
// Si el mapa es infinito... > 512
if (NF_TILEDBG_LAYERS[screen][layer].bgtype > 0) {
// Variables temporales de Fondos infinitos
u32 address = 0; // Puntero a la VRAM
u16 blockx = 0; // Nº de bloque en pantalla
u16 blocky = 0;
u32 mapmovex = 0; // Desplazamiento de la copia de datos (block x 2048)
u32 mapmovey = 0;
u16 rowsize = 0; // Calcula el espacio ocupado en RAM por cada fila
// 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);
}
// Ajusta el valor maximo de las variables a los limites del scroll
if (sx < 0) {
sx = 0;
}
if (sx > (NF_TILEDBG_LAYERS[screen][layer].bgwidth - 256)) {
sx = (NF_TILEDBG_LAYERS[screen][layer].bgwidth - 256);
}
if (sy < 0) {
sy = 0;
}
if (sy > (NF_TILEDBG_LAYERS[screen][layer].bgheight - 192)) {
sy = (NF_TILEDBG_LAYERS[screen][layer].bgheight - 192);
}
// Segun el tipo de mapa...
switch (NF_TILEDBG_LAYERS[screen][layer].bgtype) {
case 1: // 512x256 - Bloque A y B (32x32) + (32x32) (2kb x 2 = 4kb)
// Calcula el bloque
blockx = (x >> 8);
// Si has cambiado de bloque...
if (NF_TILEDBG_LAYERS[screen][layer].blockx != blockx) {
// Calcula el desplazamiento de datos
mapmovex = (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] + mapmovex), 4096);
// Y actualiza el bloque actual
NF_TILEDBG_LAYERS[screen][layer].blockx = blockx;
}
// Calcula la X del fondo
sx = x - (blockx << 8);
break;
case 2: // 256x512 - Bloque A (32x64) (2kb x 2 = 4kb)
// Calcula el bloque
blocky = (y >> 8);
// Si has cambiado de bloque...
if (NF_TILEDBG_LAYERS[screen][layer].blocky != blocky) {
// Calcula el desplazamiento de datos
mapmovey = (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] + mapmovey), 4096);
// Y actualiza el bloque actual
NF_TILEDBG_LAYERS[screen][layer].blocky = blocky;
}
// Calcula la X del fondo
sy = y - (blocky << 8);
break;
case 3: // >512x>512
rowsize = (((((NF_TILEDBG_LAYERS[screen][layer].bgwidth - 1) >> 8)) + 1) << 11);
// Calcula los bloques
blockx = (x >> 8);
blocky = (y >> 8);
if ( // Si se ha cambiado de bloque en alguna direccion...
(NF_TILEDBG_LAYERS[screen][layer].blockx != blockx)
||
(NF_TILEDBG_LAYERS[screen][layer].blocky != blocky)
) {
// Y el desplazamiento de datos
mapmovex = (blocky * rowsize) + (blockx << 11);
mapmovey = mapmovex + rowsize;
// Bloque A y B (32x32) + (32x32) (2kb x 2 = 4kb)
NF_DmaMemCopy((void*)address, (NF_BUFFER_BGMAP[NF_TILEDBG_LAYERS[screen][layer].bgslot] + mapmovex), 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] + mapmovey), 4096);
// Y actualiza el bloque actual
NF_TILEDBG_LAYERS[screen][layer].blockx = blockx;
NF_TILEDBG_LAYERS[screen][layer].blocky = blocky;
}
// Calcula la X e Y del fondo
sx = x - (blockx << 8);
sy = y - (blocky << 8);
break;
}
}
// Mueve el fondo usando los registros
if (screen == 0) { // Pantalla Superior
switch (layer) { // Segun la capa
case 0:
REG_BG0HOFS = sx;
REG_BG0VOFS = sy;
break;
case 1:
REG_BG1HOFS = sx;
REG_BG1VOFS = sy;
break;
case 2:
REG_BG2HOFS = sx;
REG_BG2VOFS = sy;
break;
case 3:
REG_BG3HOFS = sx;
REG_BG3VOFS = sy;
break;
}
} else {
switch (layer) { // Segun la capa
case 0:
REG_BG0HOFS_SUB = sx;
REG_BG0VOFS_SUB = sy;
break;
case 1:
REG_BG1HOFS_SUB = sx;
REG_BG1VOFS_SUB = sy;
break;
case 2:
REG_BG2HOFS_SUB = sx;
REG_BG2VOFS_SUB = sy;
break;
case 3:
REG_BG3HOFS_SUB = sx;
REG_BG3VOFS_SUB = sy;
break;
}
}
}
// Funcion NF_MoveSprite();
void NF_MoveSprite(u8 screen, u8 id, s16 x, s16 y) {
NF_SPRITEOAM[screen][id].x = x; // Coordenada X
NF_SPRITEOAM[screen][id].y = y; // Coordenada Y
}
// Funcion NF_SpriteLayer();
void NF_SpriteLayer(u8 screen, u8 id, u8 layer) {
NF_SPRITEOAM[screen][id].layer = layer; // Capa sobre la que esta el sprite
}
// Funcion NF_ShowSprite();
void NF_ShowSprite(u8 screen, u8 id, bool show) {
NF_SPRITEOAM[screen][id].hide = !show; // Muestra o oculta el sprite
}
// Funcion NF_HflipSprite();
void NF_HflipSprite(u8 screen, u8 id, bool hflip) {
NF_SPRITEOAM[screen][id].hflip = hflip; // Volteado horizontal;
}
// Funcion NF_GetSpriteHflip();
bool NF_GetSpriteHflip(u8 screen, u8 id) {
return NF_SPRITEOAM[screen][id].hflip;
}
// Funcion NF_VflipSprite();
void NF_VflipSprite(u8 screen, u8 id, bool vflip) {
NF_SPRITEOAM[screen][id].vflip = vflip; // Volteado vertical;
}
// Funcion NF_GetSpriteVflip();
bool NF_GetSpriteVflip(u8 screen, u8 id) {
return NF_SPRITEOAM[screen][id].vflip;
}
// Funcion NF_SpriteFrame();
void NF_SpriteFrame(u8 screen, u8 id, u16 frame) {
// Verifica el rango de Id's de Sprites
if ((id < 0) || (id > 127)) {
NF_Error(106, "Sprite", 127);
}
// Verifica el rango de frames del Sprite
if (frame > NF_SPRITEOAM[screen][id].lastframe) {
NF_Error(106, "Sprite frame", NF_SPRITEOAM[screen][id].lastframe);
}
// Verifica si el frame necesita ser actualizado
if (NF_SPRITEOAM[screen][id].frame != frame) {
// Si debes de copiar el nuevo frame desde la RAM a la VRAM...
if (NF_SPR256VRAM[screen][NF_SPRITEOAM[screen][id].gfxid].keepframes) {
// Variables temporales
char* source; // Puntero de origen
u32 destination = 0; // Puntero de destino
u16 ramid = 0; // Slot de RAM donde se encuentra el Gfx
// Calcula el origen y destino del nuevo frame a copiar
ramid = NF_SPR256VRAM[screen][NF_SPRITEOAM[screen][id].gfxid].ramid;
source = NF_BUFFER_SPR256GFX[ramid] + (NF_SPRITEOAM[screen][id].framesize * frame);
destination = NF_SPR256VRAM[screen][NF_SPRITEOAM[screen][id].gfxid].address;
// Copialo
NF_DmaMemCopy((void*)destination, source, NF_SPRITEOAM[screen][id].framesize);
} else { // Si todos los frames ya estan en VRAM...
// Calcula la direccion del Gfx del frame
u32 address = 0;
address = NF_SPR256VRAM[screen][NF_SPRITEOAM[screen][id].gfxid].address + (NF_SPRITEOAM[screen][id].framesize * frame);
NF_SPRITEOAM[screen][id].gfx = (u32*)address;
}
// Almacena el frame actual
NF_SPRITEOAM[screen][id].frame = frame;
}
}
// Funcion NF_EnableSpriteRotScale();
void NF_EnableSpriteRotScale(u8 screen, u8 sprite, u8 id, bool doublesize) {
// Verifica el rango de Id's de Sprites
if ((sprite < 0) || (sprite > 127)) {
NF_Error(106, "Sprite", 127);
}
// Verifica el rango de Id's de Rotacion
if ((id < 0) || (id > 31)) {
NF_Error(106, "RotScale", 127);
}
// Verifica si el Sprite esta creado
if (!NF_SPRITEOAM[screen][sprite].created) {
char text[4];
sprintf(text, "%d", screen);
NF_Error(112, text, sprite);
}
NF_SPRITEOAM[screen][sprite].rot = id; // Id de rotacion (-1 ninguno) (0 - 31 Id de rotacion)
NF_SPRITEOAM[screen][sprite].doublesize = doublesize; // Usar el "double size" al rotar ? ("NO" por defecto)
}
// Funcion NF_DisableSpriteRotScale();
void NF_DisableSpriteRotScale(u8 screen, u8 sprite) {
// Verifica el rango de Id's de Sprites
if ((sprite < 0) || (sprite > 127)) {
NF_Error(106, "Sprite", 127);
}
// Verifica si el Sprite esta creado
if (!NF_SPRITEOAM[screen][sprite].created) {
char text[4];
sprintf(text, "%d", screen);
NF_Error(112, text, sprite);
}
NF_SPRITEOAM[screen][sprite].rot = -1; // Id de rotacion (-1 ninguno) (0 - 31 Id de rotacion)
NF_SPRITEOAM[screen][sprite].doublesize = false; // Usar el "double size" al rotar ? ("NO" por defecto)
}
// Funcion NF_SpriteRotScale();
void NF_SpriteRotScale(u8 screen, u8 id, s16 angle, u16 sx, u16 sy) {
// Variables temporales
s16 in = 0; // Angulo dado
s16 out = 0; // Angulo convertido
in = angle;
// Limites del angulo
if (in < -512) {
in += 512;
}
if (in > 512) {
in -= 512;
}
// Limites del factor X
if (sx < 0) {
sx = 0;
}
if (sx > 512) {
sx = 512;
}
// Limites del factor Y
if (sy < 0) {
sy = 0;
}
if (sy > 512) {
sy = 512;
}
// Si es un numero negativo...
if (in < 0) {
in = -in; // Pasa a positivo (para poder hacer el bitshift)
out = (in << 6); // (in * 64); Pasa de base 512 a base 32768
// Dejalo en positivo para que <0 gire a la izquierda
} else {
out = (in << 6);
out = -out; // Pasalo a negativo para que >0 gire a la derecha
}
// Actualiza el RotScale del OAM
if (screen == 0) {
oamRotateScale(&oamMain, id, out, (512 - sx), (512 - sy));
} else {
oamRotateScale(&oamSub, id, out, (512 - sx), (512 - sy));
}
}

View File

@ -0,0 +1,133 @@
// NightFox LIB - Funciones 2D comunes
// Requiere DevkitARM
// Codigo por Cesar Rincon "NightFox"
// http://www.nightfoxandco.com/
// Version 20140413
// Includes devKitPro
#include <nds.h>
// Includes C
#include <stdio.h>
#include <string.h>
// Includes propios
#include "nf_basic.h"
#include "nf_3d.h"
#include "nf_2d.h"
// Funcion NF_Set3D();
void NF_Set3D(u8 screen, u8 mode) {
// Especifica en que pantalla estara el main engine (unico que puede usar 3D)
if (screen == 0) {
lcdMainOnTop();
} else {
lcdMainOnBottom();
}
// Selecciona modo 3D
switch (mode) {
case 0:
videoSetMode(MODE_0_3D);
break;
case 2:
videoSetMode(MODE_2_3D);
break;
case 5:
videoSetMode(MODE_5_3D);
break;
}
}
// Funcion NF_InitOpenGL();
void NF_InitOpenGL(void) {
// Inicializa el OpenGL de Libnds
glInit();
// Define el tamaño de la ventana 3D (toda la pantalla)
glViewport(0, 0, 255, 191);
// Configura la matriz de proyeccion
glMatrixMode(GL_PROJECTION); // Selecciona la matriz
glLoadIdentity(); // Y reseteala
// Ajusta OpenGL para proyeccion Ortografica
glOrthof32(0, 256, 192, 0, 1024, -1024);
// Configura la matriz de visualizacion de modelos
glMatrixMode(GL_MODELVIEW); // Selecciona la matriz
glLoadIdentity(); // Y reseteala
// Por defecto, todos los poligonos son opacos
glPolyFmt(POLY_ALPHA(31) | POLY_CULL_NONE);
// Configura el fondo
glClearColor(0, 0, 0, 0); // Fondo transparente
glClearDepth(0x7FFF); // Define la distancia de vision
// Configura la iluminacion global
glColor(RGB15(31, 31, 31));
// Habilita las texturas
glEnable(GL_TEXTURE_2D | GL_BLEND);
// Habilita la capa de dibujado
NF_ShowBg(0, 0);
}
// Funcion NF_GetTextureSize();
u16 NF_GetTextureSize(u16 textel) {
// Variables
u16 size = 0;
// Devuelve el tamaño del textel, segun su base2
switch (textel) {
case 8:
size = 0;
break;
case 16:
size = 1;
break;
case 32:
size = 2;
break;
case 64:
size = 3;
break;
case 128:
size = 4;
break;
case 256:
size = 5;
break;
case 512:
size = 6;
break;
case 1024:
size = 7;
break;
default:
size = 255;
break;
}
// Devuelve el valor
return size;
}

View File

@ -0,0 +1,674 @@
// NightFox LIB - Funciones de Fondos Affine
// Requiere DevkitARM
// Codigo por Cesar Rincon "NightFox"
// http://www.nightfoxandco.com/
// Version 20140413
// Includes devKitPro
#include <nds.h>
#include <filesystem.h>
#include <fat.h>
// Includes C
#include <stdio.h>
#include <string.h>
#include <unistd.h>
// Includes propios
#include "nf_basic.h"
#include "nf_2d.h"
#include "nf_tiledbg.h"
#include "nf_affinebg.h"
// Estructura para almacenar los parametros de los fondos Affine
NF_TYPE_AFFINE_BG NF_AFFINE_BG[2][4];
// Funcion NF_InitTiledBgSys();
void NF_InitAffineBgSys(u8 screen) {
// Variables
u8 n = 0;
// Define los 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)
vramSetBankA(VRAM_A_MAIN_BG); // Banco A de la VRAM para fondos (128kb)
memset((void*)0x06000000, 0, 131072); // Borra el contenido del banco A
for (n = 0; n < 4; n ++) { // Oculta todas las 4 capas
NF_HideBg(0, n);
}
} else {
// Si es la pantalla 1 (Inferior, Sub engine)
vramSetBankC(VRAM_C_SUB_BG); // Banco C de la VRAM para fondos (128kb)
memset((void*)0x06200000, 0, 131072); // Borra el contenido del banco C
for (n = 0; n < 4; n ++) { // Oculta todas las 4 capas
NF_HideBg(1, n);
}
}
}
// Funcion NF_LoadAffineBg();
void NF_LoadAffineBg(const char* file, const char* name, u16 width, u16 height) {
// Verifica si el fondo cumple las medidas correctas
if (((width == 256) && (height == 256)) || ((width == 512) && (height == 512))) {
// Medida Ok
} else {
// Error de tamaño
NF_Error(117, name, 0);
}
// 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);
}
// 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
sprintf(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
// swiWaitForVBlank(); // Espera al cierre del archivo (Usar en caso de corrupcion de datos)
// Verifica el tamaño del tileset (Menos de 256 tiles)
if (NF_TILEDBG[slot].tilesize > 16384) NF_Error(117, name, 0);
// Carga el archivo .MAP
sprintf(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) >> 10) + 1) << 10); // Ajusta el tamaño a bloques de 1kb
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
// swiWaitForVBlank(); // Espera al cierre del archivo (Usar en caso de corrupcion de datos)
// Carga el archivo .PAL
sprintf(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
sprintf(NF_TILEDBG[slot].name, "%s", name);
// Y las medidas
NF_TILEDBG[slot].width = width;
NF_TILEDBG[slot].height = height;
}
// Funcion NF_UnloadAffineBg();
void NF_UnloadAffineBg(const char* name) {
NF_UnloadTiledBg(name);
}
// Funcion NF_CreateAffineBg();
void NF_CreateAffineBg(u8 screen, u8 layer, const char* name, u8 wrap) {
// Variables
u8 n = 0; // Bucle
u8 slot = 255; // Slot seleccionado
char bg[32]; // Nombre
// Verifica la capa de destino
if ((layer != 2) && (layer != 3)) NF_Error(118, name, 0);
// Busca el fondo solicitado
sprintf(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
n = 0;
// ( 256 x 256 )
if ((NF_TILEDBG[slot].width == 256) && (NF_TILEDBG[slot].height == 256)) {
NF_TILEDBG_LAYERS[screen][layer].mapwidth = 256;
NF_TILEDBG_LAYERS[screen][layer].mapheight = 256;
NF_TILEDBG_LAYERS[screen][layer].bgtype = 11;
n = 1;
}
// ( 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 = 12;
n = 1;
}
// Verifica el tamaño del tileset (Menos de 256 tiles)
if (NF_TILEDBG[slot].tilesize > 16384) n = 0;
// Si el fondo es de una medida incorrecta...
if (n == 0) NF_Error(117, name, 0);
// 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;
// Calcula los bloques para mapas necesarios
mapblocks = ((NF_TILEDBG[slot].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
s32 bg_size = 0;
// 256x256
if ((NF_TILEDBG_LAYERS[screen][layer].mapwidth == 256) && (NF_TILEDBG_LAYERS[screen][layer].mapheight == 256)) {
bg_size = BG_RS_32x32;
}
// 512x512
if ((NF_TILEDBG_LAYERS[screen][layer].mapwidth == 512) && (NF_TILEDBG_LAYERS[screen][layer].mapheight == 512)) {
bg_size = BG_RS_64x64;
}
// Decide si se activa o no el WRAP
u32 wrap_mode = 0;
if (wrap == 0) {
wrap_mode = BG_WRAP_OFF;
} else {
wrap_mode = BG_WRAP_ON;
}
// Crea el fondo segun la pantalla, capa y demas caracteristicas dadas
// REG_BG0CNT <- Carracteristicas del fondo
if (screen == 0) {
switch (layer) {
case 2:
REG_BG2CNT = BgType_Rotation | bg_size | BG_PRIORITY_2 | BG_COLOR_256 | BG_TILE_BASE(basetiles) | BG_MAP_BASE(basemap) | wrap_mode;
break;
case 3:
REG_BG3CNT = BgType_Rotation | bg_size | BG_PRIORITY_3 | BG_COLOR_256 | BG_TILE_BASE(basetiles) | BG_MAP_BASE(basemap) | wrap_mode;
break;
}
} else {
switch (layer) {
case 2:
REG_BG2CNT_SUB = BgType_Rotation | bg_size | BG_PRIORITY_2 | BG_COLOR_256 | BG_TILE_BASE(basetiles) | BG_MAP_BASE(basemap) | wrap_mode;
break;
case 3:
REG_BG3CNT_SUB = BgType_Rotation | bg_size | BG_PRIORITY_3 | BG_COLOR_256 | BG_TILE_BASE(basetiles) | BG_MAP_BASE(basemap) | wrap_mode;
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);
}
NF_DmaMemCopy((void*)address, NF_BUFFER_BGMAP[slot], NF_TILEDBG[slot].mapsize);
// Tranfiere la Paleta a VRAM
if (screen == 0) {
address = (0x05000000);
NF_DmaMemCopy((void*)address, NF_BUFFER_BGPAL[slot], NF_TILEDBG[slot].palsize);
} else { // Paletas de la pantalla 1 (VRAM_H)
address = (0x05000400);
NF_DmaMemCopy((void*)address, NF_BUFFER_BGPAL[slot], NF_TILEDBG[slot].palsize);
}
// 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 ?
// Resetea los parametros del affine
NF_AffineBgTransform(screen, layer, 256, 256, 0, 0);
NF_AffineBgMove(screen, layer, 0, 0, 0);
// Haz visible el fondo creado
NF_ShowBg(screen, layer);
}
// Funcion NF_DeleteAffineBg();
void NF_DeleteAffineBg(u8 screen, u8 layer) {
// Verifica que el fondo esta creado
if (!NF_TILEDBG_LAYERS[screen][layer].created) {
char text[32];
sprintf(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
// 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_AffineBgTransform();
void NF_AffineBgTransform(u8 screen, u8 layer, s32 x_scale, s32 y_scale, s32 x_tilt, s32 y_tilt) {
if (screen == 0) {
switch (layer) {
case 2:
REG_BG2PA = x_scale;
REG_BG2PB = x_tilt;
REG_BG2PC = y_tilt;
REG_BG2PD = y_scale;
break;
case 3:
REG_BG3PA = x_scale;
REG_BG3PB = x_tilt;
REG_BG3PC = y_tilt;
REG_BG3PD = y_scale;
break;
}
} else {
switch (layer) {
case 2:
REG_BG2PA_SUB = x_scale;
REG_BG2PB_SUB = x_tilt;
REG_BG2PC_SUB = y_tilt;
REG_BG2PD_SUB = y_scale;
break;
case 3:
REG_BG3PA_SUB = x_scale;
REG_BG3PB_SUB = x_tilt;
REG_BG3PC_SUB = y_tilt;
REG_BG3PD_SUB = y_scale;
break;
}
}
// Registra los valores asignados
NF_AFFINE_BG[screen][layer].x_scale = x_scale;
NF_AFFINE_BG[screen][layer].x_tilt = x_tilt;
NF_AFFINE_BG[screen][layer].y_tilt = y_tilt;
NF_AFFINE_BG[screen][layer].y_scale = y_scale;
}
// Funcion NF_AffineBgMove();
void NF_AffineBgMove(u8 screen, u8 layer, s32 x, s32 y, s32 angle) {
// Funcion de rotacion basada en la original de Libnds
// creada por Dovoto y Wintermute.
// Variables
s32 pa = 0; // x_scale
s32 pb = 0; // x_tilt
s32 pc = 0; // y_tilt;
s32 pd = 0; // y_scale;
s16 angle_sin = 0; // Seno
s16 angle_cos = 0; // Coseno
s16 in = 0; // Angulo dado
s16 out = 0; // Angulo convertido
s32 pos_x = 0; // Posicion X del fondo
s32 pos_y = 0; // Posicion Y del fondo
in = angle;
// Limites del angulo
if (in < -2048) {
in += 2048;
}
if (in > 2048) {
in -= 2048;
}
// Si es un numero negativo...
if (in < 0) {
in = -in; // Pasa a positivo (para poder hacer el bitshift)
out = (in << 4); // (in * 16); Pasa de base 2048 a base 32768
// Dejalo en positivo para que <0 gire a la izquierda
} else {
out = (in << 4);
out = -out; // Pasalo a negativo para que >0 gire a la derecha
}
// Calcula los senos y cosenos
angle_sin = sinLerp(out);
angle_cos = cosLerp(out);
// Calcula la matriz de transformacion
pa = ( angle_cos * NF_AFFINE_BG[screen][layer].x_scale ) >> 12;
pb = (-angle_sin * NF_AFFINE_BG[screen][layer].x_scale ) >> 12;
pc = ( angle_sin * NF_AFFINE_BG[screen][layer].y_scale ) >> 12;
pd = ( angle_cos * NF_AFFINE_BG[screen][layer].y_scale ) >> 12;
// Aplica los parametros de tranformacion
NF_AffineBgTransform(screen, layer, pa, pd, pb, pc);
// Ahora calcula la posicion del fondo
pos_x = ((x << 8) - (((pa * (NF_AFFINE_BG[screen][layer].x_center << 8)) + (pb * (NF_AFFINE_BG[screen][layer].y_center << 8))) >> 8));
pos_y = ((y << 8) - (((pc * (NF_AFFINE_BG[screen][layer].x_center << 8)) + (pd * (NF_AFFINE_BG[screen][layer].y_center << 8))) >> 8));
// Aplica la posicion del centro
if (screen == 0) {
switch (layer) {
case 2:
REG_BG2X = pos_x;
REG_BG2Y = pos_y;
break;
case 3:
REG_BG3X = pos_x;
REG_BG3Y = pos_y;
break;
}
} else {
switch (layer) {
case 2:
REG_BG2X_SUB = pos_x;
REG_BG2Y_SUB = pos_y;
break;
case 3:
REG_BG3X_SUB = pos_x;
REG_BG3Y_SUB = pos_y;
break;
}
}
// Guarda los parametros
NF_AFFINE_BG[screen][layer].angle = out;
NF_AFFINE_BG[screen][layer].x = x;
NF_AFFINE_BG[screen][layer].y = y;
}
// Funcion NF_AffineBgCenter();
void NF_AffineBgCenter(u8 screen, u8 layer, s32 x, s32 y) {
NF_AFFINE_BG[screen][layer].x_center = x;
NF_AFFINE_BG[screen][layer].y_center = y;
}

View File

@ -0,0 +1,303 @@
// NightFox LIB - Funciones basicas y de Debug
// Requiere DevkitARM
// Codigo por Cesar Rincon "NightFox"
// http://www.nightfoxandco.com/
// Version
// Includes devKitPro
#include <nds.h>
#include <filesystem.h>
#include <fat.h>
// Includes C
#include <stdio.h>
#include <string.h>
#include <unistd.h>
// Includes propios
#include "nf_basic.h"
#include "nf_defines.h"
// Define la variable global NF_ROOTFOLDER
char NF_ROOTFOLDER[32];
// Funcion NF_Error();
void NF_Error(u16 code, const char* text, u32 value) {
consoleDemoInit(); // Inicializa la consola de texto
consoleClear(); // Borra la pantalla
setBrightness(3, 0); // Restaura el brillo
u32 n = 0; // Variables de uso general
// Captura el codigo de error
switch (code) {
case 101: // Fichero no encontrado
iprintf("File %s not found.\n", text);
break;
case 102: // Memoria insuficiente
iprintf("Out of memory.\n");
iprintf("%d bytes\n", (int)value);
iprintf("can't be allocated.\n");
break;
case 103: // No quedan Slots libres
iprintf("Out of %s slots.\n", text);
iprintf("All %d slots are in use.\n", (int)value);
break;
case 104: // Fondo no encontrado
iprintf("Tiled Bg %s\n", text);
iprintf("not found.\n");
break;
case 105: // Fondo no creado
iprintf("Background number %d\n", (int)value);
iprintf("on screen %s is\n", text);
iprintf("not created.\n");
break;
case 106: // Fuera de rango
iprintf("%s Id out\n", text);
iprintf("of range (%d max).\n", (int)value);
break;
case 107: // Insuficientes bloques contiguos en VRAM (Tiles)
n = (int)((value * 16384) / 1024);
iprintf("Can't allocate %d\n", (int)value);
iprintf("blocks of tiles for\n");
iprintf("%s background\n", text);
iprintf("Free %dkb of VRAM or try to\n", (int)n);
iprintf("reload all Bg's again\n");
break;
case 108: // Insuficientes bloques contiguos en VRAM (Maps)
n = (int)((value * 2048) / 1024);
iprintf("Can't allocate %d\n", (int)value);
iprintf("blocks of maps for\n");
iprintf("%s background\n", text);
iprintf("Free %dkb of VRAM or try to\n", (int)n);
iprintf("reload all Bg's again\n");
break;
case 109: // Id ocupada
iprintf("%s Id.%d\n", text, (int)value);
iprintf("is already in use.\n");
break;
case 110: // Id no cargada
iprintf("%s\n", text);
iprintf("%d not loaded.\n", (int)value);
break;
case 111: // Id no en VRAM
iprintf("%s\n", text);
iprintf("%d not in VRAM.\n", (int)value);
break;
case 112: // Sprite no creado
iprintf("Sprite number %d\n", (int)value);
iprintf("on screen %s is\n", text);
iprintf("not created.\n");
break;
case 113: // Memoria VRAM insuficiente
iprintf("Out of VRAM.\n");
iprintf("%d bytes for %s\n", (int)value, text);
iprintf("can't be allocated.\n");
break;
case 114: // La capa de Texto no existe
iprintf("Text layer on screen\n");
iprintf("nº %d don't exist.\n", (int)value);
break;
case 115: // Medidas del fondo no compatibles (no son multiplos de 256)
iprintf("Tiled Bg %s\n", text);
iprintf("has wrong size.\n");
iprintf("Your bg sizes must be\n");
iprintf("dividable by 256 pixels.\n");
break;
case 116: // Archivo demasiado grande
iprintf("File %s\n", text);
iprintf("is too big.\n");
iprintf("Max size for\n");
iprintf("file is %dkb.\n", (int)(value >> 10));
break;
case 117: // Medidas del fondo affine no compatibles (Solo se admiten 256x256 y 512x512)
iprintf("Affine Bg %s\n", text);
iprintf("has wrong size.\n");
iprintf("Your bg sizes must be\n");
iprintf("256x256 or 512x512 and\n");
iprintf("with 256 tiles or less.\n");
break;
case 118: // Medidas del fondo affine no compatibles (Solo se admiten 256x256 y 512x512)
iprintf("Affine Bg %s\n", text);
iprintf("only can be created\n");
iprintf("on layers 2 or 3.\n");
break;
case 119: // Tamaño de la textura ilegal.
iprintf("Texture id.%d illegal size.\n", (int)value);
iprintf("Only power of 2 sizes can\n");
iprintf("be used (8 to 1024).\n");
break;
case 120: // Tamaño de la Sprite ilegal.
iprintf("Sprite id.%d illegal size.\n", (int)value);
iprintf("8x8 Sprites can't be used\n");
iprintf("in 1D_128 mode.\n");
break;
}
iprintf("Error code %d.\n", (int)code); // Imprime el codigo de error
// Deten la ejecucion del programa
while (1) {
swiWaitForVBlank();
}
}
// Funcion NF_SetRootFolder();
void NF_SetRootFolder(const char* folder) {
if (strcmp(folder, "NITROFS") == 0) { // Si se debe iniciar el modo NitroFS y FAT
// Define NitroFS como la carpeta inicial
sprintf(NF_ROOTFOLDER, "%s", "");
// Intenta inicializar NitroFS
if(nitroFSInit(NULL)) {
// NitroFS ok
// Si es correcto, cambia al ROOT del NitroFS
chdir("nitro:/");
} else {
// Fallo. Deten el programa
consoleDemoInit(); // Inicializa la consola de texto
if (NF_GetLanguage() == 5) {
iprintf("Error iniciando NitroFS.\n");
iprintf("Programa detenido.\n\n");
iprintf("Verifica que tu flashcard\n");
iprintf("es compatible con Argv.\n");
iprintf("Si no lo es, intenta usar el\n");
iprintf("Homebrew Menu para ejecutarla.\n\n");
} else {
iprintf("NitroFS Init Error.\n");
iprintf("Abnormal termination.\n\n");
iprintf("Check if your flashcard is\n");
iprintf("Argv compatible.\n");
iprintf("If not, try to launch the ROM\n");
iprintf("using the Homebrew Menu.\n\n");
}
iprintf("http://sourceforge.net/projects/devkitpro/files/hbmenu/");
// Bucle infinito. Fin del programa
while(1) {
swiWaitForVBlank();
}
}
} else { // Si se debe iniciar solo la FAT
// Define la carpeta inicial de la FAT
sprintf(NF_ROOTFOLDER, "%s", folder);
// Intenta inicializar la FAT
if (fatInitDefault()) {
// Si es correcto, cambia al ROOT del FAT
chdir("fat:/");
} else {
// Fallo. Deten el programa
consoleDemoInit(); // Inicializa la consola de texto
if (NF_GetLanguage() == 5) {
iprintf("Error iniciando FAT.\n");
iprintf("Programa detenido.\n\n");
iprintf("Verifica que tu flashcard es\n");
iprintf("compatible con DLDI y la ROM\n");
iprintf("este parcheada correctamente.\n");
} else {
iprintf("FAT Init Error.\n");
iprintf("Abnormal termination.\n\n");
iprintf("Check if your flashcard is\n");
iprintf("DLDI compatible and the ROM\n");
iprintf("is correctly patched.\n");
}
// Bucle infinito. Fin del programa
while(1) {
swiWaitForVBlank();
}
}
}
}
// Funcion NF_DmaMemCopy();
void NF_DmaMemCopy(void* destination, const void* source, u32 size) {
// Funcion basada en la documentacion de Coranac
// http://www.coranac.com/2009/05/dma-vs-arm9-fight/
// Datos de origen y destino
u32 src = (u32)source;
u32 dst = (u32)destination;
// Verifica si los datos estan correctamente alineados
if ((src | dst) & 1) {
// No estan alineados para un DMA copy
// Se realiza un copia con el memcpy();
memcpy(destination, source, size);
} else {
// Estan alineados correctamente
// Espera a que el canal 3 de DMA este libre
while (dmaBusy(3));
// Manda el cache a la memoria
DC_FlushRange(source, size);
// Dependiendo de la alineacion de datos, selecciona el metodo de copia
if ((src | dst | size) & 3) {
// Copia de 16 bits
dmaCopyHalfWords(3, source, destination, size);
} else {
// Copia de 32 bits
dmaCopyWords(3, source, destination, size);
}
// Evita que el destino sea almacenado en cache
DC_InvalidateRange(destination, size);
}
}
// Funcion NF_GetLanguage();
u8 NF_GetLanguage(void) {
// Asegurate que el valor devuelto corresponde a los
// contenidos en los BITS 0, 1 y 2 de la direccion de memoria
return (NF_UDATA_LANG & 0x07);
}

View File

@ -0,0 +1,603 @@
// NightFox LIB - Include de funciones de fondos en modo Bitmap
// Requiere DevkitARM
// Codigo por Cesar Rincon "NightFox"
// http://www.nightfoxandco.com/
// Version 20140413
// Includes devKitPro
#include <nds.h>
#include <filesystem.h>
#include <fat.h>
// Includes C
#include <stdio.h>
#include <string.h>
#include <unistd.h>
// Includes propios
#include "nf_bitmapbg.h"
#include "nf_basic.h"
#include "nf_2d.h"
// Define los Buffers para almacenar datos de 16 bits
NF_TYPE_BG16B_INFO NF_BG16B[NF_SLOTS_BG16B]; // Fondos RAW de 16 bits
// Backbuffer de 16 bits de cada pantalla
u16* NF_16BITS_BACKBUFFER[2];
// Define los Buffers para almacenar datos de 8 bits
NF_TYPE_BG8B_INFO NF_BG8B[NF_SLOTS_BG8B]; // Fondos indexados de 8 bits
// Backbuffer de 8 bits de cada pantalla
NF_TYPE_BB8B_INFO NF_8BITS_BACKBUFFER[2];
// Funcion NF_Init16bitsBgBuffers();
void NF_Init16bitsBgBuffers(void) {
// Variables locales
u8 n = 0;
for (n = 0; n < NF_SLOTS_BG16B; n ++) {
NF_BG16B[n].buffer = NULL;
NF_BG16B[n].size = 0;
NF_BG16B[n].inuse = false;
NF_BG16B[n].width = 0;
NF_BG16B[n].height = 0;
}
}
// Funcion NF_Reset16bitsBgBuffers();
void NF_Reset16bitsBgBuffers(void) {
// Variables locales
u8 n = 0;
// Libera la RAM
for (n = 0; n < NF_SLOTS_BG16B; n ++) {
free(NF_BG16B[n].buffer);
}
// Reinicia los datos
NF_Init16bitsBgBuffers();
}
// Funcion NF_Init16bitsBackBuffer();
void NF_Init16bitsBackBuffer(u8 screen) {
u8 scr = screen;
if (scr > 1) scr = 1;
NF_16BITS_BACKBUFFER[scr] = NULL;
}
// Funcion NF_Enable16bitsBackBuffer();
void NF_Enable16bitsBackBuffer(u8 screen) {
u8 scr = screen;
if (scr > 1) scr = 1;
// Resetea el buffer
free(NF_16BITS_BACKBUFFER[scr]);
NF_16BITS_BACKBUFFER[scr] = NULL;
// Asignale 128kb de memoria
NF_16BITS_BACKBUFFER[scr] = (u16*) calloc(65536, sizeof(u16));
// Devuelve error si no hay suficiente memoria
if (NF_16BITS_BACKBUFFER[scr] == NULL) NF_Error(102, NULL, 131072);
}
// Funcion NF_Disble16bitsBackBuffer();
void NF_Disble16bitsBackBuffer(u8 screen) {
u8 scr = screen;
if (scr > 1) scr = 1;
// Resetea el buffer
free(NF_16BITS_BACKBUFFER[scr]);
NF_16BITS_BACKBUFFER[scr] = NULL;
}
// Funcion NF_Flip16bitsBackBuffer();
void NF_Flip16bitsBackBuffer(u8 screen) {
// Copia el contenido del Backbuffer a la VRAM
// de la pantalla solicitada
if (screen == 0) {
NF_DmaMemCopy((void*)0x06000000, NF_16BITS_BACKBUFFER[0], 131072);
} else {
NF_DmaMemCopy((void*)0x06200000, NF_16BITS_BACKBUFFER[1], 131072);
}
}
// Funcion NF_InitBitmapBgSys();
void NF_InitBitmapBgSys(u8 screen, u8 mode) {
// Habilita la capa 3 de la pantalla indicada en modo BITMAP
// Variables locales
u8 n = 0;
// Inicializa la VRAM
if (screen == 0) {
vramSetBankA(VRAM_A_MAIN_BG); // Banco A de la VRAM para fondos (128kb)
memset((void*)0x06000000, 0, 131072); // Borra el contenido del banco A
// Oculta todas las capas
for (n = 0; n < 4; n ++) { // Oculta todas las 4 capas
NF_HideBg(0, n);
}
} else {
vramSetBankC(VRAM_C_SUB_BG); // Banco C de la VRAM para fondos (128kb)
memset((void*)0x06200000, 0, 131072); // Borra el contenido del banco C
// Oculta todas las capas
for (n = 0; n < 4; n ++) { // Oculta todas las 4 capas
NF_HideBg(1, n);
}
}
// Inicializa la capa de dibujado
if (screen == 0) {
if (mode == 0) { // Modo 8 bits (Capas 1 y 3)
REG_BG3CNT = BG_PRIORITY_3 | BG_BMP_BASE(4) | BG_BMP8_256x256;
REG_BG2CNT = BG_PRIORITY_2 | BG_BMP_BASE(0) | BG_BMP8_256x256;
} else { // Modo 16 bits
REG_BG3CNT = BG_PRIORITY_3 | BG_BMP_BASE(0) | BG_BMP16_256x256;
}
// Resetea los registros de RotScale (Capa 3)
REG_BG3PA = (1 << 8);
REG_BG3PB = 0;
REG_BG3PC = 0;
REG_BG3PD = (1 << 8);
NF_ScrollBg(0, 3, 0, 0); // Posicionala en 0, 0
NF_ShowBg(0, 3); // Muestra la capa 3
// Resetea los registros de RotScale (Capa 2)
if (mode == 0) {
REG_BG2PA = (1 << 8);
REG_BG2PB = 0;
REG_BG2PC = 0;
REG_BG2PD = (1 << 8);
NF_ScrollBg(0, 2, 0, 0); // Posicionala en 0, 0
NF_ShowBg(0, 2); // Muestra la capa 2
}
} else {
if (mode == 0) { // Modo 8 bits (Capas 2 y 3)
REG_BG3CNT_SUB = BG_PRIORITY_3 | BG_BMP_BASE(4) | BG_BMP8_256x256;
REG_BG2CNT_SUB = BG_PRIORITY_2 | BG_BMP_BASE(0) | BG_BMP8_256x256;
} else { // Modo 16 bits
REG_BG3CNT_SUB = BG_PRIORITY_3 | BG_BMP_BASE(0) | BG_BMP16_256x256;
}
// Resetea los registros de RotScale (Capa 3)
REG_BG3PA_SUB = (1 << 8);
REG_BG3PB_SUB = 0;
REG_BG3PC_SUB = 0;
REG_BG3PD_SUB = (1 << 8);
NF_ScrollBg(1, 3, 0, 0); // Posicionala en 0, 0
NF_ShowBg(1, 3); // Muestra la capa 3
// Resetea los registros de RotScale (Capa 2)
if (mode == 0) {
REG_BG2PA_SUB = (1 << 8);
REG_BG2PB_SUB = 0;
REG_BG2PC_SUB = 0;
REG_BG2PD_SUB = (1 << 8);
NF_ScrollBg(1, 2, 0, 0); // Posicionala en 0, 0
NF_ShowBg(1, 2); // Muestra la capa 2
}
}
}
// Funcion NF_Load16bitsBg();
void NF_Load16bitsBg(const char* file, u8 slot) {
// Llama a la funcion de carga de datos de imagen de 16bits
NF_Load16bImgData(file, slot, 256, 256, 0);
}
// Funcion NF_Load16bitsImage();
void NF_Load16bitsImage(const char* file, u8 slot, u16 size_x, u16 size_y) {
// Llama a la funcion de carga de datos de imagen de 16bits
NF_Load16bImgData(file, slot, size_x, size_y, 1);
}
// Funcion NF_Load16bImgData();
void NF_Load16bImgData(const char* file, u8 slot, u16 x, u16 y, u8 type) {
// Verifica el rango de Id's
if ((slot < 0) || (slot >= NF_SLOTS_BG16B)) {
if (type == 0) {
NF_Error(106, "16 Bits Bg's", NF_SLOTS_BG16B);
} else {
NF_Error(106, "16 Bits Image", NF_SLOTS_BG16B);
}
}
// Vacia los buffers que se usaran
free(NF_BG16B[slot].buffer);
NF_BG16B[slot].buffer = NULL;
// Declara los punteros a los ficheros
FILE* file_id;
// Variable para almacenar el path al archivo
char filename[256];
// Variable para el tamaño de archivo
u32 size = 0;
// Carga el archivo .IMG
sprintf(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);
size = ftell(file_id);
rewind(file_id);
// Si excede del tamaño maximo (128kb), error
if (size > 131072) NF_Error(116, filename, 131072);
// Reserva el espacio en RAM
NF_BG16B[slot].buffer = (u16*) calloc ((size >> 1), sizeof(u16));
if (NF_BG16B[slot].buffer == NULL) { // Si no hay suficiente RAM libre
NF_Error(102, NULL, size);
}
// Lee el archivo y ponlo en la RAM
fread(NF_BG16B[slot].buffer, 1, size, file_id);
} else { // Si el archivo no existe...
NF_Error(101, filename, 0);
}
fclose(file_id); // Cierra el archivo
// Asegurate que el alpha bit (BIT 15) esta marcado
u32 n = 0;
for (n = 0; n < (size >> 1); n ++) {
NF_BG16B[slot].buffer[n] |= BIT(15);
}
// Guarda los parametros del fondo
NF_BG16B[slot].size = size; // Guarda el tamaño
NF_BG16B[slot].width = x; // Ancho del fondo
NF_BG16B[slot].height = y; // Altura del fondo
NF_BG16B[slot].inuse = true; // Marca que esta en uso
}
// Funcion NF_Unload16bitsBg();
void NF_Unload16bitsBg(u8 slot) {
// Verifica si el buffer contiene datos
if (!NF_BG16B[slot].inuse) NF_Error(110, "16 Bits Bg", slot);
// Vacia los buffers que se usaran
free(NF_BG16B[slot].buffer);
NF_BG16B[slot].buffer = NULL;
NF_BG16B[slot].size = 0; // Tamaño a 0
NF_BG16B[slot].inuse = false; // Marca que esta libre
}
// Funcion NF_Copy16bitsBuffer();
void NF_Copy16bitsBuffer(u8 screen, u8 destination, u8 slot) {
// Verifica si el buffer contiene datos
if (!NF_BG16B[slot].inuse) NF_Error(110, "16 Bits Bg", slot);
if (destination == 0) { // Si el destino es la VRAM
// Dependiendo de la pantalla
if (screen == 0) {
NF_DmaMemCopy((void*)0x06000000, NF_BG16B[slot].buffer, NF_BG16B[slot].size);
} else {
NF_DmaMemCopy((void*)0x06200000, NF_BG16B[slot].buffer, NF_BG16B[slot].size);
}
} else { // Si el destino es el BackBuffer
// Dependiendo de la pantalla
if (screen == 0) {
memcpy(NF_16BITS_BACKBUFFER[0], NF_BG16B[slot].buffer, NF_BG16B[slot].size);
} else {
memcpy(NF_16BITS_BACKBUFFER[1], NF_BG16B[slot].buffer, NF_BG16B[slot].size);
}
}
}
// Funcion NF_Draw16bitsImage();
void NF_Draw16bitsImage(u8 screen, u8 slot, s16 x, s16 y, bool alpha) {
// Verifica si el buffer contiene datos
if (!NF_BG16B[slot].inuse) NF_Error(110, "16 Bits Image", slot);
// Variables locales
u16 img_x = 0;
u16 img_y = 0;
s16 buff_x = 0;
s16 buff_y = 0;
u32 buff_idx = 0;
u16 data = 0;
// Filtro de pantalla
u8 scr = screen;
if (scr > 1) scr = 1;
// Si el destino es el BackBuffer
for (img_y = 0; img_y < NF_BG16B[slot].height; img_y ++) {
for (img_x = 0; img_x < NF_BG16B[slot].width; img_x ++ ) {
// Calcula donde se escribira el pixel
buff_x = (img_x + x);
buff_y = (img_y + y);
// Si esta dentro de la pantalla, dibujalo
if (
(buff_x >= 0)
&&
(buff_x <= 255)
&&
(buff_y >= 0)
&&
(buff_y <= 255)
) {
// Calcula el offset dentro del buffer
buff_idx = ((buff_y << 8) + buff_x);
// Valor del Pixel
data = NF_BG16B[slot].buffer[((img_y * NF_BG16B[slot].width) + img_x)];
// Si el pixel NO es magenta !(RGB15(31, 0, 31) | BIT(15))
if ((data != 0xFC1F) || (!alpha)) {
// Escribe el pixel en el BackBuffer
*(NF_16BITS_BACKBUFFER[scr] + buff_idx) = data;
}
}
}
}
}
// Funcion NF_Init8bitsBgBuffers();
void NF_Init8bitsBgBuffers(void) {
// Variables locales
u8 n = 0;
for (n = 0; n < NF_SLOTS_BG8B; n ++) {
NF_BG8B[n].data = NULL;
NF_BG8B[n].pal = NULL;
NF_BG8B[n].data_size = 0;
NF_BG8B[n].pal_size = 0;
NF_BG8B[n].inuse = false;
}
}
// Funcion NF_Reset8bitsBgBuffers();
void NF_Reset8bitsBgBuffers(void) {
// Variables locales
u8 n = 0;
// Libera la RAM usada
for (n = 0; n < NF_SLOTS_BG8B; n ++) {
free(NF_BG8B[n].data);
free(NF_BG8B[n].pal);
}
// Reinicia los datos
NF_Init8bitsBgBuffers();
}
// Funcion NF_Load8bitsBg();
void NF_Load8bitsBg(const char* file, u8 slot) {
// Verifica el rango de Id's
if ((slot < 0) || (slot >= NF_SLOTS_BG8B)) {
NF_Error(106, "8 Bits Bg's", NF_SLOTS_BG8B);
}
// Vacia los buffers que se usaran
free(NF_BG8B[slot].data);
NF_BG8B[slot].data = NULL;
free(NF_BG8B[slot].pal);
NF_BG8B[slot].pal = NULL;
// Declara los punteros a los ficheros
FILE* file_id;
// Variable para almacenar el path al archivo
char filename[256];
// Variable para el tamaño de archivo
u32 size = 0;
// Carga el archivo .IMG
sprintf(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);
size = ftell(file_id);
rewind(file_id);
// Si excede del tamaño maximo (64kb), error
if (size > 65536) NF_Error(116, filename, 65536);
// Reserva el espacio en RAM
NF_BG8B[slot].data = (u8*) calloc (size, sizeof(u8));
if (NF_BG8B[slot].data == NULL) { // Si no hay suficiente RAM libre
NF_Error(102, NULL, size);
}
// Lee el archivo y ponlo en la RAM
fread(NF_BG8B[slot].data, 1, size, file_id);
} else { // Si el archivo no existe...
NF_Error(101, filename, 0);
}
fclose(file_id); // Cierra el archivo
NF_BG8B[slot].data_size = size; // Guarda el tamaño del buffer
// Carga el archivo .PAL
sprintf(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);
size = ftell(file_id);
rewind(file_id);
// Si la paleta tiene un tamaño inferior a 512, ajusta el tamaño
if (size < 512) size = 512;
// Reserva el espacio en RAM
NF_BG8B[slot].pal = (u16*) calloc ((size >> 1), sizeof(u16));
if (NF_BG8B[slot].pal == NULL) { // Si no hay suficiente RAM libre
NF_Error(102, NULL, size);
}
// Lee el archivo y ponlo en la RAM
fread(NF_BG8B[slot].pal, 1, size, file_id);
} else { // Si el archivo no existe...
NF_Error(101, filename, 0);
}
fclose(file_id); // Cierra el archivo
NF_BG8B[slot].pal_size = size; // Guarda el tamaño del buffer
// Marca el slot como que esta en uso
NF_BG8B[slot].inuse = true;
}
// Funcion NF_Unload8bitsBg();
void NF_Unload8bitsBg(u8 slot) {
// Verifica si el buffer contiene datos
if (!NF_BG8B[slot].inuse) NF_Error(110, "8 Bits Bg", slot);
// Vacia los buffers que se usaran
free(NF_BG8B[slot].data);
NF_BG8B[slot].data = NULL;
NF_BG8B[slot].data_size = 0;
free(NF_BG8B[slot].pal);
NF_BG8B[slot].pal = NULL;
NF_BG8B[slot].pal_size = 0;
NF_BG8B[slot].inuse = false; // Marca que esta libre
}
// Funcion NF_Copy8bitsBuffer();
void NF_Copy8bitsBuffer(u8 screen, u8 destination, u8 slot) {
// Verifica si el buffer contiene datos
if (!NF_BG8B[slot].inuse) NF_Error(110, "8 Bits Bg", slot);
u8 scr = screen;
if (scr > 1) scr = 1;
// Si el destino es la VRAM
if (destination < 2) {
// Segun la pantalla...
u32 data = 0;
u32 pal = 0;
if (screen == 0) {
data = (0x06000000); // Direccion en VRAM para los datos
pal = (0x05000000); // Direccion en VRAM para la paleta
} else {
data = (0x06200000); // Direccion en VRAM para los datos
pal = (0x05000400); // Direccion en VRAM para la paleta
}
// Segun la capa
if (destination == 1) data += 65536;
// Copia los datos a la VRAM
NF_DmaMemCopy((void*)data, NF_BG8B[slot].data, NF_BG8B[slot].data_size);
NF_DmaMemCopy((void*)pal, NF_BG8B[slot].pal, NF_BG8B[slot].pal_size);
} else {
// Copia los datos al BackBuffer
memcpy(NF_8BITS_BACKBUFFER[scr].data, NF_BG8B[slot].data, NF_BG8B[slot].data_size);
memcpy(NF_8BITS_BACKBUFFER[scr].pal, NF_BG8B[slot].pal, NF_BG8B[slot].pal_size);
}
}
// Funcion NF_Init8bitsBackBuffer();
void NF_Init8bitsBackBuffer(u8 screen) {
u8 scr = screen;
if (scr > 1) scr = 1;
NF_8BITS_BACKBUFFER[scr].data = NULL;
NF_8BITS_BACKBUFFER[scr].pal = NULL;
}
// Funcion NF_Enable8bitsBackBuffer();
void NF_Enable8bitsBackBuffer(u8 screen) {
u8 scr = screen;
if (scr > 1) scr = 1;
// Resetea el buffer
free(NF_8BITS_BACKBUFFER[scr].data);
free(NF_8BITS_BACKBUFFER[scr].pal);
NF_8BITS_BACKBUFFER[scr].data = NULL;
NF_8BITS_BACKBUFFER[scr].pal = NULL;
// Asignale 64kb de memoria para datos
NF_8BITS_BACKBUFFER[scr].data = (u8*) calloc(65536, sizeof(u8));
if (NF_8BITS_BACKBUFFER[scr].data == NULL) NF_Error(102, NULL, 65536);
// Asignale 512 bytes de memoria para paletas
NF_8BITS_BACKBUFFER[scr].pal = (u16*) calloc(256, sizeof(u16));
if (NF_8BITS_BACKBUFFER[scr].pal == NULL) NF_Error(102, NULL, 512);
}
// Funcion NF_Disble8bitsBackBuffer();
void NF_Disble8bitsBackBuffer(u8 screen) {
u8 scr = screen;
if (scr > 1) scr = 1;
// Resetea el buffer
free(NF_8BITS_BACKBUFFER[scr].data);
free(NF_8BITS_BACKBUFFER[scr].pal);
NF_8BITS_BACKBUFFER[scr].data = NULL;
NF_8BITS_BACKBUFFER[scr].pal = NULL;
}
// Funcion NF_Flip8bitsBackBuffer();
void NF_Flip8bitsBackBuffer(u8 screen, u8 destination) {
// Copia el contenido del Backbuffer a la VRAM
// de la pantalla solicitada
u8 scr = screen;
if (scr > 1) scr = 1;
// Segun la pantalla...
u32 data = 0;
u32 pal = 0;
if (scr == 0) {
data = (0x06000000); // Direccion en VRAM para los datos
pal = (0x05000000); // Direccion en VRAM para la paleta
} else {
data = (0x06200000); // Direccion en VRAM para los datos
pal = (0x05000400); // Direccion en VRAM para la paleta
}
// Segun la capa
if (destination == 1) data += 65536;
// Copia los datos a la VRAM
NF_DmaMemCopy((void*)data, NF_8BITS_BACKBUFFER[scr].data, 65536);
NF_DmaMemCopy((void*)pal, NF_8BITS_BACKBUFFER[scr].pal, 512);
}

View File

@ -0,0 +1,365 @@
// NightFox LIB - Funciones de Colisiones
// Requiere DevkitARM
// Codigo por Cesar Rincon "NightFox"
// http://www.nightfoxandco.com/
// Version 20140413
// Includes devKitPro
#include <nds.h>
#include <filesystem.h>
#include <fat.h>
// Includes C
#include <stdio.h>
#include <string.h>
#include <unistd.h>
// Includes propios
#include "nf_basic.h"
#include "nf_colision.h"
// Define los buffers y estructuras de control de los mapas de colision
NF_TYPE_CMAP_INFO NF_CMAP[NF_SLOTS_CMAP];
// Funcion NF_InitCmapBuffers();
void NF_InitCmapBuffers(void) {
u8 n = 0;
for (n = 0; n < NF_SLOTS_CMAP; n ++) {
NF_CMAP[n].tiles = NULL; // Inicializa los punteros de los buffers
NF_CMAP[n].map = NULL;
NF_CMAP[n].tiles_size = 0; // Tamaño de archivo
NF_CMAP[n].map_size = 0;
NF_CMAP[n].width = 0; // Ancho del mapa
NF_CMAP[n].height = 0; // Alto del mapa
NF_CMAP[n].inuse = false; // Esta en uso el slot?
}
}
// Funcion NF_ResetCmapBuffers();
void NF_ResetCmapBuffers(void) {
u8 n = 0;
for (n = 0; n < NF_SLOTS_CMAP; n ++) {
free(NF_CMAP[n].tiles); // Vacia los buffers
free(NF_CMAP[n].map);
}
NF_InitCmapBuffers(); // Y reinicia todas las variables
}
// Funcion NF_LoadColisionMap();
void NF_LoadColisionMap(const char* file, u8 id, u16 width, u16 height) {
// Verifica el rango de Id's
if ((id < 0) || (id >= NF_SLOTS_CMAP)) {
NF_Error(106, "Colision Map", NF_SLOTS_CMAP);
}
// Verifica si la Id esta libre
if (NF_CMAP[id].inuse) {
NF_Error(109, "Colision Map", id);
}
// Vacia los buffers que se usaran
free(NF_CMAP[id].map);
NF_CMAP[id].map = NULL;
// Declara los punteros a los ficheros
FILE* file_id;
// Variable para almacenar el path al archivo
char filename[256];
// Carga el archivo .CMP
sprintf(filename, "%s/%s.cmp", 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_CMAP[id].map_size = ftell(file_id);
rewind(file_id);
// Reserva el espacio en RAM
NF_CMAP[id].map = (char*) calloc (NF_CMAP[id].map_size, sizeof(char));
if (NF_CMAP[id].map == NULL) { // Si no hay suficiente RAM libre
NF_Error(102, NULL, NF_CMAP[id].map_size);
}
// Lee el archivo y ponlo en la RAM
fread(NF_CMAP[id].map, 1, NF_CMAP[id].map_size, file_id);
} else { // Si el archivo no existe...
NF_Error(101, filename, 0);
}
fclose(file_id); // Cierra el archivo
// Guarda las medidas
NF_CMAP[id].width = width;
NF_CMAP[id].height = height;
// Y marca esta ID como usada
NF_CMAP[id].inuse = true;
}
// Funcion NF_UnloadColisionMap();
void NF_UnloadColisionMap(u8 id) {
// Verifica el rango de Id's
if ((id < 0) || (id >= NF_SLOTS_CMAP)) {
NF_Error(106, "Colision Map", NF_SLOTS_CMAP);
}
// Verifica si la Id esta libre
if (!NF_CMAP[id].inuse) {
NF_Error(110, "Colision Map", id);
}
// Vacia los buffers que se usaran
free(NF_CMAP[id].map);
NF_CMAP[id].map = NULL;
// Y marca esta ID como usada
NF_CMAP[id].inuse = false;
}
// Funcion NF_GetTile();
u16 NF_GetTile(u8 slot, s32 x, s32 y) {
// Si la coordenada esta fuera de rango, devuelve 0
if (
(x < 0)
||
(y < 0)
||
(x >= NF_CMAP[slot].width)
||
(y >= NF_CMAP[slot].height)
) {
// Devuelve 0
return 0;
} else { // Si la coordenada esta dentro del rango...
// Calcula el ancho en tiles del mapa
u16 columns = (NF_CMAP[slot].width >> 3); // (width / 8);
// Calcula los tiles de posicion (x / 8); (y / 8);
u16 tile_x = (x >> 3);
u16 tile_y = (y >> 3) + 1; // +1, por que la primera fila se reserva para la referencia de tiles
// Calcula el nº de tile
u32 address = (((tile_y * columns) + tile_x) << 1);
// Obten los bytes
u8 lobyte = *(NF_CMAP[slot].map + address);
u8 hibyte = *(NF_CMAP[slot].map + (address + 1));
// Devuelve el valor del tile
return ((hibyte << 8) | lobyte);
}
}
// Funcion NF_SetTile();
void NF_SetTile(u8 slot, s32 x, s32 y, u16 value) {
// Si la coordenada esta dentro del rango...
if (
(x >= 0)
&&
(y >= 0)
&&
(x < NF_CMAP[slot].width)
&&
(y < NF_CMAP[slot].height)
) {
// Calcula el ancho en tiles del mapa
u16 columns = (NF_CMAP[slot].width >> 3); // (width / 8);
// Calcula los tiles de posicion (x / 8); (y / 8);
u16 tile_x = (x >> 3);
u16 tile_y = (y >> 3) + 1; // +1, por que la primera fila se reserva para la referencia de tiles
// Calcula el nº de tile
u32 address = (((tile_y * columns) + tile_x) << 1);
// nº de tile x2, dado que el mapa es de 16 bits (2 bytes por dato) y el buffer
// es de 8 bits, se lee el 2do byte, por eso se multiplica por 2.
// Calcula los valores de los bytes
u8 hibyte = ((value >> 8) & 0xff); // HI Byte
u8 lobyte = (value & 0xff); // LO Byte
// Escribe el nuevo valor en el mapa de colisiones
*(NF_CMAP[slot].map + address) = lobyte;
*(NF_CMAP[slot].map + (address + 1)) = hibyte;
}
}
// Funcion NF_LoadColisionBg();
void NF_LoadColisionBg(const char* file, u8 id, u16 width, u16 height) {
// Verifica el rango de Id's
if ((id < 0) || (id >= NF_SLOTS_CMAP)) {
NF_Error(106, "Colision Map", NF_SLOTS_CMAP);
}
// Verifica si la Id esta libre
if (NF_CMAP[id].inuse) {
NF_Error(109, "Colision Map", id);
}
// Vacia los buffers que se usaran
free(NF_CMAP[id].tiles);
NF_CMAP[id].tiles = NULL;
free(NF_CMAP[id].map);
NF_CMAP[id].map = NULL;
// Declara los punteros a los ficheros
FILE* file_id;
// Variable para almacenar el path al archivo
char filename[256];
// Carga el archivo .DAT (TILES)
sprintf(filename, "%s/%s.dat", 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_CMAP[id].tiles_size = ftell(file_id);
rewind(file_id);
// Reserva el espacio en RAM
NF_CMAP[id].tiles = (char*) calloc (NF_CMAP[id].tiles_size, sizeof(char));
if (NF_CMAP[id].tiles == NULL) { // Si no hay suficiente RAM libre
NF_Error(102, NULL, NF_CMAP[id].tiles_size);
}
// Lee el archivo y ponlo en la RAM
fread(NF_CMAP[id].tiles, 1, NF_CMAP[id].tiles_size, file_id);
} else { // Si el archivo no existe...
NF_Error(101, filename, 0);
}
fclose(file_id); // Cierra el archivo
// Carga el archivo .CMP
sprintf(filename, "%s/%s.cmp", 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_CMAP[id].map_size = ftell(file_id);
rewind(file_id);
// Reserva el espacio en RAM
NF_CMAP[id].map = (char*) calloc (NF_CMAP[id].map_size, sizeof(char));
if (NF_CMAP[id].map == NULL) { // Si no hay suficiente RAM libre
NF_Error(102, NULL, NF_CMAP[id].map_size);
}
// Lee el archivo y ponlo en la RAM
fread(NF_CMAP[id].map, 1, NF_CMAP[id].map_size, file_id);
} else { // Si el archivo no existe...
NF_Error(101, filename, 0);
}
fclose(file_id); // Cierra el archivo
// Guarda las medidas
NF_CMAP[id].width = width;
NF_CMAP[id].height = height;
// Y marca esta ID como usada
NF_CMAP[id].inuse = true;
}
// Funcion NF_UnloadColisionBg();
void NF_UnloadColisionBg(u8 id) {
// Verifica el rango de Id's
if ((id < 0) || (id >= NF_SLOTS_CMAP)) {
NF_Error(106, "Colision Map", NF_SLOTS_CMAP);
}
// Verifica si la Id esta libre
if (!NF_CMAP[id].inuse) {
NF_Error(110, "Colision Map", id);
}
// Vacia los buffers que se usaran
free(NF_CMAP[id].tiles);
NF_CMAP[id].tiles = NULL;
free(NF_CMAP[id].map);
NF_CMAP[id].map = NULL;
// Y marca esta ID como usada
NF_CMAP[id].inuse = false;
}
// Funcion NF_GetPoint();
u8 NF_GetPoint(u8 slot, s32 x, s32 y) {
// Si la coordenada esta fuera de rango, devuelve 0
if (
(x < 0)
||
(y < 0)
||
(x >= NF_CMAP[slot].width)
||
(y >= NF_CMAP[slot].height)
) {
// Devuelve 0
return 0;
} else { // Si la coordenada esta dentro del rango...
// Calcula el ancho en tiles del mapa
u16 columns = (NF_CMAP[slot].width >> 3); // (width / 8);
// Calcula los tiles de posicion (x / 8); (y / 8);
u16 tile_x = (x >> 3);
u16 tile_y = (y >> 3) + 1; // +1, por que la primera fila se reserva para la referencia de tiles
// Calcula los pixeles relativos
u16 pixel_x = x - (tile_x << 3);
u16 pixel_y = (y + 8) - (tile_y << 3);
// Calcula la posicion de tile dentro del archivo de mapa
s32 address = (((tile_y * columns) + tile_x) << 1);
u8 lobyte = *(NF_CMAP[slot].map + address);
u8 hibyte = *(NF_CMAP[slot].map + (address + 1));
u16 tile = ((hibyte << 8) | lobyte);
// Obten el valor del pixel leyendola del archivo de tiles
address = ((tile << 6) + (pixel_y << 3) + pixel_x); // (tile * 64) + (y * 8) + x
lobyte = *(NF_CMAP[slot].tiles + address);
// Devuelve el valor del pixel
return lobyte;
}
}

View File

@ -0,0 +1,218 @@
// NightFox LIB - Include de funciones de carga de archivos multimedia
// Requiere DevkitARM
// Codigo por Cesar Rincon "NightFox"
// http://www.nightfoxandco.com/
// Version 20140413
// Includes devKitPro
#include <nds.h>
#include <filesystem.h>
#include <fat.h>
// Includes C
#include <stdio.h>
#include <string.h>
#include <unistd.h>
// Includes propios
#include "nf_media.h"
#include "nf_bitmapbg.h"
#include "nf_basic.h"
// Funcion NF_LoadBMP();
void NF_LoadBMP(const char* file, u8 slot) {
// Buffers locales
char* buffer; // Buffer temporal
buffer = NULL;
char* palette; // Paleta (requerida por algun modo)
palette = NULL;
// Magic ID
char magic_id[4];
memset(magic_id, 0, 4);
// Define la estructura para almacenar la cabecera del BMP
typedef struct {
u32 bmp_size; // Tamaño en bytes del BMP
u16 res_a; // Reservado
u16 res_b; // Reservado
u32 offset; // Offset donde empiezan los datos
u32 header_size; // Tamaño de la cabecera (40 bytes)
u32 bmp_width; // Ancho de la imagen en pixeles
u32 bmp_height; // Altura de la imagen en pixeles
u16 color_planes; // Numero de planos de color
u16 bpp; // Numero de bits por pixel
u32 compression; // Compresion usada
u32 raw_size; // Tamaño de los datos en RAW despues de la cabecera
u32 dpi_hor; // Puntos por pulgada (horizontal)
u32 dpi_ver; // Puntos por pulgada (vertical)
u32 pal_colors; // Numero de colores en la paleta
u32 imp_colors; // Colores importantes
} bmp_header_info;
bmp_header_info bmp_header;
// Pon todos los bytes de la estructura a 0
memset(&bmp_header, 0, sizeof(bmp_header));
// Declara los punteros a los ficheros
FILE* file_id;
// Variable para almacenar el path al archivo
char filename[256];
// Carga el archivo .BMP
sprintf(filename, "%s/%s.bmp", NF_ROOTFOLDER, file);
file_id = fopen(filename, "rb");
if (file_id) { // Si el archivo existe...
// Posicionate en el byte 0
fseek(file_id, 0, SEEK_SET);
// Lee el Magic String del archivo BMP (2 primeros Bytes, "BM") / (0x00 - 0x01)
fread(magic_id, 1, 2, file_id);
// Si es un archivo BMP... (Magic string == "BM")
if (strcmp(magic_id, "BM") == 0) {
// Posicionate en el byte 2
fseek(file_id, 2, SEEK_SET);
// Lee la cabecera del archivo BMP (0x02 - 0x36)
fread((void*)&bmp_header, 1, sizeof(bmp_header), file_id);
/////////////////////////////////////////////////////////////
// Es un archivo BMP valido, cargalo en un buffer temporal //
/////////////////////////////////////////////////////////////
// Crea un buffer temporal
buffer = (char*) calloc (bmp_header.raw_size, sizeof(char));
if (buffer == NULL) NF_Error(102, NULL, bmp_header.raw_size);
// Si se ha creado con exito, carga el archivo al buffer
fseek(file_id, bmp_header.offset, SEEK_SET);
fread(buffer, 1, bmp_header.raw_size, file_id);
} else {
// No es un archivo BMP valido
NF_Error(101, "BMP", 0);
}
} else {
// El archivo no existe
NF_Error(101, filename, 0);
}
// Cierra el archivo
fclose(file_id);
// Variables que se usaran a partir de aqui
u16 pixel = 0; // Color del pixel
u16 x = 0; // Coordemada X
u16 y = 0; // Coordenada Y
u32 idx = 0; // Indice en el buffer temporal
u32 offset = 0; // Indice en el buffer de destino
u8 r = 0; // Valores RGB
u8 g = 0;
u8 b = 0;
u16 colors = 0; // En 8 bits, numero de colores
u32 size = 0; // Tamaño del buffer de 16 bits (en bytes)
// Habilita el buffer de destino (u16 de alto x ancho del tamaño de imagen)
size = ((bmp_header.bmp_width * bmp_header.bmp_height) << 1);
free(NF_BG16B[slot].buffer);
NF_BG16B[slot].buffer = NULL;
NF_BG16B[slot].buffer = (u16*) calloc ((size >> 1), sizeof(u16));
if (NF_BG16B[slot].buffer == NULL) NF_Error(102, NULL, size);
// Segun los BITS por Pixel (8, 16, 24)
switch (bmp_header.bpp) {
case 8: // 8 bits por pixel
// Calcula el tamaño de la paleta
colors = ((bmp_header.offset - 0x36) >> 2);
palette = (char*) calloc ((colors << 2), sizeof(char));
if (palette == NULL) NF_Error(102, NULL, (colors << 2));
// Abre de nuevo el archivo y carga la paleta
file_id = fopen(filename, "rb");
if (!file_id) NF_Error(101, filename, 0);
fseek(file_id, 0x36, SEEK_SET);
fread(palette, 1, (colors << 2), file_id);
fclose(file_id);
// Convierte el archivo a 16 bits
for (y = 0; y < bmp_header.bmp_height; y ++) {
for (x = 0; x < bmp_header.bmp_width; x ++) {
// Calcula los offsets
offset = ((((bmp_header.bmp_height - 1) - y) * bmp_header.bmp_width) + x);
// Obten el pixel
pixel = (buffer[idx] << 2);
// Desglosa el RGB para rotar los colores BGR -> RGB
b = (palette[pixel] >> 3);
g = (palette[(pixel + 1)] >> 3);
r = (palette[(pixel + 2)] >> 3);
// Recombina el RGB a 16 bits
pixel = ((r)|((g) << 5)|((b) << 10)|(BIT(15)));
NF_BG16B[slot].buffer[offset] = pixel;
// Siguiente pixel
idx ++;
}
// Ajusta la alineacion a 4 bytes al final de linea
while ((idx % 4) != 0) idx ++;
}
// Elimina la paleta de la RAM
free(palette);
palette = NULL;
break;
case 16: // 16 bits por pixel
for (y = 0; y < bmp_header.bmp_height; y ++) {
for (x = 0; x < bmp_header.bmp_width; x ++) {
// Calcula los offsets
offset = ((((bmp_header.bmp_height - 1) - y) * bmp_header.bmp_width) + x);
// Obten el pixel
pixel = buffer[idx] + (buffer[(idx + 1)] << 8);
// Desglosa el RGB para rotar los colores BGR -> RGB
b = (pixel & 0x1F);
g = ((pixel >> 5) & 0x1F);
r = ((pixel >> 10) & 0x1F);
// Recombina el RGB a 16 bits
pixel = ((r)|((g) << 5)|((b) << 10)|(BIT(15)));
NF_BG16B[slot].buffer[offset] = pixel;
// Siguiente pixel
idx += 2;
}
// Ajusta la alineacion a 4 bytes al final de linea
while ((idx % 4) != 0) idx ++;
}
break;
case 24: // 24 bits por pixel
for (y = 0; y < bmp_header.bmp_height; y ++) {
for (x = 0; x < bmp_header.bmp_width; x ++) {
// Calcula los offsets
offset = ((((bmp_header.bmp_height - 1) - y) * bmp_header.bmp_width) + x);
// Obten el pixel
b = ((buffer[idx]) >> 3);
g = ((buffer[idx + 1]) >> 3);
r = ((buffer[idx + 2]) >> 3);
// Recombina el RGB a 16 bits
pixel = ((r)|((g) << 5)|((b) << 10)|(BIT(15)));
NF_BG16B[slot].buffer[offset] = pixel;
// Siguiente pixel
idx += 3;
}
// Ajusta la alineacion a 4 bytes al final de linea
while ((idx % 4) != 0) idx ++;
}
break;
}
// Guarda los parametros del fondo
NF_BG16B[slot].size = size; // Guarda el tamaño
NF_BG16B[slot].width = bmp_header.bmp_width; // Ancho del fondo
NF_BG16B[slot].height = bmp_header.bmp_height; // Altura del fondo
NF_BG16B[slot].inuse = true; // Marca que esta en uso
// Libera el buffer temporal
free(buffer);
buffer = NULL;
}

View File

@ -0,0 +1,126 @@
// NightFox LIB - Include de Fondos mixtos (Tiled / Bitmap 8 bits)
// Requiere DevkitARM
// Codigo por Cesar Rincon "NightFox"
// http://www.nightfoxandco.com/
// Version 20140413
// Includes devKitPro
#include <nds.h>
#include <filesystem.h>
#include <fat.h>
// Includes C
#include <stdio.h>
#include <string.h>
#include <unistd.h>
// Includes propios
#include "nf_basic.h"
#include "nf_2d.h"
#include "nf_tiledbg.h"
#include "nf_bitmapbg.h"
#include "nf_mixedbg.h"
// Funcion NF_InitMixedBgSys();
void NF_InitMixedBgSys(u8 screen) {
// Variables
u8 n = 0;
// Define el numero de bancos de Mapas y Tiles
NF_BANKS_TILES[screen] = 4; // (1 banks = 16kb) Cada banco de tiles puede alvergar 8 bancos de Mapas
NF_BANKS_MAPS[screen] = 8; // (1 bank = 2kb) Usar multiplos de 8. Cada set de 8 bancos consume 1 banco de tiles
// Por defecto Tiles = 4, Mapas = 8
// Esto nos deja 3 bancos de 16kb para tiles
// y 8 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);
}
}
// Inicializa la capa de dibujado para bitmaps (capa 3 unicamente)
if (screen == 0) {
// Modo 8 bits (Capas 3)
REG_BG3CNT = BG_PRIORITY_3 | BG_BMP_BASE(4) | BG_BMP8_256x256;
// Resetea los registros de RotScale (Capa 3)
REG_BG3PA = (1 << 8);
REG_BG3PB = 0;
REG_BG3PC = 0;
REG_BG3PD = (1 << 8);
NF_ScrollBg(0, 3, 0, 0); // Posicionala en 0, 0
NF_ShowBg(0, 3); // Muestra la capa 3
} else {
// Modo 8 bits (Capas 2 y 3)
REG_BG3CNT_SUB = BG_PRIORITY_3 | BG_BMP_BASE(4) | BG_BMP8_256x256;
// Resetea los registros de RotScale (Capa 3)
REG_BG3PA_SUB = (1 << 8);
REG_BG3PB_SUB = 0;
REG_BG3PC_SUB = 0;
REG_BG3PD_SUB = (1 << 8);
NF_ScrollBg(1, 3, 0, 0); // Posicionala en 0, 0
NF_ShowBg(1, 3); // Muestra la capa 3
}
}

View File

@ -0,0 +1,175 @@
// NightFox LIB - Funciones de de funciones de sonido
// Requiere DevkitARM
// Codigo por Cesar Rincon "NightFox"
// http://www.nightfoxandco.com/
// Version 20140413
// Includes devKitPro
#include <nds.h>
#include <filesystem.h>
#include <fat.h>
// Includes C
#include <stdio.h>
#include <string.h>
#include <unistd.h>
// Includes propios
#include "nf_basic.h"
#include "nf_sound.h"
// Define los Buffers para almacenar los archivos de audio
char* NF_BUFFER_RAWSOUND[NF_SLOTS_RAWSOUND];
// Datos de los sonidos cargado
NF_TYPE_RAWSOUND_INFO NF_RAWSOUND[NF_SLOTS_RAWSOUND];
// Funcion NF_InitRawSoundBuffers();
void NF_InitRawSoundBuffers(void) {
u8 n = 0; // Variable comun
// Inicializa Buffers de sonido en RAW
for (n = 0; n < NF_SLOTS_RAWSOUND; n ++) {
NF_BUFFER_RAWSOUND[n] = NULL; // Inicializa puntero
NF_RAWSOUND[n].available = true; // Disponibilidad del slot
NF_RAWSOUND[n].size = 0; // Tamaño del archivo
NF_RAWSOUND[n].freq = 0; // Frecuencia del sample
NF_RAWSOUND[n].format = 0; // Formato del sample
}
}
// Funcion NF_ResetRawSoundBuffers();
void NF_ResetRawSoundBuffers(void) {
u8 n = 0; // Variable comun
// Borra los datos de los buffers de sonido en RAW
for (n = 0; n < NF_SLOTS_RAWSOUND; n ++) {
free(NF_BUFFER_RAWSOUND[n]); // Borra el contenido puntero
}
// Reinicia las estructuras de datos
NF_InitRawSoundBuffers();
}
// Funcion NF_LoadRawSound();
void NF_LoadRawSound(const char* file, u16 id, u16 freq, u8 format) {
// Verifica el rango de Id's
if ((id < 0) || (id >= NF_SLOTS_RAWSOUND)) {
NF_Error(106, "Raw Sound", NF_SLOTS_RAWSOUND);
}
// Verifica si la Id esta libre
if (!NF_RAWSOUND[id].available) {
NF_Error(109, "Raw Sound", id);
}
// Vacia los buffers que se usaran
free(NF_BUFFER_RAWSOUND[id]);
NF_BUFFER_RAWSOUND[id] = NULL;
// Declara los punteros a los ficheros
FILE* file_id;
// Variable para almacenar el path al archivo
char filename[256];
// Carga el archivo .RAW
sprintf(filename, "%s/%s.raw", 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_RAWSOUND[id].size = ftell(file_id);
rewind(file_id);
// Si excede del tamaño maximo, error
if (NF_RAWSOUND[id].size > (1 << 18)) NF_Error(116, filename, (1 << 18));
// Reserva el espacio en RAM
NF_BUFFER_RAWSOUND[id] = (char*) calloc (NF_RAWSOUND[id].size, sizeof(char));
if (NF_BUFFER_RAWSOUND[id] == NULL) { // Si no hay suficiente RAM libre
NF_Error(102, NULL, NF_RAWSOUND[id].size);
}
// Lee el archivo y ponlo en la RAM
fread(NF_BUFFER_RAWSOUND[id], 1, NF_RAWSOUND[id].size, file_id);
} else { // Si el archivo no existe...
NF_Error(101, filename, 0);
}
fclose(file_id); // Cierra el archivo
// swiWaitForVBlank(); // Espera al cierre del archivo (Usar en caso de corrupcion de datos)
// Guarda los parametros del archivo de sonido
NF_RAWSOUND[id].freq = freq; // Frequencia del sample (en Hz)
NF_RAWSOUND[id].format = format; // Formato del sample (0 - > 8 bits, 1 - > 16 bits, 2 -> ADPCM)
// Y marca esta ID como usada
NF_RAWSOUND[id].available = false;
}
// Funcion UnloadRawSound();
void NF_UnloadRawSound(u8 id) {
// Verifica el rango de Id's
if ((id < 0) || (id >= NF_SLOTS_RAWSOUND)) NF_Error(106, "RAW Sound", NF_SLOTS_RAWSOUND);
// Verifica si el sonido existe
if (NF_RAWSOUND[id].available) NF_Error(110, "RAW Sound", id);
// Vacia los buffers de la Id. seleccionada
free(NF_BUFFER_RAWSOUND[id]);
NF_BUFFER_RAWSOUND[id] = NULL;
// Resetea las variables
NF_RAWSOUND[id].freq = 0; // Frequencia del sample (en Hz)
NF_RAWSOUND[id].format = 0; // Formato del sample (0 - > 8 bits, 1 - > 16 bits, 2 -> ADPCM)
// Y marca esta ID como libre
NF_RAWSOUND[id].available = true;
}
// Funcion NF_PlayRawSound();
u8 NF_PlayRawSound(u8 id, u8 volume, u8 pan, bool loop, u16 loopfrom) {
// Verifica el rango de Id's
if ((id < 0) || (id >= NF_SLOTS_RAWSOUND)) NF_Error(106, "RAW Sound", NF_SLOTS_RAWSOUND);
// Verifica si el sonido existe
if (NF_RAWSOUND[id].available) NF_Error(110, "RAW Sound", id);
return soundPlaySample(NF_BUFFER_RAWSOUND[id], NF_RAWSOUND[id].format, NF_RAWSOUND[id].size, NF_RAWSOUND[id].freq, volume, pan, loop, loopfrom);
}

View File

@ -0,0 +1,989 @@
// NightFox LIB - Funciones de Sprites a 256 colores
// Requiere DevkitARM
// Codigo por Cesar Rincon "NightFox"
// http://www.nightfoxandco.com/
// Version 20140413
// Includes devKitPro
#include <nds.h>
#include <filesystem.h>
#include <fat.h>
// Includes C
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
// Includes propios
#include "nf_basic.h"
#include "nf_2d.h"
#include "nf_sprite256.h"
// Define los Buffers para almacenar los Sprites
char* NF_BUFFER_SPR256GFX[NF_SLOTS_SPR256GFX];
char* NF_BUFFER_SPR256PAL[NF_SLOTS_SPR256PAL];
// Define la estructura de datos de los Graficos de los Sprites
NF_TYPE_SPR256GFX_INFO NF_SPR256GFX[NF_SLOTS_SPR256GFX];
// Define la estructura de datos de las Paletas de los Sprites
NF_TYPE_SPR256PAL_INFO NF_SPR256PAL[NF_SLOTS_SPR256PAL];
// Define la estructura de Gfx en VRAM
NF_TYPE_SPR256VRAM_INFO NF_SPR256VRAM[2][128];
// Datos de paletas de Sprites en VRAM (en uso, slot en ram, etc)
NF_TYPE_SPRPALSLOT_INFO NF_SPRPALSLOT[2][16];
// Define la estructura de datos del OAM (Sprites)
NF_TYPE_SPRITEOAM_INFO NF_SPRITEOAM[2][128]; // 2 pantallas, 128 sprites
// Define la esturctura de control de la VRAM para Sprites
NF_TYPE_SPRVRAM_INFO NF_SPRVRAM[2]; // Informacion VRAM de Sprites en ambas pantallas
// Funcion NF_InitSpriteBuffers()
void NF_InitSpriteBuffers(void) {
u16 n = 0; // Variable comun
// Inicializa Buffers de GFX
for (n = 0; n < NF_SLOTS_SPR256GFX; n ++) {
NF_BUFFER_SPR256GFX[n] = NULL; // Inicializa puntero
NF_SPR256GFX[n].size = 0; // Tamaño (en bytes) del grafico (GFX)
NF_SPR256GFX[n].width = 0; // Ancho del Gfx
NF_SPR256GFX[n].height = 0; // Altura del Gfx
NF_SPR256GFX[n].available = true; // Disponibilidat del Slot
}
// Inicializa Buffers de PAL
for (n = 0; n < NF_SLOTS_SPR256PAL; n ++) {
NF_BUFFER_SPR256PAL[n] = NULL; // Inicializa puntero
NF_SPR256PAL[n].size = 0; // Tamaño (en bytes) de la paleta (PAL)
NF_SPR256PAL[n].available = true; // Disponibilidat del Slot
}
}
// Funcion NF_ResetSpriteBuffers()
void NF_ResetSpriteBuffers(void) {
u16 n = 0; // Variable comun
// Borra los Buffers de GFX
for (n = 0; n < NF_SLOTS_SPR256GFX; n ++) {
free(NF_BUFFER_SPR256GFX[n]);
}
// Borra los Buffers de PAL
for (n = 0; n < NF_SLOTS_SPR256PAL; n ++) {
free(NF_BUFFER_SPR256PAL[n]);
}
// Reinicia el sistema de Sprites
NF_InitSpriteBuffers();
}
// Funcion NF_InitSpriteSys();
void NF_InitSpriteSys(int screen, ...) {
// Analiza los parametros variables de la funcion
va_list options;
va_start(options, screen);
u8 mode = va_arg(options, int);
va_end(options);
// Variables
u8 n = 0; // Uso comun
// Inicializa la estructura de Gfx en VRAM
// y la estructura de datos del OAM (Sprites)
for (n = 0; n < 128; n ++) { // 128 sprites
// Gfx en la VRAM (128 Gfx x pantalla)
NF_SPR256VRAM[screen][n].size = 0; // Tamaño (en bytes) del Gfx
NF_SPR256VRAM[screen][n].width = 0; // Ancho del Gfx
NF_SPR256VRAM[screen][n].height = 0; // Altura del Gfx
NF_SPR256VRAM[screen][n].address = 0; // Posicion en la VRAM
NF_SPR256VRAM[screen][n].ramid = 0; // Numero de Slot en RAM del que provienes
NF_SPR256VRAM[screen][n].framesize = 0; // Tamaño del frame (en bytes)
NF_SPR256VRAM[screen][n].lastframe = 0; // Ultimo frame
NF_SPR256VRAM[screen][n].keepframes = false; // Si es un Sprite animado, debes de mantener los frames en RAM ?
NF_SPR256VRAM[screen][n].inuse = false; // Esta en uso ?
// OAM (128 Sprites x pantalla)
NF_SPRITEOAM[screen][n].index = n; // Numero de Sprite (Index = N)
NF_SPRITEOAM[screen][n].x = 0; // Coordenada X del Sprite (0 por defecto)
NF_SPRITEOAM[screen][n].y = 0; // Coordenada Y del Sprite (0 por defecto)
NF_SPRITEOAM[screen][n].layer = 0; // Prioridad en las capas (0 por defecto)
NF_SPRITEOAM[screen][n].pal = 0; // Paleta que usaras (0 por defecto)
NF_SPRITEOAM[screen][n].size = SpriteSize_8x8; // Tamaño del Sprite (macro) (8x8 por defecto)
NF_SPRITEOAM[screen][n].color = SpriteColorFormat_256Color; // Modo de color (macro) (256 colores)
NF_SPRITEOAM[screen][n].gfx = NULL; // Puntero al grafico usado
NF_SPRITEOAM[screen][n].rot = -1; // Id de rotacion (-1 por defecto) (0 - 31 Id de rotacion)
NF_SPRITEOAM[screen][n].doublesize = false; // Usar el "double size" al rotar ? ("NO" por defecto)
NF_SPRITEOAM[screen][n].hide = true; // Ocultar el Sprite ("SI" por defecto)
NF_SPRITEOAM[screen][n].hflip = false; // Volteado Horizontal ("NO" por defecto)
NF_SPRITEOAM[screen][n].vflip = false; // Volteado Vertical ("NO" por defecto)
NF_SPRITEOAM[screen][n].mosaic = false; // Mosaico ("NO" por defecto)
NF_SPRITEOAM[screen][n].gfxid = 0; // Numero de Gfx usado
NF_SPRITEOAM[screen][n].frame = 0; // Frame actual
NF_SPRITEOAM[screen][n].framesize = 0; // Tamaño del frame (en bytes)
NF_SPRITEOAM[screen][n].lastframe = 0; // Ultimo frame
NF_SPRITEOAM[screen][n].created = false; // Esta creado este sprite ?
}
// Inicializa la estructura de datos de la VRAM de Sprites
if (mode == 128) {
NF_SPRVRAM[screen].max = 131072;
} else {
NF_SPRVRAM[screen].max = 65536;
}
NF_SPRVRAM[screen].free = NF_SPRVRAM[screen].max; // Memoria VRAM libre (64kb/128kb)
NF_SPRVRAM[screen].last = 0; // Ultima posicion usada
NF_SPRVRAM[screen].deleted = 0; // Ningun Gfx borrado
NF_SPRVRAM[screen].fragmented = 0; // Memoria VRAM fragmentada
NF_SPRVRAM[screen].inarow = NF_SPRVRAM[screen].max; // Memoria VRAM contigua
for (n = 0; n < 128; n ++) {
NF_SPRVRAM[screen].pos[n] = 0; // Posicion en VRAM para reusar despues de un borrado
NF_SPRVRAM[screen].size[n] = 0; // Tamaño del bloque libre para reusar
}
// Inicializa los datos de las paletas
for (n = 0; n < 16; n ++) {
NF_SPRPALSLOT[screen][n].inuse = false;
NF_SPRPALSLOT[screen][n].ramslot = 0;
}
// Configura el Motor 2D y VRAM segun la pantalla de destino
if (screen == 0) {
// Configura la pantalla 0
REG_DISPCNT |= (DISPLAY_SPR_ACTIVE); // Activa los Sprites en la pantalla superior
vramSetBankB(VRAM_B_MAIN_SPRITE_0x06400000); // Banco B de la VRAM para Sprites (128kb)
memset((void*)0x06400000, 0, 131072); // Borra el contenido del banco B
NF_SPRVRAM[screen].next = (0x06400000); // Guarda la primera posicion de VRAM para Gfx
vramSetBankF(VRAM_F_LCD); // Banco F de la VRAM para paletas extendidas (Sprites) (8kb de 16kb)
memset((void*)0x06890000, 0, 8192); // Borra el contenido del banco F
if (mode == 128) {
oamInit(&oamMain, SpriteMapping_1D_128, true); // Inicializa el OAM (Mapeado de 128 bytes, Paletas extendidas)
} else {
oamInit(&oamMain, SpriteMapping_1D_64, true); // Inicializa el OAM (Mapeado de 64 bytes, Paletas extendidas)
}
} else {
// Configura la pantalla 1
REG_DISPCNT_SUB |= (DISPLAY_SPR_ACTIVE); // Activa los Sprites en la pantalla inferior
vramSetBankD(VRAM_D_SUB_SPRITE); // Banco D de la VRAM para Sprites (128kb)
memset((void*)0x06600000, 0, 131072); // Borra el contenido del banco D
NF_SPRVRAM[screen].next = (0x06600000); // Guarda la primera posicion de VRAM para Gfx
vramSetBankI(VRAM_I_LCD); // Banco I de la VRAM para paletas extendidas (Sprites) (8kb de 16kb)
memset((void*)0x068A0000, 0, 8192); // Borra el contenido del banco I
if (mode == 128) {
oamInit(&oamSub, SpriteMapping_1D_128, true); // Inicializa el OAM (Mapeado de 128 bytes, Paletas extendidas)
} else {
oamInit(&oamSub, SpriteMapping_1D_64, true); // Inicializa el OAM (Mapeado de 64 bytes, Paletas extendidas)
}
}
}
// Funcion NF_LoadSpriteGfx();
void NF_LoadSpriteGfx(const char* file, u16 id, u16 width, u16 height) {
// Verifica el rango de Id's
if ((id < 0) || (id >= NF_SLOTS_SPR256GFX)) {
NF_Error(106, "Sprite GFX", NF_SLOTS_SPR256GFX);
}
// Verifica si la Id esta libre
if (!NF_SPR256GFX[id].available) {
NF_Error(109, "Sprite GFX", id);
}
// Vacia los buffers que se usaran
free(NF_BUFFER_SPR256GFX[id]);
NF_BUFFER_SPR256GFX[id] = NULL;
// Declara los punteros a los ficheros
FILE* file_id;
// Variable para almacenar el path al archivo
char filename[256];
// Carga el archivo .IMG
sprintf(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_SPR256GFX[id].size = ftell(file_id);
rewind(file_id);
// Reserva el espacio en RAM
NF_BUFFER_SPR256GFX[id] = (char*) calloc (NF_SPR256GFX[id].size, sizeof(char));
if (NF_BUFFER_SPR256GFX[id] == NULL) { // Si no hay suficiente RAM libre
NF_Error(102, NULL, NF_SPR256GFX[id].size);
}
// Lee el archivo y ponlo en la RAM
fread(NF_BUFFER_SPR256GFX[id], 1, NF_SPR256GFX[id].size, file_id);
} else { // Si el archivo no existe...
NF_Error(101, filename, 0);
}
fclose(file_id); // Cierra el archivo
// Guarda las medidas del grafico
NF_SPR256GFX[id].width = width; // Ancho del Gfx
NF_SPR256GFX[id].height = height; // Altura del Gfx
// Y marca esta ID como usada
NF_SPR256GFX[id].available = false;
}
// Funcion NF_UnloadSpriteGfx();
void NF_UnloadSpriteGfx(u16 id) {
// Verifica el rango de Id's
if ((id < 0) || (id >= NF_SLOTS_SPR256GFX)) {
NF_Error(106, "Sprite GFX", NF_SLOTS_SPR256GFX);
}
// Verifica si la Id esta libre
if (NF_SPR256GFX[id].available) {
NF_Error(110, "Sprite GFX", id);
}
// Vacia el buffer
free(NF_BUFFER_SPR256GFX[id]);
// Y reinicia las variables
NF_BUFFER_SPR256GFX[id] = NULL; // Inicializa puntero
NF_SPR256GFX[id].size = 0; // Tamaño (en bytes) del grafico (GFX)
NF_SPR256GFX[id].width = 0; // Ancho del Gfx
NF_SPR256GFX[id].height = 0; // Altura del Gfx
NF_SPR256GFX[id].available = true; // Disponibilidat del Slot
}
// Funcion NF_LoadSpritePal();
void NF_LoadSpritePal(const char* file, u8 id) {
// Variable temporal del tamaño de la paleta
u32 pal_size = 0;
// Verifica el rango de Id's
if ((id < 0) || (id >= NF_SLOTS_SPR256PAL)) {
NF_Error(106, "Sprite PAL", NF_SLOTS_SPR256PAL);
}
// Verifica si la Id esta libre
if (!NF_SPR256PAL[id].available) {
NF_Error(109, "Sprite PAL", id);
}
// Vacia los buffers que se usaran
free(NF_BUFFER_SPR256PAL[id]);
NF_BUFFER_SPR256PAL[id] = NULL;
// Declara los punteros a los ficheros
FILE* file_id;
// Variable para almacenar el path al archivo
char filename[256];
// Carga el archivo .PAL
sprintf(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_SPR256PAL[id].size = pal_size;
rewind(file_id);
// Si el tamaño es inferior a 512 bytes, ajustalo
if (NF_SPR256PAL[id].size < 512) NF_SPR256PAL[id].size = 512;
// Reserva el espacio en RAM
NF_BUFFER_SPR256PAL[id] = (char*) calloc (NF_SPR256PAL[id].size, sizeof(char));
if (NF_BUFFER_SPR256PAL[id] == NULL) { // Si no hay suficiente RAM libre
NF_Error(102, NULL, NF_SPR256PAL[id].size);
}
// Lee el archivo y ponlo en la RAM
fread(NF_BUFFER_SPR256PAL[id], 1, pal_size, file_id);
} else { // Si el archivo no existe...
NF_Error(101, filename, 0);
}
fclose(file_id); // Cierra el archivo
// Y marca esta ID como usada
NF_SPR256PAL[id].available = false;
}
// Funcion NF_UnloadSpritePal();
void NF_UnloadSpritePal(u8 id) {
// Verifica el rango de Id's
if ((id < 0) || (id >= NF_SLOTS_SPR256PAL)) {
NF_Error(106, "Sprite PAL", NF_SLOTS_SPR256PAL);
}
// Verifica si la Id esta libre
if (NF_SPR256PAL[id].available) {
NF_Error(110, "Sprite PAL", id);
}
// Vacia el buffer
free(NF_BUFFER_SPR256PAL[id]);
// Y reinicia las variables
NF_BUFFER_SPR256PAL[id] = NULL; // Inicializa puntero
NF_SPR256PAL[id].size = 0; // Tamaño (en bytes) de la paleta (PAL)
NF_SPR256PAL[id].available = true; // Disponibilidat del Slot
}
// Funcion NF_VramSpriteGfx();
void NF_VramSpriteGfx(u8 screen, u16 ram, u16 vram, bool keepframes) {
// Verifica el rango de Id's de RAM
if ((ram < 0) || (ram >= NF_SLOTS_SPR256GFX)) {
NF_Error(106, "Sprite GFX", (NF_SLOTS_SPR256GFX - 1));
}
// Verifica si slot de RAM esta vacio
if (NF_SPR256GFX[ram].available) {
NF_Error(110, "Sprite GFX", ram);
}
// Verifica el rango de Id's de VRAM
if ((vram < 0) || (vram > 127)) {
NF_Error(106, "VRAM GFX", 127);
}
// Verifica si el slot de VRAM esta libre
if (NF_SPR256VRAM[screen][vram].inuse) {
NF_Error(109, "VRAM", vram);
}
// Variables de uso general
s16 n = 0; // General
s16 id = 255; // Id del posible bloque libre
s16 last_reuse = 0; // Nº del ultimo bloque reusable
u32 gfxsize = 0; // Tamaño de los datos que se copiaran
u32 size = 0; // Diferencia de tamaños entre bloque libre y datos
u8 width = 0; // Calculo de las medidas
u8 height = 0;
bool organize = true; // Se debe de reorganizar el array de bloques libres ?
// Auto calcula el tamaño de 1 frame
width = (NF_SPR256GFX[ram].width >> 3); // (width / 8)
height = (NF_SPR256GFX[ram].height >> 3); // (height / 8)
NF_SPR256VRAM[screen][vram].framesize = ((width * height) << 6); // ((width * height) * 64)
// Auto calcula el ultimo frame de la animacion
NF_SPR256VRAM[screen][vram].lastframe = ((int)(NF_SPR256GFX[ram].size / NF_SPR256VRAM[screen][vram].framesize)) - 1;
NF_SPR256VRAM[screen][vram].inuse = true; // Slot ocupado
// Calcula el tamaño del grafico a copiar segun si debes o no copiar todos los frames
if (keepframes) { // Si debes de mantener los frames en RAM, solo copia el primero
gfxsize = NF_SPR256VRAM[screen][vram].framesize;
} else { // Si no, copialos todos
gfxsize = NF_SPR256GFX[ram].size;
}
// Actualiza la VRAM disponible
NF_SPRVRAM[screen].free -= gfxsize;
// Si no hay suficiente VRAM, error
if (NF_SPRVRAM[screen].free < 0) {
NF_Error(113, "Sprites", gfxsize);
}
// Si hay que aprovechar algun bloque borrado... (tamaño identico, preferente)
if (NF_SPRVRAM[screen].deleted > 0) {
// Busca un bloque vacio del tamaño identico
for (n = 0; n < NF_SPRVRAM[screen].deleted; n ++) {
if (NF_SPRVRAM[screen].size[n] == gfxsize) { // Si el bloque tiene el tamaño suficiente
id = n; // Guarda la Id
n = NF_SPRVRAM[screen].deleted; // y sal
}
}
// Si no habia ningun bloque de tamaño identico, busca el mas parecido (produce fragmentacion)
if (id == 255) {
// Busca un bloque vacio del tamaño suficiente
for (n = 0; n < NF_SPRVRAM[screen].deleted; n ++) {
if (NF_SPRVRAM[screen].size[n] > gfxsize) { // Si el bloque tiene el tamaño suficiente
id = n; // Guarda la Id
n = NF_SPRVRAM[screen].deleted; // y sal
}
}
}
}
// Si hay algun bloque borrado libre del tamaño suficiente...
if (id != 255) {
// Transfiere el grafico a la VRAM
NF_DmaMemCopy((void*)NF_SPRVRAM[screen].pos[id], NF_BUFFER_SPR256GFX[ram], gfxsize);
// Guarda el puntero donde lo has almacenado
NF_SPR256VRAM[screen][vram].address = NF_SPRVRAM[screen].pos[id];
// Si no has usado todo el tamaño, deja constancia
if (gfxsize < NF_SPRVRAM[screen].size[id]) {
// Calcula el tamaño del nuevo bloque libre
size = (NF_SPRVRAM[screen].size[id] - gfxsize);
// Actualiza los datos
NF_SPRVRAM[screen].pos[id] += gfxsize; // Nueva direccion
NF_SPRVRAM[screen].size[id] = size; // Nuevo tamaño
NF_SPRVRAM[screen].fragmented -= gfxsize; // Actualiza el contador de VRAM fragmentada
organize = false; // No se debe de reorganizar el array de bloques
} else { // Si has usado todo el tamaño, deja constancia
NF_SPRVRAM[screen].fragmented -= NF_SPRVRAM[screen].size[id]; // Actualiza el contador de VRAM fragmentada
}
// Se tiene que reorganizar el array de bloques libres ?
if (organize) {
last_reuse = (NF_SPRVRAM[screen].deleted - 1);
if (
(last_reuse > 0) // Si hay mas de un bloque borrado
&&
(id != last_reuse) // Y no es la ultima posicion
) {
// Coloca los valores de la ultima posicion en esta
NF_SPRVRAM[screen].pos[id] = NF_SPRVRAM[screen].pos[last_reuse]; // Nueva direccion
NF_SPRVRAM[screen].size[id] = NF_SPRVRAM[screen].size[last_reuse]; // Nuevo tamaño
}
NF_SPRVRAM[screen].deleted --; // Actualiza el contador de bloques libres, borrando el ultimo registro
}
} else { // Si no habia ningun bloque borrado o con el tamaño suficiente, colacalo al final de la VRAM ocupada
// Actualiza la VRAM contigua disponible (mayor bloque libre al final)
NF_SPRVRAM[screen].inarow -= gfxsize;
// Si no hay suficiente VRAM (contigua), error
if (NF_SPRVRAM[screen].inarow < 0) {
NF_Error(113, "Sprites", gfxsize);
}
// Transfiere el grafico a la VRAM
NF_DmaMemCopy((void*)NF_SPRVRAM[screen].next, NF_BUFFER_SPR256GFX[ram], gfxsize);
// Guarda el puntero donde lo has almacenado
NF_SPR256VRAM[screen][vram].address = NF_SPRVRAM[screen].next;
// Guarda la direccion actual como la ultima usada
NF_SPRVRAM[screen].last = NF_SPRVRAM[screen].next;
// Calcula la siguiente posicion libre
NF_SPRVRAM[screen].next += gfxsize;
}
// Guarda los datos del Gfx que se copiara a la VRAM.
NF_SPR256VRAM[screen][vram].size = gfxsize; // Tamaño en bytes de los datos copiados
NF_SPR256VRAM[screen][vram].width = NF_SPR256GFX[ram].width; // Alto (px)
NF_SPR256VRAM[screen][vram].height = NF_SPR256GFX[ram].height; // Ancho (px)
NF_SPR256VRAM[screen][vram].ramid = ram; // Slot RAM de origen
NF_SPR256VRAM[screen][vram].keepframes = keepframes; // Debes guardar los frames en RAM o copiarlos a la VRAM?
}
// Funcion NF_FreeSpriteGfx();
void NF_FreeSpriteGfx(u8 screen, u16 id) {
// Verifica si hay un grafico cargado en esa Id.
if (!NF_SPR256VRAM[screen][id].inuse) {
NF_Error(110, "Sprite Gfx", id);
}
// Borra el Gfx de la VRAM (pon a 0 todos los Bytes)
memset((void*)NF_SPR256VRAM[screen][id].address, 0, NF_SPR256VRAM[screen][id].size);
// Actualiza la cantidad de VRAM disponible
NF_SPRVRAM[screen].free += NF_SPR256VRAM[screen][id].size;
// Guarda la posicion y tamaño del bloque borrado para su reutilizacion
NF_SPRVRAM[screen].pos[NF_SPRVRAM[screen].deleted] = NF_SPR256VRAM[screen][id].address;
NF_SPRVRAM[screen].size[NF_SPRVRAM[screen].deleted] = NF_SPR256VRAM[screen][id].size;
// Incrementa en contador de bloques borrados
NF_SPRVRAM[screen].deleted ++;
// Incrementa el contador de memoria fragmentada
NF_SPRVRAM[screen].fragmented += NF_SPR256VRAM[screen][id].size;
// Reinicia los datos de esta Id. de gfx
NF_SPR256VRAM[screen][id].size = 0; // Tamaño en bytes
NF_SPR256VRAM[screen][id].width = 0; // Alto (px)
NF_SPR256VRAM[screen][id].height = 0; // Ancho (px)
NF_SPR256VRAM[screen][id].address = 0; // Puntero en VRAM
NF_SPR256VRAM[screen][id].framesize = 0; // Tamaño del frame (en bytes)
NF_SPR256VRAM[screen][id].lastframe = 0; // Ultimo frame
NF_SPR256VRAM[screen][id].inuse = false;
// Debes desfragmentar la VRAM
if (NF_SPRVRAM[screen].fragmented >= (NF_SPRVRAM[screen].inarow >> 1)) {
NF_VramSpriteGfxDefrag(screen);
}
}
// Funcion NF_VramSpriteGfxDefrag();
void NF_VramSpriteGfxDefrag(u8 screen) {
// Calcula la VRAM en uso y crea un buffer para guardarla
u32 used_vram = ((NF_SPRVRAM[screen].max - NF_SPRVRAM[screen].free) + 1);
char* buffer;
buffer = (char*) calloc (used_vram, sizeof(char));
if (buffer == NULL) { // Si no hay suficiente RAM libre
NF_Error(102, NULL, used_vram);
}
char* address[128]; // Guarda la direccion en RAM
u32 size[128]; // Guarda el tamaño
u32 ram = 0; // Puntero inicial de RAM
u8 n = 0; // Variable General
u32 frame_address = 0; // Guarda la direccion de VRAM del frame
// Copia los datos de la VRAM a la RAM
for (n = 0; n < 128; n ++) {
// Si esta en uso
if (NF_SPR256VRAM[screen][n].inuse) {
// Copia el Gfx a la RAM
address[n] = (buffer + ram); // Calcula el puntero
size[n] = NF_SPR256VRAM[screen][n].size; // Almacena el tamaño
NF_DmaMemCopy(address[n], (void*)NF_SPR256VRAM[screen][n].address, size[n]); // Copialo a la VRAM
ram += size[n]; // Siguiente posicion en RAM (relativa)
}
}
// Inicializa la estructura de datos de la VRAM de Sprites
NF_SPRVRAM[screen].free = NF_SPRVRAM[screen].max; // Memoria VRAM libre (128kb)
NF_SPRVRAM[screen].last = 0; // Ultima posicion usada
NF_SPRVRAM[screen].deleted = 0; // Ningun Gfx borrado
NF_SPRVRAM[screen].fragmented = 0; // Memoria VRAM fragmentada
NF_SPRVRAM[screen].inarow = NF_SPRVRAM[screen].max; // Memoria VRAM contigua
for (n = 0; n < 128; n ++) {
NF_SPRVRAM[screen].pos[n] = 0; // Posicion en VRAM para reusar despues de un borrado
NF_SPRVRAM[screen].size[n] = 0; // Tamaño del bloque libre para reusar
}
// Aplica la direccion de inicio de la VRAM
if (screen == 0) {
NF_SPRVRAM[screen].next = (0x06400000);
} else {
NF_SPRVRAM[screen].next = (0x06600000);
}
// Ahora, copia de nuevo los datos a la VRAM, pero alineados
for (n = 0; n < 128; n ++) {
// Si esta en uso
if (NF_SPR256VRAM[screen][n].inuse) {
NF_DmaMemCopy((void*)NF_SPRVRAM[screen].next, address[n], size[n]); // Vuelve a colocar la el Gfx en VRAM
NF_SPR256VRAM[screen][n].address = NF_SPRVRAM[screen].next; // Guarda la nueva posicion en VRAM
NF_SPRVRAM[screen].free -= size[n]; // Ram libre
NF_SPRVRAM[screen].inarow -= size[n]; // Ram libre en bloque
NF_SPRVRAM[screen].last = NF_SPRVRAM[screen].next; // Guarda la posicion como ultima usada
NF_SPRVRAM[screen].next += size[n]; // Y calcula la siguiente posicion a escribir
}
}
// Reasigna a los sprites las nuevas posiciones de los graficos que usan
for (n = 0; n < 128; n ++) {
if (NF_SPRITEOAM[screen][n].created) {
if (NF_SPR256VRAM[screen][NF_SPRITEOAM[screen][n].gfxid].keepframes) {
// Si la opcion de animacion KEEP FRAMES esta activada,
// simplemente asigna la nueva direccion en VRAM del grafico.
NF_SPRITEOAM[screen][n].gfx = (u32*)NF_SPR256VRAM[screen][NF_SPRITEOAM[screen][n].gfxid].address;
} else {
// Si la opcion KEEP FRAMES esta desactivada,
// calcula el desplazamiento dentro de la nueva direccion asignada.
frame_address = (NF_SPR256VRAM[screen][NF_SPRITEOAM[screen][n].gfxid].address + (NF_SPRITEOAM[screen][n].framesize * NF_SPRITEOAM[screen][n].frame));
NF_SPRITEOAM[screen][n].gfx = (u32*)frame_address;
}
}
}
// Vacia el buffer
free(buffer);
buffer = NULL;
}
// Funcion NF_VramSpritePal();
void NF_VramSpritePal(u8 screen, u8 id, u8 slot) {
// Verifica el rango de Id's
if ((id < 0) || (id >= NF_SLOTS_SPR256PAL)) {
NF_Error(106, "Sprite PAL", NF_SLOTS_SPR256PAL);
}
// Verifica si la Id esta libre
if (NF_SPR256PAL[id].available) {
NF_Error(110, "Sprite PAL", id);
}
// Verifica si te has salido de rango (Paleta)
if ((slot < 0) || (slot > 15)) {
NF_Error(106, "Sprite Palette Slot", 15);
}
// Copia la paleta a la VRAM, segun la pantalla y el Slot
u32 address = 0;
if (screen == 0) {
address = (0x06890000) + (slot << 9); // Calcula donde guardaras la paleta
vramSetBankF(VRAM_F_LCD); // Bloquea el banco F para escribir las paletas
NF_DmaMemCopy((void*)address, NF_BUFFER_SPR256PAL[id], NF_SPR256PAL[id].size); // Copia la paleta al banco F
vramSetBankF(VRAM_F_SPRITE_EXT_PALETTE); // Pon el banco F en modo paleta extendida
} else {
address = (0x068A0000) + (slot << 9); // Calcula donde guardaras la paleta
vramSetBankI(VRAM_I_LCD); // Bloquea el banco I para escribir las paletas
NF_DmaMemCopy((void*)address, NF_BUFFER_SPR256PAL[id], NF_SPR256PAL[id].size); // Copia la paleta al banco I
vramSetBankI(VRAM_I_SUB_SPRITE_EXT_PALETTE); // Pon el banco I en modo paleta extendida
}
NF_SPRPALSLOT[screen][slot].inuse = true; // Marca el SLOT de paleta como en uso
NF_SPRPALSLOT[screen][slot].ramslot = id; // Guarda el slot de RAM donde esta la paleta original
}
// Funcion NF_CreateSprite();
void NF_CreateSprite(u8 screen, u8 id, u16 gfx, u8 pal, s16 x, s16 y) {
// Verifica el rango de Id's de Sprites
if ((id < 0) || (id > 127)) {
NF_Error(106, "Sprite", 127);
}
// Verifica el rango de Id's de Gfx
if ((gfx < 0) || (gfx > 127)) {
NF_Error(106, "Sprite GFX", 127);
}
// Verifica si esta el Gfx en VRAM
if (!NF_SPR256VRAM[screen][gfx].inuse) {
NF_Error(111, "Sprite GFX", gfx);
}
// Verifica el rango de slots de paletas
if ((pal < 0) || (pal > 15)) {
NF_Error(106, "Sprite Palette Slot", 15);
}
// Verifica si esta la paleta en VRAM
if (!NF_SPRPALSLOT[screen][pal].inuse) {
NF_Error(111, "Sprite PAL", pal);
}
// // Informa al array de OAM del Id
NF_SPRITEOAM[screen][id].index = id;
// Informa al array de OAM del Gfx a usar
NF_SPRITEOAM[screen][id].gfx = (u32*)NF_SPR256VRAM[screen][gfx].address;
// Informa al array de OAM de la Paleta a usar
NF_SPRITEOAM[screen][id].pal = pal;
// Informa al array de OAM de la coordenada X
NF_SPRITEOAM[screen][id].x = x;
// Informa al array de OAM de la coordenada X
NF_SPRITEOAM[screen][id].y = y;
// Informa al array de OAM del numero de colores
NF_SPRITEOAM[screen][id].color = SpriteColorFormat_256Color;
// Informa al array de OAM de que debe mostrar el sprite
NF_SPRITEOAM[screen][id].hide = false;
// Informa al array de OAM del Id de Gfx usado
NF_SPRITEOAM[screen][id].gfxid = gfx;
// Informa al array de OAM de que el sprite se ha creado
NF_SPRITEOAM[screen][id].created = true;
// Informa al array de OAM del tamaño
if ((NF_SPR256VRAM[screen][gfx].width == 8) && (NF_SPR256VRAM[screen][gfx].height == 8)) { // 8x8
if (NF_SPRVRAM[screen].max != 131072) { // En modo 1D_128, este tamaño es ilegal
NF_SPRITEOAM[screen][id].size = SpriteSize_8x8;
} else {
NF_Error(120, NULL, id);
}
}
if ((NF_SPR256VRAM[screen][gfx].width == 16) && (NF_SPR256VRAM[screen][gfx].height == 16)) { // 16x16
NF_SPRITEOAM[screen][id].size = SpriteSize_16x16;
}
if ((NF_SPR256VRAM[screen][gfx].width == 32) && (NF_SPR256VRAM[screen][gfx].height == 32)) { // 32x32
NF_SPRITEOAM[screen][id].size = SpriteSize_32x32;
}
if ((NF_SPR256VRAM[screen][gfx].width == 64) && (NF_SPR256VRAM[screen][gfx].height == 64)) { // 64x64
NF_SPRITEOAM[screen][id].size = SpriteSize_64x64;
}
if ((NF_SPR256VRAM[screen][gfx].width == 16) && (NF_SPR256VRAM[screen][gfx].height == 8)) { // 16x8
NF_SPRITEOAM[screen][id].size = SpriteSize_16x8;
}
if ((NF_SPR256VRAM[screen][gfx].width == 32) && (NF_SPR256VRAM[screen][gfx].height == 8)) { // 32x8
NF_SPRITEOAM[screen][id].size = SpriteSize_32x8;
}
if ((NF_SPR256VRAM[screen][gfx].width == 32) && (NF_SPR256VRAM[screen][gfx].height == 16)) { // 32x16
NF_SPRITEOAM[screen][id].size = SpriteSize_32x16;
}
if ((NF_SPR256VRAM[screen][gfx].width == 64) && (NF_SPR256VRAM[screen][gfx].height == 32)) { // 64x32
NF_SPRITEOAM[screen][id].size = SpriteSize_64x32;
}
if ((NF_SPR256VRAM[screen][gfx].width == 8) && (NF_SPR256VRAM[screen][gfx].height == 16)) { // 8x16
NF_SPRITEOAM[screen][id].size = SpriteSize_8x16;
}
if ((NF_SPR256VRAM[screen][gfx].width == 8) && (NF_SPR256VRAM[screen][gfx].height == 32)) { // 8x32
NF_SPRITEOAM[screen][id].size = SpriteSize_8x32;
}
if ((NF_SPR256VRAM[screen][gfx].width == 16) && (NF_SPR256VRAM[screen][gfx].height == 32)) { // 16x32
NF_SPRITEOAM[screen][id].size = SpriteSize_16x32;
}
if ((NF_SPR256VRAM[screen][gfx].width == 32) && (NF_SPR256VRAM[screen][gfx].height == 64)) { // 32x64
NF_SPRITEOAM[screen][id].size = SpriteSize_32x64;
}
// Informa al array de OAM del ultimo frame del Sprite
NF_SPRITEOAM[screen][id].lastframe = NF_SPR256VRAM[screen][gfx].lastframe;
// Informa al array de OAM del tamaño del frame del Sprite (en bytes)
NF_SPRITEOAM[screen][id].framesize = NF_SPR256VRAM[screen][gfx].framesize;
// Por defecto, el primer frame (0)
NF_SPRITEOAM[screen][id].frame = 0;
}
// Funcion NF_DeleteSprite();
void NF_DeleteSprite(u8 screen, u8 id) {
// Verifica el rango de Id's de Sprites
if ((id < 0) || (id > 127)) {
NF_Error(106, "Sprite", 127);
}
// Verifica si el Sprite esta creado
if (!NF_SPRITEOAM[screen][id].created) {
char text[4];
sprintf(text, "%d", screen);
NF_Error(112, text, id);
}
// Reinicia todas las variables de ese Sprite
NF_SPRITEOAM[screen][id].index = id; // Numero de Sprite
NF_SPRITEOAM[screen][id].x = 0; // Coordenada X del Sprite (0 por defecto)
NF_SPRITEOAM[screen][id].y = 0; // Coordenada Y del Sprite (0 por defecto)
NF_SPRITEOAM[screen][id].layer = 0; // Prioridad en las capas (0 por defecto)
NF_SPRITEOAM[screen][id].pal = 0; // Paleta que usaras (0 por defecto)
NF_SPRITEOAM[screen][id].size = SpriteSize_8x8; // Tamaño del Sprite (macro) (8x8 por defecto)
NF_SPRITEOAM[screen][id].color = SpriteColorFormat_256Color; // Modo de color (macro) (256 colores)
NF_SPRITEOAM[screen][id].gfx = NULL; // Puntero al grafico usado
NF_SPRITEOAM[screen][id].rot = -1; // Id de rotacion (-1 ninguno) (0 - 31 Id de rotacion)
NF_SPRITEOAM[screen][id].doublesize = false; // Usar el "double size" al rotar ? ("NO" por defecto)
NF_SPRITEOAM[screen][id].hide = true; // Ocultar el Sprite ("SI" por defecto)
NF_SPRITEOAM[screen][id].hflip = false; // Volteado Horizontal ("NO" por defecto)
NF_SPRITEOAM[screen][id].vflip = false; // Volteado Vertical ("NO" por defecto)
NF_SPRITEOAM[screen][id].mosaic = false; // Mosaico ("NO" por defecto)
NF_SPRITEOAM[screen][id].gfxid = 0; // Numero de Gfx usado
NF_SPRITEOAM[screen][id].frame = 0; // Frame actual
NF_SPRITEOAM[screen][id].framesize = 0; // Tamaño del frame (en bytes)
NF_SPRITEOAM[screen][id].lastframe = 0; // Ultimo frame
NF_SPRITEOAM[screen][id].created = false; // Esta creado este sprite ?
}
// Funcion NF_SpriteOamSet();
void NF_SpriteOamSet(u8 screen) {
u8 n = 0; // Variable de uso general
if (screen == 0) {
for (n = 0; n < 128; n ++) {
oamSet(&oamMain, // OAM pantalla superior (Main, 0)
NF_SPRITEOAM[screen][n].index, // Numero de Sprite
NF_SPRITEOAM[screen][n].x, // Coordenada X del Sprite
NF_SPRITEOAM[screen][n].y, // Coordenada Y del Sprite
NF_SPRITEOAM[screen][n].layer, // Prioridad en las capas
NF_SPRITEOAM[screen][n].pal, // Paleta que usaras
NF_SPRITEOAM[screen][n].size, // Tamaño del Sprite (macro)
NF_SPRITEOAM[screen][n].color, // Modo de color (macro)
NF_SPRITEOAM[screen][n].gfx, // Puntero al grafico usado
NF_SPRITEOAM[screen][n].rot, // Valor de la rotacion
NF_SPRITEOAM[screen][n].doublesize, // Usar el "double size" al rotar ?
NF_SPRITEOAM[screen][n].hide, // Ocultar el Sprite
NF_SPRITEOAM[screen][n].hflip, // Volteado Horizontal
NF_SPRITEOAM[screen][n].vflip, // Volteado Vertical
NF_SPRITEOAM[screen][n].mosaic); // Mosaico
}
} else {
for (n = 0; n < 128; n ++) {
oamSet(&oamSub, // OAM pantalla superior (Main, 0)
NF_SPRITEOAM[screen][n].index, // Numero de Sprite
NF_SPRITEOAM[screen][n].x, // Coordenada X del Sprite
NF_SPRITEOAM[screen][n].y, // Coordenada Y del Sprite
NF_SPRITEOAM[screen][n].layer, // Prioridad en las capas
NF_SPRITEOAM[screen][n].pal, // Paleta que usaras
NF_SPRITEOAM[screen][n].size, // Tamaño del Sprite (macro)
NF_SPRITEOAM[screen][n].color, // Modo de color (macro)
NF_SPRITEOAM[screen][n].gfx, // Puntero al grafico usado
NF_SPRITEOAM[screen][n].rot, // Valor de la rotacion
NF_SPRITEOAM[screen][n].doublesize, // Usar el "double size" al rotar ?
NF_SPRITEOAM[screen][n].hide, // Ocultar el Sprite
NF_SPRITEOAM[screen][n].hflip, // Volteado Horizontal
NF_SPRITEOAM[screen][n].vflip, // Volteado Vertical
NF_SPRITEOAM[screen][n].mosaic); // Mosaico
}
}
}
// Funcion NF_SpriteSetPalColor();
void NF_SpriteSetPalColor(u8 screen, u8 pal, u8 number, u8 r, u8 g, u8 b) {
// Verifica si esta la paleta en VRAM
if (!NF_SPRPALSLOT[screen][pal].inuse) {
NF_Error(111, "Sprite PAL", pal);
}
// Calcula el valor RGB
u16 rgb = ((r)|((g) << 5)|((b) << 10));
// Direccion en VRAM
u32 address = 0;
// Modifica la paleta
if (screen == 0) {
address = (0x06890000) + (pal << 9) + (number << 1); // Calcula donde guardaras el color de la paleta
vramSetBankF(VRAM_F_LCD); // Bloquea el banco F para escribir las paletas
*((u16*)address) = rgb; // Cambia el color
vramSetBankF(VRAM_F_SPRITE_EXT_PALETTE); // Pon el banco F en modo paleta extendida
} else {
address = (0x068A0000) + (pal << 9) + (number << 1); // Calcula donde guardaras el color de la paleta
vramSetBankI(VRAM_I_LCD); // Bloquea el banco I para escribir las paletas
*((u16*)address) = rgb; // Cambia el color
vramSetBankI(VRAM_I_SUB_SPRITE_EXT_PALETTE); // Pon el banco I en modo paleta extendida
}
}
// Funcion NF_SpriteEditPalColor();
void NF_SpriteEditPalColor(u8 screen, u8 pal, u8 number, u8 r, u8 g, u8 b) {
// Verifica si esta la paleta en VRAM
if (!NF_SPRPALSLOT[screen][pal].inuse) {
NF_Error(111, "Sprite PAL", pal);
}
// 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_SPR256PAL[NF_SPRPALSLOT[screen][pal].ramslot] + (number << 1)) = lobyte;
*(NF_BUFFER_SPR256PAL[NF_SPRPALSLOT[screen][pal].ramslot] + ((number << 1) + 1)) = hibyte;
}
// Funcion NF_SpriteUpdatePalette();
void NF_SpriteUpdatePalette(u8 screen, u8 pal) {
// Verifica si esta la paleta en VRAM
if (!NF_SPRPALSLOT[screen][pal].inuse) {
NF_Error(111, "Sprite PAL", pal);
}
// Direccion en VRAM
u32 address = 0;
// Obten el slot donde esta la paleta en RAM
u8 slot = NF_SPRPALSLOT[screen][pal].ramslot;
// Actualiza la paleta en VRAM
if (screen == 0) {
address = (0x06890000) + (pal << 9); // Calcula donde guardaras la paleta
vramSetBankF(VRAM_F_LCD); // Bloquea el banco F para escribir las paletas
NF_DmaMemCopy((void*)address, NF_BUFFER_SPR256PAL[slot], NF_SPR256PAL[slot].size); // Copia la paleta al banco F
vramSetBankF(VRAM_F_SPRITE_EXT_PALETTE); // Pon el banco F en modo paleta extendida
} else {
address = (0x068A0000) + (pal << 9); // Calcula donde guardaras la paleta
vramSetBankI(VRAM_I_LCD); // Bloquea el banco I para escribir las paletas
NF_DmaMemCopy((void*)address, NF_BUFFER_SPR256PAL[slot], NF_SPR256PAL[slot].size); // Copia la paleta al banco I
vramSetBankI(VRAM_I_SUB_SPRITE_EXT_PALETTE); // Pon el banco I en modo paleta extendida
}
}
// Funcion NF_SpriteGetPalColor();
void NF_SpriteGetPalColor(u8 screen, u8 pal, u8 number, u8* r, u8* g, u8* b) {
// Verifica si esta la paleta en VRAM
if (!NF_SPRPALSLOT[screen][pal].inuse) {
NF_Error(111, "Sprite PAL", pal);
}
// Obten los bytes
u8 lobyte = *(NF_BUFFER_SPR256PAL[NF_SPRPALSLOT[screen][pal].ramslot] + (number << 1));
u8 hibyte = *(NF_BUFFER_SPR256PAL[NF_SPRPALSLOT[screen][pal].ramslot] + ((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);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,502 @@
// NightFox LIB - Funciones de Textos
// Requiere DevkitARM
// Codigo por Cesar Rincon "NightFox"
// http://www.nightfoxandco.com/
// Version 20140413
// Includes devKitPro
#include <nds.h>
#include <filesystem.h>
#include <fat.h>
// Includes C
#include <stdio.h>
#include <string.h>
#include <unistd.h>
// Includes propios
#include "nf_basic.h"
#include "nf_2d.h"
#include "nf_tiledbg.h"
#include "nf_text.h"
// Define los buffers para almacenar las capas de texto
NF_TYPE_TEXT_INFO NF_TEXT[2][4];
// Funcion NF_InitTextSys();
void NF_InitTextSys(u8 screen) {
u8 n = 0;
// Reinicia las variables
for (n = 0; n < 4; n ++) {
NF_TEXT[screen][n].width = 0; // Ancho del mapa de texto
NF_TEXT[screen][n].height = 0; // Alto del mapa de texto
NF_TEXT[screen][n].rotation = 0; // Rotacion a 0 (ninguna)
NF_TEXT[screen][n].slot = 255; // Slot donde esta el tileset
NF_TEXT[screen][n].pal = 0; // nº de paleta extendida (0 por defecto)
NF_TEXT[screen][n].exist = false; // Marcalo como no existente
NF_TEXT[screen][n].update = false; // No es necesario actualizarlo
}
}
// Funcion NF_LoadTextFont();
void NF_LoadTextFont(const char* file, const char* name, u16 width, u16 height, u8 rotation) {
// Busca un slot libre
u16 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 .FNT
sprintf(filename, "%s/%s.fnt", NF_ROOTFOLDER, file);
file_id = fopen(filename, "rb");
if (file_id) { // Si el archivo existe...
// Obten el tamaño del archivo
NF_TILEDBG[slot].tilesize = (NF_TEXT_FONT_CHARS << 6); // 100 caracteres x 64 bytes
// 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);
}
fread(NF_BUFFER_BGTILES[slot], 1, NF_TILEDBG[slot].tilesize, file_id); // Lee el resto de caracteres de la fuente
} else { // Si el archivo no existe...
NF_Error(101, filename, 0);
}
fclose(file_id); // Cierra el archivo
// Rota los Gfx de los tiles si es necesario
if (rotation > 0) {
for (n = 0; n < NF_TEXT_FONT_CHARS; n ++) {
NF_RotateTileGfx(slot, n, rotation);
}
}
// 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
sprintf(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);
NF_TILEDBG[slot].palsize = ftell(file_id);
rewind(file_id);
// 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, NF_TILEDBG[slot].palsize, file_id);
} else { // Si el archivo no existe...
NF_Error(101, filename, 0);
}
fclose(file_id); // Cierra el archivo
// Guarda el nombre del Fondo
sprintf(NF_TILEDBG[slot].name, "%s", name);
// Y las medidas
NF_TILEDBG[slot].width = width;
NF_TILEDBG[slot].height = height;
}
// Funcion NF_UnloadTestFont();
void NF_UnloadTextFont(const char* name) {
NF_UnloadTiledBg(name);
}
// Funcion NF_CreateTextLayer();
void NF_CreateTextLayer(u8 screen, u8 layer, u8 rotation, const char* name) {
u8 n = 0; // Bucle
u8 slot = 255; // Slot seleccionado
char bg[32]; // Nombre
// Crea un fondo para usarlo como capa de texto
NF_CreateTiledBg(screen, layer, name);
// Busca el numero de slot donde esta cargada la fuente
sprintf(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
}
}
// Guarda si el texto debe ser rotado
NF_TEXT[screen][layer].rotation = rotation;
// Guarda las medidas del fondo en tiles (ultimo numero de tile)
NF_TEXT[screen][layer].width = ((NF_TILEDBG[slot].width >> 3) - 1);
NF_TEXT[screen][layer].height = ((NF_TILEDBG[slot].height >> 3) - 1);
// Almacena el slot donde esta cargada la fuente
NF_TEXT[screen][layer].slot = slot;
// Y marcalo como creado
NF_TEXT[screen][layer].exist = true;
}
// Funcion NF_DeleteTextLayer();
void NF_DeleteTextLayer(u8 screen, u8 layer) {
// Verifica si la capa de texto de destino existe
if (!NF_TEXT[screen][layer].exist) {
NF_Error(114, NULL, screen);
}
// Borra el fondo usado como capa de texto
NF_DeleteTiledBg(screen, layer);
// Guarda si el texto debe ser rotado
NF_TEXT[screen][layer].rotation = 0;
// Guarda las medidas del fondo en tiles
NF_TEXT[screen][layer].width = 0;
NF_TEXT[screen][layer].height = 0;
// Y marcalo como creado
NF_TEXT[screen][layer].exist = false;
}
// Funcion NF_WriteText();
void NF_WriteText(u8 screen, u8 layer, u16 x, u16 y, const char* text) {
// Verifica si la capa de texto de destino existe
if (!NF_TEXT[screen][layer].exist) {
NF_Error(114, NULL, screen);
}
u16 n = 0; // Variable de uso general
s16 value = 0; // Valor
u16 tsize = 0; // Almacena el numero de letras
tsize = strlen(text); // Calcula el numero de letras del texto
u8* string; // Buffer temporal
string = NULL;
string = (u8*) calloc (tsize, sizeof(u8));
// Almacena en el buffer temporal el valor de los caracteres
for (n = 0; n < tsize; n ++) {
value = ((int)(text[n])) - 32; // Resta 32 al valor entrado
if (value < 0) value = 0;
string[n] = value;
// Si es un caracter especial...
if (string[n] > 95) {
// Resetea el caracter...
string[n] = 0;
// Verifica caracteres especiales
switch (((int)(text[n]))) {
// Salto de linea
case 10: // \n
string[n] = 200;
break;
// Caracteres especiales
case 199: // Ç
string[n] = 96;
break;
case 231: // ç
string[n] = 97;
break;
case 209: // Ñ
string[n] = 98;
break;
case 241: // ñ
string[n] = 99;
break;
// Acentos Mayusculas
case 193: // Á
string[n] = 100;
break;
case 201: // É
string[n] = 101;
break;
case 205: // Í
string[n] = 102;
break;
case 211: // Ó
string[n] = 103;
break;
case 218: // Ú
string[n] = 104;
break;
// Acentos Minusculas
case 225: // á
string[n] = 105;
break;
case 233: // é
string[n] = 106;
break;
case 237: // í
string[n] = 107;
break;
case 243: // ó
string[n] = 108;
break;
case 250: // ú
string[n] = 109;
break;
// Dieresis
case 239: // ï
string[n] = 110;
break;
case 252: // ü
string[n] = 111;
break;
// Admiracion e interrogante (Español)
case 161: // ¡
string[n] = 112;
break;
case 191: // ¿
string[n] = 113;
break;
// Caracter invalido
default:
string[n] = 0;
break;
}
}
}
// Variable para calcular la posicion del texto
s16 tx = 0; // X
s16 ty = 0; // Y
// Escribe los datos en el buffer de texto, segun la rotacion
switch (NF_TEXT[screen][layer].rotation) {
case 0: // Sin rotacion
// Traspasa las coordenadas virtuales a las reales
tx = x;
ty = y;
// Copia el texto al buffer letra a letra
for (n = 0; n < tsize; n ++) {
// Si es un caracter valido
if (string[n] <= NF_TEXT_FONT_LAST_VALID_CHAR) {
// Escribe la letra correspondiente
NF_SetTileOfMap(screen,layer, tx, ty, ((NF_TEXT[screen][layer].pal << 12) + string[n]));
// Siguiente letra
tx ++;
}
if ((tx > NF_TEXT[screen][layer].width) || (string[n] == 200)) { // Si llegas al final de linea,
tx = 0; // salto de linea
ty ++;
if (ty > NF_TEXT[screen][layer].height) { // Si estas en la ultima linea,
ty = 0; // vuelve a la primera
}
}
}
break;
case 1: // Rotacion 90º a la derecha
// Traspasa las coordenadas virtuales a las reales
tx = (NF_TEXT[screen][layer].width - y);
ty = x;
// Copia el texto al buffer letra a letra
for (n = 0; n < tsize; n ++) {
// Si es un caracter valido
if (string[n] <= NF_TEXT_FONT_LAST_VALID_CHAR) {
// Escribe la letra correspondiente
NF_SetTileOfMap(screen,layer, tx, ty, ((NF_TEXT[screen][layer].pal << 12) + string[n]));
// Siguiente letra
ty ++;
}
if ((ty > NF_TEXT[screen][layer].height) || (string[n] == 200)) { // Si llegas al final de linea,
ty = 0; // salto de linea
tx --;
if (tx < 0) { // Si estas en la ultima linea,
tx = NF_TEXT[screen][layer].width; // vuelve a la primera
}
}
}
break;
case 2: // Rotacion 90º a la izquierda
// Traspasa las coordenadas virtuales a las reales
tx = y;
ty = (NF_TEXT[screen][layer].height - x);
// Copia el texto al buffer letra a letra
for (n = 0; n < tsize; n ++) {
// Si es un caracter valido
if (string[n] <= NF_TEXT_FONT_LAST_VALID_CHAR) {
// Escribe la letra correspondiente
NF_SetTileOfMap(screen,layer, tx, ty, ((NF_TEXT[screen][layer].pal << 12) + string[n]));
// Siguiente letra
ty --;
}
if ((ty < 0) || (string[n] == 200)) { // Si llegas al final de linea,
ty = NF_TEXT[screen][layer].height; // Salto de linea
tx ++;
if (tx > NF_TEXT[screen][layer].width) { // Si llegas a la ultima linea
tx = 0; // vuelve a la primera
}
}
}
break;
}
// Marca esta capa de texto para actualizar
NF_TEXT[screen][layer].update = true;
// Libera el buffer
free(string);
}
// Funcion NF_UpdateTextLayers();
void NF_UpdateTextLayers(void) {
// Variables
u8 screen = 0;
u8 layer = 0;
// Verifica si se tiene que actualizar la capa de texto
for (screen = 0; screen < 2; screen ++) { // Bucle de pantalla
for (layer = 0; layer < 4; layer ++) { // Bucle de capas
if (NF_TEXT[screen][layer].update) { // Si estas marcado para actualizar, hazlo
NF_UpdateVramMap(screen, layer);
// Y marcala como actualizada
NF_TEXT[screen][layer].update = false;
}
}
}
}
// Funcion NF_ClearTextLayer();
void NF_ClearTextLayer(u8 screen, u8 layer) {
// Verifica si la capa de texto de destino existe
if (!NF_TEXT[screen][layer].exist) {
NF_Error(114, NULL, screen);
}
// Calcula el tamaño del buffer
u32 size = (((NF_TEXT[screen][layer].width + 1) * (NF_TEXT[screen][layer].height + 1)) << 1);
// Pon a 0 todos los bytes del mapa de la capa de texto
memset(NF_BUFFER_BGMAP[NF_TEXT[screen][layer].slot], 0, size);
// Marca esta capa de texto para actualizar
NF_TEXT[screen][layer].update = true;
}
// Funcion NF_DefineTextColor();
void NF_DefineTextColor(u8 screen, u8 layer, u8 color, u8 r, u8 g, u8 b) {
// Verifica si la capa de texto de destino existe
if (!NF_TEXT[screen][layer].exist) {
NF_Error(114, NULL, screen);
}
// 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) + (color << 9); // Primer color de la paleta
*((u16*)address) = (u16)0xFF00FF;
address = (0x06880000) + (layer << 13) + (color << 9) + 2; // Segundo color de la paleta
*((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) + (color << 9); // Primer color de la paleta
*((u16*)address) = (u16)0xFF00FF;
address = (0x06898000) + (layer << 13) + (color << 9) + 2; // Segundo color de la paleta
*((u16*)address) = rgb;
vramSetBankH(VRAM_H_SUB_BG_EXT_PALETTE);
}
}
// Function NF_SetTextColor();
void NF_SetTextColor(u8 screen, u8 layer, u8 color) {
NF_TEXT[screen][layer].pal = color;
}

View File

@ -0,0 +1,430 @@
// NightFox LIB - Funciones de Textos de 16 pixeles
// Requiere DevkitARM
// Codigo por Cesar Rincon "NightFox"
// http://www.nightfoxandco.com/
// Version 20140413
// Includes devKitPro
#include <nds.h>
#include <filesystem.h>
#include <fat.h>
// Includes C
#include <stdio.h>
#include <string.h>
#include <unistd.h>
// Includes propios
#include "nf_basic.h"
#include "nf_2d.h"
#include "nf_tiledbg.h"
#include "nf_text.h"
#include "nf_text16.h"
// Funcion NF_LoadTextFont16();
void NF_LoadTextFont16(const char* file, const char* name, u16 width, u16 height, u8 rotation) {
// Variable temporal del tamaño de la paleta
u32 pal_size = 0;
// Busca un slot libre
u16 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 .fnt
sprintf(filename, "%s/%s.fnt", NF_ROOTFOLDER, file);
file_id = fopen(filename, "rb");
if (file_id) { // Si el archivo existe...
// Obten el tamaño del archivo
NF_TILEDBG[slot].tilesize = (NF_TEXT_FONT_CHARS_16 << 7); // 1 letra 128 bytes (letras * 128)
// 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
// Rota los Gfx de los tiles si es necesario
if (rotation > 0) {
for (n = 0; n < (NF_TEXT_FONT_CHARS_16 << 1); n ++) {
NF_RotateTileGfx(slot, n, rotation);
}
}
// 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
sprintf(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
sprintf(NF_TILEDBG[slot].name, "%s", name);
// Y las medidas
NF_TILEDBG[slot].width = width;
NF_TILEDBG[slot].height = height;
}
// Funcion NF_CreateTextLayer16();
void NF_CreateTextLayer16(u8 screen, u8 layer, u8 rotation, const char* name) {
u8 n = 0; // Bucle
u8 slot = 255; // Slot seleccionado
char bg[32]; // Nombre
// Crea un fondo para usarlo como capa de texto
NF_CreateTiledBg(screen, layer, name);
// Busca el numero de slot donde esta cargada la fuente
sprintf(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
}
}
// Guarda si el texto debe ser rotado
NF_TEXT[screen][layer].rotation = rotation;
// Guarda las medidas del fondo en tiles (ultimo numero de tile)
switch (rotation) {
case 0: // Sin rotacion
NF_TEXT[screen][layer].width = ((NF_TILEDBG[slot].width >> 3) - 1);
NF_TEXT[screen][layer].height = ((NF_TILEDBG[slot].height >> 4) - 1);
break;
case 1: // 90º derecha
NF_TEXT[screen][layer].width = ((NF_TILEDBG[slot].width >> 4) - 1);
NF_TEXT[screen][layer].height = ((NF_TILEDBG[slot].height >> 3) - 1);
break;
case 2: // 90º izquierda
NF_TEXT[screen][layer].width = ((NF_TILEDBG[slot].width >> 4) - 1);
NF_TEXT[screen][layer].height = ((NF_TILEDBG[slot].height >> 3) - 1);
break;
}
// Almacena el slot donde esta cargada la fuente
NF_TEXT[screen][layer].slot = slot;
// Y marcalo como creado
NF_TEXT[screen][layer].exist = true;
}
// Funcion NF_WriteText16();
void NF_WriteText16(u8 screen, u8 layer, u16 x, u16 y, const char* text) {
// Verifica si la capa de texto de destino existe
if (!NF_TEXT[screen][layer].exist) {
NF_Error(114, NULL, screen);
}
u16 n = 0; // Variable de uso general
s16 value = 0; // Valor
u16 tsize = strlen(text); // Calcula el numero de letras del texto
u8* string; // Buffer temporal
string = NULL;
string = (u8*) calloc (tsize, sizeof(u8));
// Almacena en el buffer temporal el valor de los caracteres
for (n = 0; n < tsize; n ++) {
value = ((int)(text[n])) - 32; // Resta 32 al valor entrado
if (value < 0) value = 0;
string[n] = value;
// Si es un caracter especial...
if (string[n] > 95) {
// Resetea el caracter...
string[n] = 0;
// Verifica caracteres especiales
switch (((int)(text[n]))) {
// Salto de linea
case 10: // \n
string[n] = 200;
break;
// Caracteres especiales
case 199: // Ç
string[n] = 96;
break;
case 231: // ç
string[n] = 97;
break;
case 209: // Ñ
string[n] = 98;
break;
case 241: // ñ
string[n] = 99;
break;
// Acentos Mayusculas
case 193: // Á
string[n] = 100;
break;
case 201: // É
string[n] = 101;
break;
case 205: // Í
string[n] = 102;
break;
case 211: // Ó
string[n] = 103;
break;
case 218: // Ú
string[n] = 104;
break;
// Acentos Minusculas
case 225: // á
string[n] = 105;
break;
case 233: // é
string[n] = 106;
break;
case 237: // í
string[n] = 107;
break;
case 243: // ó
string[n] = 108;
break;
case 250: // ú
string[n] = 109;
break;
// Dieresis
case 239: // ï
string[n] = 110;
break;
case 252: // ü
string[n] = 111;
break;
// Admiracion e interrogante (Español)
case 161: // ¡
string[n] = 112;
break;
case 191: // ¿
string[n] = 113;
break;
// Caracter invalido
default:
string[n] = 0;
break;
}
}
}
// Variable para calcular la posicion del texto
s16 pos_x = 0; // Posicion X real en tiles
s16 pos_y = 0; // Posicion Y real en tiles
s16 tx = 0; // Posicion X del texto
s16 ty = 0; // Posicion Y del texto
switch (NF_TEXT[screen][layer].rotation) {
case 0: // Sin rotacion
// Traspasa las coordenadas
tx = x;
ty = y;
// Copia el texto al buffer letra a letra
for (n = 0; n < tsize; n ++) {
// Si es un caracter valido
if (string[n] <= NF_TEXT_FONT_LAST_VALID_CHAR_16) {
// Calcula la posicion en el tilemap
pos_x = tx;
pos_y = (ty << 1);
// Escribe la letra correspondiente
value = ((((int)(string[n] >> 5)) << 5) + string[n]);
NF_SetTileOfMap(screen,layer, pos_x, pos_y, ((NF_TEXT[screen][layer].pal << 12) + value));
NF_SetTileOfMap(screen,layer, pos_x, (pos_y + 1), ((NF_TEXT[screen][layer].pal << 12) + (value + 32)));
// Siguiente letra
tx ++;
}
if ((tx > NF_TEXT[screen][layer].width) || (string[n] == 200)) { // Si llegas al final de linea,
tx = 0; // salto de linea
ty ++;
if (ty > NF_TEXT[screen][layer].height) { // Si estas en la ultima linea,
ty = 0; // vuelve a la primera
}
}
}
break;
case 1: // 90º derecha
// Traspasa las coordenadas
tx = (NF_TEXT[screen][layer].width - y);
ty = x;
// Copia el texto al buffer letra a letra
for (n = 0; n < tsize; n ++) {
// Si es un caracter valido
if (string[n] <= NF_TEXT_FONT_LAST_VALID_CHAR_16) {
// Calcula la posicion en el tilemap
pos_x = (tx << 1);
pos_y = ty;
// Escribe la letra correspondiente
value = ((((int)(string[n] >> 5)) << 5) + string[n]);
NF_SetTileOfMap(screen,layer, pos_x, pos_y, ((NF_TEXT[screen][layer].pal << 12) + value));
NF_SetTileOfMap(screen,layer, (pos_x - 1), pos_y, ((NF_TEXT[screen][layer].pal << 12) + (value + 32)));
// Siguiente letra
ty ++;
}
if ((ty > NF_TEXT[screen][layer].height) || (string[n] == 200)) { // Si llegas al final de linea,
ty = 0; // salto de linea
tx --;
if (tx < 0) { // Si estas en la ultima linea,
tx = NF_TEXT[screen][layer].width; // vuelve a la primera
}
}
}
break;
case 2: // 90º izquierda
// Traspasa las coordenadas
tx = y;
ty = (NF_TEXT[screen][layer].height - x);
// Copia el texto al buffer letra a letra
for (n = 0; n < tsize; n ++) {
// Si es un caracter valido
if (string[n] <= NF_TEXT_FONT_LAST_VALID_CHAR_16) {
// Calcula la posicion en el tilemap
pos_x = (tx << 1);
pos_y = ty;
// Escribe la letra correspondiente
value = ((((int)(string[n] >> 5)) << 5) + string[n]);
NF_SetTileOfMap(screen,layer, pos_x, pos_y, ((NF_TEXT[screen][layer].pal << 12) + value));
NF_SetTileOfMap(screen,layer, (pos_x + 1), pos_y, ((NF_TEXT[screen][layer].pal << 12) + (value + 32)));
// Siguiente letra
ty --;
}
if ((ty < 0) || (string[n] == 200)) { // Si llegas al final de linea,
ty = NF_TEXT[screen][layer].height; // Salto de linea
tx ++;
if (tx > NF_TEXT[screen][layer].width) { // Si llegas a la ultima linea
tx = 0; // vuelve a la primera
}
}
}
break;
default:
break;
}
// Marca esta capa de texto para actualizar
NF_TEXT[screen][layer].update = true;
// Libera el buffer
free(string);
}
// Funcion NF_ClearTextLayer16();
void NF_ClearTextLayer16(u8 screen, u8 layer) {
// Verifica si la capa de texto de destino existe
if (!NF_TEXT[screen][layer].exist) {
NF_Error(114, NULL, screen);
}
// Calcula el tamaño del buffer (segun la rotacion)
u32 size = 0;
switch (NF_TEXT[screen][layer].rotation) {
case 0: // Sin rotacion
size = (((NF_TEXT[screen][layer].width + 1) * ((NF_TEXT[screen][layer].height + 1) << 1)) << 1);
break;
case 1: // 90º a la derecha
size = ((((NF_TEXT[screen][layer].width + 1) << 1) * (NF_TEXT[screen][layer].height + 1)) << 1);
break;
case 2: // 90º a la izquierda
size = ((((NF_TEXT[screen][layer].width + 1) << 1) * (NF_TEXT[screen][layer].height + 1)) << 1);
break;
}
// Pon a 0 todos los bytes del mapa de la capa de texto
memset(NF_BUFFER_BGMAP[NF_TEXT[screen][layer].slot], 0, size);
// Marca esta capa de texto para actualizar
NF_TEXT[screen][layer].update = true;
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,276 @@
// SPDX-License-Identifier: CC0-1.0
//
// SPDX-FileContributor: Antonio Niño Díaz, 2008-2011, 2019, 2022
// SPDX-FileContributor: NightFox, 2009-2011
//
// This file is part of Nitro Engine
// NightFoxs Lib (NFlib) is a library that can supports the 2D hardware of the
// NDS. It's ideal to complement Nitro Engine, as it only supports the 3D
// hardware. The latest version can be found at the following link:
//
// https://github.com/knightfox75/nds_nflib
//
// A few notes:
//
// - Remember to avoid using 3D features of NFlib.
//
// - You are free to use any features of NFlib in the secondary screen, but you
// need to assign VRAM C and D to NFlib to get space for sprites and
// backgrounds.
//
// - You could load 2D background and sprites in the same screen as the 3D
// rendering, but you will have to give up VRAM banks A and B. If you also use
// banks C and D for the secondary screen, it will leave you without any VRAM
// for textures.
//
// - Including the code of the library with your game (or the prebuilt .a file),
// like in this template, isn't good practice. This may change in the near
// future if I find a better way to integrate both libraries.
//
// I have prebuilt NFlib in this example so that it's easier to use it, but
// this may cause future problems when there are updates in devkitARM. At
// that point, it will be needed to clean NFlib and rebuild it.
#include <stdio.h>
#include <stdlib.h>
#include <nds.h>
#include <NEMain.h>
#include <nf_lib.h>
NE_Camera *Camera;
NE_Model *Model;
NE_Animation *Animation;
NE_Material *Material;
void Draw3DScene(void)
{
NE_CameraUse(Camera);
NE_PolyFormat(31, 0, NE_LIGHT_0, NE_CULL_NONE, 0);
NE_ModelDraw(Model);
}
void WaitLoop(void)
{
while(1)
swiWaitForVBlank();
}
void LoadAndSetupGraphics3D(void)
{
// When using nflib for the 2D sub screen engine, banks C and H are used for
// backgrounds and banks D and I are used for sprites. Nitro Engine only
// uses bank E for palettes, so the only thing we need to do is to tell
// Nitro Engine to only use banks A and B and leave C and D unused.
NE_Init3D();
NE_TextureSystemReset(0, 0, NE_VRAM_AB);
// Create objects
Model = NE_ModelCreate(NE_Animated);
Camera = NE_CameraCreate();
Material = NE_MaterialCreate();
Animation = NE_AnimationCreate();
// Load assets from the filesystem
if (NE_ModelLoadDSMFAT(Model, "robot.dsm") == 0)
{
consoleDemoInit();
iprintf("Couldn't load model...");
WaitLoop();
}
if (NE_AnimationLoadFAT(Animation, "robot_wave.dsa") == 0)
{
consoleDemoInit();
iprintf("Couldn't load animation...");
WaitLoop();
}
if (NE_MaterialTexLoadFAT(Material, NE_A1RGB5, 256, 256, NE_TEXGEN_TEXCOORD,
"texture_tex.bin") == 0)
{
consoleDemoInit();
iprintf("Couldn't load texture...");
WaitLoop();
}
// Assign material to the model
NE_ModelSetMaterial(Model, Material);
// Assign animation to the model and start it
NE_ModelSetAnimation(Model, Animation);
NE_ModelAnimStart(Model, NE_ANIM_LOOP, floattof32(0.1));
// Setup light
NE_LightSet(0, NE_White, 0, -1, -1);
// Setup background color
NE_ClearColorSet(NE_Black, 31, 63);
// Setup camera
NE_CameraSet(Camera,
6, 3, -4,
0, 3, 0,
0, 1, 0);
}
void LoadAndSetupGraphics2D(void)
{
// Initialize sub 2D engine
NF_Set2D(1, 0);
// Initialize sprites for sub screen (it uses VRAM D and I)
NF_InitSpriteBuffers();
NF_InitSpriteSys(1);
// Load assets from filesystem to RAM
NF_LoadSpriteGfx("sprite/personaje", 1, 64, 64);
NF_LoadSpritePal("sprite/personaje", 1);
// Copy all frames to VRAM
NF_VramSpriteGfx(1, 1, 0, false);
NF_VramSpritePal(1, 1, 0);
// Display sprite on the screen
NF_CreateSprite(1, 0, 0, 0, 0, 0);
// Initialize tiled backgrounds and text systems for the 2D sub engine (it
// uses VRAM C and H)
NF_InitTiledBgBuffers();
NF_InitTiledBgSys(1);
NF_InitTextSys(1);
// Load assets from filesystem to RAM
NF_LoadTiledBg("bg/bg3", "capa_3", 256, 256);
NF_LoadTiledBg("bg/bg1", "capa_1", 1536, 256);
NF_LoadTiledBg("bg/bg0", "capa_0", 2048, 256);
NF_LoadTextFont("fnt/default", "normal", 256, 256, 0);
// Create tiled backgrounds
NF_CreateTiledBg(1, 3, "capa_3");
NF_CreateTiledBg(1, 2, "capa_1");
NF_CreateTiledBg(1, 1, "capa_0");
// Create text layer
NF_CreateTextLayer(1, 0, 0, "normal");
}
int main(void)
{
// Initialize nitroFS before doing anything else
NF_Set2D(0, 0);
NF_Set2D(1, 0);
consoleDemoInit();
iprintf("Starting nitroFS...");
swiWaitForVBlank();
// Set the root folder to the nitroFS filesystem
NF_SetRootFolder("NITROFS");
// Setup interrupt handlers
irqEnable(IRQ_HBLANK);
irqSet(IRQ_VBLANK, NE_VBLFunc);
irqSet(IRQ_HBLANK, NE_HBLFunc);
// Load and setup graphics
LoadAndSetupGraphics3D();
LoadAndSetupGraphics2D();
// Initialize variables to control the sprite
int pj_x = 0;
int pj_y = 127;
unsigned int pj_frame = 0;
unsigned int pj_anim_ticks = 0;
int pj_speed = 1;
// Initialize variables to control the backgrounds
int bg_x[4] = {0, 0, 0};
// Print instructions for the user
NF_WriteText(1, 0, 1, 1, "PAD: Rotate model");
NF_WriteText(1, 0, 1, 2, "L/R: Scroll background");
NF_WriteText(1, 0, 1, 3, "START: Exit");
NF_UpdateTextLayers();
while (1)
{
scanKeys();
uint32 keys = keysHeld();
if (keys & KEY_START)
break;
if (keys & KEY_RIGHT)
NE_ModelRotate(Model, 0, 2, 0);
if (keys & KEY_LEFT)
NE_ModelRotate(Model, 0, -2, 0);
if (keys & KEY_UP)
NE_ModelRotate(Model, 0, 0, 2);
if (keys & KEY_DOWN)
NE_ModelRotate(Model, 0, 0, -2);
if (keys & KEY_L)
{
bg_x[0] -= 2;
if (bg_x[0] < 0)
bg_x[0] = 0;
}
if (keys & KEY_R)
{
bg_x[0] += 2;
if (bg_x[0] > 1152)
bg_x[0] = 1152;
}
// For the parallax effect, calculate the scroll of the second layer
// based on the scroll of the first one.
bg_x[1] = bg_x[0] / 2;
// Move sprite
pj_x += pj_speed;
if ((pj_x < 0) || (pj_x > 191))
{
pj_speed = -pj_speed;
if (pj_speed > 0)
NF_HflipSprite(1, 0, false);
else
NF_HflipSprite(1, 0, true);
}
NF_MoveSprite(1, 0, pj_x, pj_y);
// Animate sprite
pj_anim_ticks++;
if (pj_anim_ticks > 5)
{
pj_anim_ticks = 0;
pj_frame++;
if (pj_frame > 11)
pj_frame = 0;
NF_SpriteFrame(1, 0, pj_frame);
}
// Refresh shadow OAM copy
NF_SpriteOamSet(1);
// Draw scene...
NE_Process(Draw3DScene);
NE_WaitForVBL(NE_UPDATE_ANIMATIONS);
// At this point we are in the vertical blank period. This is where 2D
// entities have to be updated to avoid flickering.
// Update the scroll of the backgrounds
for (int n = 0; n < 3; n ++)
NF_ScrollBg(1, n + 1, bg_x[n], 0);
// Copy shadow OAM copy to the OAM of the 2D sub engine
oamUpdate(&oamSub);
}
return 0;
}

View File

@ -16,13 +16,20 @@ Features:
<https://github.com/AntonioND/dsma-library>`_, which converts MD5 models (with
skeletal animation) into a format that can be rendered with hardware
acceleration. It can also blend two animations together (for transitions).
- Support for all format of textures (except compressed textures).
- Support for all format of textures (even compressed textures, but the
converter included in this repository doesn't support them yet).
- Dual 3D (render 3D to both screens, but at 30 FPS instead of 60 FPS).
- Functions to render 2D images accelerated by 3D hardware.
- Basic text system.
- Basic GUI elements like buttons and scrollbars.
- Basic physic system: Axis-aligned bounding boxes (AABB) only.
Nitro Engine doesn't support any of the 2D hardware of the DS. In order to use
the 2D hardware you can use libnds directly, or you can use a library like
`NFlib <https://github.com/knightfox75/nds_nflib>`_. There is an example of how
to integrate Nitro Engine and NFlib in the same project `here
<./examples/templates/using_nflib>`_.
Setup
-----