mirror of
https://github.com/AntonioND/ulibrary.git
synced 2025-06-18 23:05:50 -04:00
449 lines
13 KiB
C
449 lines
13 KiB
C
#include "ulib.h"
|
|
|
|
// TODO: Calculer la taille totale de la VRAM textures en fonction de l'allocation des banques
|
|
|
|
// On commence au début de la VRAM mappée en LCD
|
|
void *ul_texVramBase = (void*)0x06800000;
|
|
|
|
// 128 ko par défaut
|
|
int ul_texVramSize = 128 << 10;
|
|
|
|
// Banque A seulement par défaut
|
|
UL_BANKS ul_texVramBanks = UL_BANK_A;
|
|
|
|
u8 ul_optimizeTextureSize = 1;
|
|
|
|
// By default, initialize every texture to zero
|
|
UL_TEXINITZERO_TYPE ul_initTexturesToZero = UL_TEXINITZERO_ALL;
|
|
|
|
#define DEFAULT_TABLE_SIZE 1024
|
|
|
|
int ulTexRamBlocksMax, ulTexRamBlocksNb;
|
|
|
|
typedef struct
|
|
{
|
|
u16 offset, size;
|
|
} UL_TEXRAMBLOCK;
|
|
|
|
#define isBlockFree(i) (ulTexRamBlocks[i].size & 0x8000)
|
|
#define getBlockSize(i) (ulTexRamBlocks[i].size & 0x7fff)
|
|
#define getBlockOffset(i) (ulTexRamBlocks[i].offset)
|
|
|
|
#define setBlockFree(i, free) \
|
|
(ulTexRamBlocks[i].size = (ulTexRamBlocks[i].size & ((free)? 0xffff : 0x7fff)) | ((free)? 0x8000 : 0))
|
|
|
|
#define setBlockSize(i, nsize) \
|
|
(ulTexRamBlocks[i].size = (ulTexRamBlocks[i].size & ~0x7fff) | (nsize))
|
|
|
|
#define setBlockOffset(i, noffset) \
|
|
(ulTexRamBlocks[i].offset = noffset)
|
|
|
|
// >> 3 dans textureparams et << 4 (mult. 16 ici)
|
|
#define getTextureOffset(name) ((ulTextureParams[name] & 0xFFFF) >> 1)
|
|
|
|
UL_TEXRAMBLOCK *ulTexRamBlocks;
|
|
|
|
void ulTexVramInit()
|
|
{
|
|
ulTexRamBlocksMax = DEFAULT_TABLE_SIZE;
|
|
ulTexRamBlocksNb = 1;
|
|
ulTexRamBlocks = (UL_TEXRAMBLOCK*)calloc(1, ulTexRamBlocksMax * sizeof(UL_TEXRAMBLOCK));
|
|
|
|
// Premier bloc: libre, taille totale de la VRAM, adresse 0
|
|
setBlockOffset(0, 0);
|
|
|
|
// La taille en blocs doit être divisée par 16 puisqu'on n'utilise pas des
|
|
// octets sinon il serait impossible de coder toute la VRAM sur 16 bits
|
|
setBlockSize(0, ul_texVramSize >> 4);
|
|
setBlockFree(0, 1);
|
|
}
|
|
|
|
int ulTexVramAllocBlock(int blockSize)
|
|
{
|
|
int i;
|
|
|
|
// Le bloc ne peut pas être de taille nulle ou négative
|
|
if (blockSize <= 0)
|
|
return -1;
|
|
|
|
// La taille est toujours multiple de 16 - arrondir au bloc supérieur
|
|
if (blockSize & 15)
|
|
blockSize += 16;
|
|
blockSize >>= 4;
|
|
|
|
for (i = 0; i < ulTexRamBlocksNb; i++)
|
|
{
|
|
// Ce bloc est-il suffisant?
|
|
if (isBlockFree(i) && getBlockSize(i) >= blockSize)
|
|
break;
|
|
}
|
|
|
|
// Aucun bloc libre
|
|
if (i >= ulTexRamBlocksNb)
|
|
return -1;
|
|
|
|
// Pile la mémoire qu'il faut? - pas géré, il faut toujours que le dernier
|
|
// bloc soit marqué comme libre (même s'il reste 0 octet) pour
|
|
// ulSetTexVramParameters()
|
|
if (getBlockSize(i) == blockSize && i != ulTexRamBlocksNb - 1)
|
|
{
|
|
// Il n'est plus libre
|
|
setBlockFree(i, 0);
|
|
}
|
|
else
|
|
{
|
|
// On va ajouter un nouveau bloc
|
|
ulTexRamBlocksNb++;
|
|
|
|
// Plus de mémoire pour le tableau? On l'aggrandit
|
|
if (ulTexRamBlocksNb >= ulTexRamBlocksMax)
|
|
{
|
|
UL_TEXRAMBLOCK *oldBlock = ulTexRamBlocks;
|
|
ulTexRamBlocksMax += DEFAULT_TABLE_SIZE;
|
|
ulTexRamBlocks = (UL_TEXRAMBLOCK*)realloc(ulTexRamBlocks, ulTexRamBlocksMax);
|
|
|
|
// Vérification que la mémoire a bien pu être allouée
|
|
if (!ulTexRamBlocks)
|
|
{
|
|
ulTexRamBlocks = oldBlock;
|
|
ulTexRamBlocksMax -= DEFAULT_TABLE_SIZE;
|
|
// Pas assez de mémoire
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
// Décalage pour insérer notre nouvel élément
|
|
memmove(ulTexRamBlocks + i + 1, ulTexRamBlocks + i,
|
|
sizeof(UL_TEXRAMBLOCK) * (ulTexRamBlocksNb - i - 1));
|
|
|
|
// Remplissons notre nouveau bloc
|
|
setBlockSize(i, blockSize);
|
|
// Il a l'adresse du bloc qui était là avant
|
|
setBlockOffset(i, getBlockOffset(i + 1));
|
|
// Il n'est pas libre
|
|
setBlockFree(i, 0);
|
|
|
|
// Pour le prochain, sa taille diminue
|
|
setBlockSize(i + 1, getBlockSize(i + 1) - blockSize);
|
|
// ATTENTION: calcul d'offset
|
|
setBlockOffset(i + 1, getBlockOffset(i + 1) + blockSize);
|
|
}
|
|
|
|
// Note: il faut traduire l'offset en vraie adresse
|
|
return getBlockOffset(i);
|
|
}
|
|
|
|
// Note: il faut traduire une vraie adresse en offset
|
|
int ulTexVramFreeBlock(int blockOffset)
|
|
{
|
|
int i, j, updateNeeded;
|
|
|
|
for (i = 0; i < ulTexRamBlocksNb; i++)
|
|
{
|
|
if (getBlockOffset(i) == blockOffset)
|
|
break;
|
|
}
|
|
|
|
// Impossible de trouver le bloc
|
|
if (i >= ulTexRamBlocksNb)
|
|
return 0;
|
|
|
|
// Le bloc est maintenant libre ^^
|
|
setBlockFree(i, 1);
|
|
|
|
// Bon maintenant reste à "assembler" les blocs libres adjacents
|
|
do
|
|
{
|
|
updateNeeded = 0;
|
|
for (j = 0; j < ulTexRamBlocksNb - 1; j++)
|
|
{
|
|
// Cherchons deux blocs adjacents
|
|
if ((isBlockFree(j) && isBlockFree(j + 1)) ||
|
|
(isBlockFree(j) && getBlockSize(j) == 0))
|
|
{
|
|
// Assemblons ces blocs maintenant
|
|
int newSize = getBlockSize(j) + getBlockSize(j + 1);
|
|
int newAdd = getBlockOffset(j);
|
|
memmove(ulTexRamBlocks + j, ulTexRamBlocks + j + 1,
|
|
sizeof(UL_TEXRAMBLOCK) * (ulTexRamBlocksNb - j - 1));
|
|
setBlockOffset(j, newAdd);
|
|
setBlockSize(j, newSize);
|
|
// Le bloc entre deux est supprimé
|
|
ulTexRamBlocksNb--;
|
|
// ATT: On devra refaire un tour pour vérifier si de nouveaux
|
|
// blocs n'ont pas été créés
|
|
updateNeeded = 1;
|
|
}
|
|
}
|
|
|
|
} while (updateNeeded);
|
|
|
|
return 1;
|
|
}
|
|
|
|
// Inspirée de la fonction de libnds
|
|
//
|
|
// Attention: sizeX et sizeY sont les VRAIES tailles (en pixel)! Elles seront
|
|
// alignées aux prochaines puissances de deux!
|
|
int ulTexImage2D(int target, int empty1, UL_IMAGE_FORMATS type,
|
|
int sizeX, int sizeY, int empty2, int param, uint8* texture)
|
|
{
|
|
uint32 size = 0;
|
|
int32 texId;
|
|
uint32* addr;
|
|
// Unoptimized sizeX
|
|
int uoSizeX = sizeX;
|
|
//uint32 vramTemp;
|
|
|
|
sizeX = 1 << ulGetPowerOf2Count(sizeX);
|
|
|
|
// L'optimisation pour les tailles de palettes permet de réduire l'espace
|
|
// vertical alloué (pas d'alignement à une puissance de deux)
|
|
if (!ul_optimizeTextureSize)
|
|
sizeY = 1 << ulGetPowerOf2Count(sizeY);
|
|
|
|
size = (sizeX * sizeY * ul_pixelSizes[type]) >> 3;
|
|
|
|
texId = ulTexVramAllocBlock(size);
|
|
if (texId < 0)
|
|
return 0;
|
|
|
|
addr = ulTexVramOffsetToAddress(texId);
|
|
|
|
swiWaitForVBlank();
|
|
// unlock texture memory
|
|
ulChangeVramAllocation(ul_texVramBanks, UL_BANK_TYPE_LCD);
|
|
|
|
if (type == UL_PF_5550)
|
|
{
|
|
// We do UL_PF_5550 as UL_PF_5551, but we set each alpha bit to 1 during the copy
|
|
u16 * src = (u16*)texture;
|
|
u16 * dest = (u16*)addr;
|
|
|
|
// Valeur de la texture: utilisé pour GFX_TEX_FORMAT
|
|
ulTexParameter(ulGetPowerOf2Count(sizeX) - 3, ulGetPowerOf2Count(sizeY) - 3,
|
|
addr, UL_PF_5551, param);
|
|
|
|
if (texture)
|
|
{
|
|
int number = 0;
|
|
while (size--)
|
|
{
|
|
// Do not make opaque pixels that are outside of the screen
|
|
if (number < uoSizeX)
|
|
*dest++ = *src | (1 << 15);
|
|
else
|
|
*dest++ = *src & 0x7fff;
|
|
src++;
|
|
number++;
|
|
if (number >= sizeX)
|
|
number -= sizeX;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// For everything else, we do a straight copy
|
|
ulTexParameter(ulGetPowerOf2Count(sizeX) - 3, ulGetPowerOf2Count(sizeY) - 3,
|
|
addr, type, param);
|
|
if (texture)
|
|
swiCopy((uint32*)texture, addr , (size >> 2) | COPY_MODE_WORD);
|
|
}
|
|
|
|
// No texture passed - eventually fill the texture with zero
|
|
if (!texture)
|
|
{
|
|
if (ul_initTexturesToZero & UL_TEXINITZERO_VRAM)
|
|
memset(addr, 0, size);
|
|
}
|
|
|
|
ulChangeVramAllocation(ul_texVramBanks, UL_BANK_TYPE_TEXTURE);
|
|
return 1;
|
|
}
|
|
|
|
#define UL_MAX_TEXTURES 128
|
|
#define TEXTURE_FREE (~0)
|
|
int *ulTextureParams;
|
|
int ulTextureNb;
|
|
int ulTextureMax;
|
|
int ulTextureActive;
|
|
|
|
void ulInitTextures()
|
|
{
|
|
ulTextureActive = 0;
|
|
ulTextureMax = UL_MAX_TEXTURES;
|
|
ulTextureParams = (int *)malloc(sizeof(ulTextureParams[0]) * ulTextureMax);
|
|
memset(ulTextureParams, 0xff, sizeof(ulTextureParams[0]) * ulTextureMax);
|
|
ulTextureNb = 0;
|
|
}
|
|
|
|
int ulGetNextAvailableTexture()
|
|
{
|
|
int iterate = 0;
|
|
|
|
while (iterate < 3)
|
|
{
|
|
// Trouve la prochaine texture libre
|
|
while (ulTextureNb < ulTextureMax && ulTextureParams[ulTextureNb] != TEXTURE_FREE)
|
|
{
|
|
ulTextureNb++;
|
|
}
|
|
|
|
// Pas de texture disponible, on recommence à zéro
|
|
if (ulTextureNb >= ulTextureMax)
|
|
{
|
|
iterate++;
|
|
|
|
// On a déjà fait une fois un tour complet + un tour partiel mais on
|
|
// n'a rien trouvé => plus de mémoire
|
|
if (iterate == 2)
|
|
{
|
|
int *oldPtr = ulTextureParams;
|
|
// On rajoute un peu de mémoire
|
|
ulTextureParams =
|
|
(int *)realloc(ulTextureParams,
|
|
sizeof(ulTextureParams[0]) * (ulTextureMax + UL_MAX_TEXTURES));
|
|
|
|
// L'allocation a foiré => Plus de mémoire
|
|
if (!ulTextureParams)
|
|
{
|
|
ulTextureParams = oldPtr;
|
|
break;
|
|
}
|
|
|
|
// Remplit les prochaines éléments du tableau pour les marquer
|
|
// comme "libres"
|
|
memset(ulTextureParams + ulTextureMax, 0xff,
|
|
sizeof(ulTextureParams[0]) * UL_MAX_TEXTURES);
|
|
|
|
ulTextureMax += UL_MAX_TEXTURES;
|
|
}
|
|
|
|
ulTextureNb = 0;
|
|
}
|
|
else
|
|
{
|
|
// On a trouvé notre texture =)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (iterate >= 3)
|
|
{
|
|
// Rien à faire: (vraiment) plus de mémoire
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
// La prochaine fois, on ne prendra plus la même (post incrémentation)
|
|
return ulTextureNb++;
|
|
}
|
|
}
|
|
|
|
int ulGenTextures(int n, int *names)
|
|
{
|
|
for (int index = 0; index < n; index++)
|
|
{
|
|
int newTexture = ulGetNextAvailableTexture();
|
|
|
|
if (newTexture >= 0)
|
|
{
|
|
names[index] = newTexture;
|
|
// Pour éviter de le considérer comme pris
|
|
ulTextureParams[newTexture] = 0;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void ulFreeTextures(int n, int *names)
|
|
{
|
|
for (int index = 0; index < n; index++)
|
|
{
|
|
// Pas libre => à libérer
|
|
if (ulTextureParams[names[index]] != TEXTURE_FREE)
|
|
ulTexVramFreeBlock(getTextureOffset(names[index]));
|
|
|
|
ulTextureParams[names[index]] = TEXTURE_FREE;
|
|
}
|
|
}
|
|
|
|
// Paramétrage d'une texture
|
|
void ulTexParameter(uint8 sizeX, uint8 sizeY, uint32* addr, UL_IMAGE_FORMATS mode, uint32 param)
|
|
{
|
|
ulTextureParams[ulTextureActive] = param | (sizeX << 20) | (sizeY << 23) |
|
|
(((uint32)addr >> 3) & 0xFFFF) | (mode << 26);
|
|
}
|
|
|
|
void ulBindTexture(int target, int name)
|
|
{
|
|
//if (name == 0)
|
|
// GFX_TEX_FORMAT = 0;
|
|
//else
|
|
GFX_TEX_FORMAT = ulTextureParams[name];
|
|
|
|
ulTextureActive = name;
|
|
}
|
|
|
|
#if 0
|
|
// Permet d'utiliser une texture de UL avec la librairie VideoGL intégrée à libnds
|
|
void ulBindTextureToGl(int target, int name)
|
|
{
|
|
glGlob->textures[glGlob->activeTexture] = ulTextureParams[name];
|
|
glBindTexture(target, name);
|
|
}
|
|
#endif
|
|
|
|
// 1 on success, 0 on failure
|
|
int ulSetTexVramParameters(int activeBanks, void *baseAddr, int totalSize)
|
|
{
|
|
int curVramSize = ul_texVramSize >> 4;
|
|
int blockNum = ulTexRamBlocksNb - 1;
|
|
int sizeDiff;
|
|
|
|
// La taille est toujours multiple de 16 - arrondir au bloc supérieur
|
|
if (totalSize & 15)
|
|
totalSize += 16;
|
|
totalSize >>= 4;
|
|
|
|
// Différence de taille (négatif pour réduction, positif pour aggrandissement)
|
|
sizeDiff = totalSize - curVramSize;
|
|
|
|
// Le dernier bloc est TOUJOURS libre, même s'il reste 0 octet. Cf la
|
|
// bidouille dans ulTexVramAlloc
|
|
if (isBlockFree(blockNum) && getBlockSize(blockNum) + sizeDiff >= 0)
|
|
{
|
|
setBlockSize(blockNum, getBlockSize(blockNum) + sizeDiff);
|
|
ul_texVramBase = baseAddr;
|
|
ul_texVramSize = totalSize;
|
|
ul_texVramBanks = activeBanks;
|
|
ulChangeVramAllocation(ul_texVramBanks, UL_BANK_TYPE_TEXTURE);
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int ulGetTexVramAvailMemory()
|
|
{
|
|
return getBlockSize(ulTexRamBlocksNb - 1) << 4;
|
|
}
|
|
|
|
int ulGetTexVramTotalMemory()
|
|
{
|
|
return ul_texVramSize;
|
|
}
|
|
|
|
int ulGetTexVramUsedMemory()
|
|
{
|
|
return ul_texVramSize - ulGetTexVramAvailMemory();
|
|
}
|