mirror of
https://github.com/zeldaret/tp
synced 2026-05-23 06:54:28 -04:00
210 lines
8.2 KiB
C++
210 lines
8.2 KiB
C++
#include "JSystem/JSystem.h" // IWYU pragma: keep
|
|
|
|
#include "JSystem/JParticle/JPADynamicsBlock.h"
|
|
#include "JSystem/JMath/JMATrigonometric.h"
|
|
#include "JSystem/JParticle/JPAEmitter.h"
|
|
|
|
void JPAVolumePoint(JPAEmitterWorkData* work) {
|
|
work->mVolumeCalcData.mVolumePos.zero();
|
|
work->mVolumeCalcData.mVelOmni.set(work->mpEmtr->get_r_zh(), work->mpEmtr->get_r_zh(),
|
|
work->mpEmtr->get_r_zh());
|
|
work->mVolumeCalcData.mVelAxis.set(work->mVolumeCalcData.mVelOmni.x, 0.0f,
|
|
work->mVolumeCalcData.mVelOmni.z);
|
|
}
|
|
|
|
void JPAVolumeLine(JPAEmitterWorkData* work) {
|
|
if (work->mpEmtr->checkFlag(JPADynFlag_FixedInterval)) {
|
|
work->mVolumeCalcData.mVolumePos.set(
|
|
0.0f, 0.0f,
|
|
work->mVolumeSize * ((work->mVolumeEmitIdx / (work->mEmitCount - 1.0f) - 0.5f)));
|
|
work->mVolumeEmitIdx++;
|
|
} else {
|
|
work->mVolumeCalcData.mVolumePos.set(0.0f, 0.0f,
|
|
work->mVolumeSize * work->mpEmtr->get_r_zh());
|
|
}
|
|
|
|
work->mVolumeCalcData.mVelOmni.set(0.0f, 0.0f,
|
|
work->mVolumeCalcData.mVolumePos.z * work->mGlobalScl.z);
|
|
work->mVolumeCalcData.mVelAxis.set(0.0f, 0.0f, work->mVolumeCalcData.mVolumePos.z);
|
|
}
|
|
|
|
// NONMATCHING regalloc. Could be issue with mul asm implementations
|
|
void JPAVolumeCircle(JPAEmitterWorkData* work) {
|
|
s16 theta;
|
|
f32 distance;
|
|
|
|
if (work->mpEmtr->checkFlag(JPADynFlag_FixedInterval)) {
|
|
theta = (s16)((work->mVolumeEmitIdx << 16) / work->mEmitCount);
|
|
theta = theta * work->mVolumeSweep;
|
|
work->mVolumeEmitIdx++;
|
|
} else {
|
|
theta = work->mVolumeSweep * work->mpEmtr->get_r_ss();
|
|
}
|
|
|
|
distance = work->mpEmtr->get_r_f();
|
|
if (work->mpEmtr->checkFlag(JPADynFlag_FixedDensity)) {
|
|
distance = 1.0f - (distance * distance);
|
|
}
|
|
|
|
distance = work->mVolumeSize * (work->mVolumeMinRad + distance * (1.0f - work->mVolumeMinRad));
|
|
work->mVolumeCalcData.mVolumePos.set(distance * JMASSin(theta), 0.0f,
|
|
distance * JMASCos(theta));
|
|
work->mVolumeCalcData.mVelOmni.mul(work->mVolumeCalcData.mVolumePos, work->mGlobalScl);
|
|
work->mVolumeCalcData.mVelAxis.set(work->mVolumeCalcData.mVolumePos.x, 0.0f,
|
|
work->mVolumeCalcData.mVolumePos.z);
|
|
}
|
|
|
|
void JPAVolumeCube(JPAEmitterWorkData* work) {
|
|
work->mVolumeCalcData.mVolumePos.set(work->mpEmtr->get_r_zh() * work->mVolumeSize,
|
|
work->mpEmtr->get_r_zh() * work->mVolumeSize,
|
|
work->mpEmtr->get_r_zh() * work->mVolumeSize);
|
|
work->mVolumeCalcData.mVelOmni.mul(work->mVolumeCalcData.mVolumePos, work->mGlobalScl);
|
|
work->mVolumeCalcData.mVelAxis.set(work->mVolumeCalcData.mVolumePos.x, 0.0f, work->mVolumeCalcData.mVolumePos.z);
|
|
}
|
|
|
|
static void JPAVolumeSphere(JPAEmitterWorkData* work) {
|
|
s16 phi, r28;
|
|
if (work->mpEmtr->checkFlag(JPADynFlag_FixedInterval)) {
|
|
phi = u16(work->mVolumeX * 0x8000 / (work->mDivNumber - 1) + 0x4000);
|
|
u16 r26 = u16(work->mVolumeAngleNum * 0x10000 / (work->mVolumeAngleMax - 1));
|
|
r28 = f32(r26) * work->mVolumeSweep + 0x8000;
|
|
work->mVolumeAngleNum++;
|
|
if (work->mVolumeAngleNum == work->mVolumeAngleMax) {
|
|
work->mVolumeAngleNum = 0;
|
|
work->mVolumeX++;
|
|
if (work->mVolumeX * 2 < work->mDivNumber) {
|
|
work->mVolumeAngleMax = work->mVolumeAngleMax != 1 ?
|
|
work->mVolumeAngleMax + 4 : work->mVolumeAngleMax + 3;
|
|
} else {
|
|
work->mVolumeAngleMax = work->mVolumeAngleMax != 4 ? work->mVolumeAngleMax - 4 : 1;
|
|
}
|
|
}
|
|
} else {
|
|
phi = work->mpEmtr->get_r_ss() >> 1;
|
|
r28 = work->mVolumeSweep * work->mpEmtr->get_r_ss();
|
|
}
|
|
|
|
f32 f31 = work->mpEmtr->get_r_f();
|
|
if (work->mpEmtr->checkFlag(JPADynFlag_FixedDensity)) {
|
|
f31 = 1.0f - f31 * f31 * f31;
|
|
}
|
|
f31 = work->mVolumeSize * (work->mVolumeMinRad + f31 * (1.0f - work->mVolumeMinRad));
|
|
work->mVolumeCalcData.mVolumePos.set(f31 * JMASCos(phi) * JMASSin(r28), -f31 * JMASSin(phi),
|
|
f31 * JMASCos(phi) * JMASCos(r28));
|
|
work->mVolumeCalcData.mVelOmni.mul(work->mVolumeCalcData.mVolumePos, work->mGlobalScl);
|
|
work->mVolumeCalcData.mVelAxis.set(work->mVolumeCalcData.mVolumePos.x, 0.0f,
|
|
work->mVolumeCalcData.mVolumePos.z);
|
|
}
|
|
|
|
static void JPAVolumeCylinder(JPAEmitterWorkData* work) {
|
|
s16 r30 = work->mVolumeSweep * work->mpEmtr->get_r_ss();
|
|
f32 f31 = work->mpEmtr->get_r_f();
|
|
if (work->mpEmtr->checkFlag(JPADynFlag_FixedDensity)) {
|
|
f31 = 1.0f - f31 * f31;
|
|
}
|
|
f31 = work->mVolumeSize * (work->mVolumeMinRad + f31 * (1.0f - work->mVolumeMinRad));
|
|
work->mVolumeCalcData.mVolumePos.set(
|
|
f31 * JMASSin(r30), work->mVolumeSize * work->mpEmtr->get_r_zp(), f31 * JMASCos(r30));
|
|
work->mVolumeCalcData.mVelOmni.mul(work->mVolumeCalcData.mVolumePos, work->mGlobalScl);
|
|
work->mVolumeCalcData.mVelAxis.set(work->mVolumeCalcData.mVolumePos.x, 0.0f,
|
|
work->mVolumeCalcData.mVolumePos.z);
|
|
}
|
|
|
|
static void JPAVolumeTorus(JPAEmitterWorkData* work) {
|
|
s16 theta = work->mVolumeSweep * work->mpEmtr->get_r_ss();
|
|
s16 phi = work->mpEmtr->get_r_ss();
|
|
f32 rad = work->mVolumeSize * work->mVolumeMinRad;
|
|
work->mVolumeCalcData.mVelAxis.set(rad * JMASSin(theta) * JMASCos(phi), rad * JMASSin(phi),
|
|
rad * JMASCos(theta) * JMASCos(phi));
|
|
work->mVolumeCalcData.mVolumePos.set(
|
|
work->mVolumeCalcData.mVelAxis.x + work->mVolumeSize * JMASSin(theta),
|
|
work->mVolumeCalcData.mVelAxis.y,
|
|
work->mVolumeCalcData.mVelAxis.z + work->mVolumeSize * JMASCos(theta));
|
|
work->mVolumeCalcData.mVelOmni.mul(work->mVolumeCalcData.mVolumePos, work->mGlobalScl);
|
|
}
|
|
|
|
JPADynamicsBlock::JPADynamicsBlock(u8 const* data) {
|
|
mpData = (const JPADynamicsBlockData*)data;
|
|
init();
|
|
}
|
|
|
|
enum {
|
|
VOL_Cube = 0x00,
|
|
VOL_Sphere = 0x01,
|
|
VOL_Cylinder = 0x02,
|
|
VOL_Torus = 0x03,
|
|
VOL_Point = 0x04,
|
|
VOL_Circle = 0x05,
|
|
VOL_Line = 0x06,
|
|
};
|
|
|
|
void JPADynamicsBlock::init() {
|
|
switch (getVolumeType()) {
|
|
case VOL_Cube:
|
|
mpCalcVolumeFunc = &JPAVolumeCube;
|
|
break;
|
|
case VOL_Sphere:
|
|
mpCalcVolumeFunc = &JPAVolumeSphere;
|
|
break;
|
|
case VOL_Cylinder:
|
|
mpCalcVolumeFunc = &JPAVolumeCylinder;
|
|
break;
|
|
case VOL_Torus:
|
|
mpCalcVolumeFunc = &JPAVolumeTorus;
|
|
break;
|
|
case VOL_Point:
|
|
mpCalcVolumeFunc = &JPAVolumePoint;
|
|
break;
|
|
case VOL_Circle:
|
|
mpCalcVolumeFunc = &JPAVolumeCircle;
|
|
break;
|
|
case VOL_Line:
|
|
mpCalcVolumeFunc = &JPAVolumeLine;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void JPADynamicsBlock::create(JPAEmitterWorkData* work) {
|
|
if (work->mpEmtr->checkStatus(JPAEmtrStts_RateStepEmit)) {
|
|
s32 emitCount = 0;
|
|
|
|
if (work->mpEmtr->checkFlag(JPADynFlag_FixedInterval)) {
|
|
emitCount = getVolumeType() == VOL_Sphere ? 4 * getDivNumber() * getDivNumber() + 2 : getDivNumber();
|
|
|
|
work->mVolumeEmitIdx = 0;
|
|
} else {
|
|
f32 newPtclCount =
|
|
work->mpEmtr->mRate * (getRateRndm() * work->mpEmtr->get_r_zp() + 1.0f);
|
|
emitCount = work->mpEmtr->mEmitCount += newPtclCount;
|
|
work->mpEmtr->mEmitCount -= emitCount;
|
|
|
|
if (work->mpEmtr->checkStatus(JPAEmtrStts_FirstEmit) && 0.0f < newPtclCount &&
|
|
newPtclCount < 1.0f)
|
|
emitCount = 1;
|
|
}
|
|
|
|
work->mEmitCount = emitCount;
|
|
if (work->mpEmtr->checkStatus(JPAEmtrStts_StopEmit)) {
|
|
emitCount = 0;
|
|
}
|
|
|
|
JPABaseParticle* ptcl = NULL;
|
|
s32 createCount = emitCount;
|
|
while (createCount > 0) {
|
|
ptcl = work->mpEmtr->createParticle();
|
|
if (ptcl == NULL)
|
|
break;
|
|
createCount--;
|
|
}
|
|
}
|
|
|
|
if (++work->mpEmtr->mRateStepTimer >= (work->mpEmtr->mRateStep + 1)) {
|
|
work->mpEmtr->mRateStepTimer -= work->mpEmtr->mRateStep + 1;
|
|
work->mpEmtr->setStatus(JPAEmtrStts_RateStepEmit);
|
|
} else {
|
|
work->mpEmtr->clearStatus(JPAEmtrStts_RateStepEmit);
|
|
}
|
|
|
|
work->mpEmtr->clearStatus(JPAEmtrStts_FirstEmit);
|
|
}
|