mirror of https://github.com/pmret/papermario.git
343 lines
12 KiB
C
343 lines
12 KiB
C
#include "common.h"
|
|
#include "effects.h"
|
|
#include "ld_addrs.h"
|
|
|
|
typedef s32 TlbEntry[0x1000 / 4];
|
|
typedef TlbEntry TlbMappablePage[15];
|
|
|
|
SHIFT_BSS EffectGraphics gEffectGraphicsData[15];
|
|
SHIFT_BSS EffectInstance* gEffectInstances[96];
|
|
|
|
extern TlbMappablePage D_80197000;
|
|
extern Addr D_801A6000;
|
|
|
|
#define FX_ENTRY(name, gfx_name) { \
|
|
name##_main, effect_##name##_ROM_START, effect_##name##_ROM_END, effect_##name##_VRAM, gfx_name##_ROM_START, \
|
|
gfx_name##_ROM_END \
|
|
}
|
|
|
|
#include "effects/effect_table.c"
|
|
|
|
s32 D_8007FEB8[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 5, 3, 4, 13, 60, 0, 512, 0, 0, 3, 0 };
|
|
|
|
/// Used for unbound function points in effect structs.
|
|
void stub_effect_delegate(EffectInstance* effect) {
|
|
}
|
|
|
|
void set_effect_pos_offset(EffectInstance* effect, f32 x, f32 y, f32 z) {
|
|
s32* data = effect->data.any;
|
|
|
|
((f32*)data)[1] = x;
|
|
((f32*)data)[2] = y;
|
|
((f32*)data)[3] = z;
|
|
}
|
|
|
|
void clear_effect_data(void) {
|
|
s32 i;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(gEffectGraphicsData); i++) {
|
|
gEffectGraphicsData[i].flags = 0;
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_COUNT(gEffectInstances); i++) {
|
|
gEffectInstances[i] = NULL;
|
|
}
|
|
|
|
osUnmapTLBAll();
|
|
osMapTLB(0x10, NULL, _325AD0_VRAM, (s32)&D_801A6000 & 0xFFFFFF, -1, -1);
|
|
DMA_COPY_SEGMENT(_325AD0);
|
|
}
|
|
|
|
void func_80059D48(void) {
|
|
}
|
|
|
|
void update_effects(void) {
|
|
if (!(gOverrideFlags & (GLOBAL_OVERRIDES_800 | GLOBAL_OVERRIDES_400))) {
|
|
EffectGraphics* effectGraphics;
|
|
s32 i;
|
|
|
|
// reset free delay for each EffectGraphics touched in previous update
|
|
for (i = 0, effectGraphics = gEffectGraphicsData; i < ARRAY_COUNT(gEffectGraphicsData); i++, effectGraphics++) {
|
|
if (effectGraphics->flags & FX_GRAPHICS_LOADED) {
|
|
if (!(effectGraphics->flags & FX_GRAPHICS_CAN_FREE)) {
|
|
effectGraphics->flags |= FX_GRAPHICS_CAN_FREE;
|
|
effectGraphics->freeDelay = 3;
|
|
}
|
|
}
|
|
}
|
|
|
|
// update each EffectInstances
|
|
for (i = 0; i < ARRAY_COUNT(gEffectInstances); i++) {
|
|
EffectInstance* effectInstance = gEffectInstances[i];
|
|
|
|
if (effectInstance != NULL && (effectInstance->flags & FX_INSTANCE_FLAG_ENABLED)) {
|
|
effectInstance->graphics->flags &= ~FX_GRAPHICS_CAN_FREE;
|
|
|
|
if (gGameStatusPtr->isBattle) {
|
|
if (effectInstance->flags & FX_INSTANCE_FLAG_BATTLE) {
|
|
effectInstance->graphics->update(effectInstance);
|
|
effectInstance->flags |= FX_INSTANCE_FLAG_HAS_UPDATED;
|
|
}
|
|
} else {
|
|
if (!(effectInstance->flags & FX_INSTANCE_FLAG_BATTLE)) {
|
|
effectInstance->graphics->update(effectInstance);
|
|
effectInstance->flags |= FX_INSTANCE_FLAG_HAS_UPDATED;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// free any EffectGraphics which haven't been used recently
|
|
for (i = 0, effectGraphics = gEffectGraphicsData; i < ARRAY_COUNT(gEffectGraphicsData); i++, effectGraphics++) {
|
|
if (effectGraphics->flags & FX_GRAPHICS_LOADED) {
|
|
if (effectGraphics->flags & FX_GRAPHICS_CAN_FREE) {
|
|
if (effectGraphics->freeDelay != 0) {
|
|
effectGraphics->freeDelay--;
|
|
} else {
|
|
if (effectGraphics->data != NULL) {
|
|
general_heap_free(effectGraphics->data);
|
|
effectGraphics->data = NULL;
|
|
}
|
|
effectGraphics->flags = FX_GRAPHICS_DISABLED;
|
|
osUnmapTLB(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void render_effects_world(void) {
|
|
s32 i;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(gEffectInstances); i++) {
|
|
EffectInstance* effectInstance = gEffectInstances[i];
|
|
|
|
if (effectInstance != NULL) {
|
|
if (effectInstance->flags & FX_INSTANCE_FLAG_ENABLED) {
|
|
if (effectInstance->flags & FX_INSTANCE_FLAG_HAS_UPDATED) {
|
|
if (gGameStatusPtr->isBattle) {
|
|
if (effectInstance->flags & FX_INSTANCE_FLAG_BATTLE) {
|
|
effectInstance->graphics->renderWorld(effectInstance);
|
|
}
|
|
} else {
|
|
if (!(effectInstance->flags & FX_INSTANCE_FLAG_BATTLE)) {
|
|
effectInstance->graphics->renderWorld(effectInstance);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void render_effects_UI(void) {
|
|
s32 cond = TRUE;
|
|
s32 i;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(gEffectInstances); i++) {
|
|
EffectInstance* effectInstance = gEffectInstances[i];
|
|
|
|
if (effectInstance != NULL) {
|
|
if (effectInstance->flags & FX_INSTANCE_FLAG_ENABLED) {
|
|
if (effectInstance->flags & FX_INSTANCE_FLAG_HAS_UPDATED) {
|
|
void (*renderUI)(EffectInstance* effect);
|
|
|
|
if (gGameStatusPtr->isBattle && !(effectInstance->flags & FX_INSTANCE_FLAG_BATTLE)) {
|
|
continue;
|
|
}
|
|
|
|
if (!gGameStatusPtr->isBattle && effectInstance->flags & FX_INSTANCE_FLAG_BATTLE) {
|
|
continue;
|
|
}
|
|
|
|
renderUI = effectInstance->graphics->renderUI;
|
|
if (renderUI != stub_effect_delegate) {
|
|
if (cond) {
|
|
Camera* camera = &gCameras[gCurrentCameraID];
|
|
|
|
gDPPipeSync(gMainGfxPos++);
|
|
gSPViewport(gMainGfxPos++, &camera->vp);
|
|
gSPClearGeometryMode(gMainGfxPos++, G_ZBUFFER | G_SHADE | G_CULL_BOTH | G_FOG |
|
|
G_LIGHTING | G_TEXTURE_GEN | G_TEXTURE_GEN_LINEAR | G_LOD |
|
|
G_SHADING_SMOOTH | G_CLIPPING | 0x40F9FA);
|
|
gSPSetGeometryMode(gMainGfxPos++, G_ZBUFFER | G_SHADE | G_CULL_BACK | G_SHADING_SMOOTH);
|
|
gDPSetScissor(gMainGfxPos++, G_SC_NON_INTERLACE,
|
|
camera->viewportStartX,
|
|
camera->viewportStartY,
|
|
camera->viewportStartX + camera->viewportW,
|
|
camera->viewportStartY + camera->viewportH);
|
|
gSPClipRatio(gMainGfxPos++, FRUSTRATIO_2);
|
|
|
|
cond = FALSE;
|
|
if (!(camera->flags & CAMERA_FLAG_ORTHO)) {
|
|
gSPPerspNormalize(gMainGfxPos++, camera->perspNorm);
|
|
gSPMatrix(gMainGfxPos++, &gDisplayContext->camPerspMatrix[gCurrentCameraID],
|
|
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
|
|
}
|
|
}
|
|
|
|
renderUI(effectInstance);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
EffectInstance* create_effect_instance(EffectBlueprint* effectBp) {
|
|
EffectInstance* newEffectInst;
|
|
EffectGraphics* effectGraphics;
|
|
s32 i;
|
|
|
|
// Search for an unused instance
|
|
for (i = 0; i < ARRAY_COUNT(gEffectInstances); i++) {
|
|
if (gEffectInstances[i] == NULL) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
ASSERT(i < ARRAY_COUNT(gEffectInstances));
|
|
|
|
// Allocate space for the new instance
|
|
gEffectInstances[i] = newEffectInst = general_heap_malloc(sizeof(*newEffectInst));
|
|
ASSERT(newEffectInst != NULL);
|
|
|
|
effectGraphics = &gEffectGraphicsData[0];
|
|
newEffectInst->effectIndex = effectBp->effectID;
|
|
newEffectInst->flags = FX_INSTANCE_FLAG_ENABLED;
|
|
|
|
// Look for a loaded effect of the proper index
|
|
for (i = 0; i < ARRAY_COUNT(gEffectGraphicsData); i++) {
|
|
if ((effectGraphics->flags & FX_GRAPHICS_LOADED) && (effectGraphics->effectIndex == effectBp->effectID)) {
|
|
break;
|
|
}
|
|
effectGraphics++;
|
|
}
|
|
|
|
ASSERT(i < ARRAY_COUNT(gEffectGraphicsData));
|
|
|
|
// If this is the first new instance of the effect, initialize the function pointers
|
|
if (effectGraphics->instanceCounter == 0) {
|
|
effectGraphics->update = effectBp->update;
|
|
if (effectGraphics->update == NULL) {
|
|
effectGraphics->renderWorld = stub_effect_delegate;
|
|
}
|
|
|
|
effectGraphics->renderWorld = effectBp->renderWorld;
|
|
// @bug? null check for renderUI instead of renderWorld
|
|
if (effectGraphics->renderUI == NULL) {
|
|
effectGraphics->renderUI = stub_effect_delegate;
|
|
}
|
|
|
|
effectGraphics->renderUI = effectBp->renderUI;
|
|
if (effectGraphics->renderUI == NULL) {
|
|
effectGraphics->renderUI = stub_effect_delegate;
|
|
}
|
|
}
|
|
|
|
effectGraphics->instanceCounter++;
|
|
newEffectInst->graphics = effectGraphics;
|
|
|
|
if (effectBp->init != NULL) {
|
|
effectBp->init(newEffectInst);
|
|
}
|
|
|
|
if (gGameStatusPtr->isBattle) {
|
|
newEffectInst->flags |= FX_INSTANCE_FLAG_BATTLE;
|
|
}
|
|
return newEffectInst;
|
|
}
|
|
|
|
void remove_effect(EffectInstance* effectInstance) {
|
|
s32 i;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(gEffectInstances); i++) {
|
|
if (gEffectInstances[i] == effectInstance) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
ASSERT(i < ARRAY_COUNT(gEffectInstances));
|
|
|
|
if (effectInstance->data.any == NULL) {
|
|
general_heap_free(effectInstance);
|
|
gEffectInstances[i] = NULL;
|
|
} else {
|
|
general_heap_free(effectInstance->data.any);
|
|
general_heap_free(effectInstance);
|
|
gEffectInstances[i] = NULL;
|
|
}
|
|
}
|
|
|
|
void remove_all_effects(void) {
|
|
s32 i;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(gEffectInstances); i++) {
|
|
EffectInstance* effect = gEffectInstances[i];
|
|
|
|
if (effect != NULL && effect->flags & FX_INSTANCE_FLAG_BATTLE) {
|
|
if (effect->data.any != NULL) {
|
|
general_heap_free(effect->data.any);
|
|
}
|
|
general_heap_free(effect);
|
|
gEffectInstances[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
s32 load_effect(s32 effectIndex) {
|
|
EffectTableEntry* effectEntry = &gEffectTable[effectIndex];
|
|
EffectGraphics* effectGraphics;
|
|
TlbMappablePage* tlbMappablePages;
|
|
s32 i;
|
|
|
|
// Look for a loaded effect matching the desired index
|
|
for (i = 0, effectGraphics = &gEffectGraphicsData[0]; i < ARRAY_COUNT(gEffectGraphicsData); i++) {
|
|
if (effectGraphics->flags & FX_GRAPHICS_LOADED && effectGraphics->effectIndex == effectIndex) {
|
|
break;
|
|
}
|
|
effectGraphics++;
|
|
}
|
|
|
|
// If an effect was found within the table, initialize it and return
|
|
if (i < ARRAY_COUNT(gEffectGraphicsData)) {
|
|
effectGraphics->effectIndex = effectIndex;
|
|
effectGraphics->instanceCounter = 0;
|
|
effectGraphics->flags = FX_GRAPHICS_LOADED;
|
|
return 1;
|
|
}
|
|
|
|
// If a loaded effect wasn't found, look for the first empty space
|
|
for (i = 0, effectGraphics = &gEffectGraphicsData[0]; i < ARRAY_COUNT(gEffectGraphicsData); i++) {
|
|
if (!(effectGraphics->flags & FX_GRAPHICS_LOADED)) {
|
|
break;
|
|
}
|
|
effectGraphics++;
|
|
}
|
|
|
|
// If no empty space was found, panic
|
|
ASSERT(i < ARRAY_COUNT(gEffectGraphicsData));
|
|
|
|
// Map space for the effect
|
|
tlbMappablePages = &D_80197000;
|
|
osMapTLB(i, 0, effectEntry->dmaDest, (s32)((*tlbMappablePages)[i]) & 0xFFFFFF, -1, -1);
|
|
|
|
// Copy the effect into the newly mapped space
|
|
dma_copy(effectEntry->dmaStart, effectEntry->dmaEnd, effectEntry->dmaDest);
|
|
|
|
// If there's graphics data for the effect, allocate space and copy into the new space
|
|
if (effectEntry->graphicsDmaStart != NULL) {
|
|
void* effectDataBuf = general_heap_malloc(effectEntry->graphicsDmaEnd - effectEntry->graphicsDmaStart);
|
|
effectGraphics->data = effectDataBuf;
|
|
ASSERT(effectDataBuf != NULL);
|
|
dma_copy(effectEntry->graphicsDmaStart, effectEntry->graphicsDmaEnd, effectGraphics->data);
|
|
}
|
|
|
|
// Initialize the newly loaded effect data
|
|
effectGraphics->effectIndex = effectIndex;
|
|
effectGraphics->instanceCounter = 0;
|
|
effectGraphics->flags = FX_GRAPHICS_LOADED;
|
|
return 1;
|
|
}
|