Document SPLAnim

This commit is contained in:
Fexty12573 2024-08-02 17:40:15 +02:00
parent d79dad4c74
commit 86b9e9f2a4
8 changed files with 198 additions and 207 deletions

View File

@ -43,7 +43,7 @@ typedef struct SPLEmitter {
u16 age;
fx16 emissionCountFractional; // fractional part of the number of particles to emit (doesn't seem to be used)
VecFx16 axis;
u16 unk_C6;
u16 initAngle;
fx32 emissionCount;
fx32 radius;
fx32 length;

View File

@ -29,12 +29,12 @@ void sub_0209F3D0(SPLManager *mgr, SPLParticle *ptcl);
void sub_0209E9A0(SPLManager *mgr, SPLParticle *ptcl);
void sub_0209E1D4(SPLManager *mgr, SPLParticle *ptcl);
void sub_020A1DA0(SPLParticle *ptcl, SPLResource *res, int lifeRate); // spl_scl_in_out
void sub_020A1BD4(SPLParticle *ptcl, SPLResource *res, int lifeRate); // spl_clr_in_out
void sub_020A1AF8(SPLParticle *ptcl, SPLResource *res, int lifeRate); // spl_alp_in_out
void sub_020A1A94(SPLParticle *ptcl, SPLResource *res, int lifeRate); // spl_tex_ptn_anm
void sub_020A1A48(SPLParticle *ptcl, SPLResource *res, int lifeRate); // spl_chld_scl_out
void sub_020A19F0(SPLParticle *ptcl, SPLResource *res, int lifeRate); // spl_chld_alp_out
void SPLAnim_Scale(SPLParticle *ptcl, SPLResource *res, int lifeRate); // spl_scl_in_out
void SPLAnim_Color(SPLParticle *ptcl, SPLResource *res, int lifeRate); // spl_clr_in_out
void SPLAnim_Alpha(SPLParticle *ptcl, SPLResource *res, int lifeRate); // spl_alp_in_out
void SPLAnim_Texture(SPLParticle *ptcl, SPLResource *res, int lifeRate); // spl_tex_ptn_anm
void SPLAnim_ChildScale(SPLParticle *ptcl, SPLResource *res, int lifeRate); // spl_chld_scl_out
void SPLAnim_ChildAlpha(SPLParticle *ptcl, SPLResource *res, int lifeRate); // spl_chld_alp_out
void SPLEmitter_EmitParticles(SPLEmitter *emtr, SPLParticleList *list);
void SPLEmitter_EmitChildren(SPLParticle *ptcl, SPLEmitter *emtr, SPLParticleList *list);

View File

@ -56,7 +56,7 @@ typedef union SPLResourceFlags {
u32 hasAlphaAnim : 1;
u32 hasTexAnim : 1;
u32 hasRotation : 1;
u32 unk_05_5 : 1;
u32 randomInitAngle : 1;
// Whether the emitter manages itself or not.
// If set, the emitter will automatically terminate when it reaches the end of its life
// and all of its particles have died
@ -96,23 +96,23 @@ typedef union SPLChildResourceFlags {
};
} SPLChildResourceFlags;
typedef union {
u16 val1;
typedef union SPLCurveInOut {
u16 all;
struct {
u16 val2_00 : 8;
u16 val2_01 : 8;
u16 in : 8;
u16 out : 8;
};
} UnkSPLUnion3; // size=0x2
} SPLCurveInOut;
typedef union {
u32 unk_00;
typedef union SPLCurveInPeakOut {
u32 all;
struct {
u32 unk_04_0 : 8;
u32 unk_05_0 : 8;
u32 unk_06_0 : 8;
u32 unk_07_0 : 8;
u32 in : 8;
u32 peak : 8;
u32 out : 8;
u32 : 8;
};
} UnkSPLUnion4; // size=0x4
} SPLCurveInPeakOut;
typedef struct SPLResourceHeader {
SPLResourceFlags flags;
@ -169,46 +169,46 @@ typedef struct SPLResourceHeader {
} SPLResourceHeader; // size=0x5C
typedef struct SPLScaleAnim {
fx16 unk_00;
fx16 unk_02;
fx16 unk_04;
UnkSPLUnion3 unk_06;
fx16 start;
fx16 mid;
fx16 end;
SPLCurveInOut curve;
struct {
u16 unk_00_0 : 1;
u16 reserved_00_1 : 15;
} unk_08;
u16 reserved_0A;
u16 loop : 1;
u16 : 15;
} flags;
u16 padding;
} SPLScaleAnim; // size=0xc
typedef struct SPLColorAnim {
GXRgb startColor;
GXRgb endColor;
UnkSPLUnion4 unk_04;
GXRgb start;
GXRgb end;
SPLCurveInPeakOut curve;
struct {
u16 unk_00_0 : 1;
u16 unk_00_1 : 1;
u16 unk_00_2 : 1;
u16 unk_00_3 : 13;
} unk_08;
u16 reserved_0A;
u16 randomStartColor : 1;
u16 loop : 1;
u16 interpolate : 1;
u16 : 13;
} flags;
u16 padding;
} SPLColorAnim;
typedef struct SPLAlphaAnim {
union {
u16 val1;
u16 all;
struct {
u16 val2_00_0 : 5;
u16 val2_00_5 : 5;
u16 val2_01_2 : 5;
u16 val2_reserved_01_7 : 1;
u16 start : 5;
u16 mid : 5;
u16 end : 5;
u16 : 1;
};
} unk_00;
} alpha;
struct {
u16 unk_00_0 : 8;
u16 unk_01_0 : 1;
u16 unk_01_1 : 7;
} unk_02;
UnkSPLUnion3 unk_04;
u16 randomRange : 8;
u16 loop : 1;
u16 : 7;
} flags;
SPLCurveInOut curve;
u16 reserved_06;
} SPLAlphaAnim; // size=0x8
@ -216,17 +216,17 @@ typedef struct SPLTexAnim {
u8 textures[SPL_TEX_ANIM_MAX_FRAMES];
struct {
u32 frameCount : 8;
u32 unk_01_0 : 8;
u32 step : 8; // Number of frames between each texture frame
u32 randomizeInit : 1; // Randomize the initial texture frame
u32 unk_02_1 : 1;
u32 reserved_02_2 : 14;
u32 loop : 1;
u32 : 14;
} param;
} SPLTexAnim;
typedef struct SPLChildResource {
SPLChildResourceFlags flags;
fx16 randomInitVelMag; // Randomization factor for the initial velocity magnitude (0 = no randomization)
fx16 unk_04;
fx16 endScale; // For scaling animations
u16 lifeTime;
u8 velocityRatio; // Ratio of the parent particle's velocity to inherit (255 = 100%)
u8 scaleRatio; // Ratio of the parent particle's scale to inherit (255 = 100%)

View File

@ -19,7 +19,7 @@ libspl_srcs = files(
'src/spl_emitter.c',
'src/unk_0209DD54.c',
'src/spl_emit.c',
'src/unk_020A19F0.c',
'src/spl_anim.c',
'src/spl_behavior.c',
'src/spl_list.c',
'src/spl_random.c'

125
lib/spl/src/spl_anim.c Normal file
View File

@ -0,0 +1,125 @@
#include <nitro/fx/fx.h>
#include <nitro/fx/fx_const.h>
#include "spl_random.h"
#include "spl_internal.h"
void SPLAnim_Scale(SPLParticle *ptcl, SPLResource *res, int lifeRate)
{
SPLScaleAnim *scaleAnim = res->scaleAnim;
int in = scaleAnim->curve.in;
int out = scaleAnim->curve.out;
if (lifeRate < in) {
fx16 start = scaleAnim->start;
fx16 mid = scaleAnim->mid;
ptcl->animScale = start + ((lifeRate * (mid - start)) / in);
} else if (lifeRate < out) {
ptcl->animScale = scaleAnim->mid;
} else {
fx16 mid = scaleAnim->mid;
fx16 end = scaleAnim->end;
ptcl->animScale = end + (((lifeRate - 255) * (end - mid)) / (255 - out));
}
}
void SPLAnim_Color(SPLParticle *ptcl, SPLResource *res, int lifeRate)
{
SPLResourceHeader *header = res->header;
SPLColorAnim *colorAnim = res->colorAnim;
int peak = colorAnim->curve.peak;
int out = colorAnim->curve.out;
int in = colorAnim->curve.in;
if (lifeRate < in) {
ptcl->color = colorAnim->start;
} else if (lifeRate < peak) {
int peakR = GX_RGB_R(header->color);
int startR = GX_RGB_R(colorAnim->start);
int peakG = GX_RGB_G(header->color);
int startG = GX_RGB_G(colorAnim->start);
int peakB = GX_RGB_B(header->color);
int startB = GX_RGB_B(colorAnim->start);
if (colorAnim->flags.interpolate) {
int a = lifeRate - in;
int b = peak - in;
ptcl->color = GX_RGB(
startR + (a * (int)(peakR - startR)) / b,
startG + (a * (int)(peakG - startG)) / b,
startB + (a * (int)(peakB - startB)) / b
);
} else {
ptcl->color = GX_RGB(peakR, peakG, peakB);
}
} else if (lifeRate < out) {
int peakR = GX_RGB_R(header->color);
int endR = GX_RGB_R(colorAnim->end);
int peakG = GX_RGB_G(header->color);
int endG = GX_RGB_G(colorAnim->end);
int peakB = GX_RGB_B(header->color);
int endB = GX_RGB_B(colorAnim->end);
if (colorAnim->flags.interpolate) {
int a = lifeRate - peak;
int b = out - peak;
ptcl->color = GX_RGB(
peakR + (a * (int)(endR - peakR)) / b,
peakG + (a * (int)(endG - peakG)) / b,
peakB + (a * (int)(endB - peakB)) / b
);
} else {
ptcl->color = GX_RGB(endR, endG, endB);
}
} else {
ptcl->color = colorAnim->end;
}
}
void SPLAnim_Alpha(SPLParticle *ptcl, SPLResource *res, int lifeRate)
{
u32 value;
SPLAlphaAnim *alphaAnim = res->alphaAnim;
int in = alphaAnim->curve.in;
int out = alphaAnim->curve.out;
if (lifeRate < in) {
value = (lifeRate * (alphaAnim->alpha.mid - alphaAnim->alpha.start)) / in;
value += alphaAnim->alpha.start;
} else if (lifeRate < out) {
value = alphaAnim->alpha.mid;
} else {
value = ((lifeRate - 255) * (alphaAnim->alpha.end - alphaAnim->alpha.mid)) / (255 - out);
value += alphaAnim->alpha.end;
}
ptcl->visibility.animAlpha = SPLRandom_ScaledRangeFX32(value, alphaAnim->flags.randomRange);
}
void SPLAnim_Texture(SPLParticle *ptcl, SPLResource *res, int lifeRate)
{
SPLTexAnim *texAnim = res->texAnim;
for (int i = 0; i < texAnim->param.frameCount; i++) {
if (lifeRate < texAnim->param.step * (i + 1)) {
ptcl->misc.texture = texAnim->textures[i];
return;
}
}
}
void SPLAnim_ChildScale(SPLParticle *ptcl, SPLResource *res, int lifeRate)
{
ptcl->animScale = res->childResource->endScale + ((res->childResource->endScale - FX16_ONE) * (lifeRate - 255)) / 255;
}
void SPLAnim_ChildAlpha(SPLParticle *ptcl, SPLResource *res, int lifeRate)
{
ptcl->visibility.animAlpha = ((255 - lifeRate) * 31) / 255;
}

View File

@ -237,12 +237,12 @@ void SPLEmitter_EmitParticles(SPLEmitter *emtr, SPLParticleList *list)
ptcl->baseScale = SPLRandom_DoubleScaledRangeFX32(emtr->baseScale, header->randomAttenuation.baseScale);
ptcl->animScale = FX32_ONE;
if (header->flags.hasColorAnim && res->colorAnim->unk_08.unk_00_0) {
if (header->flags.hasColorAnim && res->colorAnim->flags.randomStartColor) {
u16 clr[3];
u32 index = SPLRandom_S32(12);
clr[0] = res->colorAnim->startColor;
clr[0] = res->colorAnim->start;
clr[1] = header->color;
clr[2] = res->colorAnim->endColor;
clr[2] = res->colorAnim->end;
ptcl->color = clr[index % 3];
} else {
ptcl->color = header->color;
@ -251,10 +251,10 @@ void SPLEmitter_EmitParticles(SPLEmitter *emtr, SPLParticleList *list)
ptcl->visibility.baseAlpha = emtr->misc.baseAlpha;
ptcl->visibility.animAlpha = 31;
if (header->flags.unk_05_5) {
if (header->flags.randomInitAngle) {
ptcl->rotation = SPLRandom_S32(32);
} else {
ptcl->rotation = emtr->unk_C6;
ptcl->rotation = emtr->initAngle;
}
if (header->flags.hasRotation) {

View File

@ -5,7 +5,6 @@
#include "spl_emitter.h"
#include "spl_internal.h"
#include "spl_list.h"
#include "spl_manager.h"
#include "spl_particle.h"
#include "spl_texture.h"
@ -77,7 +76,7 @@ void SPLEmitter_Init(SPLEmitter *emtr, SPLResource *res, const VecFx32 *pos)
emtr->emissionCountFractional = 0;
emtr->axis = emtr->resource->header->unk_1C;
emtr->unk_C6 = emtr->resource->header->unk_38;
emtr->initAngle = emtr->resource->header->unk_38;
emtr->emissionCount = emtr->resource->header->emissionCount;
emtr->radius = emtr->resource->header->unk_14;
emtr->length = emtr->resource->header->unk_18;
@ -159,24 +158,24 @@ void SPLEmitter_Update(SPLManager *mgr, SPLEmitter *emtr)
}
}
if (resFlags.hasScaleAnim) { // ScaleAnim
animFuncs[animCount].func = sub_020A1DA0;
animFuncs[animCount++].loop = res->scaleAnim->unk_08.unk_00_0;
if (resFlags.hasScaleAnim) {
animFuncs[animCount].func = SPLAnim_Scale;
animFuncs[animCount++].loop = res->scaleAnim->flags.loop;
}
if (resFlags.hasColorAnim && !res->colorAnim->unk_08.unk_00_0) { // ColorAnim
animFuncs[animCount].func = sub_020A1BD4;
animFuncs[animCount++].loop = res->colorAnim->unk_08.unk_00_1;
if (resFlags.hasColorAnim && !res->colorAnim->flags.randomStartColor) {
animFuncs[animCount].func = SPLAnim_Color;
animFuncs[animCount++].loop = res->colorAnim->flags.loop;
}
if (resFlags.hasAlphaAnim) { // AlphaAnim
animFuncs[animCount].func = sub_020A1AF8;
animFuncs[animCount++].loop = res->alphaAnim->unk_02.unk_01_0;
if (resFlags.hasAlphaAnim) {
animFuncs[animCount].func = SPLAnim_Alpha;
animFuncs[animCount++].loop = res->alphaAnim->flags.loop;
}
if (resFlags.hasTexAnim && !res->texAnim->param.randomizeInit) { // TexAnim
animFuncs[animCount].func = sub_020A1A94;
animFuncs[animCount++].loop = res->texAnim->param.unk_02_1;
if (resFlags.hasTexAnim && !res->texAnim->param.randomizeInit) {
animFuncs[animCount].func = SPLAnim_Texture;
animFuncs[animCount++].loop = res->texAnim->param.loop;
}
for (ptcl = emtr->particles.first; ptcl != NULL; ptcl = next) {
@ -252,12 +251,12 @@ void SPLEmitter_Update(SPLManager *mgr, SPLEmitter *emtr)
if (resFlags.hasChildResource) {
animCount = 0;
if (child->flags.hasScaleAnim) {
childAnimFuncs[animCount].func = sub_020A1A48;
childAnimFuncs[animCount].func = SPLAnim_ChildScale;
childAnimFuncs[animCount++].loop = FALSE;
}
if (child->flags.hasAlphaAnim) {
childAnimFuncs[animCount].func = sub_020A19F0;
childAnimFuncs[animCount].func = SPLAnim_ChildAlpha;
childAnimFuncs[animCount++].loop = FALSE;
}

View File

@ -1,133 +0,0 @@
#include <nitro/fx/fx.h>
#include <nitro/fx/fx_const.h>
#include "spl_random.h"
#include "spl_internal.h"
void sub_020A1DA0(SPLParticle *ptcl, SPLResource *res, int lifeRate)
{
SPLScaleAnim *scaleAnim;
int in, out;
fx16 start, n, end;
scaleAnim = res->scaleAnim;
in = scaleAnim->unk_06.val2_00;
out = scaleAnim->unk_06.val2_01;
if (lifeRate < in) {
start = scaleAnim->unk_00;
n = scaleAnim->unk_02;
ptcl->animScale = start + ((lifeRate * (n - start)) / in);
} else if (lifeRate >= out) {
end = scaleAnim->unk_04;
n = scaleAnim->unk_02;
ptcl->animScale = end + (((lifeRate - 255) * (end - n)) / (255 - out));
} else {
ptcl->animScale = scaleAnim->unk_02;
}
}
void sub_020A1BD4(SPLParticle *ptcl, SPLResource *res, int lifeRate)
{
SPLResourceHeader *resBase;
SPLColorAnim *colorAnim;
int in, peak, out;
colorAnim = res->colorAnim;
resBase = res->header;
peak = colorAnim->unk_04.unk_05_0;
out = colorAnim->unk_04.unk_06_0;
in = colorAnim->unk_04.unk_04_0;
if (lifeRate < in) {
ptcl->color = colorAnim->startColor;
} else if (lifeRate < peak) {
int peakR = GX_RGB_R(resBase->color);
int startR = GX_RGB_R(colorAnim->startColor);
int peakG = GX_RGB_G(resBase->color);
int startG = GX_RGB_G(colorAnim->startColor);
int peakB = GX_RGB_B(resBase->color);
int startB = GX_RGB_B(colorAnim->startColor);
if (colorAnim->unk_08.unk_00_2) { // interpolate
int a = lifeRate - in;
int b = peak - in;
ptcl->color = GX_RGB(
startR + (a * (int)(peakR - startR)) / b,
startG + (a * (int)(peakG - startG)) / b,
startB + (a * (int)(peakB - startB)) / b
);
} else {
ptcl->color = GX_RGB(peakR, peakG, peakB);
}
} else if (lifeRate < out) {
int peakR = GX_RGB_R(resBase->color);
int endR = GX_RGB_R(colorAnim->endColor);
int peakG = GX_RGB_G(resBase->color);
int endG = GX_RGB_G(colorAnim->endColor);
int peakB = GX_RGB_B(resBase->color);
int endB = GX_RGB_B(colorAnim->endColor);
if (colorAnim->unk_08.unk_00_2) { // interpolate
int a = lifeRate - peak;
int b = out - peak;
ptcl->color = GX_RGB(
peakR + (a * (int)(endR - peakR)) / b,
peakG + (a * (int)(endG - peakG)) / b,
peakB + (a * (int)(endB - peakB)) / b
);
} else {
ptcl->color = GX_RGB(endR, endG, endB);
}
} else {
ptcl->color = colorAnim->endColor;
}
}
void sub_020A1AF8(SPLParticle *ptcl, SPLResource *res, int lifeRate)
{
u32 x;
SPLAlphaAnim *alphaAnim = res->alphaAnim;
int maxA = alphaAnim->unk_04.val2_00;
int maxB = alphaAnim->unk_04.val2_01;
if (lifeRate < maxA) {
x = ((lifeRate * (alphaAnim->unk_00.val2_00_5 - alphaAnim->unk_00.val2_00_0)) / alphaAnim->unk_04.val2_00);
x += alphaAnim->unk_00.val2_00_0;
} else if (lifeRate < maxB) {
x = alphaAnim->unk_00.val2_00_5;
} else {
x = ((lifeRate - 255) * (alphaAnim->unk_00.val2_01_2 - alphaAnim->unk_00.val2_00_5)) / (255 - alphaAnim->unk_04.val2_01);
x += alphaAnim->unk_00.val2_01_2;
}
ptcl->visibility.animAlpha = SPLRandom_ScaledRangeFX32(x, alphaAnim->unk_02.unk_00_0);
}
void sub_020A1A94(SPLParticle *ptcl, SPLResource *res, int lifeRate)
{
SPLTexAnim *texAnim = res->texAnim;
for (int i = 0; i < texAnim->param.frameCount; i++) {
if (lifeRate < texAnim->param.unk_01_0 * (i + 1)) {
ptcl->misc.texture = texAnim->textures[i];
return;
}
}
}
void sub_020A1A48(SPLParticle *ptcl, SPLResource *res, int lifeRate)
{
ptcl->animScale = res->childResource->unk_04 + ((res->childResource->unk_04 - FX16_ONE) * (lifeRate - 255)) / 255;
}
void sub_020A19F0(SPLParticle *ptcl, SPLResource *res, int lifeRate)
{
ptcl->visibility.animAlpha = ((255 - lifeRate) * 31) / 255;
}