nds_nflib/source/nf_affinebg.c
Antonio Niño Díaz 151db13cc0 license: Fix licenses
- Creative Commons (except for CC0) shouldn't be used for code:

   https://creativecommons.org/faq/#can-i-apply-a-creative-commons-license-to-software

   MIT has the same spirit as the CC-BY license.

- CC-BY has been retained for the assets included in the repository.

- Also, the years were wrong, this library was started in 2009.

- Make all examples use the CC0 license.
2023-04-01 19:56:45 +01:00

676 lines
21 KiB
C
Raw Blame History

// SPDX-License-Identifier: MIT
//
// Copyright (c) 2009-2014 Cesar Rincon "NightFox"
//
// NightFox LIB - Funciones de Fondos Affine
// 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<6D>o
NF_Error(117, name, 0);
}
// Variable temporal del tama<6D>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<6D>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<6D>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<6D>o del archivo
fseek(file_id, 0, SEEK_END);
NF_TILEDBG[slot].mapsize = ((((ftell(file_id) - 1) >> 10) + 1) << 10); // Ajusta el tama<6D>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<6D>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<6D>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<6D>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<6D>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<6D>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<6D>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<6D>o del Tileset
u16 mapsize = 0; // Tama<6D>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;
}