mirror of
https://github.com/pret/pokeplatinum.git
synced 2026-03-21 17:55:13 -05:00
505 lines
14 KiB
C
505 lines
14 KiB
C
#include "pltt_transfer.h"
|
|
|
|
#include "nitro/gx/g3.h"
|
|
#include <nitro.h>
|
|
#include <string.h>
|
|
|
|
#include "constants/graphics.h"
|
|
#include "constants/heap.h"
|
|
|
|
#include "heap.h"
|
|
#include "vram_transfer.h"
|
|
|
|
#define NUM_VRAM_PALETTES 16
|
|
#define PLTT_RESOURCE_ID_NONE -1
|
|
#define PLTT_RANGE_SIZE (PALETTE_SIZE_BYTES * NUM_VRAM_PALETTES)
|
|
#define PLTT_EXT_RANGE_SIZE (PALETTE_SIZE_EXT_BYTES * NUM_VRAM_PALETTES)
|
|
|
|
typedef struct PlttTransferTask {
|
|
NNSG2dPaletteData *data;
|
|
NNS_G2D_VRAM_TYPE vramType;
|
|
u32 numPalettes;
|
|
u32 resourceID;
|
|
NNSG2dImagePaletteProxy paletteProxy;
|
|
u32 baseAddrMain;
|
|
u32 baseAddrSub;
|
|
u8 initialized;
|
|
} PlttTransferTask;
|
|
|
|
typedef struct PlttTransferTaskManager {
|
|
PlttTransferTask *tasks;
|
|
int capacity;
|
|
int length;
|
|
u32 offsetMain;
|
|
u32 offsetSub;
|
|
u32 extPlttOffsetMain;
|
|
u32 extPlttOffsetSub;
|
|
u32 extPlttVramSizeMain;
|
|
u32 extPlttVramSizeSub;
|
|
u16 vramTransferMain;
|
|
u16 vramTransferSub;
|
|
} PlttTransferTaskManager;
|
|
|
|
static void InitTransferTask(PlttTransferTask *task);
|
|
static BOOL InitTransferTaskFromTemplate(const PlttTransferTaskTemplate *template, PlttTransferTask *task);
|
|
static void ResetTransferTask(PlttTransferTask *task);
|
|
static void LoadImagePalette(PlttTransferTask *task);
|
|
static BOOL ReserveAndTransferWholeRange(const PlttTransferTaskTemplate *unused, PlttTransferTask *task);
|
|
static BOOL ReserveAndTransferFreeSpace(const PlttTransferTaskTemplate *unused, PlttTransferTask *task);
|
|
static void ReserveTaskTransferRanges(PlttTransferTask *task);
|
|
static void ClearTaskTransferRanges(PlttTransferTask *task);
|
|
static PlttTransferTask *FindTransferTask(int resourceID);
|
|
static PlttTransferTask *FindNextFreeTask(void);
|
|
static void UpdateVramCapacities(void);
|
|
static void UpdateTransferSize(PlttTransferTask *task);
|
|
static BOOL TryGetDestOffsets(PlttTransferTask *task, u32 offsetMain, u32 offsetSub, u32 sizeMain, u32 sizeSub);
|
|
static void ReserveVramSpace(PlttTransferTask *task, u32 *offsetMain, u32 *offsetSub);
|
|
|
|
static void ReserveTransferRange(u16 *range, int count, int start);
|
|
static void ClearTransferRange(u16 *range, int count, int start);
|
|
static int FindAvailableTransferSlot(u16 palette, int size);
|
|
|
|
static void ResetBothTransferRanges(PlttTransferTaskManager *task);
|
|
|
|
static PlttTransferTaskManager *sTaskManager = NULL;
|
|
|
|
void PlttTransfer_Init(int capacity, enum HeapID heapID)
|
|
{
|
|
if (sTaskManager == NULL) {
|
|
sTaskManager = Heap_Alloc(heapID, sizeof(PlttTransferTaskManager));
|
|
MI_CpuClear32(sTaskManager, sizeof(PlttTransferTaskManager));
|
|
|
|
sTaskManager->capacity = capacity;
|
|
sTaskManager->tasks = Heap_Alloc(heapID, sizeof(PlttTransferTask) * capacity);
|
|
|
|
for (int i = 0; i < capacity; i++) {
|
|
InitTransferTask(sTaskManager->tasks + i);
|
|
}
|
|
}
|
|
}
|
|
|
|
void PlttTransfer_MarkReservedSlots(u16 reservedMask, NNS_G2D_VRAM_TYPE vramType)
|
|
{
|
|
if (vramType == NNS_G2D_VRAM_TYPE_2DMAIN) {
|
|
sTaskManager->vramTransferMain |= reservedMask;
|
|
} else if (vramType == NNS_G2D_VRAM_TYPE_2DSUB) {
|
|
sTaskManager->vramTransferSub |= reservedMask;
|
|
}
|
|
}
|
|
|
|
void PlttTransfer_Free(void)
|
|
{
|
|
if (sTaskManager != NULL) {
|
|
PlttTransfer_ResetAllTasks();
|
|
Heap_Free(sTaskManager->tasks);
|
|
Heap_Free(sTaskManager);
|
|
sTaskManager = NULL;
|
|
}
|
|
}
|
|
|
|
static void DummyFunc(void)
|
|
{
|
|
return;
|
|
}
|
|
|
|
void PlttTransfer_Clear(void)
|
|
{
|
|
sTaskManager->offsetMain = 0;
|
|
sTaskManager->offsetSub = 0;
|
|
sTaskManager->extPlttOffsetMain = 0;
|
|
sTaskManager->extPlttOffsetSub = 0;
|
|
|
|
UpdateVramCapacities();
|
|
ResetBothTransferRanges(sTaskManager);
|
|
}
|
|
|
|
BOOL PlttTransfer_RequestWholeRange(const PlttTransferTaskTemplate *template)
|
|
{
|
|
PlttTransferTask *task = FindNextFreeTask();
|
|
if (task == NULL) {
|
|
GF_ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
if (InitTransferTaskFromTemplate(template, task) == FALSE) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (ReserveAndTransferWholeRange(template, task) == FALSE) {
|
|
// unreachable
|
|
PlttTransfer_ResetTask(template->resourceID);
|
|
return FALSE;
|
|
}
|
|
|
|
ReserveTaskTransferRanges(task);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL PlttTransfer_RequestFreeSpace(const PlttTransferTaskTemplate *template)
|
|
{
|
|
PlttTransferTask *task = FindNextFreeTask();
|
|
if (task == NULL) {
|
|
GF_ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
if (InitTransferTaskFromTemplate(template, task) == FALSE) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (ReserveAndTransferFreeSpace(template, task) == FALSE) {
|
|
PlttTransfer_ResetTask(template->resourceID);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void PlttTransfer_ReplacePlttData(int resourceID, NNSG2dPaletteData *data)
|
|
{
|
|
GF_ASSERT(data);
|
|
|
|
PlttTransferTask *task = FindTransferTask(resourceID);
|
|
GF_ASSERT(task);
|
|
task->data = data;
|
|
|
|
if (task->vramType & NNS_G2D_VRAM_TYPE_2DMAIN) {
|
|
VramTransfer_Request(NNS_GFD_DST_2D_OBJ_PLTT_MAIN, task->baseAddrMain, data->pRawData, task->numPalettes * PALETTE_SIZE_BYTES);
|
|
}
|
|
|
|
if (task->vramType & NNS_G2D_VRAM_TYPE_2DSUB) {
|
|
VramTransfer_Request(NNS_GFD_DST_2D_OBJ_PLTT_SUB, task->baseAddrSub, data->pRawData, task->numPalettes * PALETTE_SIZE_BYTES);
|
|
}
|
|
}
|
|
|
|
BOOL PlttTransfer_HasTask(int resourceID)
|
|
{
|
|
return FindTransferTask(resourceID) != NULL;
|
|
}
|
|
|
|
void PlttTransfer_ResetTask(int resourceID)
|
|
{
|
|
PlttTransferTask *task = FindTransferTask(resourceID);
|
|
GF_ASSERT(task);
|
|
|
|
if (task->initialized == TRUE) {
|
|
ClearTaskTransferRanges(task);
|
|
ResetTransferTask(task);
|
|
}
|
|
}
|
|
|
|
void PlttTransfer_ResetAllTasks(void)
|
|
{
|
|
for (int i = 0; i < sTaskManager->capacity; i++) {
|
|
if (sTaskManager->tasks[i].initialized == TRUE) {
|
|
ClearTaskTransferRanges(&sTaskManager->tasks[i]);
|
|
ResetTransferTask(&sTaskManager->tasks[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
NNSG2dImagePaletteProxy *PlttTransfer_GetPaletteProxy(int resourceID)
|
|
{
|
|
PlttTransferTask *task = FindTransferTask(resourceID);
|
|
if (task == NULL) {
|
|
GF_ASSERT(task);
|
|
return NULL;
|
|
}
|
|
|
|
if (task->initialized == TRUE) {
|
|
return &task->paletteProxy;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
NNSG2dImagePaletteProxy *PlttTransfer_ToggleExtPalette(int resourceID, NNSG2dImageProxy *imageProxy)
|
|
{
|
|
PlttTransferTask *task = FindTransferTask(resourceID);
|
|
if (task == NULL) {
|
|
GF_ASSERT(task);
|
|
return NULL;
|
|
}
|
|
|
|
if (task->initialized != TRUE) {
|
|
return NULL;
|
|
}
|
|
|
|
if (task->data->bExtendedPlt) {
|
|
NNS_G2dSetImageExtPaletteFlag(imageProxy, TRUE);
|
|
}
|
|
|
|
return &task->paletteProxy;
|
|
}
|
|
|
|
u32 PlttTransfer_GetPlttOffset(const NNSG2dImagePaletteProxy *paletteProxy, NNS_G2D_VRAM_TYPE vramType)
|
|
{
|
|
u32 size;
|
|
if (paletteProxy->bExtendedPlt) {
|
|
size = PALETTE_SIZE_EXT_BYTES;
|
|
} else if (paletteProxy->fmt == GX_TEXFMT_PLTT256) {
|
|
size = 0;
|
|
} else {
|
|
size = PALETTE_SIZE_BYTES;
|
|
}
|
|
|
|
return size != 0 ? NNS_G2dGetImagePaletteLocation(paletteProxy, vramType) / size : 0;
|
|
}
|
|
|
|
static void ResetTransferTask(PlttTransferTask *task)
|
|
{
|
|
InitTransferTask(task);
|
|
}
|
|
|
|
static BOOL InitTransferTaskFromTemplate(const PlttTransferTaskTemplate *template, PlttTransferTask *task)
|
|
{
|
|
task->data = template->data;
|
|
|
|
if (PlttTransfer_HasTask(template->resourceID) == TRUE) {
|
|
GF_ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
task->resourceID = template->resourceID;
|
|
task->vramType = template->vramType;
|
|
task->initialized = TRUE;
|
|
task->numPalettes = template->plttIndex;
|
|
return TRUE;
|
|
}
|
|
|
|
static void InitTransferTask(PlttTransferTask *task)
|
|
{
|
|
memset(task, 0, sizeof(PlttTransferTask));
|
|
task->resourceID = PLTT_RESOURCE_ID_NONE;
|
|
NNS_G2dInitImagePaletteProxy(&task->paletteProxy);
|
|
}
|
|
|
|
static BOOL ReserveAndTransferWholeRange(const PlttTransferTaskTemplate *unused, PlttTransferTask *task)
|
|
{
|
|
u32 *targetOffsetMain;
|
|
u32 *targetOffsetSub;
|
|
u32 plttSizeMain;
|
|
u32 plttSizeSub;
|
|
|
|
if (task->data->bExtendedPlt) {
|
|
targetOffsetMain = &sTaskManager->extPlttOffsetMain;
|
|
targetOffsetSub = &sTaskManager->extPlttOffsetSub;
|
|
plttSizeMain = sTaskManager->extPlttVramSizeMain;
|
|
plttSizeSub = sTaskManager->extPlttVramSizeSub;
|
|
} else {
|
|
targetOffsetMain = &sTaskManager->offsetMain;
|
|
targetOffsetSub = &sTaskManager->offsetSub;
|
|
plttSizeMain = PLTT_RANGE_SIZE;
|
|
plttSizeSub = PLTT_RANGE_SIZE;
|
|
}
|
|
|
|
TryGetDestOffsets(task, *targetOffsetMain, *targetOffsetSub, plttSizeMain, plttSizeSub);
|
|
UpdateTransferSize(task);
|
|
ReserveVramSpace(task, targetOffsetMain, targetOffsetSub);
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL ReserveAndTransferFreeSpace(const PlttTransferTaskTemplate *unused, PlttTransferTask *task)
|
|
{
|
|
if (task->data->bExtendedPlt) {
|
|
GF_ASSERT(FALSE);
|
|
}
|
|
|
|
int offsetMain;
|
|
if (task->vramType & NNS_G2D_VRAM_TYPE_2DMAIN) {
|
|
offsetMain = FindAvailableTransferSlot(sTaskManager->vramTransferMain, task->numPalettes);
|
|
if (offsetMain == -1) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
int offsetSub;
|
|
if (task->vramType & NNS_G2D_VRAM_TYPE_2DSUB) {
|
|
offsetSub = FindAvailableTransferSlot(sTaskManager->vramTransferSub, task->numPalettes);
|
|
if (offsetSub == -1) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (task->vramType & NNS_G2D_VRAM_TYPE_2DMAIN) {
|
|
task->baseAddrMain = offsetMain;
|
|
}
|
|
|
|
if (task->vramType & NNS_G2D_VRAM_TYPE_2DSUB) {
|
|
task->baseAddrSub = offsetSub;
|
|
}
|
|
|
|
task->data->szByte = task->numPalettes * PALETTE_SIZE_BYTES;
|
|
LoadImagePalette(task);
|
|
ReserveTaskTransferRanges(task);
|
|
return TRUE;
|
|
}
|
|
|
|
static PlttTransferTask *FindTransferTask(int resourceID)
|
|
{
|
|
for (int i = 0; i < sTaskManager->capacity; i++) {
|
|
if (sTaskManager->tasks[i].resourceID == resourceID) {
|
|
return sTaskManager->tasks + i;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static PlttTransferTask *FindNextFreeTask(void)
|
|
{
|
|
for (int i = 0; i < sTaskManager->capacity; i++) {
|
|
if (sTaskManager->tasks[i].initialized == FALSE) {
|
|
return sTaskManager->tasks + i;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void UpdateVramCapacities(void)
|
|
{
|
|
switch (GX_GetBankForOBJExtPltt()) {
|
|
case GX_VRAM_OBJEXTPLTT_0_F:
|
|
case GX_VRAM_OBJEXTPLTT_0_G:
|
|
sTaskManager->extPlttVramSizeMain = PLTT_EXT_RANGE_SIZE;
|
|
break;
|
|
default:
|
|
sTaskManager->extPlttVramSizeMain = 0;
|
|
break;
|
|
}
|
|
|
|
switch (GX_GetBankForSubOBJExtPltt()) {
|
|
case GX_VRAM_SUB_OBJEXTPLTT_0_I:
|
|
sTaskManager->extPlttVramSizeSub = PLTT_EXT_RANGE_SIZE;
|
|
break;
|
|
default:
|
|
sTaskManager->extPlttVramSizeSub = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void UpdateTransferSize(PlttTransferTask *task)
|
|
{
|
|
task->data->szByte = task->numPalettes * PALETTE_SIZE_BYTES;
|
|
LoadImagePalette(task);
|
|
}
|
|
|
|
static void LoadImagePalette(PlttTransferTask *task)
|
|
{
|
|
NNS_G2dInitImagePaletteProxy(&task->paletteProxy);
|
|
if (task->vramType & NNS_G2D_VRAM_TYPE_2DMAIN) {
|
|
NNS_G2dLoadPalette(task->data, task->baseAddrMain, NNS_G2D_VRAM_TYPE_2DMAIN, &task->paletteProxy);
|
|
}
|
|
|
|
if (task->vramType & NNS_G2D_VRAM_TYPE_2DSUB) {
|
|
NNS_G2dLoadPalette(task->data, task->baseAddrSub, NNS_G2D_VRAM_TYPE_2DSUB, &task->paletteProxy);
|
|
}
|
|
}
|
|
|
|
static void ReserveTransferRange(u16 *range, int count, int start)
|
|
{
|
|
for (int i = 0; i < count; i++) {
|
|
*range |= 1 << (start + i);
|
|
}
|
|
}
|
|
|
|
static void ClearTransferRange(u16 *range, int count, int start)
|
|
{
|
|
for (int i = 0; i < count; i++) {
|
|
*range &= ~(1 << (start + i));
|
|
}
|
|
}
|
|
|
|
static int FindAvailableTransferSlot(u16 palette, int size)
|
|
{
|
|
int slot;
|
|
for (slot = 0; slot < NUM_VRAM_PALETTES; slot++) {
|
|
int colorIdx = 0;
|
|
while ((palette & (1 << (slot + colorIdx))) == 0 && colorIdx < size) {
|
|
if (slot + colorIdx >= NUM_VRAM_PALETTES) {
|
|
break;
|
|
}
|
|
colorIdx++;
|
|
}
|
|
|
|
if (colorIdx >= size) {
|
|
break;
|
|
}
|
|
|
|
slot += colorIdx;
|
|
}
|
|
|
|
if (slot >= NUM_VRAM_PALETTES) {
|
|
return -1;
|
|
}
|
|
|
|
return PLTT_OFFSET(slot);
|
|
}
|
|
|
|
static void ResetBothTransferRanges(PlttTransferTaskManager *manager)
|
|
{
|
|
manager->vramTransferMain = 0;
|
|
manager->vramTransferSub = 0;
|
|
}
|
|
|
|
static void ReserveTaskTransferRanges(PlttTransferTask *task)
|
|
{
|
|
if (task->vramType & NNS_G2D_VRAM_TYPE_2DMAIN) {
|
|
ReserveTransferRange(&sTaskManager->vramTransferMain, task->numPalettes, task->baseAddrMain / PALETTE_SIZE_BYTES);
|
|
}
|
|
|
|
if (task->vramType & NNS_G2D_VRAM_TYPE_2DSUB) {
|
|
ReserveTransferRange(&sTaskManager->vramTransferSub, task->numPalettes, task->baseAddrSub / PALETTE_SIZE_BYTES);
|
|
}
|
|
}
|
|
|
|
static void ClearTaskTransferRanges(PlttTransferTask *task)
|
|
{
|
|
if (task->vramType & NNS_G2D_VRAM_TYPE_2DMAIN) {
|
|
ClearTransferRange(&sTaskManager->vramTransferMain, task->numPalettes, task->baseAddrMain / PALETTE_SIZE_BYTES);
|
|
}
|
|
|
|
if (task->vramType & NNS_G2D_VRAM_TYPE_2DSUB) {
|
|
ClearTransferRange(&sTaskManager->vramTransferSub, task->numPalettes, task->baseAddrSub / PALETTE_SIZE_BYTES);
|
|
}
|
|
}
|
|
|
|
static BOOL TryGetDestOffsets(PlttTransferTask *task, u32 offsetMain, u32 offsetSub, u32 sizeMain, u32 sizeSub)
|
|
{
|
|
BOOL result = TRUE;
|
|
|
|
if (task->vramType & NNS_G2D_VRAM_TYPE_2DMAIN) {
|
|
if (offsetMain + (task->numPalettes * PALETTE_SIZE_BYTES) > sizeMain) {
|
|
GF_ASSERT(FALSE);
|
|
DummyFunc();
|
|
result = FALSE;
|
|
} else {
|
|
task->baseAddrMain = offsetMain;
|
|
}
|
|
}
|
|
|
|
if (task->vramType & NNS_G2D_VRAM_TYPE_2DSUB) {
|
|
if (offsetSub + (task->numPalettes * PALETTE_SIZE_BYTES) > sizeSub) {
|
|
GF_ASSERT(FALSE);
|
|
DummyFunc();
|
|
result = FALSE;
|
|
} else {
|
|
task->baseAddrSub = offsetSub;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static void ReserveVramSpace(PlttTransferTask *task, u32 *offsetMain, u32 *offsetSub)
|
|
{
|
|
if (task->vramType & NNS_G2D_VRAM_TYPE_2DMAIN) {
|
|
*offsetMain += task->numPalettes * PALETTE_SIZE_BYTES;
|
|
}
|
|
|
|
if (task->vramType & NNS_G2D_VRAM_TYPE_2DSUB) {
|
|
*offsetSub += task->numPalettes * PALETTE_SIZE_BYTES;
|
|
}
|
|
}
|