diff --git a/lib/spl/include/spl_emitter.h b/lib/spl/include/spl_emitter.h index cf31c5eaa..c4e1d6317 100644 --- a/lib/spl/include/spl_emitter.h +++ b/lib/spl/include/spl_emitter.h @@ -39,17 +39,17 @@ typedef struct SPLEmitter { UnkSPLStruct7 state; VecFx32 position; VecFx32 velocity; - VecFx32 unk_B0; + VecFx32 particleInitVelocity; u16 age; - fx16 unk_BE; + fx16 emissionCountFractional; // fractional part of the number of particles to emit (doesn't seem to be used) VecFx16 axis; u16 unk_C6; - fx32 unk_C8; - fx32 unk_CC; + fx32 emissionCount; + fx32 radius; fx32 length; - fx32 unk_D4; - fx32 unk_D8; - fx32 unk_DC; + fx32 initVelPositionAmplifier; // amplifies the initial velocity of the particles based on their position + fx32 initVelAxisAmplifier; // amplifies the initial velocity of the particles based on the emitter's axis + fx32 baseScale; // base scale of the particles u16 particleLifeTime; GXRgb color; fx32 collisionPlaneHeight; @@ -59,12 +59,12 @@ typedef struct SPLEmitter { fx16 unk_EE; struct { u32 emissionInterval : 8; // number of frames between particle emissions - u32 unk_01_0 : 8; + u32 baseAlpha : 8; u32 updateCycle : 3; // 0 = every frame, 1 = cycle A, 2 = cycle B, cycles A and B alternate u32 unk_02_3 : 13; } misc; - VecFx16 unk_F4; - VecFx16 unk_FA; + VecFx16 crossAxis1; + VecFx16 crossAxis2; SPLEmitterUpdateCallback updateCallback; void * unk_104; union { diff --git a/lib/spl/include/spl_internal.h b/lib/spl/include/spl_internal.h index 4c3ed9ae9..f41962ba1 100644 --- a/lib/spl/include/spl_internal.h +++ b/lib/spl/include/spl_internal.h @@ -36,13 +36,13 @@ void sub_020A1A94(SPLParticle *ptcl, SPLResource *res, int lifeRate); // spl_tex 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 sub_020A08DC(SPLEmitter *emtr, SPLList *list); +void SPLEmitter_EmitParticles(SPLEmitter *emtr, SPLParticleList *list); void sub_020A05BC(SPLParticle *ptcl, SPLEmitter *emtr, SPLList *list); void SPLEmitter_Update(SPLManager *mgr, SPLEmitter *emtr); void SPLManager_DoDraw(SPLManager *mgr); void SPLEmitter_Init(SPLEmitter *emtr, SPLResource *res, const VecFx32 *pos); -void SPLEmitter_Emit(SPLEmitter *emtr, SPLList *list); +void SPLEmitter_Emit(SPLEmitter *emtr, SPLParticleList *list); static inline void SPLParticleList_PushFront(SPLParticleList *list, SPLParticle *ptcl) { diff --git a/lib/spl/include/spl_particle.h b/lib/spl/include/spl_particle.h index a478f8ff6..115e0297c 100644 --- a/lib/spl/include/spl_particle.h +++ b/lib/spl/include/spl_particle.h @@ -8,7 +8,7 @@ typedef struct SPLParticle { struct SPLParticle *next; struct SPLParticle *prev; - VecFx32 position; + VecFx32 position; // position of the particle, relative to the emitter VecFx32 velocity; u16 rotation; s16 angularVelocity; @@ -22,7 +22,7 @@ typedef struct SPLParticle { u16 lifeTimeFactor; struct { - u16 unk_00 : 8; + u16 texture : 8; // Index of the current texture in the resource // A value between 0 and 255 that is added to the life rate of the particle. // This is used only for looping particles, so particles spawned at the same time @@ -30,13 +30,13 @@ typedef struct SPLParticle { u16 lifeRateOffset : 8; } misc; struct { - u16 unk_00_0 : 5; - u16 unk_00_5 : 5; + u16 baseAlpha : 5; + u16 animAlpha : 5; u16 currentPolygonID : 6; - } unk_2E; - fx32 unk_30; + } visibility; + fx32 baseScale; fx16 unk_34; - GXRgb unk_36; + GXRgb color; VecFx32 emitterPos; } SPLParticle; // size=0x44 diff --git a/lib/spl/include/spl_resource.h b/lib/spl/include/spl_resource.h index db4013f76..0cb2f2f48 100644 --- a/lib/spl/include/spl_resource.h +++ b/lib/spl/include/spl_resource.h @@ -5,6 +5,27 @@ #include "struct_defs/struct_020147B8.h" +#define SPL_TEX_ANIM_MAX_FRAMES 8 + +enum SPLCircleAxis { + SPL_CIRCLE_AXIS_Z = 0, + SPL_CIRCLE_AXIS_Y = 1, + SPL_CIRCLE_AXIS_X = 2, + SPL_CIRCLE_AXIS_EMITTER = 3, // The emitter's axis +}; + +enum SPLEmissionType { + SPL_EMISSION_TYPE_POINT = 0, // A single point + SPL_EMISSION_TYPE_SPHERE_SURFACE, // Any point on the surface of a sphere + SPL_EMISSION_TYPE_CIRCLE_BORDER, // Any point on a circle around an axis (specified by flags) + SPL_EMISSION_TYPE_CIRCLE_BORDER_UNIFORM, // Uniform distribution of points on a circle around an axis (specified by flags) + SPL_EMISSION_TYPE_SPHERE, // Any point inside a sphere + SPL_EMISSION_TYPE_CIRCLE, // Any point inside a circle around an axis (specified by flags) + SPL_EMISSION_TYPE_CYLINDER_SURFACE, // Any point on the surface of a cylinder + SPL_EMISSION_TYPE_CYLINDER, // Any point inside a cylinder + SPL_EMISSION_TYPE_HEMISPHERE_SURFACE, // Any point on the surface of a hemisphere (direction specified by flags) + SPL_EMISSION_TYPE_HEMISPHERE, // Any point inside a hemisphere (direction specified by flags) +}; typedef struct SPLArcHdr { u32 magic; @@ -21,14 +42,14 @@ typedef struct SPLArcHdr { typedef union SPLResourceFlags { u32 all; struct { - u32 unk_04_0 : 4; + u32 emissionType : 4; // Maps to SPLEmissionType u32 drawType : 2; - u32 unk_04_6 : 2; + u32 circleAxis : 2; // Maps to SPLCircleAxis u32 hasScaleAnim : 1; u32 hasColorAnim : 1; u32 hasAlphaAnim : 1; u32 hasTexAnim : 1; - u32 unk_05_4 : 1; + u32 hasRotation : 1; u32 unk_05_5 : 1; // Whether the emitter manages itself or not. // If set, the emitter will automatically terminate when it reaches the end of its life @@ -38,7 +59,7 @@ typedef union SPLResourceFlags { u32 hasChildResource : 1; u32 unk_06_1 : 2; u32 unk_06_3 : 1; - u32 unk_06_4 : 1; + u32 randomizeLoopedAnim : 1; u32 drawChildrenFirst : 1; // If set, child particles will be rendered before parent particles u32 hideParent : 1; // If set, only child particles will be rendered u32 unk_06_7 : 1; @@ -90,35 +111,39 @@ typedef union { typedef struct SPLResourceHeader { SPLResourceFlags flags; VecFx32 emitterBasePos; - fx32 unk_10; + fx32 emissionCount; // Number of particles to emit per emission interval fx32 unk_14; fx32 unk_18; VecFx16 unk_1C; - GXRgb unk_22; + GXRgb color; fx32 unk_24; fx32 unk_28; fx32 unk_2C; fx16 unk_30; u16 startDelay; // Delay, in frames, before the emitter starts emitting particles - s16 unk_34; - s16 unk_36; + s16 minRotation; + s16 maxRotation; u16 unk_38; u16 reserved_3A; u16 emitterLifeTime; u16 particleLifeTime; + + // All of these values are mapped to the range [0, 1] + // They are used to attenuate the particle's properties at initialization, + // acting as a sort of randomization factor which scales down the initial values struct { - u32 unk_00_0 : 8; - u32 unk_01_0 : 8; - u32 unk_02_0 : 8; - u32 reserved_03_0 : 8; - } unk_44; + u32 baseScale : 8; // Damping factor for the base scale of the particles (0 = no damping) + u32 lifeTime : 8; + u32 initVel : 8; // Attenuation factor for the initial velocity of the particles (0 = no attenuation) + u32 : 8; + } randomAttenuation; struct { u32 unk_00_0 : 8; u32 unk_01_0 : 8; u32 airResistance : 8; u32 textureIndex : 8; - u32 unk_04_0 : 8; + u32 loopFrames : 8; u32 unk_05_0 : 16; u32 unk_07_0 : 2; u32 unk_07_2 : 2; @@ -150,8 +175,8 @@ typedef struct SPLScaleAnim { } SPLScaleAnim; // size=0xc typedef struct SPLColorAnim { - GXRgb unk_00; - GXRgb unk_02; + GXRgb startColor; + GXRgb endColor; UnkSPLUnion4 unk_04; struct { u16 unk_00_0 : 1; @@ -182,14 +207,14 @@ typedef struct SPLAlphaAnim { } SPLAlphaAnim; // size=0x8 typedef struct SPLTexAnim { - u8 unk_00[8]; + u8 textures[SPL_TEX_ANIM_MAX_FRAMES]; struct { - u32 unk_00_0 : 8; + u32 frameCount : 8; u32 unk_01_0 : 8; - u32 unk_02_0 : 1; + u32 randomizeInit : 1; // Randomize the initial texture frame u32 unk_02_1 : 1; u32 reserved_02_2 : 14; - } unk_08; + } param; } SPLTexAnim; typedef struct SPLChildResource { diff --git a/lib/spl/src/spl_emitter.c b/lib/spl/src/spl_emitter.c index 93948383f..aa8956468 100644 --- a/lib/spl/src/spl_emitter.c +++ b/lib/spl/src/spl_emitter.c @@ -68,27 +68,27 @@ void SPLEmitter_Init(SPLEmitter *emtr, SPLResource *res, const VecFx32 *pos) emtr->position.y = pos->y + emtr->resource->header->emitterBasePos.y; emtr->position.z = pos->z + emtr->resource->header->emitterBasePos.z; - emtr->unk_B0.x = 0; - emtr->unk_B0.y = 0; - emtr->unk_B0.z = 0; + emtr->particleInitVelocity.x = 0; + emtr->particleInitVelocity.y = 0; + emtr->particleInitVelocity.z = 0; emtr->velocity.x = emtr->velocity.y = emtr->velocity.z = 0; emtr->age = 0; - emtr->unk_BE = 0; + emtr->emissionCountFractional = 0; emtr->axis = emtr->resource->header->unk_1C; emtr->unk_C6 = emtr->resource->header->unk_38; - emtr->unk_C8 = emtr->resource->header->unk_10; - emtr->unk_CC = emtr->resource->header->unk_14; + emtr->emissionCount = emtr->resource->header->emissionCount; + emtr->radius = emtr->resource->header->unk_14; emtr->length = emtr->resource->header->unk_18; - emtr->unk_D4 = emtr->resource->header->unk_24; - emtr->unk_D8 = emtr->resource->header->unk_28; - emtr->unk_DC = emtr->resource->header->unk_2C; + emtr->initVelPositionAmplifier = emtr->resource->header->unk_24; + emtr->initVelAxisAmplifier = emtr->resource->header->unk_28; + emtr->baseScale = emtr->resource->header->unk_2C; emtr->particleLifeTime = emtr->resource->header->particleLifeTime; emtr->color = GX_RGB(31, 31, 31); emtr->misc.emissionInterval = emtr->resource->header->misc.unk_00_0; - emtr->misc.unk_01_0 = emtr->resource->header->misc.unk_01_0; + emtr->misc.baseAlpha = emtr->resource->header->misc.unk_01_0; emtr->misc.updateCycle = 0; emtr->misc.unk_02_3 = 0; emtr->collisionPlaneHeight = FX32_MIN; @@ -154,7 +154,7 @@ void SPLEmitter_Update(SPLManager *mgr, SPLEmitter *emtr) if (header->emitterLifeTime == 0 || emtr->age < header->emitterLifeTime) { if (emtr->age % emtr->misc.emissionInterval == 0) { if (!emtr->state.terminate && !emtr->state.emissionPaused && emtr->state.started) { - sub_020A08DC(emtr, (SPLList *)(&mgr->inactiveParticles)); + SPLEmitter_EmitParticles(emtr, &mgr->inactiveParticles); } } } @@ -174,9 +174,9 @@ void SPLEmitter_Update(SPLManager *mgr, SPLEmitter *emtr) animFuncs[animCount++].loop = res->alphaAnim->unk_02.unk_01_0; } - if (resFlags.hasTexAnim && !res->texAnim->unk_08.unk_02_0) { // TexAnim + if (resFlags.hasTexAnim && !res->texAnim->param.randomizeInit) { // TexAnim animFuncs[animCount].func = sub_020A1A94; - animFuncs[animCount++].loop = res->texAnim->unk_08.unk_02_1; + animFuncs[animCount++].loop = res->texAnim->param.unk_02_1; } for (ptcl = emtr->particles.first; ptcl != NULL; ptcl = next) { @@ -231,9 +231,9 @@ void SPLEmitter_Update(SPLManager *mgr, SPLEmitter *emtr) } if (emtr->resource->header->flags.hasFixedPolygonID) { - ptcl->unk_2E.currentPolygonID = mgr->polygonID.fix; + ptcl->visibility.currentPolygonID = mgr->polygonID.fix; } else { - ptcl->unk_2E.currentPolygonID = mgr->polygonID.current; + ptcl->visibility.currentPolygonID = mgr->polygonID.current; mgr->polygonID.current += 1; if (mgr->polygonID.current > mgr->polygonID.max) { @@ -300,9 +300,9 @@ void SPLEmitter_Update(SPLManager *mgr, SPLEmitter *emtr) ptcl->position.z += ptcl->velocity.z + emtr->velocity.z; if (emtr->resource->header->flags.childHasFixedPolygonID) { - ptcl->unk_2E.currentPolygonID = mgr->polygonID.fix; + ptcl->visibility.currentPolygonID = mgr->polygonID.fix; } else { - ptcl->unk_2E.currentPolygonID = mgr->polygonID.current; + ptcl->visibility.currentPolygonID = mgr->polygonID.current; mgr->polygonID.current += 1; if (mgr->polygonID.current > mgr->polygonID.max) { @@ -355,7 +355,7 @@ static void SPLManager_DrawParticles(SPLManager *mgr) SetTexFunc setTexFunc = header->flags.hasTexAnim ? SPLUtil_SetTexture : SPLUtil_SetTexture_Stub; for (SPLParticle *ptcl = emtr->particles.first; ptcl != NULL; ptcl = ptcl->next) { - setTexFunc(mgr->textures + ptcl->misc.unk_00); + setTexFunc(mgr->textures + ptcl->misc.texture); drawFunc(mgr, ptcl); } } @@ -414,16 +414,16 @@ void SPLManager_DoDraw(SPLManager *mgr) } } -void SPLEmitter_Emit(SPLEmitter *emtr, SPLList *list) +void SPLEmitter_Emit(SPLEmitter *emtr, SPLParticleList *list) { - sub_020A08DC(emtr, list); + SPLEmitter_EmitParticles(emtr, list); } void SPLUtil_SetCylinderEmitterDir(SPLEmitter *emtr, VecFx32 *p1, VecFx32 *p2) { VecFx32 vex; - if (emtr->resource->header->flags.unk_04_0 == 6 || emtr->resource->header->flags.unk_04_0 == 7) { + if (emtr->resource->header->flags.emissionType == 6 || emtr->resource->header->flags.emissionType == 7) { emtr->position.x = (p2->x + p1->x) / 2; emtr->position.y = (p2->y + p1->y) / 2; emtr->position.z = (p2->z + p1->z) / 2; diff --git a/lib/spl/src/spl_manager.c b/lib/spl/src/spl_manager.c index ad9e5be50..837868563 100644 --- a/lib/spl/src/spl_manager.c +++ b/lib/spl/src/spl_manager.c @@ -426,7 +426,7 @@ void SPLManager_DeleteAllEmitters(SPLManager *mgr) void SPL_Emit(SPLManager *mgr, SPLEmitter *emtr) { - SPLEmitter_Emit(emtr, (SPLList *)&mgr->inactiveParticles); + SPLEmitter_Emit(emtr, &mgr->inactiveParticles); } void SPL_EmitAt(SPLManager *mgr, SPLEmitter *emtr, VecFx32 *pos) @@ -434,5 +434,5 @@ void SPL_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, (SPLList *)&mgr->inactiveParticles); + SPLEmitter_Emit(emtr, &mgr->inactiveParticles); } diff --git a/lib/spl/src/unk_0209DD54.c b/lib/spl/src/unk_0209DD54.c index fb923e835..d9ec08a03 100644 --- a/lib/spl/src/unk_0209DD54.c +++ b/lib/spl/src/unk_0209DD54.c @@ -135,18 +135,18 @@ void sub_0209FF0C(SPLManager *mgr, SPLParticle *ptcl) aspect = mgr->renderState.emitter->resource->header->unk_30; animScale = ptcl->unk_34; - ptclCol = ptcl->unk_36; + ptclCol = ptcl->color; emtrCol = emtr->color; scaleAnimDirect = resBase->misc.unk_07_4; - fx32 alpha = ptcl->unk_2E.unk_00_0 * (ptcl->unk_2E.unk_00_5 + 1) >> 5; + fx32 alpha = ptcl->visibility.baseAlpha * (ptcl->visibility.animAlpha + 1) >> 5; G3_PolygonAttr( GX_LIGHTMASK_NONE, GX_POLYGONMODE_MODULATE, GX_CULL_NONE, - ptcl->unk_2E.currentPolygonID, + ptcl->visibility.currentPolygonID, alpha, mgr->unk_3C); @@ -156,7 +156,7 @@ void sub_0209FF0C(SPLManager *mgr, SPLParticle *ptcl) return; } - sclY = ptcl->unk_30; + sclY = ptcl->baseScale; sclX = FX_MUL(sclY, aspect); if (scaleAnimDirect == 0) { @@ -240,13 +240,13 @@ void sub_0209FAB8(SPLManager *mgr, SPLParticle *ptcl) cmr = mgr->renderState.viewMatrix; aspect = mgr->renderState.emitter->resource->header->unk_30; - fx32 alpha = (fx32)(ptcl->unk_2E.unk_00_0 * (ptcl->unk_2E.unk_00_5 + 1)) >> 5; + fx32 alpha = (fx32)(ptcl->visibility.baseAlpha * (ptcl->visibility.animAlpha + 1)) >> 5; G3_PolygonAttr( GX_LIGHTMASK_NONE, GX_POLYGONMODE_MODULATE, GX_CULL_NONE, - ptcl->unk_2E.currentPolygonID, + ptcl->visibility.currentPolygonID, alpha, mgr->unk_3C); @@ -256,7 +256,7 @@ void sub_0209FAB8(SPLManager *mgr, SPLParticle *ptcl) return; } - sclY = ptcl->unk_30; + sclY = ptcl->baseScale; sclX = FX_MUL(sclY, aspect); switch (mgr->renderState.emitter->resource->header->misc.unk_07_4) { @@ -325,7 +325,7 @@ void sub_0209FAB8(SPLManager *mgr, SPLParticle *ptcl) G3_MultMtx43(&load); } - GXRgb colA = ptcl->unk_36; + GXRgb colA = ptcl->color; GXRgb colB = mgr->renderState.emitter->color; G3_Color(GX_RGB( GX_RGB_R_(colA) * GX_RGB_R_(colB) >> 5, @@ -351,13 +351,13 @@ void sub_0209F3D0(SPLManager *mgr, SPLParticle *ptcl) cmr = mgr->renderState.viewMatrix; aspect = mgr->renderState.emitter->resource->header->unk_30; - fx32 alpha = (fx32)(ptcl->unk_2E.unk_00_0 * (ptcl->unk_2E.unk_00_5 + 1)) >> 5; + fx32 alpha = (fx32)(ptcl->visibility.baseAlpha * (ptcl->visibility.animAlpha + 1)) >> 5; G3_PolygonAttr( GX_LIGHTMASK_NONE, GX_POLYGONMODE_MODULATE, GX_CULL_NONE, - ptcl->unk_2E.currentPolygonID, + ptcl->visibility.currentPolygonID, alpha, mgr->unk_3C); @@ -367,7 +367,7 @@ void sub_0209F3D0(SPLManager *mgr, SPLParticle *ptcl) return; } - sclY = ptcl->unk_30; + sclY = ptcl->baseScale; sclX = FX_MUL(sclY, aspect); switch (mgr->renderState.emitter->resource->header->misc.unk_07_4) { @@ -480,7 +480,7 @@ void sub_0209F3D0(SPLManager *mgr, SPLParticle *ptcl) G3_MultMtx43(&load); } - GXRgb colA = ptcl->unk_36; + GXRgb colA = ptcl->color; GXRgb colB = mgr->renderState.emitter->color; G3_Color(GX_RGB( GX_RGB_R_(colA) * GX_RGB_R_(colB) >> 5, @@ -506,13 +506,13 @@ void sub_0209ECF0(SPLManager *mgr, SPLParticle *ptcl) cmr = mgr->renderState.viewMatrix; aspect = mgr->renderState.emitter->resource->header->unk_30; - fx32 alpha = (fx32)(ptcl->unk_2E.unk_00_0 * (ptcl->unk_2E.unk_00_5 + 1)) >> 5; + fx32 alpha = (fx32)(ptcl->visibility.baseAlpha * (ptcl->visibility.animAlpha + 1)) >> 5; G3_PolygonAttr( GX_LIGHTMASK_NONE, GX_POLYGONMODE_MODULATE, GX_CULL_NONE, - ptcl->unk_2E.currentPolygonID, + ptcl->visibility.currentPolygonID, alpha, mgr->unk_3C); @@ -522,7 +522,7 @@ void sub_0209ECF0(SPLManager *mgr, SPLParticle *ptcl) return; } - sclY = ptcl->unk_30; + sclY = ptcl->baseScale; sclX = FX_MUL(sclY, aspect); switch (mgr->renderState.emitter->resource->header->misc.unk_07_4) { @@ -635,7 +635,7 @@ void sub_0209ECF0(SPLManager *mgr, SPLParticle *ptcl) G3_MultMtx43(&load); } - GXRgb colA = ptcl->unk_36; + GXRgb colA = ptcl->color; GXRgb colB = mgr->renderState.emitter->color; G3_Color(GX_RGB( GX_RGB_R_(colA) * GX_RGB_R_(colB) >> 5, @@ -656,13 +656,13 @@ void sub_0209E9A0(SPLManager *mgr, SPLParticle *ptcl) fx32 alpha; SPLResourceHeader *resBase; - alpha = (fx32)(ptcl->unk_2E.unk_00_0 * (ptcl->unk_2E.unk_00_5 + 1)) >> 5; + alpha = (fx32)(ptcl->visibility.baseAlpha * (ptcl->visibility.animAlpha + 1)) >> 5; G3_PolygonAttr( GX_LIGHTMASK_NONE, GX_POLYGONMODE_MODULATE, GX_CULL_NONE, - ptcl->unk_2E.currentPolygonID, + ptcl->visibility.currentPolygonID, alpha, mgr->unk_3C); @@ -674,7 +674,7 @@ void sub_0209E9A0(SPLManager *mgr, SPLParticle *ptcl) Unk_02100DA8[mgr->renderState.emitter->resource->header->flags.unk_06_1](FX_SinIdx(ptcl->rotation), FX_CosIdx(ptcl->rotation), &rotMtx); - sclY = ptcl->unk_30; + sclY = ptcl->baseScale; resBase = mgr->renderState.emitter->resource->header; sclX = FX_MUL(sclY, resBase->unk_30); @@ -717,7 +717,7 @@ void sub_0209E9A0(SPLManager *mgr, SPLParticle *ptcl) G3_MultMtx43(&load); } - GXRgb colA = ptcl->unk_36; + GXRgb colA = ptcl->color; GXRgb colB = mgr->renderState.emitter->color; G3_Color(GX_RGB( GX_RGB_R_(colA) * GX_RGB_R_(colB) >> 5, @@ -739,13 +739,13 @@ void sub_0209E650(SPLManager *mgr, SPLParticle *ptcl) fx32 alpha; SPLResourceHeader *resBase; - alpha = ptcl->unk_2E.unk_00_0 * (ptcl->unk_2E.unk_00_5 + 1) >> 5; + alpha = ptcl->visibility.baseAlpha * (ptcl->visibility.animAlpha + 1) >> 5; G3_PolygonAttr( GX_LIGHTMASK_NONE, GX_POLYGONMODE_MODULATE, GX_CULL_NONE, - ptcl->unk_2E.currentPolygonID, + ptcl->visibility.currentPolygonID, alpha, mgr->unk_3C); @@ -757,7 +757,7 @@ void sub_0209E650(SPLManager *mgr, SPLParticle *ptcl) Unk_02100DA8[mgr->renderState.emitter->resource->childResource->flags.unk_03_1](FX_SinIdx(ptcl->rotation), FX_CosIdx(ptcl->rotation), &rotMtx); - sclY = ptcl->unk_30; + sclY = ptcl->baseScale; resBase = mgr->renderState.emitter->resource->header; sclX = FX_MUL(sclY, resBase->unk_30); @@ -798,7 +798,7 @@ void sub_0209E650(SPLManager *mgr, SPLParticle *ptcl) G3_MultMtx43(&load); } - GXRgb colA = ptcl->unk_36; + GXRgb colA = ptcl->color; GXRgb colB = mgr->renderState.emitter->color; G3_Color(GX_RGB( GX_RGB_R_(colA) * GX_RGB_R_(colB) >> 5, @@ -821,13 +821,13 @@ void sub_0209E1D4(SPLManager *mgr, SPLParticle *ptcl) SPLEmitter *emtr; GXRgb colA, colB; - alpha = ptcl->unk_2E.unk_00_0 * (ptcl->unk_2E.unk_00_5 + 1) >> 5; + alpha = ptcl->visibility.baseAlpha * (ptcl->visibility.animAlpha + 1) >> 5; G3_PolygonAttr( GX_LIGHTMASK_NONE, GX_POLYGONMODE_MODULATE, GX_CULL_NONE, - ptcl->unk_2E.currentPolygonID, + ptcl->visibility.currentPolygonID, alpha, mgr->unk_3C); @@ -876,7 +876,7 @@ void sub_0209E1D4(SPLManager *mgr, SPLParticle *ptcl) MTX_Concat43(&rotMat, &mat, &rotMat); resBase = mgr->renderState.emitter->resource->header; - scaleY = ptcl->unk_30; + scaleY = ptcl->baseScale; scaleX = FX_MUL(scaleY, resBase->unk_30); switch (resBase->misc.unk_07_4) { @@ -917,7 +917,7 @@ void sub_0209E1D4(SPLManager *mgr, SPLParticle *ptcl) G3_MultMtx43(&transform); } - colA = ptcl->unk_36; + colA = ptcl->color; colB = mgr->renderState.emitter->color; G3_Color(GX_RGB( GX_RGB_R_(colA) * GX_RGB_R_(colB) >> 5, @@ -939,13 +939,13 @@ void sub_0209DD54(SPLManager *mgr, SPLParticle *ptcl) fx32 dot, scaleX, scaleY, scaleZ, alpha, tmp; SPLResourceHeader *resBase; - alpha = ptcl->unk_2E.unk_00_0 * (ptcl->unk_2E.unk_00_5 + 1) >> 5; + alpha = ptcl->visibility.baseAlpha * (ptcl->visibility.animAlpha + 1) >> 5; G3_PolygonAttr( GX_LIGHTMASK_NONE, GX_POLYGONMODE_MODULATE, GX_CULL_NONE, - ptcl->unk_2E.currentPolygonID, + ptcl->visibility.currentPolygonID, alpha, mgr->unk_3C); @@ -994,7 +994,7 @@ void sub_0209DD54(SPLManager *mgr, SPLParticle *ptcl) MTX_Concat43(&rotMtx, &mat, &rotMtx); resBase = mgr->renderState.emitter->resource->header; - scaleY = ptcl->unk_30; + scaleY = ptcl->baseScale; scaleX = FX_MUL(scaleY, resBase->unk_30); switch (resBase->misc.unk_07_4) { @@ -1035,7 +1035,7 @@ void sub_0209DD54(SPLManager *mgr, SPLParticle *ptcl) G3_MultMtx43(&transform); } - GXRgb colA = ptcl->unk_36; + GXRgb colA = ptcl->color; GXRgb colB = mgr->renderState.emitter->color; G3_Color(GX_RGB( GX_RGB_R_(colA) * GX_RGB_R_(colB) >> 5, diff --git a/lib/spl/src/unk_020A05BC.c b/lib/spl/src/unk_020A05BC.c index 53c36611f..896c91c69 100644 --- a/lib/spl/src/unk_020A05BC.c +++ b/lib/spl/src/unk_020A05BC.c @@ -1,44 +1,45 @@ +#include "nitro/types.h" #include #include #include #include "spl_emitter.h" +#include "spl_internal.h" #include "spl_list.h" +#include "spl_particle.h" #include "spl_random.h" +#include "spl_resource.h" -#define IS_IN_RANGE(x, min, max) (((x) - (min)) <= ((max) - (min))) +static void SPLEmitter_ComputeOrthogonalAxes(SPLEmitter *emtr); +static void SPLUtil_TiltCoordinates(VecFx32 *ptclPos, VecFx32 *pos, SPLEmitter *emtr); + +static VecFx16 sUpVector = { 0, FX16_ONE, 0 }; -static void sub_020A1768(SPLEmitter *emtr); -static void sub_020A1608(VecFx32 *ptclPos, VecFx32 *pos, SPLEmitter *emtr); - -VecFx16 Unk_02100DB0 = { 0, FX16_ONE, 0 }; - - -static void sub_020A1768(SPLEmitter *emtr) +static void SPLEmitter_ComputeOrthogonalAxes(SPLEmitter *emtr) { VecFx16 vec, axis; - vec = Unk_02100DB0; + vec = sUpVector; - switch (emtr->resource->header->flags.unk_04_6) { - case 2: + switch (emtr->resource->header->flags.circleAxis) { + case SPL_CIRCLE_AXIS_X: axis.x = FX32_ONE; axis.y = 0; axis.z = 0; break; - case 1: + case SPL_CIRCLE_AXIS_Y: axis.x = 0; axis.y = FX32_ONE; axis.z = 0; break; - case 0: + case SPL_CIRCLE_AXIS_Z: axis.x = 0; axis.y = 0; axis.z = FX32_ONE; break; - default: + default: // SPL_CIRCLE_AXIS_EMITTER VEC_Fx16Normalize(&emtr->axis, &axis); break; } @@ -50,240 +51,237 @@ static void sub_020A1768(SPLEmitter *emtr) vec.z = 0; } - emtr->unk_F4.x = FX_MUL(axis.y, vec.z) - FX_MUL(axis.z, vec.y); - emtr->unk_F4.y = FX_MUL(axis.z, vec.x) - FX_MUL(axis.x, vec.z); - emtr->unk_F4.z = FX_MUL(axis.x, vec.y) - FX_MUL(axis.y, vec.x); + emtr->crossAxis1.x = FX_MUL(axis.y, vec.z) - FX_MUL(axis.z, vec.y); + emtr->crossAxis1.y = FX_MUL(axis.z, vec.x) - FX_MUL(axis.x, vec.z); + emtr->crossAxis1.z = FX_MUL(axis.x, vec.y) - FX_MUL(axis.y, vec.x); - emtr->unk_FA.x = FX_MUL(axis.y, emtr->unk_F4.z) - FX_MUL(axis.z, emtr->unk_F4.y); - emtr->unk_FA.y = FX_MUL(axis.z, emtr->unk_F4.x) - FX_MUL(axis.x, emtr->unk_F4.z); - emtr->unk_FA.z = FX_MUL(axis.x, emtr->unk_F4.y) - FX_MUL(axis.y, emtr->unk_F4.x); + emtr->crossAxis2.x = FX_MUL(axis.y, emtr->crossAxis1.z) - FX_MUL(axis.z, emtr->crossAxis1.y); + emtr->crossAxis2.y = FX_MUL(axis.z, emtr->crossAxis1.x) - FX_MUL(axis.x, emtr->crossAxis1.z); + emtr->crossAxis2.z = FX_MUL(axis.x, emtr->crossAxis1.y) - FX_MUL(axis.y, emtr->crossAxis1.x); - VEC_Fx16Normalize(&emtr->unk_F4, &emtr->unk_F4); - VEC_Fx16Normalize(&emtr->unk_FA, &emtr->unk_FA); + VEC_Fx16Normalize(&emtr->crossAxis1, &emtr->crossAxis1); + VEC_Fx16Normalize(&emtr->crossAxis2, &emtr->crossAxis2); } -static void sub_020A1608(VecFx32 *ptclPos, VecFx32 *pos, SPLEmitter *emtr) +// Tilt the coordinates of a particle based on the emitter's axis +static void SPLUtil_TiltCoordinates(VecFx32 *ptclPos, VecFx32 *pos, SPLEmitter *emtr) { VecFx16 vec; - VEC_Fx16CrossProduct(&emtr->unk_F4, &emtr->unk_FA, &vec); + VEC_Fx16CrossProduct(&emtr->crossAxis1, &emtr->crossAxis2, &vec); VEC_Fx16Normalize(&vec, &vec); - ptclPos->x = FX_MUL(pos->x, emtr->unk_F4.x) + FX_MUL(pos->y, emtr->unk_FA.x) + FX_MUL(pos->z, vec.x); - ptclPos->y = FX_MUL(pos->x, emtr->unk_F4.y) + FX_MUL(pos->y, emtr->unk_FA.y) + FX_MUL(pos->z, vec.y); - ptclPos->z = FX_MUL(pos->x, emtr->unk_F4.z) + FX_MUL(pos->y, emtr->unk_FA.z) + FX_MUL(pos->z, vec.z); + ptclPos->x = FX_MUL(pos->x, emtr->crossAxis1.x) + FX_MUL(pos->y, emtr->crossAxis2.x) + FX_MUL(pos->z, vec.x); + ptclPos->y = FX_MUL(pos->x, emtr->crossAxis1.y) + FX_MUL(pos->y, emtr->crossAxis2.y) + FX_MUL(pos->z, vec.y); + ptclPos->z = FX_MUL(pos->x, emtr->crossAxis1.z) + FX_MUL(pos->y, emtr->crossAxis2.z) + FX_MUL(pos->z, vec.z); } -void sub_020A08DC(SPLEmitter *emtr, SPLList *list) +void SPLEmitter_EmitParticles(SPLEmitter *emtr, SPLParticleList *list) { - SPLResource *res; - SPLResourceHeader *resBase; - int i, curGenNum; - SPLParticle *ptcl; - fx32 magPos; - fx32 magAxis; + SPLResource *res = emtr->resource; + SPLResourceHeader *header = res->header; - res = emtr->resource; - resBase = res->header; + int i = 0; + int emitCountDec = emtr->emissionCount + FX32_CAST(emtr->emissionCountFractional); + int totalEmissions = emitCountDec >> FX32_SHIFT; + int emission = 0; + emtr->emissionCountFractional = emitCountDec & FX32_DEC_MASK; - int temp = emtr->unk_C8 + FX32_CAST(emtr->unk_BE); - curGenNum = temp >> FX32_SHIFT; - emtr->unk_BE = temp & FX32_DEC_MASK; - - u32 initType = resBase->flags.unk_04_0; - if (initType == 2 || initType == 3 || IS_IN_RANGE(initType, 5, 9)) { - sub_020A1768(emtr); + enum SPLEmissionType emitType = header->flags.emissionType; + if (emitType == SPL_EMISSION_TYPE_CIRCLE_BORDER || + emitType == SPL_EMISSION_TYPE_CIRCLE_BORDER_UNIFORM || + emitType == SPL_EMISSION_TYPE_CIRCLE || + emitType == SPL_EMISSION_TYPE_CYLINDER_SURFACE || + emitType == SPL_EMISSION_TYPE_CYLINDER || + emitType == SPL_EMISSION_TYPE_HEMISPHERE_SURFACE || + emitType == SPL_EMISSION_TYPE_HEMISPHERE) { + SPLEmitter_ComputeOrthogonalAxes(emtr); } - i = 0; - if (i < curGenNum) { - fx32 genNum = 0; - do { - ptcl = (SPLParticle *)SPLList_PopFront(list); + for (i = 0; i < totalEmissions; i++) { + SPLParticle *ptcl = SPLParticleList_PopFront(list); + if (ptcl == NULL) { + return; + } - if (ptcl == NULL) { - return; + SPLParticleList_PushFront(&emtr->particles, ptcl); + + switch (header->flags.emissionType) { + case SPL_EMISSION_TYPE_POINT: + ptcl->position.x = ptcl->position.y = ptcl->position.z = 0; + break; + + case SPL_EMISSION_TYPE_SPHERE_SURFACE: + SPLRandom_VecFx32(&ptcl->position); + ptcl->position.x = FX_MUL(ptcl->position.x, emtr->radius); + ptcl->position.y = FX_MUL(ptcl->position.y, emtr->radius); + ptcl->position.z = FX_MUL(ptcl->position.z, emtr->radius); + break; + + case SPL_EMISSION_TYPE_CIRCLE_BORDER: { + VecFx32 pos; + SPLRandom_VecFx32_XY(&pos); + pos.x = FX_MUL(pos.x, emtr->radius); + pos.y = FX_MUL(pos.y, emtr->radius); + pos.z = 0; + SPLUtil_TiltCoordinates(&ptcl->position, &pos, emtr); + } break; + + case SPL_EMISSION_TYPE_CIRCLE_BORDER_UNIFORM: { + VecFx32 pos; + int idx = (emission * FX32_CONST(16)) / totalEmissions; + emission += 1; + + fx32 sin = FX_SinIdx(idx); + fx32 cos = FX_CosIdx(idx); + pos.x = FX_MUL(sin, emtr->radius); + pos.y = FX_MUL(cos, emtr->radius); + pos.z = 0; + SPLUtil_TiltCoordinates(&ptcl->position, &pos, emtr); + } break; + + case SPL_EMISSION_TYPE_SPHERE: + SPLRandom_VecFx32(&ptcl->position); + ptcl->position.x = FX_MUL(FX_MUL(ptcl->position.x, emtr->radius), SPLRandom_RangeFX32(FX32_ONE)); + ptcl->position.y = FX_MUL(FX_MUL(ptcl->position.y, emtr->radius), SPLRandom_RangeFX32(FX32_ONE)); + ptcl->position.z = FX_MUL(FX_MUL(ptcl->position.z, emtr->radius), SPLRandom_RangeFX32(FX32_ONE)); + break; + + case SPL_EMISSION_TYPE_CIRCLE: { + VecFx32 pos; + SPLRandom_VecFx32_XY(&pos); + pos.x = FX_MUL(FX_MUL(pos.x, emtr->radius), SPLRandom_RangeFX32(FX32_ONE)); + pos.y = FX_MUL(FX_MUL(pos.y, emtr->radius), SPLRandom_RangeFX32(FX32_ONE)); + SPLUtil_TiltCoordinates(&ptcl->position, &pos, emtr); + } break; + + case SPL_EMISSION_TYPE_HEMISPHERE_SURFACE: { + VecFx32 pos; + VecFx16 emitterUp; + SPLRandom_VecFx32(&ptcl->position); + VEC_Fx16CrossProduct(&emtr->crossAxis1, &emtr->crossAxis2, &emitterUp); + pos.x = emitterUp.x; + pos.y = emitterUp.y; + pos.z = emitterUp.z; + if (VEC_DotProduct(&pos, &ptcl->position) <= 0) { + ptcl->position.x = -ptcl->position.x; + ptcl->position.y = -ptcl->position.y; + ptcl->position.z = -ptcl->position.z; } - SPLList_PushFront((SPLList *)&emtr->particles, (SPLNode *)ptcl); + ptcl->position.x = FX_MUL(ptcl->position.x, emtr->radius); + ptcl->position.y = FX_MUL(ptcl->position.y, emtr->radius); + ptcl->position.z = FX_MUL(ptcl->position.z, emtr->radius); + } break; - switch (resBase->flags.unk_04_0) { - case 0: - ptcl->position.x = ptcl->position.y = ptcl->position.z = 0; - break; - - case 1: - SPLRandom_VecFx32(&ptcl->position); - ptcl->position.x = FX_MUL(ptcl->position.x, emtr->unk_CC); - ptcl->position.y = FX_MUL(ptcl->position.y, emtr->unk_CC); - ptcl->position.z = FX_MUL(ptcl->position.z, emtr->unk_CC); - break; - - case 2: { - VecFx32 pos; - SPLRandom_VecFx32_XY(&pos); - pos.x = FX_MUL(pos.x, emtr->unk_CC); - pos.y = FX_MUL(pos.y, emtr->unk_CC); - pos.z = 0; - sub_020A1608(&ptcl->position, &pos, emtr); - } break; - - case 3: { - VecFx32 pos; - int idx = genNum / curGenNum; - genNum += 0x10000; - fx32 sin = FX_SinIdx(idx); - fx32 cos = FX_CosIdx(idx); - pos.x = FX_MUL(sin, emtr->unk_CC); - pos.y = FX_MUL(cos, emtr->unk_CC); - pos.z = 0; - sub_020A1608(&ptcl->position, &pos, emtr); - } break; - - case 4: - SPLRandom_VecFx32(&ptcl->position); - ptcl->position.x = FX_MUL(FX_MUL(ptcl->position.x, emtr->unk_CC), SPLRandom_RangeFX32(FX32_ONE)); - ptcl->position.y = FX_MUL(FX_MUL(ptcl->position.y, emtr->unk_CC), SPLRandom_RangeFX32(FX32_ONE)); - ptcl->position.z = FX_MUL(FX_MUL(ptcl->position.z, emtr->unk_CC), SPLRandom_RangeFX32(FX32_ONE)); - break; - - case 5: { - VecFx32 pos; - SPLRandom_VecFx32_XY(&pos); - pos.x = FX_MUL(FX_MUL(pos.x, emtr->unk_CC), SPLRandom_RangeFX32(FX32_ONE)); - pos.y = FX_MUL(FX_MUL(pos.y, emtr->unk_CC), SPLRandom_RangeFX32(FX32_ONE)); - sub_020A1608(&ptcl->position, &pos, emtr); - } break; - - case 8: { - VecFx32 pos; - VecFx16 tmpUnitVec; - SPLRandom_VecFx32(&ptcl->position); - VEC_Fx16CrossProduct(&emtr->unk_F4, &emtr->unk_FA, &tmpUnitVec); - pos.x = tmpUnitVec.x; - pos.y = tmpUnitVec.y; - pos.z = tmpUnitVec.z; - if (VEC_DotProduct(&pos, &ptcl->position) <= 0) { - ptcl->position.x = -ptcl->position.x; - ptcl->position.y = -ptcl->position.y; - ptcl->position.z = -ptcl->position.z; - } - - ptcl->position.x = FX_MUL(ptcl->position.x, emtr->unk_CC); - ptcl->position.y = FX_MUL(ptcl->position.y, emtr->unk_CC); - ptcl->position.z = FX_MUL(ptcl->position.z, emtr->unk_CC); - } break; - - case 9: { - VecFx32 pos; - VecFx16 tmpUnitVec; - SPLRandom_VecFx32(&ptcl->position); - VEC_Fx16CrossProduct(&emtr->unk_F4, &emtr->unk_FA, &tmpUnitVec); - pos.x = tmpUnitVec.x; - pos.y = tmpUnitVec.y; - pos.z = tmpUnitVec.z; - if (VEC_DotProduct(&pos, &ptcl->position) < 0) { - ptcl->position.x = -ptcl->position.x; - ptcl->position.y = -ptcl->position.y; - ptcl->position.z = -ptcl->position.z; - } - - ptcl->position.x = FX_MUL(FX_MUL(ptcl->position.x, emtr->unk_CC), (SPLRandom_RangeFX32(FX32_ONE) >> 1) + FX32_HALF); - ptcl->position.y = FX_MUL(FX_MUL(ptcl->position.y, emtr->unk_CC), (SPLRandom_RangeFX32(FX32_ONE) >> 1) + FX32_HALF); - ptcl->position.z = FX_MUL(FX_MUL(ptcl->position.z, emtr->unk_CC), (SPLRandom_RangeFX32(FX32_ONE) >> 1) + FX32_HALF); - } break; - - case 6: { - VecFx32 pos; - SPLRandom_VecFx32_XY(&ptcl->velocity); - pos.x = FX_MUL(ptcl->velocity.x, emtr->unk_CC); - pos.y = FX_MUL(ptcl->velocity.y, emtr->unk_CC); - pos.z = SPLRandom_RangeFX32(emtr->length); - sub_020A1608(&ptcl->position, &pos, emtr); - } break; - - case 7: { - VecFx32 pos; - SPLRandom_VecFx32_XY(&ptcl->velocity); - pos.x = FX_MUL(FX_MUL(ptcl->velocity.x, emtr->unk_CC), SPLRandom_RangeFX32(FX32_ONE)); - pos.y = FX_MUL(FX_MUL(ptcl->velocity.y, emtr->unk_CC), SPLRandom_RangeFX32(FX32_ONE)); - pos.z = SPLRandom_RangeFX32(emtr->length); - sub_020A1608(&ptcl->position, &pos, emtr); - } break; + case SPL_EMISSION_TYPE_HEMISPHERE: { + VecFx32 pos; + VecFx16 tmpUnitVec; + SPLRandom_VecFx32(&ptcl->position); + VEC_Fx16CrossProduct(&emtr->crossAxis1, &emtr->crossAxis2, &tmpUnitVec); + pos.x = tmpUnitVec.x; + pos.y = tmpUnitVec.y; + pos.z = tmpUnitVec.z; + if (VEC_DotProduct(&pos, &ptcl->position) < 0) { + ptcl->position.x = -ptcl->position.x; + ptcl->position.y = -ptcl->position.y; + ptcl->position.z = -ptcl->position.z; } - magPos = SPLRandom_DoubleScaledRangeFX32(emtr->unk_D4, resBase->unk_44.unk_02_0); - magAxis = SPLRandom_DoubleScaledRangeFX32(emtr->unk_D8, resBase->unk_44.unk_02_0); + ptcl->position.x = FX_MUL(FX_MUL(ptcl->position.x, emtr->radius), (SPLRandom_RangeFX32(FX32_ONE) >> 1) + FX32_HALF); + ptcl->position.y = FX_MUL(FX_MUL(ptcl->position.y, emtr->radius), (SPLRandom_RangeFX32(FX32_ONE) >> 1) + FX32_HALF); + ptcl->position.z = FX_MUL(FX_MUL(ptcl->position.z, emtr->radius), (SPLRandom_RangeFX32(FX32_ONE) >> 1) + FX32_HALF); + } break; - VecFx32 posNorm; - if (resBase->flags.unk_04_0 == 6) { - VecFx32 tmp; - tmp.x = FX_MUL(ptcl->velocity.x, emtr->unk_F4.x) + FX_MUL(ptcl->velocity.y, emtr->unk_FA.x); - tmp.y = FX_MUL(ptcl->velocity.x, emtr->unk_F4.y) + FX_MUL(ptcl->velocity.y, emtr->unk_FA.y); - tmp.z = FX_MUL(ptcl->velocity.x, emtr->unk_F4.z) + FX_MUL(ptcl->velocity.y, emtr->unk_FA.z); + case SPL_EMISSION_TYPE_CYLINDER_SURFACE: { + VecFx32 pos; + SPLRandom_VecFx32_XY(&ptcl->velocity); + pos.x = FX_MUL(ptcl->velocity.x, emtr->radius); + pos.y = FX_MUL(ptcl->velocity.y, emtr->radius); + pos.z = SPLRandom_RangeFX32(emtr->length); + SPLUtil_TiltCoordinates(&ptcl->position, &pos, emtr); + } break; - VEC_Normalize(&tmp, &posNorm); - } else if (ptcl->position.x == 0 && ptcl->position.y == 0 && ptcl->position.z == 0) { - SPLRandom_VecFx32(&posNorm); - } else { - VEC_Normalize(&ptcl->position, &posNorm); - } + case SPL_EMISSION_TYPE_CYLINDER: { + VecFx32 pos; + SPLRandom_VecFx32_XY(&ptcl->velocity); + pos.x = FX_MUL(FX_MUL(ptcl->velocity.x, emtr->radius), SPLRandom_RangeFX32(FX32_ONE)); + pos.y = FX_MUL(FX_MUL(ptcl->velocity.y, emtr->radius), SPLRandom_RangeFX32(FX32_ONE)); + pos.z = SPLRandom_RangeFX32(emtr->length); + SPLUtil_TiltCoordinates(&ptcl->position, &pos, emtr); + } break; + } - ptcl->velocity.x = FX_MUL(posNorm.x, magPos) + FX_MUL(emtr->axis.x, magAxis) + emtr->unk_B0.x; - ptcl->velocity.y = FX_MUL(posNorm.y, magPos) + FX_MUL(emtr->axis.y, magAxis) + emtr->unk_B0.y; - ptcl->velocity.z = FX_MUL(posNorm.z, magPos) + FX_MUL(emtr->axis.z, magAxis) + emtr->unk_B0.z; + fx32 magPos = SPLRandom_DoubleScaledRangeFX32(emtr->initVelPositionAmplifier, header->randomAttenuation.initVel); + fx32 magAxis = SPLRandom_DoubleScaledRangeFX32(emtr->initVelAxisAmplifier, header->randomAttenuation.initVel); - ptcl->emitterPos = emtr->position; + VecFx32 posNorm; + if (header->flags.emissionType == SPL_EMISSION_TYPE_CYLINDER_SURFACE) { + VecFx32 tmp; + tmp.x = FX_MUL(ptcl->velocity.x, emtr->crossAxis1.x) + FX_MUL(ptcl->velocity.y, emtr->crossAxis2.x); + tmp.y = FX_MUL(ptcl->velocity.x, emtr->crossAxis1.y) + FX_MUL(ptcl->velocity.y, emtr->crossAxis2.y); + tmp.z = FX_MUL(ptcl->velocity.x, emtr->crossAxis1.z) + FX_MUL(ptcl->velocity.y, emtr->crossAxis2.z); - ptcl->unk_30 = SPLRandom_DoubleScaledRangeFX32(emtr->unk_DC, resBase->unk_44.unk_00_0); - ptcl->unk_34 = FX32_ONE; + VEC_Normalize(&tmp, &posNorm); + } else if (ptcl->position.x == 0 && ptcl->position.y == 0 && ptcl->position.z == 0) { + SPLRandom_VecFx32(&posNorm); + } else { + VEC_Normalize(&ptcl->position, &posNorm); + } - if (resBase->flags.hasColorAnim && res->colorAnim->unk_08.unk_00_0) { - u16 clr[3]; - u32 index = SPLRandom_S32(12); - clr[0] = res->colorAnim->unk_00; - clr[1] = resBase->unk_22; - clr[2] = res->colorAnim->unk_02; - ptcl->unk_36 = clr[index % 3]; - } else { - ptcl->unk_36 = resBase->unk_22; - } + ptcl->velocity.x = FX_MUL(posNorm.x, magPos) + FX_MUL(emtr->axis.x, magAxis) + emtr->particleInitVelocity.x; + ptcl->velocity.y = FX_MUL(posNorm.y, magPos) + FX_MUL(emtr->axis.y, magAxis) + emtr->particleInitVelocity.y; + ptcl->velocity.z = FX_MUL(posNorm.z, magPos) + FX_MUL(emtr->axis.z, magAxis) + emtr->particleInitVelocity.z; - ptcl->unk_2E.unk_00_0 = emtr->misc.unk_01_0; - ptcl->unk_2E.unk_00_5 = 31; + ptcl->emitterPos = emtr->position; - if (resBase->flags.unk_05_5) { - ptcl->rotation = SPLRandom_S32(32); - } else { - ptcl->rotation = emtr->unk_C6; - } + ptcl->baseScale = SPLRandom_DoubleScaledRangeFX32(emtr->baseScale, header->randomAttenuation.baseScale); + ptcl->unk_34 = FX32_ONE; - if (resBase->flags.unk_05_4) { - ptcl->angularVelocity = (u32)SPLRandom_BetweenFX32(resBase->unk_34, resBase->unk_36) >> FX32_SHIFT; - } else { - ptcl->angularVelocity = 0; - } + if (header->flags.hasColorAnim && res->colorAnim->unk_08.unk_00_0) { + u16 clr[3]; + u32 index = SPLRandom_S32(12); + clr[0] = res->colorAnim->startColor; + clr[1] = header->color; + clr[2] = res->colorAnim->endColor; + ptcl->color = clr[index % 3]; + } else { + ptcl->color = header->color; + } - ptcl->lifeTime = SPLRandom_ScaledRangeFX32(emtr->particleLifeTime, resBase->unk_44.unk_01_0) + 1; - ptcl->age = 0; + ptcl->visibility.baseAlpha = emtr->misc.baseAlpha; + ptcl->visibility.animAlpha = 31; - if (resBase->flags.hasTexAnim && res->texAnim->unk_08.unk_02_0) { - ptcl->misc.unk_00 = res->texAnim->unk_00[SPLRandom_U32(12) % res->texAnim->unk_08.unk_00_0]; - } else if (resBase->flags.hasTexAnim && !res->texAnim->unk_08.unk_02_0) { - ptcl->misc.unk_00 = res->texAnim->unk_00[0]; - } else { - ptcl->misc.unk_00 = resBase->misc.textureIndex; - } + if (header->flags.unk_05_5) { + ptcl->rotation = SPLRandom_S32(32); + } else { + ptcl->rotation = emtr->unk_C6; + } - ptcl->loopTimeFactor = 0xFFFF / res->header->misc.unk_04_0; - ptcl->lifeTimeFactor = 0xFFFF / ptcl->lifeTime; + if (header->flags.hasRotation) { + ptcl->angularVelocity = (u32)SPLRandom_BetweenFX32(header->minRotation, header->maxRotation) >> FX32_SHIFT; + } else { + ptcl->angularVelocity = 0; + } - ptcl->misc.lifeRateOffset = 0; + ptcl->lifeTime = SPLRandom_ScaledRangeFX32(emtr->particleLifeTime, header->randomAttenuation.lifeTime) + 1; // Life is always at least 1 frame + ptcl->age = 0; - if (resBase->flags.unk_06_4) { - ptcl->misc.lifeRateOffset = (u8)SPLRandom_S32(8); - } - i++; - } while (i < curGenNum); + if (header->flags.hasTexAnim && res->texAnim->param.randomizeInit) { + ptcl->misc.texture = res->texAnim->textures[SPLRandom_U32(12) % res->texAnim->param.frameCount]; + } else if (header->flags.hasTexAnim && !res->texAnim->param.randomizeInit) { + ptcl->misc.texture = res->texAnim->textures[0]; + } else { + ptcl->misc.texture = header->misc.textureIndex; + } + + ptcl->loopTimeFactor = 0xFFFF / res->header->misc.loopFrames; + ptcl->lifeTimeFactor = 0xFFFF / ptcl->lifeTime; + + ptcl->misc.lifeRateOffset = 0; + + if (header->flags.randomizeLoopedAnim) { + ptcl->misc.lifeRateOffset = (u8)SPLRandom_S32(8); + } } } @@ -322,19 +320,19 @@ void sub_020A05BC(SPLParticle *ptcl, SPLEmitter *emtr, SPLList *list) // `unk_08.unk_00_0` and `unk_08.unk_01_0` in `UnkSPLStruct14` // could just be `u8 unk_08;` and `u8 unk_09;` // instead of an inner struct - int idk = ptcl->unk_30 * ptcl->unk_34 >> FX32_SHIFT; - chld->unk_30 = idk * (chldRes->unk_08.unk_01_0 + 1) >> 6; + int idk = ptcl->baseScale * ptcl->unk_34 >> FX32_SHIFT; + chld->baseScale = idk * (chldRes->unk_08.unk_01_0 + 1) >> 6; chld->unk_34 = FX32_ONE; if (chldRes->flags.unk_02_6) { - chld->unk_36 = chldRes->unk_0A; + chld->color = chldRes->unk_0A; } else { - chld->unk_36 = ptcl->unk_36; + chld->color = ptcl->color; } - chld->unk_2E.unk_00_0 = (ptcl->unk_2E.unk_00_0 * (ptcl->unk_2E.unk_00_5 + 1)) >> 5; - chld->unk_2E.unk_00_5 = 31; + chld->visibility.baseAlpha = (ptcl->visibility.baseAlpha * (ptcl->visibility.animAlpha + 1)) >> 5; + chld->visibility.animAlpha = 31; switch (chldRes->flags.unk_02_3) { case 0: @@ -353,7 +351,7 @@ void sub_020A05BC(SPLParticle *ptcl, SPLEmitter *emtr, SPLList *list) chld->lifeTime = chldRes->unk_06; chld->age = 0; - chld->misc.unk_00 = chldRes->misc.textureIndex; + chld->misc.texture = chldRes->misc.textureIndex; chld->loopTimeFactor = 0xFFFF / (ptcl->lifeTime / 2); chld->lifeTimeFactor = 0xFFFF / ptcl->lifeTime; diff --git a/lib/spl/src/unk_020A19F0.c b/lib/spl/src/unk_020A19F0.c index 07a6590bd..9288b1dde 100644 --- a/lib/spl/src/unk_020A19F0.c +++ b/lib/spl/src/unk_020A19F0.c @@ -41,53 +41,53 @@ void sub_020A1BD4(SPLParticle *ptcl, SPLResource *res, int lifeRate) in = colorAnim->unk_04.unk_04_0; if (lifeRate < in) { - ptcl->unk_36 = colorAnim->unk_00; + ptcl->color = colorAnim->startColor; } else if (lifeRate < peak) { - int peakR = GX_RGB_R(resBase->unk_22); - int startR = GX_RGB_R(colorAnim->unk_00); + int peakR = GX_RGB_R(resBase->color); + int startR = GX_RGB_R(colorAnim->startColor); - int peakG = GX_RGB_G(resBase->unk_22); - int startG = GX_RGB_G(colorAnim->unk_00); + int peakG = GX_RGB_G(resBase->color); + int startG = GX_RGB_G(colorAnim->startColor); - int peakB = GX_RGB_B(resBase->unk_22); - int startB = GX_RGB_B(colorAnim->unk_00); + 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->unk_36 = GX_RGB( + ptcl->color = GX_RGB( startR + (a * (int)(peakR - startR)) / b, startG + (a * (int)(peakG - startG)) / b, startB + (a * (int)(peakB - startB)) / b ); } else { - ptcl->unk_36 = GX_RGB(peakR, peakG, peakB); + ptcl->color = GX_RGB(peakR, peakG, peakB); } } else if (lifeRate < out) { - int peakR = GX_RGB_R(resBase->unk_22); - int endR = GX_RGB_R(colorAnim->unk_02); + int peakR = GX_RGB_R(resBase->color); + int endR = GX_RGB_R(colorAnim->endColor); - int peakG = GX_RGB_G(resBase->unk_22); - int endG = GX_RGB_G(colorAnim->unk_02); + int peakG = GX_RGB_G(resBase->color); + int endG = GX_RGB_G(colorAnim->endColor); - int peakB = GX_RGB_B(resBase->unk_22); - int endB = GX_RGB_B(colorAnim->unk_02); + 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->unk_36 = GX_RGB( + ptcl->color = GX_RGB( peakR + (a * (int)(endR - peakR)) / b, peakG + (a * (int)(endG - peakG)) / b, peakB + (a * (int)(endB - peakB)) / b ); } else { - ptcl->unk_36 = GX_RGB(endR, endG, endB); + ptcl->color = GX_RGB(endR, endG, endB); } } else { - ptcl->unk_36 = colorAnim->unk_02; + ptcl->color = colorAnim->endColor; } } @@ -108,15 +108,15 @@ void sub_020A1AF8(SPLParticle *ptcl, SPLResource *res, int lifeRate) x += alphaAnim->unk_00.val2_01_2; } - ptcl->unk_2E.unk_00_5 = SPLRandom_ScaledRangeFX32(x, alphaAnim->unk_02.unk_00_0); + 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->unk_08.unk_00_0; i++) { - if (lifeRate < texAnim->unk_08.unk_01_0 * (i + 1)) { - ptcl->misc.unk_00 = texAnim->unk_00[i]; + 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; } } @@ -129,5 +129,5 @@ void sub_020A1A48(SPLParticle *ptcl, SPLResource *res, int lifeRate) void sub_020A19F0(SPLParticle *ptcl, SPLResource *res, int lifeRate) { - ptcl->unk_2E.unk_00_5 = ((255 - lifeRate) * 31) / 255; + ptcl->visibility.animAlpha = ((255 - lifeRate) * 31) / 255; } diff --git a/src/unk_02014000.c b/src/unk_02014000.c index 97e604b0c..8ca026e70 100644 --- a/src/unk_02014000.c +++ b/src/unk_02014000.c @@ -652,7 +652,7 @@ void sub_02014798(SPLEmitter *param0, VecFx16 *param1) void sub_020147B0(SPLEmitter *param0, fx32 param1) { - param0->resource->header->unk_10 = param1; + param0->resource->header->emissionCount = param1; } enum {