mirror of
https://github.com/pret/pokeplatinum.git
synced 2026-08-02 16:14:36 -05:00
429 lines
14 KiB
C
429 lines
14 KiB
C
#include "spl_manager.h"
|
|
|
|
#include <nitro/fx/fx.h>
|
|
#include <nnsys/gfd/VramManager/gfd_PlttVramMan_Types.h>
|
|
#include <nnsys/gfd/VramManager/gfd_TexVramMan_Types.h>
|
|
|
|
#include "spl_behavior.h"
|
|
#include "spl_emitter.h"
|
|
#include "spl_internal.h"
|
|
#include "spl_particle.h"
|
|
|
|
#define DECODE_WH(X) ((u16)(1 << ((X) + 3)))
|
|
#define EMITTER_SHOULD_TERMINATE(emtr, header) \
|
|
(((header->flags.selfMaintaining && header->emitterLifeTime != 0 && emtr->state.started && emtr->age > header->emitterLifeTime) \
|
|
|| emtr->state.terminate) \
|
|
&& emtr->particles.count == 0 && emtr->childParticles.count == 0)
|
|
|
|
static u32 SPLUtil_AllocTextureVRAM(u32 size, BOOL is4x4);
|
|
static u32 SPLUtil_AllocPaletteVRAM(u32 size, BOOL is4Pltt);
|
|
|
|
static u32 SPLUtil_AllocTextureVRAM(u32 size, BOOL is4x4)
|
|
{
|
|
return (NNS_GfdAllocTexVram(size, is4x4, 0) & 0xFFFF) * 8;
|
|
}
|
|
|
|
static u32 SPLUtil_AllocPaletteVRAM(u32 size, BOOL is4Pltt)
|
|
{
|
|
return (NNS_GfdAllocPlttVram(size, is4Pltt, 0) & 0xFFFF) * 8;
|
|
}
|
|
|
|
SPLManager *SPLManager_New(SPLAllocFunc alloc, u16 maxEmitters, u16 maxParticles, u16 fixPolyID, u16 minPolyID, u16 maxPolyID)
|
|
{
|
|
int i; // Required to match
|
|
|
|
SPLManager *mgr = alloc(sizeof(SPLManager));
|
|
MI_CpuFill8(mgr, 0, sizeof(SPLManager));
|
|
|
|
mgr->maxEmitters = maxEmitters;
|
|
mgr->maxParticles = maxParticles;
|
|
|
|
mgr->polygonID.min = minPolyID;
|
|
mgr->polygonID.max = maxPolyID;
|
|
mgr->polygonID.current = mgr->polygonID.min;
|
|
mgr->polygonID.fix = fixPolyID;
|
|
mgr->polygonID.drawOrder = SPL_DRAW_ORDER_REVERSE;
|
|
mgr->polygonID.unused = 0;
|
|
|
|
mgr->alloc = alloc;
|
|
|
|
mgr->activeEmitters.count = 0;
|
|
mgr->inactiveEmitters.count = 0;
|
|
mgr->inactiveParticles.count = 0;
|
|
|
|
mgr->activeEmitters.first = NULL;
|
|
mgr->inactiveEmitters.first = NULL;
|
|
mgr->inactiveParticles.first = NULL;
|
|
|
|
mgr->miscPolygonAttr = GX_POLYGON_ATTR_MISC_NONE;
|
|
mgr->currentCycle = 0;
|
|
|
|
SPLEmitter *emtr = alloc(maxEmitters * sizeof(SPLEmitter));
|
|
MI_CpuFill8(emtr, 0, maxEmitters * sizeof(SPLEmitter));
|
|
|
|
for (i = 0; i < maxEmitters; ++i) {
|
|
SPLEmitterList_PushFront(&mgr->inactiveEmitters, &emtr[i]);
|
|
}
|
|
|
|
SPLParticle *ptcl = alloc(maxParticles * sizeof(SPLParticle));
|
|
MI_CpuFill8(ptcl, 0, maxParticles * sizeof(SPLParticle));
|
|
|
|
for (i = 0; i < maxParticles; ++i) {
|
|
SPLParticleList_PushFront(&mgr->inactiveParticles, &ptcl[i]);
|
|
}
|
|
|
|
mgr->resources = NULL;
|
|
mgr->textures = NULL;
|
|
mgr->resCount = mgr->texCount = 0;
|
|
|
|
return mgr;
|
|
}
|
|
|
|
void SPLManager_LoadResources(SPLManager *mgr, const void *data)
|
|
{
|
|
// Required to match
|
|
int i, offset;
|
|
SPLFileHeader *spa;
|
|
|
|
spa = (SPLFileHeader *)data;
|
|
offset = sizeof(SPLFileHeader);
|
|
|
|
mgr->resCount = spa->resCount;
|
|
mgr->texCount = spa->texCount;
|
|
|
|
mgr->resources = mgr->alloc(mgr->resCount * sizeof(SPLResource));
|
|
|
|
MI_CpuFill8(mgr->resources, 0, mgr->resCount * sizeof(SPLResource));
|
|
|
|
for (i = 0; i < mgr->resCount; ++i) {
|
|
SPLResource *res = mgr->resources + i;
|
|
res->header = (SPLResourceHeader *)((u8 *)spa + offset);
|
|
|
|
offset += sizeof(SPLResourceHeader);
|
|
SPLResourceFlags flags = res->header->flags;
|
|
|
|
if (flags.hasScaleAnim) {
|
|
res->scaleAnim = (SPLScaleAnim *)((u8 *)spa + offset);
|
|
offset += sizeof(SPLScaleAnim);
|
|
} else {
|
|
res->scaleAnim = NULL;
|
|
}
|
|
|
|
if (flags.hasColorAnim) {
|
|
res->colorAnim = (SPLColorAnim *)((u8 *)spa + offset);
|
|
offset += sizeof(SPLColorAnim);
|
|
} else {
|
|
res->colorAnim = NULL;
|
|
}
|
|
|
|
if (flags.hasAlphaAnim) {
|
|
res->alphaAnim = (SPLAlphaAnim *)((u8 *)spa + offset);
|
|
offset += sizeof(SPLAlphaAnim);
|
|
} else {
|
|
res->alphaAnim = NULL;
|
|
}
|
|
|
|
if (flags.hasTexAnim) {
|
|
res->texAnim = (SPLTexAnim *)((u8 *)spa + offset);
|
|
offset += sizeof(SPLTexAnim);
|
|
} else {
|
|
res->texAnim = NULL;
|
|
}
|
|
|
|
if (flags.hasChildResource) {
|
|
res->childResource = (SPLChildResource *)((u8 *)spa + offset);
|
|
offset += sizeof(SPLChildResource);
|
|
} else {
|
|
res->childResource = NULL;
|
|
}
|
|
|
|
// Sum up all behaviors
|
|
res->behaviorCount = flags.hasGravityBehavior
|
|
+ flags.hasRandomBehavior
|
|
+ flags.hasMagnetBehavior
|
|
+ flags.hasSpinBehavior
|
|
+ flags.hasCollisionPlaneBehavior
|
|
+ flags.hasConvergenceBehavior;
|
|
|
|
if (res->behaviorCount != 0) {
|
|
res->behaviors = (SPLBehavior *)mgr->alloc(res->behaviorCount * sizeof(SPLBehavior));
|
|
SPLBehavior *behavior = res->behaviors;
|
|
|
|
if (flags.hasGravityBehavior) {
|
|
behavior->object = (const void *)((u8 *)spa + offset);
|
|
behavior->applyFunc = SPLBehavior_ApplyGravity;
|
|
offset += sizeof(SPLGravityBehavior);
|
|
behavior++;
|
|
}
|
|
|
|
if (flags.hasRandomBehavior) {
|
|
behavior->object = (const void *)((u8 *)spa + offset);
|
|
behavior->applyFunc = SPLBehavior_ApplyRandom;
|
|
offset += sizeof(SPLRandomBehavior);
|
|
behavior++;
|
|
}
|
|
|
|
if (flags.hasMagnetBehavior) {
|
|
behavior->object = (const void *)((u8 *)spa + offset);
|
|
behavior->applyFunc = SPLBehavior_ApplyMagnet;
|
|
offset += sizeof(SPLMagnetBehavior);
|
|
behavior++;
|
|
}
|
|
|
|
if (flags.hasSpinBehavior) {
|
|
behavior->object = (const void *)((u8 *)spa + offset);
|
|
behavior->applyFunc = SPLBehavior_ApplySpin;
|
|
offset += sizeof(SPLSpinBehavior);
|
|
behavior++;
|
|
}
|
|
|
|
if (flags.hasCollisionPlaneBehavior) {
|
|
behavior->object = (const void *)((u8 *)spa + offset);
|
|
behavior->applyFunc = SPLBehavior_ApplyCollisionPlane;
|
|
offset += sizeof(SPLCollisionPlaneBehavior);
|
|
behavior++;
|
|
}
|
|
|
|
if (flags.hasConvergenceBehavior) {
|
|
behavior->object = (const void *)((u8 *)spa + offset);
|
|
behavior->applyFunc = SPLBehavior_ApplyConvergence;
|
|
offset += sizeof(SPLConvergenceBehavior);
|
|
}
|
|
} else {
|
|
res->behaviors = NULL;
|
|
}
|
|
}
|
|
|
|
mgr->textures = (SPLTexture *)mgr->alloc(mgr->texCount * sizeof(SPLTexture));
|
|
|
|
MI_CpuFill8(mgr->textures, 0, mgr->texCount * sizeof(SPLTexture));
|
|
|
|
for (i = 0; i < mgr->texCount; ++i) {
|
|
SPLTexture *texture = &mgr->textures[i];
|
|
SPLTextureResource *texRes = (SPLTextureResource *)((u8 *)spa + offset);
|
|
texture->resource = texRes;
|
|
texture->width = DECODE_WH(texRes->param.s);
|
|
texture->height = DECODE_WH(texRes->param.t);
|
|
texture->param = texRes->param;
|
|
offset += texRes->resourceSize;
|
|
}
|
|
}
|
|
|
|
BOOL SPLManager_UploadTexturesEx(SPLManager *mgr, SPLTexVRAMAllocFunc vramAlloc)
|
|
{
|
|
GX_BeginLoadTex();
|
|
|
|
for (int i = 0; i < mgr->texCount; i++) {
|
|
SPLTexture *textures = mgr->textures;
|
|
SPLTexture *tex = &textures[i];
|
|
SPLTextureResource *texRes = (SPLTextureResource *)tex->resource;
|
|
|
|
if (texRes->param.useSharedTexture) {
|
|
tex->texAddr = textures[texRes->param.sharedTexID].texAddr;
|
|
} else {
|
|
u32 addr = vramAlloc(texRes->textureSize, texRes->param.format == GX_TEXFMT_COMP4x4);
|
|
const void *data = SPLTextureResource_GetTexData((SPLTextureResource *)tex->resource);
|
|
GX_LoadTex(data, addr, texRes->textureSize);
|
|
tex->texAddr = addr;
|
|
}
|
|
}
|
|
|
|
GX_EndLoadTex();
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL SPLManager_UploadPalettesEx(SPLManager *mgr, SPLPalVRAMAllocFunc vramAlloc)
|
|
{
|
|
// Required to match
|
|
s32 i;
|
|
SPLTexture *tex;
|
|
SPLTextureResource *texRes;
|
|
|
|
GX_BeginLoadTexPltt();
|
|
|
|
for (i = 0; i < mgr->texCount; i++) {
|
|
u32 addr = 0;
|
|
tex = &mgr->textures[i];
|
|
texRes = (SPLTextureResource *)tex->resource;
|
|
|
|
if (texRes->paletteSize != 0) {
|
|
addr = vramAlloc(texRes->paletteSize, texRes->param.format == GX_TEXFMT_PLTT4);
|
|
GX_LoadTexPltt((u8 *)tex->resource + texRes->paletteOffset, addr, texRes->paletteSize);
|
|
}
|
|
|
|
tex->palAddr = addr;
|
|
}
|
|
|
|
GX_EndLoadTexPltt();
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL SPLManager_UploadTextures(SPLManager *mgr)
|
|
{
|
|
return SPLManager_UploadTexturesEx(mgr, SPLUtil_AllocTextureVRAM);
|
|
}
|
|
|
|
BOOL SPLManager_UploadPalettes(SPLManager *mgr)
|
|
{
|
|
return SPLManager_UploadPalettesEx(mgr, SPLUtil_AllocPaletteVRAM);
|
|
}
|
|
|
|
void SPLManager_Update(SPLManager *mgr)
|
|
{
|
|
// Required to match
|
|
SPLEmitter *emtr;
|
|
SPLEmitter *next;
|
|
|
|
emtr = mgr->activeEmitters.first;
|
|
while (emtr != NULL) {
|
|
SPLResourceHeader *header = emtr->resource->header;
|
|
next = emtr->next;
|
|
|
|
if (!emtr->state.started && emtr->age >= header->startDelay) {
|
|
emtr->state.started = TRUE;
|
|
emtr->age = 0;
|
|
}
|
|
|
|
if (!emtr->state.paused) {
|
|
if (emtr->misc.updateCycle == 0 || mgr->currentCycle == emtr->misc.updateCycle - 1) {
|
|
SPLEmitter_Update(mgr, emtr);
|
|
}
|
|
}
|
|
|
|
if (EMITTER_SHOULD_TERMINATE(emtr, header)) {
|
|
SPLEmitter *terminatedEmitter = SPLEmitterList_Erase(&mgr->activeEmitters, emtr);
|
|
SPLEmitterList_PushFront(&mgr->inactiveEmitters, terminatedEmitter);
|
|
}
|
|
|
|
emtr = next;
|
|
}
|
|
|
|
mgr->currentCycle += 1;
|
|
if (mgr->currentCycle > 1) {
|
|
mgr->currentCycle = 0;
|
|
}
|
|
}
|
|
|
|
void SPLManager_Draw(SPLManager *mgr, const MtxFx43 *viewMatrix)
|
|
{
|
|
G3X_AlphaBlend(TRUE);
|
|
|
|
mgr->renderState.viewMatrix = viewMatrix;
|
|
if (mgr->polygonID.drawOrder == SPL_DRAW_ORDER_REVERSE) {
|
|
for (SPLEmitter *emtr = mgr->activeEmitters.first; emtr != NULL; emtr = emtr->next) {
|
|
mgr->renderState.emitter = emtr;
|
|
if (!emtr->state.renderingDisabled) {
|
|
SPLManager_DoDraw(mgr);
|
|
}
|
|
}
|
|
} else {
|
|
for (SPLEmitter *emtr = mgr->activeEmitters.last; emtr != NULL; emtr = emtr->prev) {
|
|
mgr->renderState.emitter = emtr;
|
|
if (!emtr->state.renderingDisabled) {
|
|
SPLManager_DoDraw(mgr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SPLEmitter *SPLManager_CreateEmitter(SPLManager *mgr, int resourceID, const VecFx32 *pos)
|
|
{
|
|
SPLEmitter *emtr = NULL;
|
|
|
|
if (mgr->inactiveEmitters.first != NULL) {
|
|
emtr = SPLEmitterList_PopFront(&mgr->inactiveEmitters);
|
|
SPLEmitter_Init(emtr, mgr->resources + resourceID, pos);
|
|
SPLEmitterList_PushFront(&mgr->activeEmitters, emtr);
|
|
|
|
if (emtr->resource->header->flags.selfMaintaining) { // Self-maintaining emitters are not returned to the user
|
|
emtr = NULL;
|
|
}
|
|
}
|
|
|
|
return emtr;
|
|
}
|
|
|
|
SPLEmitter *SPLManager_CreateEmitterWithCallback(SPLManager *mgr, int resourceID, SPLEmitterCallback initCallback)
|
|
{
|
|
SPLEmitter *emtr = NULL;
|
|
if (mgr->inactiveEmitters.first != NULL) {
|
|
VecFx32 pos = { 0, 0, 0 };
|
|
emtr = SPLEmitterList_PopFront(&mgr->inactiveEmitters);
|
|
SPLEmitter_Init(emtr, mgr->resources + resourceID, &pos);
|
|
|
|
if (initCallback != NULL) {
|
|
initCallback(emtr);
|
|
}
|
|
|
|
SPLEmitterList_PushFront(&mgr->activeEmitters, emtr);
|
|
|
|
if (emtr->resource->header->flags.selfMaintaining) { // Self-maintaining emitters are not returned to the user
|
|
emtr = NULL;
|
|
}
|
|
}
|
|
|
|
return emtr;
|
|
}
|
|
|
|
SPLEmitter *SPLManager_CreateEmitterWithCallbackEx(SPLManager *mgr, int resourceID, VecFx32 *pos, void *param, SPLEmitterCallbackEx initCallback)
|
|
{
|
|
SPLEmitter *emtr = NULL;
|
|
if (mgr->inactiveEmitters.first != NULL) {
|
|
emtr = SPLEmitterList_PopFront(&mgr->inactiveEmitters);
|
|
SPLEmitter_Init(emtr, mgr->resources + resourceID, pos);
|
|
|
|
if (initCallback != NULL) {
|
|
initCallback(emtr, param);
|
|
}
|
|
|
|
SPLEmitterList_PushFront(&mgr->activeEmitters, emtr);
|
|
|
|
if (emtr->resource->header->flags.selfMaintaining) { // Self-maintaining emitters are not returned to the user
|
|
emtr = NULL;
|
|
}
|
|
}
|
|
|
|
return emtr;
|
|
}
|
|
|
|
void SPLManager_DeleteEmitter(SPLManager *mgr, SPLEmitter *emtr)
|
|
{
|
|
SPLParticle *ptcl = SPLParticleList_PopFront(&emtr->particles);
|
|
while (ptcl != NULL) {
|
|
SPLParticleList_PushFront(&mgr->inactiveParticles, ptcl);
|
|
ptcl = SPLParticleList_PopFront(&emtr->particles);
|
|
}
|
|
|
|
ptcl = SPLParticleList_PopFront(&emtr->childParticles);
|
|
while (ptcl != NULL) {
|
|
SPLParticleList_PushFront(&mgr->inactiveParticles, ptcl);
|
|
ptcl = SPLParticleList_PopFront(&emtr->childParticles);
|
|
}
|
|
|
|
SPLEmitterList_Erase(&mgr->activeEmitters, emtr);
|
|
SPLEmitterList_PushFront(&mgr->inactiveEmitters, emtr);
|
|
}
|
|
|
|
void SPLManager_DeleteAllEmitters(SPLManager *mgr)
|
|
{
|
|
SPLEmitter *emtr = mgr->activeEmitters.first;
|
|
while (emtr != NULL) {
|
|
SPLEmitter *next = emtr->next;
|
|
SPLManager_DeleteEmitter(mgr, emtr);
|
|
emtr = next;
|
|
}
|
|
}
|
|
|
|
void SPLManager_Emit(SPLManager *mgr, SPLEmitter *emtr)
|
|
{
|
|
SPLEmitter_Emit(emtr, &mgr->inactiveParticles);
|
|
}
|
|
|
|
void SPLManager_EmitAt(SPLManager *mgr, SPLEmitter *emtr, VecFx32 *pos)
|
|
{
|
|
emtr->position.x = pos->x + emtr->resource->header->emitterBasePos.x;
|
|
emtr->position.y = pos->y + emtr->resource->header->emitterBasePos.y;
|
|
emtr->position.z = pos->z + emtr->resource->header->emitterBasePos.z;
|
|
SPLEmitter_Emit(emtr, &mgr->inactiveParticles);
|
|
}
|