summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/JSystem/JGeometry.h508
-rw-r--r--include/JSystem/JMath/JMATrigonometric.h136
-rw-r--r--include/JSystem/JMath/JMath.h263
-rw-r--r--include/JSystem/JMath/random.h51
-rw-r--r--include/JSystem/JParticle/JPABaseShape.h210
-rw-r--r--include/JSystem/JParticle/JPAChildShape.h89
-rw-r--r--include/JSystem/JParticle/JPADrawInfo.h29
-rw-r--r--include/JSystem/JParticle/JPADynamicsBlock.h109
-rw-r--r--include/JSystem/JParticle/JPAEmitter.h272
-rw-r--r--include/JSystem/JParticle/JPAEmitterManager.h49
-rw-r--r--include/JSystem/JParticle/JPAExTexShape.h45
-rw-r--r--include/JSystem/JParticle/JPAExtraShape.h112
-rw-r--r--include/JSystem/JParticle/JPAFieldBlock.h174
-rw-r--r--include/JSystem/JParticle/JPAKeyBlock.h21
-rw-r--r--include/JSystem/JParticle/JPAList.h131
-rw-r--r--include/JSystem/JParticle/JPAMath.h16
-rw-r--r--include/JSystem/JParticle/JPAParticle.h93
-rw-r--r--include/JSystem/JParticle/JPARandom.h43
-rw-r--r--include/JSystem/JParticle/JPAResource.h81
-rw-r--r--include/JSystem/JParticle/JPAResourceLoader.h14
-rw-r--r--include/JSystem/JParticle/JPAResourceManager.h36
-rw-r--r--include/JSystem/JParticle/JPATexture.h36
-rw-r--r--include/JSystem/JSupport/JSUList.h254
-rw-r--r--include/JSystem/JSupport/JSupport.h45
-rw-r--r--include/JSystem/JUtility/JUTAssert.h64
-rw-r--r--include/JSystem/JUtility/JUTTexture.h113
-rw-r--r--include/JSystem/TPosition3.h86
-rw-r--r--src/JSystem/JParticle/JPABaseShape.cpp1449
-rw-r--r--src/JSystem/JParticle/JPAChildShape.cpp48
-rw-r--r--src/JSystem/JParticle/JPADynamicsBlock.cpp233
-rw-r--r--src/JSystem/JParticle/JPAEmitter.cpp183
-rw-r--r--src/JSystem/JParticle/JPAEmitterManager.cpp203
-rw-r--r--src/JSystem/JParticle/JPAExTexShape.cpp35
-rw-r--r--src/JSystem/JParticle/JPAExtraShape.cpp152
-rw-r--r--src/JSystem/JParticle/JPAFieldBlock.cpp299
-rw-r--r--src/JSystem/JParticle/JPAKeyBlock.cpp25
-rw-r--r--src/JSystem/JParticle/JPAMath.cpp182
-rw-r--r--src/JSystem/JParticle/JPAParticle.cpp331
-rw-r--r--src/JSystem/JParticle/JPAResource.cpp1124
-rw-r--r--src/JSystem/JParticle/JPAResourceLoader.cpp106
-rw-r--r--src/JSystem/JParticle/JPAResourceManager.cpp84
-rw-r--r--src/JSystem/JParticle/JPATexture.cpp15
-rw-r--r--src/JSystem/JSupport/JSUList.cpp162
43 files changed, 7711 insertions, 0 deletions
diff --git a/include/JSystem/JGeometry.h b/include/JSystem/JGeometry.h
new file mode 100644
index 00000000..5ae2e827
--- /dev/null
+++ b/include/JSystem/JGeometry.h
@@ -0,0 +1,508 @@
+#ifndef JGEOMETRY_H
+#define JGEOMETRY_H
+
+#include "dolphin/mtx.h"
+#include "math.h"
+#include "JSystem/JMath/JMath.h"
+
+namespace JGeometry {
+
+template<typename T>
+struct TUtil {
+ static inline T clamp(T v, T min, T max) {
+ if (v < min) {
+ return min;
+ }
+ if (v > max) {
+ return max;
+ }
+ return v;
+ }
+};
+
+template<>
+struct TUtil<f32> {
+ static inline f32 clamp(f32 v, f32 min, f32 max) {
+ if (v < min) {
+ return min;
+ }
+ if (v > max) {
+ return max;
+ }
+ return v;
+ }
+ static inline f32 epsilon() { return 32.0f * FLT_EPSILON; }
+ static inline f32 PI() { return 3.1415927f; }
+ static inline f32 inv_sqrt(f32 x) {
+ if (x <= 0.0f) {
+ return x;
+ }
+ f32 root = __frsqrte(x);
+ root = 0.5f * root * (3.0f - x * (root * root));
+ return root;
+ }
+};
+
+template<>
+struct TUtil<double> {
+ static inline double epsilon() { return 32.0f * FLT_EPSILON; }
+ static inline double one() { return 1.0; }
+ static inline double atan2(double x, double y) { return ::atan2(x, y); }
+ static inline double asin(double x) { return ::asin(x); }
+ static inline double halfPI() { return 1.5707963267948966; }
+};
+
+template <typename T>
+struct TVec3 {
+ T x;
+ T y;
+ T z;
+
+ void set(const TVec3& other) {
+ x = other.x;
+ y = other.y;
+ z = other.z;
+ }
+};
+
+template <>
+struct TVec3<double> {
+ double x, y, z;
+
+ void set(double x_, double y_, double z_) {
+ x = x_;
+ y = y_;
+ z = z_;
+ }
+
+ inline TVec3<double>& operator*=(double b) {
+ scale(b);
+ return *this;
+ }
+
+ void scale(double b) {
+ x *= b;
+ y *= b;
+ z *= b;
+ }
+};
+
+template <>
+struct TVec3<s16> {
+ s16 x, y, z;
+
+ TVec3() {}
+
+ TVec3(s16 x, s16 y, s16 z) {
+ set(x, y, z);
+ }
+
+ TVec3& operator=(const TVec3& b) {
+ // Force copies to use lwz/lha
+ *((s32*)this) = *((s32*)&b);
+ z = b.z;
+ return *this;
+ }
+
+ void set(s16 x_, s16 y_, s16 z_) {
+ x = x_;
+ y = y_;
+ z = z_;
+ }
+};
+
+inline void setTVec3f(const f32* vec_a, f32* vec_b) {
+ const register f32* v_a = vec_a;
+ register f32* v_b = vec_b;
+
+ register f32 a_x;
+ register f32 b_x;
+
+#ifdef __MWERKS__
+ asm {
+ psq_l a_x, 0(v_a), 0, 0
+ lfs b_x, 8(v_a)
+ psq_st a_x, 0(v_b), 0, 0
+ stfs b_x, 8(v_b)
+ };
+#endif
+}
+
+// Until we figure out TVec3 ctors
+inline void setTVec3f(const Vec& vec_a, Vec& vec_b) {
+ setTVec3f(&vec_a.x, &vec_b.x);
+}
+
+inline float fsqrt_step(float mag) {
+ f32 root = __frsqrte(mag);
+ return 0.5f * root * (3.0f - mag * (root * root));
+}
+
+inline void mulInternal(register const f32* a, register const f32* b, register float* dst) {
+ register f32 a_x_y;
+ register f32 b_x_y;
+ register f32 x_y;
+ register f32 za;
+ register f32 zb;
+ register f32 z;
+#ifdef __MWERKS__
+ asm {
+ psq_l a_x_y, 0(a), 0, 0
+ psq_l b_x_y, 0(b), 0, 0
+ ps_mul x_y, a_x_y, b_x_y
+ psq_st x_y, 0(dst), 0, 0
+ };
+ dst[2] = a[2] * b[2];
+#endif
+}
+
+template <>
+struct TVec3<f32> : public Vec {
+ inline TVec3(const Vec& i_vec) {
+ setTVec3f(&i_vec.x, &x);
+ }
+
+ inline TVec3(const TVec3<f32>& i_vec) {
+ setTVec3f(&i_vec.x, &x);
+ }
+
+ template<class U>
+ TVec3(U x, U y, U z) {
+ set(x, y, z);
+ }
+
+ TVec3() {}
+
+ operator Vec*() { return (Vec*)&x; }
+ operator const Vec*() const { return (Vec*)&x; }
+
+ template<class U>
+ void set(const TVec3<U>& other) {
+ x = other.x;
+ y = other.y;
+ z = other.z;
+ }
+
+ void set(const Vec& other) {
+ x = other.x;
+ y = other.y;
+ z = other.z;
+ }
+
+ template<class U>
+ void set(U x_, U y_, U z_) {
+ x = x_;
+ y = y_;
+ z = z_;
+ }
+
+ inline void add(const TVec3<f32>& b) {
+ JMathInlineVEC::C_VECAdd((Vec*)&x, (Vec*)&b.x, (Vec*)&x);
+ }
+
+ void zero() { x = y = z = 0.0f; }
+
+ void mul(const TVec3<f32>& a, const TVec3<f32>& b) {
+ mulInternal(&a.x, &b.x, &this->x);
+ }
+
+ inline void mul(const TVec3<f32>& a) {
+ mul(*this, a);
+ }
+
+ inline TVec3<f32>& operator=(const Vec& b) {
+ setTVec3f(&b.x, &this->x);
+ return *this;
+ }
+
+ inline TVec3<f32>& operator=(const TVec3<f32>& b) {
+ set(b.x, b.y, b.z);
+ return *this;
+ }
+
+ inline TVec3<f32>& operator+=(const TVec3<f32>& b) {
+ add(b);
+ return *this;
+ }
+
+ inline TVec3<f32> operator+(const TVec3<f32>& b) {
+ TVec3<f32> a = *this;
+ a += b;
+ return a;
+ }
+
+ // inline TVec3<f32> operator+(const TVec3<f32>& b) {
+ // TVec3<f32> res(*(Vec*)this);
+ // res += b;
+ // return res;
+ // }
+
+ f32 squared() const {
+ return JMathInlineVEC::C_VECSquareMag((Vec*)&x);
+ }
+
+ f32 normalize() {
+ f32 sq = squared();
+ if (sq <= TUtil<f32>::epsilon()) {
+ return 0.0f;
+ }
+ f32 inv_norm = TUtil<f32>::inv_sqrt(sq);
+ scale(inv_norm);
+ return inv_norm * sq;
+ }
+
+ void normalize(const TVec3<f32>& other) {
+ f32 sq = other.squared();
+ if (sq <= TUtil<f32>::epsilon()) {
+ zero();
+ return;
+ }
+ f32 norm;
+ if (sq <= 0.0f) {
+ norm = sq;
+ } else {
+ norm = fsqrt_step(sq);
+ }
+ scale(norm, other);
+ }
+
+ f32 length() const {
+ return VECMag((Vec*)this);
+ }
+
+ void scale(register f32 sc) {
+ register f32 z;
+ register f32 x_y;
+ register f32* dst = &x;
+ register f32 zres;
+#ifdef __MWERKS__
+ asm {
+ psq_l x_y, 0(dst), 0, 0
+ psq_l z, 8(dst), 1, 0
+ ps_muls0 x_y, x_y, sc
+ psq_st x_y, 0(dst), 0, 0
+ ps_muls0 zres, z, sc
+ psq_st zres, 8(dst), 1, 0
+ };
+#endif
+ }
+
+ void scale(register f32 sc, const TVec3<f32>& other) {
+ register const f32* src = &other.x;
+ register f32 z;
+ register f32 x_y;
+ register f32* dst = &x;
+ register f32 zres;
+#ifdef __MWERKS__
+ asm {
+ psq_l x_y, 0(src), 0, 0
+ psq_l z, 8(src), 1, 0
+ ps_muls0 x_y, x_y, sc
+ psq_st x_y, 0(dst), 0, 0
+ ps_muls0 zres, z, sc
+ psq_st zres, 8(dst), 1, 0
+ };
+#endif
+ }
+
+ void scaleAdd(register f32 sc, const TVec3<f32>& a, const TVec3<f32>& b) {
+ JMAVECScaleAdd(&a, &b, this, sc);
+ }
+
+ void negateInternal(TVec3<f32>* dst) {
+ register f32* rdst = &dst->x;
+ const register f32* src = &x;
+ register f32 x_y;
+ register f32 z;
+#ifdef __MWERKS__
+ asm {
+ psq_l x_y, 0(src), 0, 0
+ ps_neg x_y, x_y
+ psq_st x_y, 0(rdst), 0, 0
+ lfs z, 8(src)
+ fneg z, z
+ stfs z, 8(rdst)
+ };
+#endif
+ }
+
+ void negate() {
+ negateInternal(this);
+ }
+
+ void sub(const TVec3<f32>& b) {
+ JMathInlineVEC::C_VECSubtract((Vec*)&x, (Vec*)&b.x, (Vec*)&x);
+ }
+
+ void sub(const TVec3<f32>& a, const TVec3<f32>& b) {
+ JMathInlineVEC::C_VECSubtract((Vec*)&a.x, (Vec*)&b.x, (Vec*)&x);
+ }
+
+ bool isZero() const {
+ return squared() <= TUtil<f32>::epsilon();
+ }
+
+ void cross(const TVec3<f32>& a, const TVec3<f32>& b) {
+ VECCrossProduct(a, b, *this);
+ }
+
+ f32 setLength(f32 len) {
+ f32 sq = squared();
+ if (sq <= TUtil<f32>::epsilon()) {
+ return 0.0f;
+ }
+ f32 inv_norm = TUtil<f32>::inv_sqrt(sq);
+ scale(inv_norm * len);
+ return inv_norm * sq;
+ }
+
+ f32 setLength(const TVec3<f32>& other, f32 len) {
+ f32 sq = other.squared();
+ if (sq <= TUtil<f32>::epsilon()) {
+ zero();
+ return 0.0f;
+ }
+ f32 inv_norm = TUtil<f32>::inv_sqrt(sq);
+ scale(inv_norm * len, other);
+ return inv_norm * sq;
+ }
+
+ f32 dot(const TVec3<f32>& other) const {
+ return JMathInlineVEC::C_VECDotProduct(this, &other);
+ }
+
+ void cubic(const TVec3<f32>& param_1, const TVec3<f32>& param_2, const TVec3<f32>& param_3,
+ const TVec3<f32>& param_4, f32 param_5) {
+ f32 fVar5 = param_5 * param_5;
+ f32 fVar6 = fVar5 * param_5;
+ f32 fVar8 = 1.0f + (2.0f * fVar6 - 3.0f * fVar5);
+ f32 fVar9 = -2.0f * fVar6 + 3.0f * fVar5;
+ f32 fVar7 = param_5 + (fVar6 - 2.0f * fVar5);
+ f32 fVar4 = fVar6 - fVar5;
+ x = fVar8 * param_1.x + fVar9 * param_4.x + fVar7 * param_2.x + fVar4 * param_3.x;
+ y = fVar8 * param_1.y + fVar9 * param_4.y + fVar7 * param_2.y + fVar4 * param_3.y;
+ z = fVar8 * param_1.z + fVar9 * param_4.z + fVar7 * param_2.z + fVar4 * param_3.z;
+ }
+};
+
+template <typename T>
+struct TVec2 {
+ TVec2() {}
+ TVec2(T v) { set(v); }
+ TVec2(T x, T y) { set(x, y); }
+
+ void set(T v) { y = x = v; }
+
+ void set(T x, T y) {
+ this->x = x;
+ this->y = y;
+ }
+
+ void set(const TVec2& other) {
+ x = other.x;
+ y = other.y;
+ }
+
+ void setMin(const TVec2<f32>& min) {
+ if (x >= min.x)
+ x = min.x;
+ if (y >= min.y)
+ y = min.y;
+ }
+
+ void setMax(const TVec2<f32>& max) {
+ if (x <= max.x)
+ x = max.x;
+ if (y <= max.y)
+ y = max.y;
+ }
+
+ void add(const TVec2<T>& other) {
+ x += other.x;
+ y += other.y;
+ }
+
+ bool isAbove(const TVec2<T>& other) const {
+ return (x >= other.x) && (y >= other.y) ? true : false;
+ }
+
+ f32 dot(const TVec2<T>& other) const {
+ return x * other.x + y * other.y;
+ }
+
+ f32 squared() const {
+ return dot(*this);
+ }
+
+ f32 length() const {
+ f32 sqr = squared();
+ if (sqr <= 0.0f) {
+ return sqr;
+ }
+ sqr *= fsqrt_step(sqr);
+ return sqr;
+ }
+
+ T x;
+ T y;
+};
+
+template <class T>
+struct TBox {
+ TBox() : i(), f() {}
+ TBox(const TBox& other) : i(other.i), f(other.f) {}
+
+ T i, f;
+};
+
+// clang-format off
+template<> struct TBox<TVec2<f32> > {
+ f32 getWidth() const { return f.x - i.x; }
+ f32 getHeight() const { return f.y - i.y; }
+
+ bool isValid() const { return f.isAbove(i); }
+
+ void addPos(f32 x, f32 y) {
+ addPos(TVec2<f32>(x, y));
+ }
+
+ void addPos(const TVec2<f32>& pos) {
+ i.add(pos);
+ f.add(pos);
+ }
+
+ bool intersect(const TBox<TVec2<f32> >& other) {
+ i.setMax(other.i);
+ f.setMin(other.f);
+ return isValid();
+ }
+
+ TVec2<f32> i, f;
+};
+
+template <typename T>
+struct TBox2 : TBox<TVec2<T> > {
+ TBox2() {}
+ TBox2(const TVec2<f32>& i, const TVec2<f32>& f) { set(i, f); }
+ TBox2(f32 x0, f32 y0, f32 x1, f32 y1) { set(x0, y0, x1, y1); }
+
+ void absolute() {
+ if (!this->isValid()) {
+ TBox2<T> box(*this);
+ this->i.setMin(box.i);
+ this->i.setMin(box.f);
+ this->f.setMax(box.i);
+ this->f.setMax(box.f);
+ }
+ }
+
+ void set(const TBox2& other) { set(other.i, other.f); }
+ void set(const TVec2<f32>& i, const TVec2<f32>& f) { this->i.set(i), this->f.set(f); }
+ void set(f32 x0, f32 y0, f32 x1, f32 y1) { this->i.set(x0, y0); this->f.set(x1, y1); }
+};
+
+// clang-format on
+
+} // namespace JGeometry
+
+#endif
diff --git a/include/JSystem/JMath/JMATrigonometric.h b/include/JSystem/JMath/JMATrigonometric.h
new file mode 100644
index 00000000..2b162c56
--- /dev/null
+++ b/include/JSystem/JMath/JMATrigonometric.h
@@ -0,0 +1,136 @@
+#ifndef JMATRIGONOMETRIC_H
+#define JMATRIGONOMETRIC_H
+
+#include "dolphin/types.h"
+#include "utility.h"
+
+template<typename T>
+struct TAngleConstant_;
+
+/**
+ * @ingroup jsystem-jmath
+ *
+ */
+template<>
+struct TAngleConstant_<f32> {
+ static f32 RADIAN_DEG090() { return 1.5707964f; }
+ static f32 RADIAN_DEG180() { return 3.1415927f; }
+ static f32 RADIAN_DEG360() { return 6.2831855f; }
+ static f32 RADIAN_TO_DEGREE_FACTOR() { return 180.0f / RADIAN_DEG180(); }
+};
+
+/**
+ * @ingroup jsystem-jmath
+ *
+ */
+template<int N, typename T>
+struct TSinCosTable {
+ std::pair<T, T> table[1 << N];
+
+ T sinShort(s16 v) const { return table[(u16)v >> (16U - N)].first; }
+ T cosShort(s16 v) const { return table[(u16)v >> (16U - N)].second; }
+
+ inline T sinLap(T v) {
+ if (v < (T)0.0) {
+ return -table[(u16)(-(T)(1 << N) * v) & ((1 << N) - 1)].first;
+ }
+ return table[(u16)((T)(1 << N) * v) & ((1 << N) - 1)].first;
+ }
+
+ inline T sinDegree(T degree) {
+ if (degree < (T)0.0) {
+ return -table[(u16)(-((T)(1 << N) / (T)360.0) * degree) & ((1 << N) - 1)].first;
+ }
+ return table[(u16)(((T)(1 << N) / (T)360.0) * degree) & ((1 << N) - 1)].first;
+ }
+
+ inline T cosDegree(T degree) {
+ if (degree < (T)0.0) {
+ degree = -degree;
+ }
+ return table[(u16)(((T)(1 << N) / (T)360.0) * degree) & ((1 << N) - 1)].second;
+ }
+
+ inline T sinRadian(T radian) {
+ if (radian < (T)0.0) {
+ return -table[(u16)(-(T)(1 << N) / TAngleConstant_<T>::RADIAN_DEG360() * radian) & ((1 << N) - 1)].first;
+ }
+ return table[(u16)((T)(1 << N) / TAngleConstant_<T>::RADIAN_DEG360() * radian) & ((1 << N) - 1)].first;
+ }
+};
+
+/**
+ * @ingroup jsystem-jmath
+ *
+ */
+struct TAtanTable {
+ f32 table[1025];
+ u8 pad[0x1C];
+};
+
+/**
+ * @ingroup jsystem-jmath
+ *
+ */
+struct TAsinAcosTable {
+ f32 table[1025];
+ u8 pad[0x1C];
+
+ f32 acos_(f32 x) {
+ if (x >= 1.0f) {
+ return 0.0f;
+ } else if (x <= -1.0f) {
+ return TAngleConstant_<f32>::RADIAN_DEG180();
+ } else if (x < 0.0f) {
+ return table[(u32)(-x * 1023.5f)] + TAngleConstant_<f32>::RADIAN_DEG090();
+ } else {
+ return TAngleConstant_<f32>::RADIAN_DEG090() - table[(u32)(x * 1023.5f)];
+ }
+ }
+
+ f32 acosDegree(f32 x) {
+ return acos_(x) * TAngleConstant_<f32>::RADIAN_TO_DEGREE_FACTOR();
+ }
+};
+
+namespace JMath {
+extern TSinCosTable<13, f32> sincosTable_;
+extern TAtanTable atanTable_;
+extern TAsinAcosTable asinAcosTable_;
+
+inline f32 acosDegree(f32 x) {
+ return asinAcosTable_.acosDegree(x);
+}
+}; // namespace JMath
+
+inline f32 JMASCosShort(s16 v) {
+ return JMath::sincosTable_.cosShort(v);
+}
+inline f32 JMASinShort(s16 v) {
+ return JMath::sincosTable_.sinShort(v);
+}
+
+inline f32 JMASCos(s16 v) {
+ return JMASCosShort(v);
+}
+inline f32 JMASSin(s16 v) {
+ return JMASinShort(v);
+}
+
+inline f32 JMASinLap(f32 v) {
+ return JMath::sincosTable_.sinLap(v);
+}
+
+inline f32 JMASinDegree(f32 degree) {
+ return JMath::sincosTable_.sinDegree(degree);
+}
+
+inline f32 JMACosDegree(f32 degree) {
+ return JMath::sincosTable_.cosDegree(degree);
+}
+
+inline f32 JMASinRadian(f32 radian) {
+ return JMath::sincosTable_.sinRadian(radian);
+}
+
+#endif /* JMATRIGONOMETRIC_H */
diff --git a/include/JSystem/JMath/JMath.h b/include/JSystem/JMath/JMath.h
new file mode 100644
index 00000000..eb7932e8
--- /dev/null
+++ b/include/JSystem/JMath/JMath.h
@@ -0,0 +1,263 @@
+#ifndef JMATH_H
+#define JMATH_H
+
+#include "dolphin/mtx.h"
+#include "math.h"
+
+void JMAMTXApplyScale(const Mtx, Mtx, f32, f32, f32);
+void JMAEulerToQuat(s16 param_0, s16 param_1, s16 param_2, Quaternion* param_3);
+void JMAQuatLerp(const Quaternion*, const Quaternion*, f32, Quaternion*);
+void JMAFastVECNormalize(register const Vec* src, register Vec* dst);
+void JMAVECScaleAdd(register const Vec* vec1, register const Vec* vec2, register Vec* dst,
+ register f32 scale);
+
+inline int JMAAbs(int value) {
+ return __abs(value);
+}
+
+inline f32 JMAFastReciprocal(f32 value) {
+ return __fres(value);
+}
+
+inline float __frsqrtes(register double f) {
+ register float out;
+ // clang-format off
+#ifdef __MWERKS__
+ asm {
+ frsqrte out, f
+ }
+#endif
+ // clang-format on
+ return out;
+}
+
+inline f32 JMAFastSqrt(register f32 input) {
+ if (input > 0.0f) {
+ register f32 out;
+#ifdef __MWERKS__
+ asm {
+ frsqrte out, input
+ }
+#endif
+ return out * input;
+ } else {
+ return input;
+ }
+}
+
+inline f32 JMAHermiteInterpolation(register f32 p1, register f32 p2, register f32 p3,
+ register f32 p4, register f32 p5, register f32 p6,
+ register f32 p7) {
+ register f32 ff25;
+ register f32 ff31;
+ register f32 ff30;
+ register f32 ff29;
+ register f32 ff28;
+ register f32 ff27;
+ register f32 ff26;
+ // clang-format off
+#ifdef __MWERKS__
+ asm {
+ fsubs ff31, p1, p2
+ fsubs ff30, p5, p2
+ fdivs ff29, ff31, ff30
+ fmuls ff28,ff29,ff29
+ fadds ff25,ff29,ff29
+ fsubs ff27,ff28,ff29
+ fsubs ff30, p3, p6
+ fmsubs ff26,ff25,ff27,ff28
+ fmadds ff25,p4,ff27,p4
+ fmadds ff26,ff26,ff30,p3
+ fmadds ff25,p7,ff27,ff25
+ fmsubs ff25,ff29,p4,ff25
+ fnmsubs ff25,ff31,ff25,ff26
+
+ }
+#endif
+ // clang-format on
+ return ff25;
+}
+
+namespace JMath {
+
+inline f32 fastReciprocal(f32 value) {
+ return JMAFastReciprocal(value);
+}
+
+inline void gekko_ps_copy3(register void* dst, register const void* src) {
+ register f32 src0;
+ register f32 src1;
+#ifdef __MWERKS__
+ asm {
+ psq_l src0, 0(src), 0, 0
+ lfs src1, 8(src)
+ psq_st src0, 0(dst), 0, 0
+ stfs src1, 8(dst)
+ };
+#endif
+}
+
+inline void gekko_ps_copy6(register void* dst, register const void* src) {
+ register f32 src0;
+ register f32 src1;
+ register f32 src2;
+#ifdef __MWERKS__
+ asm {
+ psq_l src0, 0(src), 0, 0
+ psq_l src1, 8(src), 0, 0
+ psq_l src2, 16(src), 0, 0
+ psq_st src0, 0(dst), 0, 0
+ psq_st src1, 8(dst), 0, 0
+ psq_st src2, 16(dst), 0, 0
+ };
+#endif
+}
+
+inline void gekko_ps_copy12(register void* dst, register const void* src) {
+ register f32 src0;
+ register f32 src1;
+ register f32 src2;
+ register f32 src3;
+ register f32 src4;
+ register f32 src5;
+#ifdef __MWERKS__
+ asm {
+ psq_l src0, 0(src), 0, 0
+ psq_l src1, 8(src), 0, 0
+ psq_l src2, 16(src), 0, 0
+ psq_l src3, 24(src), 0, 0
+ psq_l src4, 32(src), 0, 0
+ psq_l src5, 40(src), 0, 0
+ psq_st src0, 0(dst), 0, 0
+ psq_st src1, 8(dst), 0, 0
+ psq_st src2, 16(dst), 0, 0
+ psq_st src3, 24(dst), 0, 0
+ psq_st src4, 32(dst), 0, 0
+ psq_st src5, 40(dst), 0, 0
+ };
+#endif
+}
+
+inline void gekko_ps_copy16(register void* dst, register const void* src) {
+ register f32 src0;
+ register f32 src1;
+ register f32 src2;
+ register f32 src3;
+ register f32 src4;
+ register f32 src5;
+ register f32 src6;
+ register f32 src7;
+#ifdef __MWERKS__
+ asm {
+ psq_l src0, 0(src), 0, 0
+ psq_l src1, 8(src), 0, 0
+ psq_l src2, 16(src), 0, 0
+ psq_l src3, 24(src), 0, 0
+ psq_l src4, 32(src), 0, 0
+ psq_l src5, 40(src), 0, 0
+ psq_l src6, 48(src), 0, 0
+ psq_l src7, 56(src), 0, 0
+ psq_st src0, 0(dst), 0, 0
+ psq_st src1, 8(dst), 0, 0
+ psq_st src2, 16(dst), 0, 0
+ psq_st src3, 24(dst), 0, 0
+ psq_st src4, 32(dst), 0, 0
+ psq_st src5, 40(dst), 0, 0
+ psq_st src6, 48(dst), 0, 0
+ psq_st src7, 56(dst), 0, 0
+ };
+#endif
+}
+
+}; // namespace JMath
+
+namespace JMathInlineVEC {
+ inline void C_VECAdd(register const Vec* a, register const Vec* b, register Vec* ab) {
+ register f32 axy;
+ register f32 bxy;
+ register f32 az;
+ register f32 sumz;
+ register f32 bz;
+ #ifdef __MWERKS__
+ asm {
+ psq_l axy, 0(a), 0, 0
+ psq_l bxy, 0(b), 0, 0
+ ps_add bxy, axy, bxy
+ psq_st bxy, 0(ab), 0, 0
+ psq_l az, 8(a), 1, 0
+ psq_l bz, 8(b), 1, 0
+ ps_add sumz, az, bz
+ psq_st sumz, 8(ab), 1, 0
+ }
+ #endif
+ }
+
+ inline void C_VECSubtract(register const Vec* a, register const Vec* b, register Vec* ab) {
+ register f32 axy;
+ register f32 bxy;
+ register f32 az;
+ register f32 subz;
+ register f32 bz;
+ #ifdef __MWERKS__
+ asm {
+ psq_l axy, 0(a), 0, 0
+ psq_l bxy, 0(b), 0, 0
+ ps_sub bxy, axy, bxy
+ psq_st bxy, 0(ab), 0, 0
+ psq_l az, 8(a), 1, 0
+ psq_l bz, 8(b), 1, 0
+ ps_sub subz, az, bz
+ psq_st subz, 8(ab), 1, 0
+ }
+ #endif
+ }
+
+ inline f32 C_VECSquareMag(register const Vec* v) {
+ register f32 x_y;
+ register f32 z;
+ register f32 res;
+ #ifdef __MWERKS__
+ asm {
+ psq_l x_y, 0(v), 0, 0
+ ps_mul x_y, x_y, x_y
+ lfs z, 8(v)
+ ps_madd res, z, z, x_y
+ ps_sum0 res, res, x_y, x_y
+ }
+ #endif
+ return res;
+ }
+
+ inline f32 C_VECDotProduct(register const Vec *a, register const Vec *b) {
+ register f32 res;
+ register f32 thisyz;
+ register f32 otheryz;
+ register f32 otherxy;
+ register f32 thisxy;
+#ifdef __MWERKS__
+ asm {
+ psq_l thisyz, 4(a), 0, 0
+ psq_l otheryz, 4(b), 0, 0
+ ps_mul thisyz, thisyz, otheryz
+ psq_l thisxy, 0(a), 0, 0
+ psq_l otherxy, 0(b), 0, 0
+ ps_madd otheryz, thisxy, otherxy, thisyz
+ ps_sum0 res, otheryz, thisyz, thisyz
+ };
+#endif
+ return res;
+ }
+};
+
+template<typename T>
+inline T JMAMax(T param_0, T param_1) {
+ T ret;
+ if (param_0 > param_1) {
+ ret = param_0;
+ } else {
+ ret = param_1;
+ }
+ return ret;
+}
+
+#endif /* JMATH_H */
diff --git a/include/JSystem/JMath/random.h b/include/JSystem/JMath/random.h
new file mode 100644
index 00000000..cfb8ecc1
--- /dev/null
+++ b/include/JSystem/JMath/random.h
@@ -0,0 +1,51 @@
+#ifndef RANDOM_H
+#define RANDOM_H
+
+#include "dolphin/types.h"
+
+namespace JMath {
+
+/**
+ * @ingroup jsystem-jmath
+ *
+ */
+struct TRandom_fast_ {
+ u32 value;
+
+ TRandom_fast_(u32 value);
+ u32 get(void) {
+ value = (value * 0x19660d) + 0x3c6ef35f;
+ return value;
+ }
+
+ u32 get_bit32(void) { return this->get(); }
+
+ // due to the float constant, having this function inlined adds that float to data,
+ // making it not match
+ float get_ufloat_1(void) {
+ // !@bug UB: in C++ it's not legal to read from an union member other
+ // than the last one that was written to.
+ union {
+ f32 f;
+ u32 s;
+ } out;
+ out.s = (this->get() >> 9) | 0x3f800000;
+ return out.f - 1;
+ }
+
+ void setSeed(u32 seed) { value = seed; }
+};
+
+template <class RandomT>
+class TRandom_ : public RandomT {
+public:
+ TRandom_(u32 value) : RandomT(value) {}
+
+ u8 get_uint8(u8 param_0) {
+ return get_ufloat_1() * param_0;
+ }
+};
+
+} // namespace JMath
+
+#endif /* RANDOM_H */
diff --git a/include/JSystem/JParticle/JPABaseShape.h b/include/JSystem/JParticle/JPABaseShape.h
new file mode 100644
index 00000000..3ebff452
--- /dev/null
+++ b/include/JSystem/JParticle/JPABaseShape.h
@@ -0,0 +1,210 @@
+#ifndef JPABASESHAPE_H
+#define JPABASESHAPE_H
+
+#include <dolphin/gx.h>
+
+class JPAEmitterWorkData;
+class JPABaseParticle;
+class JKRHeap;
+
+/**
+ * @ingroup jsystem-jparticle
+ *
+ */
+struct JPABaseShapeData {
+ // Common header.
+ /* 0x00 */ u8 mMagic[4];
+ /* 0x04 */ u32 mSize;
+
+ /* 0x08 */ u32 mFlags;
+ /* 0x0C */ s16 mClrPrmAnmOffset;
+ /* 0x0E */ s16 mClrEnvAnmOffset;
+ /* 0x10 */ f32 mBaseSizeX;
+ /* 0x14 */ f32 mBaseSizeY;
+ /* 0x18 */ u16 mBlendModeCfg;
+ /* 0x1A */ u8 mAlphaCompareCfg;
+ /* 0x1B */ u8 mAlphaRef0;
+ /* 0x1C */ u8 mAlphaRef1;
+ /* 0x1D */ u8 mZModeCfg;
+ /* 0x1E */ u8 mTexFlg;
+ /* 0x1F */ u8 mTexAnmNum;
+ /* 0x20 */ u8 mTexIdx;
+ /* 0x21 */ u8 mClrFlg;
+ /* 0x22 */ u8 mClrPrmKeyNum;
+ /* 0x23 */ u8 mClrEnvKeyNum;
+ /* 0x24 */ s16 mClrAnmFrmMax;
+ /* 0x26 */ GXColor mClrPrm;
+ /* 0x2A */ GXColor mClrEnv;
+ /* 0x2E */ u8 mAnmRndm;
+ /* 0x2F */ u8 mClrAnmRndmMask;
+ /* 0x30 */ u8 mTexAnmRndmMask;
+};
+
+/**
+ * @ingroup jsystem-jparticle
+ *
+ */
+struct JPABaseShape {
+public:
+ /* 8027A6DC */ JPABaseShape(u8 const*, JKRHeap*);
+ /* 8027A7E8 */ void setGX(JPAEmitterWorkData*) const;
+
+ static GXBlendMode st_bm[3];
+ static GXBlendFactor st_bf[10];
+ static GXLogicOp st_lo[16];
+ static GXCompare st_c[8];
+ static GXAlphaOp st_ao[4];
+ static GXTevColorArg st_ca[6][4];
+ static GXTevAlphaArg st_aa[2][4];
+
+ GXBlendMode getBlendMode() const { return st_bm[mpData->mBlendModeCfg & 0x03]; }
+ GXBlendFactor getBlendSrc() const { return st_bf[(mpData->mBlendModeCfg >> 2) & 0x0F]; }
+ GXBlendFactor getBlendDst() const { return st_bf[(mpData->mBlendModeCfg >> 6) & 0x0F]; }
+ GXLogicOp getLogicOp() const { return st_lo[(mpData->mBlendModeCfg >> 10) & 0x0F]; }
+ GXBool getZCompLoc() const { return (GXBool)((mpData->mZModeCfg >> 5) & 0x01); }
+
+ GXBool getZEnable() const { return (GXBool)(mpData->mZModeCfg & 0x01); }
+ GXCompare getZCmp() const { return st_c[(mpData->mZModeCfg >> 1) & 0x07]; }
+ GXBool getZUpd() const { return (GXBool)((mpData->mZModeCfg >> 4) & 0x01); }
+
+ GXCompare getAlphaCmp0() const { return st_c[mpData->mAlphaCompareCfg & 0x07]; }
+ u8 getAlphaRef0() const { return mpData->mAlphaRef0; }
+ GXAlphaOp getAlphaOp() const { return st_ao[(mpData->mAlphaCompareCfg >> 3) & 0x03]; }
+ GXCompare getAlphaCmp1() const { return st_c[(mpData->mAlphaCompareCfg >> 5) & 0x07]; }
+ u8 getAlphaRef1() const { return mpData->mAlphaRef1; }
+
+ const GXTevColorArg* getTevColorArg() const { return st_ca[(mpData->mFlags >> 0x0F) & 0x07]; }
+ const GXTevAlphaArg* getTevAlphaArg() const { return st_aa[(mpData->mFlags >> 0x12) & 0x01]; }
+
+ u32 getType() const { return (mpData->mFlags >> 0) & 0x0F; }
+ u32 getDirType() const { return (mpData->mFlags >> 4) & 0x07; }
+ u32 getRotType() const { return (mpData->mFlags >> 7) & 0x07; }
+ u32 getBasePlaneType() const { return (mpData->mFlags >> 10) & 0x01; }
+ u32 getTilingS() const { return (mpData->mFlags >> 25) & 0x01; }
+ u32 getTilingT() const { return (mpData->mFlags >> 26) & 0x01; }
+ BOOL isGlblClrAnm() const { return mpData->mFlags & 0x00001000; }
+ BOOL isGlblTexAnm() const { return mpData->mFlags & 0x00004000; }
+ BOOL isPrjTex() const { return mpData->mFlags & 0x00100000; }
+ bool isDrawFwdAhead() const { return !!(mpData->mFlags & 0x00200000); }
+ bool isDrawPrntAhead() const { return !!(mpData->mFlags & 0x00400000); }
+ bool isClipOn() const { return !!(mpData->mFlags & 0x00800000); }
+ BOOL isTexCrdAnm() const { return mpData->mFlags & 0x01000000; }
+ bool isNoDrawParent() const { return !!(mpData->mFlags & 0x08000000); }
+ bool isNoDrawChild() const { return !!(mpData->mFlags & 0x10000000); }
+
+ BOOL isPrmAnm() const { return mpData->mClrFlg & 0x02; }
+ BOOL isEnvAnm() const { return mpData->mClrFlg & 0x08; }
+ u8 getClrAnmType() const { return (mpData->mClrFlg >> 4) & 0x07; }
+ s16 getClrAnmMaxFrm() const { return mpData->mClrAnmFrmMax; }
+ void getPrmClr(GXColor* dst) { *dst = mpData->mClrPrm; }
+ void getPrmClr(s16 idx, GXColor* dst) { *dst = mpPrmClrAnmTbl[idx]; }
+ void getEnvClr(GXColor* dst) { *dst = mpData->mClrEnv; }
+ void getEnvClr(s16 idx, GXColor* dst) { *dst = mpEnvClrAnmTbl[idx]; }
+
+ BOOL isTexAnm() const { return mpData->mTexFlg & 0x01; }
+ u8 getTexAnmType() const { return (mpData->mTexFlg >> 2) & 0x07; }
+ u32 getTexIdx() const { return mpData->mTexIdx; }
+ u8 getTexIdx(u8 idx) const { return mpTexIdxAnimTbl[idx]; }
+
+ f32 getBaseSizeX() const { return mpData->mBaseSizeX; }
+ f32 getBaseSizeY() const { return mpData->mBaseSizeY; }
+ u8 getClrLoopOfstMask() const { return mpData->mClrAnmRndmMask; }
+ u32 getClrLoopOfst(u32 param_1) const { return getClrLoopOfstMask() & param_1; }
+ u8 getTexLoopOfstMask() const { return mpData->mTexAnmRndmMask; }
+ u32 getTexLoopOfst(u8 param_1) const { return getTexLoopOfstMask() & param_1; }
+ u8 getLoopOfstValue() const { return mpData->mAnmRndm; }
+
+ f32 getIncTransX() const { return ((f32*)mpTexCrdMtxAnmTbl)[5]; }
+ f32 getInitTransX() const { return ((f32*)mpTexCrdMtxAnmTbl)[0]; }
+ f32 getIncTransY() const { return ((f32*)mpTexCrdMtxAnmTbl)[6]; }
+ f32 getInitTransY() const { return ((f32*)mpTexCrdMtxAnmTbl)[1]; }
+ f32 getIncScaleX() const { return ((f32*)mpTexCrdMtxAnmTbl)[7]; }
+ f32 getInitScaleX() const { return ((f32*)mpTexCrdMtxAnmTbl)[2]; }
+ f32 getIncScaleY() const { return ((f32*)mpTexCrdMtxAnmTbl)[8]; }
+ f32 getInitScaleY() const { return ((f32*)mpTexCrdMtxAnmTbl)[3]; }
+ f32 getIncRot() const { return ((f32*)mpTexCrdMtxAnmTbl)[9]; }
+ f32 getInitRot() const { return ((f32*)mpTexCrdMtxAnmTbl)[4]; }
+ u8 getTexAnmKeyNum() const { return mpData->mTexAnmNum; }
+
+public:
+ /* 0x00 */ const JPABaseShapeData* mpData;
+ /* 0x04 */ const void* mpTexCrdMtxAnmTbl;
+ /* 0x08 */ const u8* mpTexIdxAnimTbl;
+ /* 0x0C */ GXColor* mpPrmClrAnmTbl;
+ /* 0x10 */ GXColor* mpEnvClrAnmTbl;
+};
+
+/**
+ * @ingroup jsystem-jparticle
+ *
+ */
+struct JPAClrAnmKeyData {
+ /* 0x0 */ s16 index;
+ /* 0x2 */ GXColor color;
+};
+
+void JPACalcTexIdxNormal(JPAEmitterWorkData*);
+void JPACalcTexIdxRepeat(JPAEmitterWorkData*);
+void JPACalcTexIdxReverse(JPAEmitterWorkData*);
+void JPACalcTexIdxMerge(JPAEmitterWorkData*);
+void JPACalcTexIdxRandom(JPAEmitterWorkData*);
+void JPACalcPrm(JPAEmitterWorkData*);
+void JPACalcEnv(JPAEmitterWorkData*);
+void JPACalcClrIdxNormal(JPAEmitterWorkData*);
+void JPACalcClrIdxRepeat(JPAEmitterWorkData*);
+void JPACalcClrIdxReverse(JPAEmitterWorkData*);
+void JPACalcClrIdxMerge(JPAEmitterWorkData*);
+void JPACalcClrIdxRandom(JPAEmitterWorkData*);
+
+void JPACalcTexIdxNormal(JPAEmitterWorkData*, JPABaseParticle*);
+void JPACalcTexIdxRepeat(JPAEmitterWorkData*, JPABaseParticle*);
+void JPACalcTexIdxReverse(JPAEmitterWorkData*, JPABaseParticle*);
+void JPACalcTexIdxMerge(JPAEmitterWorkData*, JPABaseParticle*);
+void JPACalcTexIdxRandom(JPAEmitterWorkData*, JPABaseParticle*);
+void JPACalcPrm(JPAEmitterWorkData*, JPABaseParticle*);
+void JPACalcEnv(JPAEmitterWorkData*, JPABaseParticle*);
+void JPACalcClrIdxNormal(JPAEmitterWorkData*, JPABaseParticle*);
+void JPACalcClrIdxRepeat(JPAEmitterWorkData*, JPABaseParticle*);
+void JPACalcClrIdxReverse(JPAEmitterWorkData*, JPABaseParticle*);
+void JPACalcClrIdxMerge(JPAEmitterWorkData*, JPABaseParticle*);
+void JPACalcClrIdxRandom(JPAEmitterWorkData*, JPABaseParticle*);
+void JPACalcColorCopy(JPAEmitterWorkData*, JPABaseParticle*);
+
+void JPADrawStripe(JPAEmitterWorkData*);
+void JPADrawStripeX(JPAEmitterWorkData*);
+void JPADrawEmitterCallBackB(JPAEmitterWorkData*);
+void JPALoadTex(JPAEmitterWorkData*);
+void JPALoadTexAnm(JPAEmitterWorkData*);
+void JPAGenTexCrdMtxIdt(JPAEmitterWorkData*);
+void JPAGenCalcTexCrdMtxAnm(JPAEmitterWorkData*);
+void JPAGenTexCrdMtxAnm(JPAEmitterWorkData*);
+void JPAGenTexCrdMtxPrj(JPAEmitterWorkData*);
+void JPALoadPosMtxCam(JPAEmitterWorkData*);
+void JPASetLineWidth(JPAEmitterWorkData*);
+void JPASetPointSize(JPAEmitterWorkData*);
+void JPARegistPrm(JPAEmitterWorkData*);
+void JPARegistEnv(JPAEmitterWorkData*);
+void JPARegistPrmEnv(JPAEmitterWorkData*);
+
+void JPADrawPoint(JPAEmitterWorkData*, JPABaseParticle*);
+void JPADrawLine(JPAEmitterWorkData*, JPABaseParticle*);
+void JPADrawRotBillboard(JPAEmitterWorkData*, JPABaseParticle*);
+void JPADrawBillboard(JPAEmitterWorkData*, JPABaseParticle*);
+void JPADrawRotDirection(JPAEmitterWorkData*, JPABaseParticle*);
+void JPADrawDirection(JPAEmitterWorkData*, JPABaseParticle*);
+void JPADrawRotation(JPAEmitterWorkData*, JPABaseParticle*);
+void JPADrawDBillboard(JPAEmitterWorkData*, JPABaseParticle*);
+void JPADrawRotYBillboard(JPAEmitterWorkData*, JPABaseParticle*);
+void JPADrawYBillboard(JPAEmitterWorkData*, JPABaseParticle*);
+void JPADrawParticleCallBack(JPAEmitterWorkData*, JPABaseParticle*);
+void JPALoadTexAnm(JPAEmitterWorkData*, JPABaseParticle*);
+void JPASetPointSize(JPAEmitterWorkData*, JPABaseParticle*);
+void JPASetLineWidth(JPAEmitterWorkData*, JPABaseParticle*);
+void JPALoadCalcTexCrdMtxAnm(JPAEmitterWorkData*, JPABaseParticle*);
+void JPARegistAlpha(JPAEmitterWorkData*, JPABaseParticle*);
+void JPARegistEnv(JPAEmitterWorkData*, JPABaseParticle*);
+void JPARegistAlphaEnv(JPAEmitterWorkData*, JPABaseParticle*);
+void JPARegistPrmAlpha(JPAEmitterWorkData*, JPABaseParticle*);
+void JPARegistPrmAlphaEnv(JPAEmitterWorkData*, JPABaseParticle*);
+
+#endif /* JPABASESHAPE_H */
diff --git a/include/JSystem/JParticle/JPAChildShape.h b/include/JSystem/JParticle/JPAChildShape.h
new file mode 100644
index 00000000..2761a567
--- /dev/null
+++ b/include/JSystem/JParticle/JPAChildShape.h
@@ -0,0 +1,89 @@
+#ifndef JPACHILDSHAPE_H
+#define JPACHILDSHAPE_H
+
+#include <dolphin/gx.h>
+
+class JPAEmitterWorkData;
+class JPABaseParticle;
+
+/**
+ * @ingroup jsystem-jparticle
+ *
+ */
+struct JPAChildShapeData {
+ // Common header.
+ /* 0x00 */ u8 mMagic[4];
+ /* 0x04 */ u32 mSize;
+
+ /* 0x08 */ u32 mFlags;
+ /* 0x0C */ f32 mPosRndm;
+ /* 0x10 */ f32 mBaseVel;
+ /* 0x14 */ f32 mBaseVelRndm;
+ /* 0x18 */ f32 mVelInfRate;
+ /* 0x1C */ f32 mGravity;
+ /* 0x20 */ f32 mScaleX;
+ /* 0x24 */ f32 mScaleY;
+ /* 0x28 */ f32 mInheritScale;
+ /* 0x2C */ f32 mInheritAlpha;
+ /* 0x30 */ f32 mInheritRGB;
+ /* 0x34 */ GXColor mPrmClr;
+ /* 0x38 */ GXColor mEnvClr;
+ /* 0x3C */ f32 mTiming;
+ /* 0x40 */ s16 mLife;
+ /* 0x42 */ s16 mRate;
+ /* 0x44 */ u8 mStep;
+ /* 0x45 */ u8 mTexIdx;
+ /* 0x46 */ s16 mRotSpeed;
+};
+
+/**
+ * @ingroup jsystem-jparticle
+ *
+ */
+class JPAChildShape {
+public:
+ /* 8027B038 */ JPAChildShape(u8 const*);
+
+ f32 getPosRndm() const { return mpData->mPosRndm; }
+ f32 getBaseVel() const { return mpData->mBaseVel; }
+ f32 getBaseVelRndm() const { return mpData->mBaseVelRndm; }
+ f32 getVelInhRate() const { return mpData->mVelInfRate; }
+ f32 getGravity() const { return mpData->mGravity; }
+ f32 getScaleX() const { return mpData->mScaleX; }
+ f32 getScaleY() const { return mpData->mScaleY; }
+ f32 getScaleInhRate() const { return mpData->mInheritScale; }
+ f32 getAlphaInhRate() const { return mpData->mInheritAlpha; }
+ f32 getColorInhRate() const { return mpData->mInheritRGB; }
+ void getPrmClr(GXColor* dst) const { *dst = mpData->mPrmClr; }
+ u8 getPrmAlpha() const { return mpData->mPrmClr.a; }
+ void getEnvClr(GXColor* dst) const { *dst = mpData->mEnvClr; }
+ f32 getTiming() const { return mpData->mTiming; }
+ s16 getLife() const { return mpData->mLife; }
+ s16 getRate() const { return mpData->mRate; }
+ u8 getStep() const { return mpData->mStep; }
+ u8 getTexIdx() const { return mpData->mTexIdx; }
+ s16 getRotInitSpeed() const { return mpData->mRotSpeed; }
+ u32 getType() const { return mpData->mFlags & 0xF; }
+ u32 getDirType() const { return (mpData->mFlags >> 4) & 7; }
+ u32 getRotType() const { return (mpData->mFlags >> 7) & 7; }
+ u32 getBasePlaneType() const { return (mpData->mFlags >> 10) & 1; }
+
+ BOOL isScaleInherited() const { return mpData->mFlags & 0x10000; }
+ BOOL isAlphaInherited() const { return mpData->mFlags & 0x20000; }
+ BOOL isColorInherited() const { return mpData->mFlags & 0x40000; }
+ BOOL isClipOn() const { return mpData->mFlags & 0x100000; }
+ BOOL isFieldAffected() const { return mpData->mFlags & 0x200000; }
+ BOOL isScaleOutOn() const { return mpData->mFlags & 0x400000; }
+ BOOL isAlphaOutOn() const { return mpData->mFlags & 0x800000; }
+ BOOL isRotateOn() const { return mpData->mFlags & 0x1000000; }
+
+public:
+ /* 0x00 */ const JPAChildShapeData* mpData;
+};
+
+void JPARegistChildPrmEnv(JPAEmitterWorkData*);
+
+void JPACalcChildAlphaOut(JPAEmitterWorkData*, JPABaseParticle*);
+void JPACalcChildScaleOut(JPAEmitterWorkData*, JPABaseParticle*);
+
+#endif /* JPACHILDSHAPE_H */
diff --git a/include/JSystem/JParticle/JPADrawInfo.h b/include/JSystem/JParticle/JPADrawInfo.h
new file mode 100644
index 00000000..061783af
--- /dev/null
+++ b/include/JSystem/JParticle/JPADrawInfo.h
@@ -0,0 +1,29 @@
+#ifndef JPADRAWINFO_H
+#define JPADRAWINFO_H
+
+#include "dolphin/mtx.h"
+
+/**
+ * @ingroup jsystem-jparticle
+ *
+ */
+class JPADrawInfo {
+public:
+ JPADrawInfo(Mtx param_0, f32 fovY, f32 aspect) {
+ MTXCopy(param_0, mCamMtx);
+ C_MTXLightPerspective(mPrjMtx, fovY, aspect, 0.5f, -0.5f, 0.5f, 0.5f);
+ }
+
+ JPADrawInfo(Mtx param_0, f32 top, f32 bottom, f32 left, f32 right) {
+ MTXCopy(param_0, mCamMtx);
+ C_MTXLightOrtho(mPrjMtx, top, bottom, left, right, 0.5f, 0.5f, 0.5f, 0.5f);
+ }
+
+ Mtx mCamMtx;
+ Mtx mPrjMtx;
+
+ void getCamMtx(Mtx dst) const { MTXCopy(mCamMtx, dst); }
+ void getPrjMtx(Mtx dst) const { MTXCopy(mPrjMtx, dst); }
+};
+
+#endif
diff --git a/include/JSystem/JParticle/JPADynamicsBlock.h b/include/JSystem/JParticle/JPADynamicsBlock.h
new file mode 100644
index 00000000..fc175ff6
--- /dev/null
+++ b/include/JSystem/JParticle/JPADynamicsBlock.h
@@ -0,0 +1,109 @@
+#ifndef JPADYNAMICSBLOCK_H
+#define JPADYNAMICSBLOCK_H
+
+#include "JSystem/JGeometry.h"
+
+#include "dolphin/types.h"
+
+class JPAEmitterWorkData;
+
+/**
+ * @ingroup jsystem-jparticle
+ *
+ */
+struct JPADynamicsBlockData {
+ // Common header.
+ /* 0x00 */ u8 mMagic[4];
+ /* 0x04 */ u32 mSize;
+
+ /* 0x08 */ u32 mFlags;
+ /* 0x0C */ u32 mResUserWork;
+ /* 0x10 */ JGeometry::TVec3<f32> mEmitterScl;
+ /* 0x1C */ JGeometry::TVec3<f32> mEmitterTrs;
+ /* 0x28 */ JGeometry::TVec3<f32> mEmitterDir;
+ /* 0x34 */ f32 mInitialVelOmni;
+ /* 0x38 */ f32 mInitialVelAxis;
+ /* 0x3C */ f32 mInitialVelRndm;
+ /* 0x40 */ f32 mInitialVelDir;
+ /* 0x44 */ f32 mSpread;
+ /* 0x48 */ f32 mInitialVelRatio;
+ /* 0x4C */ f32 mRate;
+ /* 0x50 */ f32 mRateRndm;
+ /* 0x54 */ f32 mLifeTimeRndm;
+ /* 0x58 */ f32 mVolumeSweep;
+ /* 0x5C */ f32 mVolumeMinRad;
+ /* 0x60 */ f32 mAirResist;
+ /* 0x64 */ f32 mMoment;
+ /* 0x68 */ JGeometry::TVec3<s16> mEmitterRot;
+ /* 0x6E */ s16 mMaxFrame;
+ /* 0x70 */ s16 mStartFrame;
+ /* 0x72 */ s16 mLifeTime;
+ /* 0x74 */ u16 mVolumeSize;
+ /* 0x76 */ u16 mDivNumber;
+ /* 0x78 */ u8 mRateStep;
+ /* 0x7C */ u32 field_0x7c;
+};
+
+typedef void (*JPADynamicsCalcVolumeFunc)(JPAEmitterWorkData*);
+
+enum {
+ JPADynFlag_FixedDensity = 0x01,
+ JPADynFlag_FixedInterval = 0x02,
+ JPADynFlag_InheritScale = 0x04,
+ JPADynFlag_FollowEmtr = 0x08,
+ JPADynFlag_FollowEmtrChld = 0x10,
+};
+
+/**
+ * @ingroup jsystem-jparticle
+ *
+ */
+class JPADynamicsBlock {
+public:
+ /* 8027BB18 */ JPADynamicsBlock(u8 const*);
+ /* 8027BB4C */ void init();
+ /* 8027BBE8 */ void create(JPAEmitterWorkData*);
+
+ void calc(JPAEmitterWorkData* work) { mpCalcVolumeFunc(work); }
+
+ s16 getStartFrame() const { return mpData->mStartFrame; }
+ u32 getResUserWork() const { return mpData->mResUserWork; }
+ u32 getFlag() const { return mpData->mFlags; }
+ u32 getVolumeType() const { return (mpData->mFlags >> 8) & 0x07; }
+ u16 getDivNumber() const { return mpData->mDivNumber; }
+ f32 getRateRndm() const { return mpData->mRateRndm; }
+ void getEmitterScl(JGeometry::TVec3<f32>* vec) const {
+ vec->set(mpData->mEmitterScl.x, mpData->mEmitterScl.y, mpData->mEmitterScl.z);
+ }
+ void getEmitterTrs(JGeometry::TVec3<f32>* vec) const {
+ vec->set(mpData->mEmitterTrs.x, mpData->mEmitterTrs.y, mpData->mEmitterTrs.z);
+ }
+ void getEmitterDir(JGeometry::TVec3<f32>* vec) const {
+ vec->set(mpData->mEmitterDir.x, mpData->mEmitterDir.y, mpData->mEmitterDir.z);
+ }
+ void getEmitterRot(JGeometry::TVec3<s16>* vec) const {
+ vec->set(mpData->mEmitterRot.x, mpData->mEmitterRot.y, mpData->mEmitterRot.z);
+ }
+ s16 getMaxFrame() { return mpData->mMaxFrame; }
+ s16 getLifetime() { return mpData->mLifeTime; }
+ u16 getVolumeSize() { return mpData->mVolumeSize; }
+ f32 getRate() { return mpData->mRate; }
+ u8 getRateStep() { return mpData->mRateStep; }
+ f32 getVolumeSweep() { return mpData->mVolumeSweep; }
+ f32 getVolumeMinRad() { return mpData->mVolumeMinRad; }
+ f32 getInitVelOmni() { return mpData->mInitialVelOmni; }
+ f32 getInitVelAxis() { return mpData->mInitialVelAxis; }
+ f32 getInitVelDir() { return mpData->mInitialVelDir; }
+ f32 getInitVelDirSp() { return mpData->mSpread; }
+ f32 getInitVelRndm() { return mpData->mInitialVelRndm; }
+ f32 getInitVelRatio() const { return mpData->mInitialVelRatio; }
+ f32 getAirRes() { return mpData->mAirResist; }
+ f32 getLifetimeRndm() const { return mpData->mLifeTimeRndm; }
+ f32 getMomentRndm() const { return mpData->mMoment; }
+
+public:
+ /* 0x00 */ const JPADynamicsBlockData* mpData;
+ /* 0x04 */ JPADynamicsCalcVolumeFunc mpCalcVolumeFunc;
+};
+
+#endif /* JPADYNAMICSBLOCK_H */
diff --git a/include/JSystem/JParticle/JPAEmitter.h b/include/JSystem/JParticle/JPAEmitter.h
new file mode 100644
index 00000000..063b7c1f
--- /dev/null
+++ b/include/JSystem/JParticle/JPAEmitter.h
@@ -0,0 +1,272 @@
+#ifndef JPAEMITTER_H
+#define JPAEMITTER_H
+
+#include <dolphin/gx.h>
+#include "JSystem/JParticle/JPAResource.h"
+#include "JSystem/JParticle/JPAList.h"
+#include "JSystem/JParticle/JPARandom.h"
+#include "JSystem/JParticle/JPAMath.h"
+#include "JSystem/JParticle/JPADynamicsBlock.h"
+#include "JSystem/JSupport/JSUList.h"
+
+class JPAResourceManager;
+class JPABaseEmitter;
+class JPAEmitterManager;
+class JPAParticleCallBack;
+
+/**
+ * @ingroup jsystem-jparticle
+ *
+ */
+struct JPAEmitterWorkData {
+ struct JPAVolumeCalcData {
+ /* 0x00 */ JGeometry::TVec3<f32> mVolumePos;
+ /* 0x0C */ JGeometry::TVec3<f32> mVelOmni;
+ /* 0x18 */ JGeometry::TVec3<f32> mVelAxis;
+ };
+
+ JPAEmitterWorkData() : mRndm(0) {}
+
+ /* 0x00 */ JPABaseEmitter* mpEmtr;
+ /* 0x04 */ JPAResource* mpRes;
+ /* 0x08 */ JPAResourceManager* mpResMgr;
+ /* 0x0C */ JPARandom mRndm;
+ /* 0x10 */ JPAVolumeCalcData mVolumeCalcData;
+ /* 0x34 */ f32 mVolumeSize;
+ /* 0x38 */ f32 mVolumeMinRad;
+ /* 0x3C */ f32 mVolumeSweep;
+ /* 0x40 */ s32 mEmitCount;
+ /* 0x44 */ s32 mVolumeEmitIdx;
+ /* 0x48 */ Mtx mDirectionMtx;
+ /* 0x78 */ Mtx mRotationMtx;
+ /* 0xA8 */ Mtx mGlobalRot;
+ /* 0xD8 */ Mtx mGlobalSR;
+ /* 0x108 */ JGeometry::TVec3<f32> mEmitterPos;
+ /* 0x114 */ JGeometry::TVec3<f32> mGlobalScl;
+ /* 0x120 */ JGeometry::TVec3<f32> mGlobalEmtrDir;
+ /* 0x12C */ JGeometry::TVec3<f32> mPublicScale;
+ /* 0x138 */ JGeometry::TVec3<f32> mGlobalPos;
+ /* 0x144 */ JGeometry::TVec2<f32> mGlobalPtclScl;
+ /* 0x14C */ JGeometry::TVec2<f32> mPivot;
+ /* 0x154 */ Mtx mYBBCamMtx;
+ /* 0x184 */ Mtx mPosCamMtx;
+ /* 0x1B4 */ Mtx mPrjMtx;
+ /* 0x1E4 */ JPAList<JPABaseParticle>* mpAlivePtcl;
+ /* 0x1E8 */ JPANode<JPABaseParticle>* mpCurNode;
+ /* 0x1EC */ s32 mVolumeAngleNum;
+ /* 0x1F0 */ s32 mVolumeAngleMax;
+ /* 0x1F4 */ s32 mVolumeX;
+ /* 0x1F8 */ s32 mDivNumber;
+ /* 0x1FC */ f32 mScaleAnm;
+ /* 0x200 */ u32 mDirType;
+ /* 0x204 */ u32 mRotType;
+ /* 0x208 */ u32 mPlaneType;
+ /* 0x20C */ u32 mDLType;
+ /* 0x210 */ u32 mPrjType;
+ /* 0x214 */ s16 mClrKeyFrame;
+ /* 0x216 */ u8 mDrawCount;
+};
+
+/**
+ * @ingroup jsystem-jparticle
+ *
+ */
+class JPAEmitterCallBack {
+public:
+ virtual ~JPAEmitterCallBack() = 0;
+ /* 80050368 */ virtual void execute(JPABaseEmitter*) {}
+ /* 80050374 */ virtual void executeAfter(JPABaseEmitter*) {}
+ /* 8005036C */ virtual void draw(JPABaseEmitter*) {}
+ /* 80050370 */ virtual void drawAfter(JPABaseEmitter*) {}
+
+ /* 8027E6A4 */ //~JPAEmitterCallBack();
+};
+
+enum {
+ JPAEmtrStts_StopEmit = 0x01,
+ JPAEmtrStts_StopCalc = 0x02,
+ JPAEmtrStts_StopDraw = 0x04,
+ JPAEmtrStts_EnableDeleteEmitter = 0x08,
+ JPAEmtrStts_FirstEmit = 0x10,
+ JPAEmtrStts_RateStepEmit = 0x20,
+ JPAEmtrStts_Immortal = 0x40,
+ JPAEmtrStts_Delete = 0x100,
+};
+
+/**
+ * @ingroup jsystem-jparticle
+ *
+ */
+class JPABaseEmitter {
+public:
+ /* 8027E5EC */ ~JPABaseEmitter() {}
+ /* 8027E64C */ JPABaseEmitter() : mLink(this), mRndm(0) {}
+ /* 8027E6EC */ void init(JPAEmitterManager*, JPAResource*);
+ /* 8027EDD4 */ bool processTillStartFrame();
+ /* 8027EE14 */ bool processTermination();
+ /* 8027EEB0 */ void calcEmitterGlobalPosition(JGeometry::TVec3<f32>*) const;
+ /* 8027EC60 */ void deleteAllParticle();
+ /* 8027EB60 */ JPABaseParticle* createChild(JPABaseParticle*);
+ /* 8027EA40 */ JPABaseParticle* createParticle();
+ /* 8027EF30 */ u32 getCurrentCreateNumber() const;
+ /* 8027EF40 */ u8 getDrawCount() const;
+ /* 8027EF50 */ bool loadTexture(u8, GXTexMapID);
+
+ void initStatus(u32 status) { mStatus = status; }
+ void setStatus(u32 status) { mStatus |= status; }
+ void clearStatus(u32 status) { mStatus &= ~status; }
+ u32 checkStatus(u32 status) const { return (mStatus & status); }
+ bool checkFlag(u32 flag) const { return !!(mpRes->getDyn()->getFlag() & flag); }
+ u8 getResourceManagerID() const { return mResMgrID; }
+ u8 getGroupID() const { return mGroupID; }
+ u8 getDrawTimes() const { return mDrawTimes; }
+ void setRate(f32 rate) { mRate = rate; }
+ void setDirectionalSpeed(f32 i_speed) { mDirSpeed = i_speed; }
+ void setRandomDirectionSpeed(f32 i_speed) { mRndmDirSpeed = i_speed; }
+ void setEmitterCallBackPtr(JPAEmitterCallBack* ptr) { mpEmtrCallBack = ptr; }
+ void setGlobalRTMatrix(const Mtx m) { JPASetRMtxTVecfromMtx(m, mGlobalRot, &mGlobalTrs); }
+ void setGlobalSRTMatrix(const Mtx m) {
+ JPASetRMtxSTVecfromMtx(m, mGlobalRot, &mGlobalScl, &mGlobalTrs);
+
+ // set is actually used here in debug
+ mGlobalPScl.x = mGlobalScl.x;
+ mGlobalPScl.y = mGlobalScl.y;
+ }
+ void setGlobalTranslation(f32 x, f32 y, f32 z) { mGlobalTrs.set(x, y, z); }
+ void setGlobalTranslation(const JGeometry::TVec3<f32>& trs) { mGlobalTrs.set(trs); }
+ void getLocalTranslation(JGeometry::TVec3<f32>& vec) { vec.set(mLocalTrs); }
+ void setGlobalRotation(const JGeometry::TVec3<s16>& rot) {
+ JPAGetXYZRotateMtx(rot.x, rot.y, rot.z, mGlobalRot);
+ }
+ void getGlobalTranslation(JGeometry::TVec3<f32>* out) const { out->set(mGlobalTrs); }
+ void setGlobalDynamicsScale(const JGeometry::TVec3<f32>& i_scale) { mGlobalScl.set(i_scale); }
+ void setGlobalAlpha(u8 alpha) { mGlobalPrmClr.a = alpha; }
+ u8 getGlobalAlpha() { return mGlobalPrmClr.a; }
+ void getGlobalPrmColor(GXColor& color) { color = mGlobalPrmClr; }
+ void setGlobalPrmColor(u8 r, u8 g, u8 b) { mGlobalPrmClr.r = r; mGlobalPrmClr.g = g; mGlobalPrmClr.b = b; }
+ void setGlobalEnvColor(u8 r, u8 g, u8 b) { mGlobalEnvClr.r = r; mGlobalEnvClr.g = g; mGlobalEnvClr.b = b; }
+ void setVolumeSize(u16 size) { mVolumeSize = size; }
+ void setLifeTime(s16 lifetime) { mLifeTime = lifetime; }
+ void setAwayFromCenterSpeed(f32 i_speed) { mAwayFromCenterSpeed = i_speed; }
+ void setAwayFromAxisSpeed(f32 i_speed) { mAwayFromAxisSpeed = i_speed; }
+ void setSpread(f32 i_spread) { mSpread = i_spread; }
+ void setLocalTranslation(const JGeometry::TVec3<f32>& i_trans) { mLocalTrs.set(i_trans); }
+ void setLocalRotation(const JGeometry::TVec3<s16>& i_rot) { mLocalRot.set(i_rot.x * 0.005493248f, i_rot.y * 0.005493248f, i_rot.z * 0.005493248f); }
+ void setRateStep(u8 i_step) { mRateStep = i_step; }
+
+ void setGlobalParticleHeightScale(f32 height) {
+ mGlobalPScl.y = height;
+ }
+ void setGlobalParticleScale(const JGeometry::TVec3<f32>& scale) {
+ mGlobalPScl.set(scale.x, scale.y);
+ }
+ void setGlobalParticleScale(f32 scaleX, f32 scaleY) {
+ mGlobalPScl.set(scaleX, scaleY);
+ }
+ void getGlobalParticleScale(JGeometry::TVec3<f32>& scale) {
+ scale.set(mGlobalPScl.x, mGlobalPScl.y, 1.0f);
+ }
+ void setGlobalScale(const JGeometry::TVec3<f32>& scale) {
+ mGlobalScl.set(scale);
+ mGlobalPScl.set(scale.x ,scale.y);
+ }
+ void setGlobalSRTMatrix(const MtxP matrix) {
+ JPASetRMtxSTVecfromMtx(matrix, mGlobalRot, &mGlobalScl, &mGlobalTrs);
+ mGlobalPScl.set(mGlobalScl.x, mGlobalScl.y);
+ }
+ void setDirection(const JGeometry::TVec3<f32>& direction) {
+ mLocalDir.set(direction);
+ }
+
+ void setLocalScale(const JGeometry::TVec3<f32>& scale) {
+ mLocalScl.set(scale);
+ }
+
+ f32 get_r_f() { return mRndm.get_rndm_f(); }
+ f32 get_r_zp() { return mRndm.get_rndm_zp(); }
+ f32 get_r_zh() { return mRndm.get_rndm_zh(); }
+ s16 get_r_ss() { return mRndm.get_rndm_ss(); }
+
+ void stopCreateParticle() { setStatus(JPAEmtrStts_StopEmit); }
+ void playCreateParticle() { clearStatus(JPAEmtrStts_StopEmit); }
+ void becomeImmortalEmitter() { setStatus(JPAEmtrStts_Immortal); }
+ void becomeContinuousParticle() { mMaxFrame = 0; }
+ void becomeDeleteEmitter() { setStatus(JPAEmtrStts_Delete); }
+ void becomeInvalidEmitter() {
+ stopCreateParticle();
+ mMaxFrame = 1;
+ }
+
+ void quitImmortalEmitter() { clearStatus(JPAEmtrStts_Immortal); }
+ void stopCalcEmitter() { setStatus(JPAEmtrStts_StopCalc); }
+ void playCalcEmitter() { clearStatus(JPAEmtrStts_StopCalc); }
+ void stopDrawParticle() { setStatus(JPAEmtrStts_StopDraw); }
+ void playDrawParticle() { clearStatus(JPAEmtrStts_StopDraw); }
+
+ u32 getUserWork() { return mpUserWork; }
+ void setUserWork(u32 userWork) { mpUserWork = userWork; }
+ u32 getParticleNumber() {
+ return mAlivePtclBase.getNum() + mAlivePtclChld.getNum();
+ }
+ bool isEnableDeleteEmitter() {
+ return checkStatus(JPAEmtrStts_EnableDeleteEmitter) && getParticleNumber() == 0;
+ }
+ void setDrawTimes(u8 drawTimes) { mDrawTimes = drawTimes; }
+ void setParticleCallBackPtr(JPAParticleCallBack* cb) { mpPtclCallBack = cb; }
+ JPAParticleCallBack* getParticleCallBackPtr() { return mpPtclCallBack; }
+ JPAEmitterCallBack* getEmitterCallBackPtr() const { return mpEmtrCallBack; }
+ u32 getAge() const { return mTick; }
+
+public:
+ /* 0x00 */ JGeometry::TVec3<f32> mLocalScl;
+ /* 0x0C */ JGeometry::TVec3<f32> mLocalTrs;
+ /* 0x18 */ JGeometry::TVec3<f32> mLocalDir;
+ /* 0x24 */ s32 mMaxFrame;
+ /* 0x28 */ f32 mRate;
+ /* 0x2C */ f32 mVolumeSweep;
+ /* 0x30 */ f32 mVolumeMinRad;
+ /* 0x34 */ f32 mAwayFromCenterSpeed;
+ /* 0x38 */ f32 mAwayFromAxisSpeed;
+ /* 0x3C */ f32 mDirSpeed;
+ /* 0x40 */ f32 mSpread;
+ /* 0x44 */ f32 mRndmDirSpeed;
+ /* 0x48 */ f32 mAirResist;
+ /* 0x4C */ JGeometry::TVec3<s16> mLocalRot;
+ /* 0x52 */ s16 mLifeTime;
+ /* 0x54 */ u16 mVolumeSize;
+ /* 0x56 */ u8 mRateStep;
+ /* 0x58 */ JSULink<JPABaseEmitter> mLink;
+ /* 0x68 */ Mtx mGlobalRot;
+ /* 0x98 */ JGeometry::TVec3<f32> mGlobalScl;
+ /* 0xA4 */ JGeometry::TVec3<f32> mGlobalTrs;
+ /* 0xB0 */ JGeometry::TVec2<f32> mGlobalPScl;
+ /* 0xB8 */ GXColor mGlobalPrmClr;
+ /* 0xBC */ GXColor mGlobalEnvClr;
+ /* 0xC0 */ s32 mpUserWork;
+ /* 0xC4 */ JPARandom mRndm;
+ /* 0xC8 */ JPAList<JPABaseParticle> mAlivePtclBase;
+ /* 0xD4 */ JPAList<JPABaseParticle> mAlivePtclChld;
+ /* 0xE0 */ JPAList<JPABaseParticle>* mpPtclPool;
+ /* 0xE4 */ JPAEmitterManager* mpEmtrMgr;
+ /* 0xE8 */ JPAResource* mpRes;
+ /* 0xEC */ JPAEmitterCallBack* mpEmtrCallBack;
+ /* 0xF0 */ JPAParticleCallBack* mpPtclCallBack;
+ /* 0xF4 */ volatile u32 mStatus;
+ /* 0xF8 */ f32 mEmitCount;
+ /* 0xFC */ f32 mScaleOut;
+ /* 0x100 */ u32 mTick;
+ /* 0x104 */ s16 mWaitTime;
+ /* 0x106 */ s16 mRateStepTimer;
+ /* 0x108 */ GXColor mPrmClr;
+ /* 0x10C */ GXColor mEnvClr;
+ /* 0x110 */ u8 mDrawTimes;
+ /* 0x111 */ u8 mTexAnmIdx;
+ /* 0x112 */ u8 mGroupID;
+ /* 0x113 */ u8 mResMgrID;
+};
+
+enum {
+ JPAPtclStts_Invisible = 0x08,
+};
+
+#endif /* JPAEMITTER_H */
diff --git a/include/JSystem/JParticle/JPAEmitterManager.h b/include/JSystem/JParticle/JPAEmitterManager.h
new file mode 100644
index 00000000..5cd69a28
--- /dev/null
+++ b/include/JSystem/JParticle/JPAEmitterManager.h
@@ -0,0 +1,49 @@
+#ifndef JPAEMITTERMANAGER_H
+#define JPAEMITTERMANAGER_H
+
+#include "dolphin/types.h"
+#include "JSystem/JParticle/JPAList.h"
+#include "JSystem/JParticle/JPADrawInfo.h"
+#include "JSystem/JSupport/JSUList.h"
+#include "JSystem/JGeometry.h"
+
+class JPAEmitterCallBack;
+class JPAParticleCallBack;
+class JPABaseEmitter;
+class JPAResourceManager;
+class JPABaseParticle;
+class JKRHeap;
+struct JPAEmitterWorkData;
+
+/**
+ * @ingroup jsystem-jparticle
+ *
+ */
+class JPAEmitterManager {
+public:
+ /* 8027DCA0 */ JPAEmitterManager(u32, u32, JKRHeap*, u8, u8);
+ /* 8027DEBC */ JPABaseEmitter* createSimpleEmitterID(JGeometry::TVec3<f32> const&, u16, u8, u8,
+ JPAEmitterCallBack*, JPAParticleCallBack*);
+ /* 8027DFA0 */ void calc(u8);
+ /* 8027E028 */ void draw(JPADrawInfo const*, u8);
+ /* 8027E220 */ void forceDeleteAllEmitter();
+ /* 8027E278 */ void forceDeleteGroupEmitter(u8);
+ /* 8027E2D8 */ void forceDeleteEmitter(JPABaseEmitter*);
+ /* 8027E344 */ void entryResourceManager(JPAResourceManager*, u8);
+ /* 8027E354 */ void clearResourceManager(u8);
+ /* 8027E3F4 */ void calcYBBCam();
+ JPAResourceManager* getResourceManager(u16 idx) { return pResMgrAry[idx]; }
+
+public:
+ /* 0x00 */ JSUList<JPABaseEmitter>* pEmtrUseList;
+ /* 0x04 */ JSUList<JPABaseEmitter> mFreeEmtrList;
+ /* 0x10 */ JPAList<JPABaseParticle> mPtclPool;
+ /* 0x1C */ JPAResourceManager** pResMgrAry;
+ /* 0x20 */ JPAEmitterWorkData* pWd;
+ /* 0x24 */ u32 emtrNum;
+ /* 0x28 */ u32 ptclNum;
+ /* 0x2C */ u8 gidMax;
+ /* 0x2D */ u8 ridMax;
+};
+
+#endif /* JPAEMITTERMANAGER_H */
diff --git a/include/JSystem/JParticle/JPAExTexShape.h b/include/JSystem/JParticle/JPAExTexShape.h
new file mode 100644
index 00000000..b202cc9d
--- /dev/null
+++ b/include/JSystem/JParticle/JPAExTexShape.h
@@ -0,0 +1,45 @@
+#ifndef JPAEXTEXSHAPE_H
+#define JPAEXTEXSHAPE_H
+
+#include "dolphin/types.h"
+
+class JPAEmitterWorkData;
+
+/**
+ * @ingroup jsystem-jparticle
+ *
+ */
+struct JPAExTexShapeData {
+ // Common header.
+ /* 0x00 */ u8 mMagic[4];
+ /* 0x04 */ u32 mSize;
+
+ /* 0x08 */ u32 mFlags;
+ /* 0x0C */ f32 mIndTexMtx[2][3];
+ /* 0x24 */ s8 mExpScale;
+ /* 0x25 */ s8 mIndTexIdx;
+ /* 0x26 */ s8 mSecTexIdx;
+};
+
+/**
+ * @ingroup jsystem-jparticle
+ *
+ */
+class JPAExTexShape {
+public:
+ /* 8027B13C */ JPAExTexShape(u8 const*);
+
+ const f32* getIndTexMtx() const { return &mpData->mIndTexMtx[0][0]; }
+ s8 getExpScale() const { return mpData->mExpScale; }
+ u8 getIndTexIdx() const { return mpData->mIndTexIdx; }
+ u8 getSecTexIdx() const { return mpData->mSecTexIdx; }
+ bool isUseIndirect() const { return !!(mpData->mFlags & 0x01); }
+ bool isUseSecTex() const { return !!(mpData->mFlags & 0x0100); }
+
+public:
+ const JPAExTexShapeData* mpData;
+};
+
+void JPALoadExTex(JPAEmitterWorkData*);
+
+#endif /* JPAEXTEXSHAPE_H */
diff --git a/include/JSystem/JParticle/JPAExtraShape.h b/include/JSystem/JParticle/JPAExtraShape.h
new file mode 100644
index 00000000..dbf46363
--- /dev/null
+++ b/include/JSystem/JParticle/JPAExtraShape.h
@@ -0,0 +1,112 @@
+#ifndef JPAEXTRASHAPE_H
+#define JPAEXTRASHAPE_H
+
+#include "dolphin/types.h"
+
+class JPAEmitterWorkData;
+class JPABaseParticle;
+
+/**
+ * @ingroup jsystem-jparticle
+ *
+ */
+struct JPAExtraShapeData {
+ // Common header.
+ /* 0x00 */ u8 mMagic[4];
+ /* 0x04 */ u32 mSize;
+
+ /* 0x08 */ u32 mFlags;
+ /* 0x0C */ f32 mScaleInTiming;
+ /* 0x10 */ f32 mScaleOutTiming;
+ /* 0x14 */ f32 mScaleInValueX;
+ /* 0x18 */ f32 mScaleOutValueX;
+ /* 0x1C */ f32 mScaleInValueY;
+ /* 0x20 */ f32 mScaleOutValueY;
+ /* 0x24 */ f32 mScaleOutRandom;
+ /* 0x28 */ s16 mScaleAnmCycleX;
+ /* 0x2A */ s16 mScaleAnmCycleY;
+ /* 0x2C */ f32 mAlphaInTiming;
+ /* 0x30 */ f32 mAlphaOutTiming;
+ /* 0x34 */ f32 mAlphaInValue;
+ /* 0x38 */ f32 mAlphaBaseValue;
+ /* 0x3C */ f32 mAlphaOutValue;
+ /* 0x40 */ f32 mAlphaWaveFrequency;
+ /* 0x44 */ f32 mAlphaWaveRandom;
+ /* 0x48 */ f32 mAlphaWaveAmplitude;
+ /* 0x4C */ f32 mRotateAngle;
+ /* 0x50 */ f32 mRotateAngleRandom;
+ /* 0x54 */ f32 mRotateSpeed;
+ /* 0x58 */ f32 mRotateSpeedRandom;
+ /* 0x5C */ f32 mRotateDirection;
+};
+
+/**
+ * @ingroup jsystem-jparticle
+ *
+ */
+class JPAExtraShape {
+public:
+ /* 8027AD88 */ JPAExtraShape(u8 const*);
+ /* 8027ADBC */ void init();
+
+ f32 getScaleInTiming() const { return mpData->mScaleInTiming; }
+ f32 getScaleOutTiming() const { return mpData->mScaleOutTiming; }
+ f32 getScaleInValueX() const { return mpData->mScaleInValueX; }
+ f32 getScaleInValueY() const { return mpData->mScaleInValueY; }
+ f32 getScaleOutValueX() const { return mpData->mScaleOutValueX; }
+ f32 getScaleOutValueY() const { return mpData->mScaleOutValueY; }
+ f32 getScaleRndm() const { return mpData->mScaleOutRandom; }
+ s16 getScaleAnmCycleX() const { return mpData->mScaleAnmCycleX; }
+ s16 getScaleAnmCycleY() const { return mpData->mScaleAnmCycleY; }
+ f32 getAlphaInTiming() const { return mpData->mAlphaInTiming; }
+ f32 getAlphaOutTiming() const { return mpData->mAlphaOutTiming; }
+ f32 getAlphaInValue() const { return mpData->mAlphaInValue; }
+ f32 getAlphaOutValue() const { return mpData->mAlphaOutValue; }
+ f32 getAlphaBaseValue() const { return mpData->mAlphaBaseValue; }
+ f32 getAlphaFreq() const { return mpData->mAlphaWaveFrequency; }
+ f32 getAlphaFreqRndm() const { return mpData->mAlphaWaveRandom; }
+ f32 getAlphaAmp() const { return mpData->mAlphaWaveAmplitude; }
+ f32 getRotateInitAngle() const { return mpData->mRotateAngle; }
+ f32 getRotateRndmAngle() const { return mpData->mRotateAngleRandom; }
+ f32 getRotateInitSpeed() const { return mpData->mRotateSpeed; }
+ f32 getRotateRndmSpeed() const { return mpData->mRotateSpeedRandom; }
+ f32 getRotateDirection() const { return mpData->mRotateDirection; }
+ f32 getScaleIncRateX() const { return mScaleIncRateX; }
+ f32 getScaleDecRateX() const { return mScaleDecRateX; }
+ f32 getScaleIncRateY() const { return mScaleIncRateY; }
+ f32 getScaleDecRateY() const { return mScaleDecRateY; }
+ f32 getAlphaIncRate() const { return mAlphaIncRate; }
+ f32 getAlphaDecRate() const { return mAlphaDecRate; }
+
+ BOOL isEnableScaleAnm() const { return mpData->mFlags & 1; }
+ BOOL isScaleXYDiff() const { return mpData->mFlags & 2; }
+ u32 getScaleAnmTypeX() const { return (mpData->mFlags >> 8) & 3; }
+ u32 getScaleAnmTypeY() const { return (mpData->mFlags >> 10) & 3; }
+ u32 getScaleCenterX() const { return (mpData->mFlags >> 12) & 3; }
+ u32 getScaleCenterY() const { return (mpData->mFlags >> 14) & 3; }
+ BOOL isEnableAlphaAnm() const { return mpData->mFlags & 0x10000; }
+ BOOL isEnableAlphaFlick() const { return mpData->mFlags & 0x20000; }
+ BOOL isEnableRotateAnm() const { return mpData->mFlags & 0x1000000; }
+
+private:
+ /* 0x00 */ const JPAExtraShapeData* mpData;
+ /* 0x04 */ f32 mAlphaIncRate;
+ /* 0x08 */ f32 mAlphaDecRate;
+ /* 0x0C */ f32 mScaleIncRateX;
+ /* 0x10 */ f32 mScaleIncRateY;
+ /* 0x14 */ f32 mScaleDecRateX;
+ /* 0x18 */ f32 mScaleDecRateY;
+};
+
+void JPACalcAlphaFlickAnm(JPAEmitterWorkData*, JPABaseParticle*);
+void JPACalcAlphaAnm(JPAEmitterWorkData*, JPABaseParticle*);
+void JPACalcScaleX(JPAEmitterWorkData*, JPABaseParticle*);
+void JPACalcScaleY(JPAEmitterWorkData*, JPABaseParticle*);
+void JPACalcScaleCopy(JPAEmitterWorkData*, JPABaseParticle*);
+void JPACalcScaleAnmNormal(JPAEmitterWorkData*, JPABaseParticle*);
+void JPACalcScaleAnmRepeatX(JPAEmitterWorkData*, JPABaseParticle*);
+void JPACalcScaleAnmReverseX(JPAEmitterWorkData*, JPABaseParticle*);
+void JPACalcScaleAnmRepeatY(JPAEmitterWorkData*, JPABaseParticle*);
+void JPACalcScaleAnmReverseY(JPAEmitterWorkData*, JPABaseParticle*);
+
+#endif /* JPAEXTRASHAPE_H */
diff --git a/include/JSystem/JParticle/JPAFieldBlock.h b/include/JSystem/JParticle/JPAFieldBlock.h
new file mode 100644
index 00000000..2031ba26
--- /dev/null
+++ b/include/JSystem/JParticle/JPAFieldBlock.h
@@ -0,0 +1,174 @@
+#ifndef JPAFIELDBLOCK_H
+#define JPAFIELDBLOCK_H
+
+#include "JSystem/JGeometry.h"
+#include "dolphin/types.h"
+
+class JKRHeap;
+class JPAEmitterWorkData;
+class JPABaseParticle;
+class JPAFieldBlock;
+
+class JPAFieldBase {
+public:
+ /* 8027BDEC */ void calcAffect(JPAFieldBlock*, JPABaseParticle*);
+ /* 8027BF18 */ f32 calcFadeAffect(JPAFieldBlock*, f32) const;
+
+ /* 8027D3AC */ virtual ~JPAFieldBase() {}
+ /* 80276A8C */ virtual void prepare(JPAEmitterWorkData*, JPAFieldBlock*) {}
+ virtual void calc(JPAEmitterWorkData*, JPAFieldBlock*, JPABaseParticle*) = 0;
+
+ /* 0x04 */ JGeometry::TVec3<f32> mAccel;
+};
+
+class JPAFieldVortex : public JPAFieldBase {
+public:
+ /* 8027C56C */ void prepare(JPAEmitterWorkData*, JPAFieldBlock*);
+ /* 8027C674 */ void calc(JPAEmitterWorkData*, JPAFieldBlock*, JPABaseParticle*);
+ /* 8027D564 */ ~JPAFieldVortex() {}
+
+ /* 0x10 */ JGeometry::TVec3<f32> field_0x10;
+ /* 0x1C */ f32 field_0x1c;
+ /* 0x20 */ f32 field_0x20;
+};
+
+class JPAFieldSpin : public JPAFieldBase {
+public:
+ /* 8027CE64 */ void prepare(JPAEmitterWorkData*, JPAFieldBlock*);
+ /* 8027CFA8 */ void calc(JPAEmitterWorkData*, JPAFieldBlock*, JPABaseParticle*);
+ /* 8027D3F4 */ ~JPAFieldSpin() {}
+
+ /* 0x10 */ JGeometry::TVec3<f32> field_0x10;
+ /* 0x1C */ JGeometry::TVec3<f32> field_0x1c;
+ /* 0x28 */ JGeometry::TVec3<f32> field_0x28;
+};
+
+class JPAFieldRandom : public JPAFieldBase {
+public:
+ /* 8027CCCC */ void calc(JPAEmitterWorkData*, JPAFieldBlock*, JPABaseParticle*);
+ /* 8027D4AC */ ~JPAFieldRandom() {}
+};
+
+class JPAFieldNewton : public JPAFieldBase {
+public:
+ /* 8027C36C */ void prepare(JPAEmitterWorkData*, JPAFieldBlock*);
+ /* 8027C3E0 */ void calc(JPAEmitterWorkData*, JPAFieldBlock*, JPABaseParticle*);
+ /* 8027D5C0 */ ~JPAFieldNewton() {}
+
+ /* 0x10 */ JGeometry::TVec3<f32> mDir;
+ /* 0x1C */ f32 mCutoff;
+};
+
+class JPAFieldMagnet : public JPAFieldBase {
+public:
+ /* 8027C24C */ void prepare(JPAEmitterWorkData*, JPAFieldBlock*);
+ /* 8027C29C */ void calc(JPAEmitterWorkData*, JPAFieldBlock*, JPABaseParticle*);
+ /* 8027D61C */ ~JPAFieldMagnet() {}
+
+ /* 0x10 */ JGeometry::TVec3<f32> mDir;
+};
+
+class JPAFieldGravity : public JPAFieldBase {
+public:
+ /* 8027BFB4 */ void prepare(JPAEmitterWorkData*, JPAFieldBlock*);
+ /* 8027C054 */ void calc(JPAEmitterWorkData*, JPAFieldBlock*, JPABaseParticle*);
+ /* 8027D6D4 */ ~JPAFieldGravity() {}
+};
+
+class JPAFieldDrag : public JPAFieldBase {
+public:
+ /* 8027CDE4 */ void calc(JPAEmitterWorkData*, JPAFieldBlock*, JPABaseParticle*);
+ /* 8027D450 */ ~JPAFieldDrag() {}
+};
+
+class JPAFieldConvection : public JPAFieldBase {
+public:
+ /* 8027C814 */ void prepare(JPAEmitterWorkData*, JPAFieldBlock*);
+ /* 8027CA94 */ void calc(JPAEmitterWorkData*, JPAFieldBlock*, JPABaseParticle*);
+ /* 8027D508 */ ~JPAFieldConvection() {}
+
+ /* 0x10 */ JGeometry::TVec3<f32> field_0x10;
+ /* 0x1C */ JGeometry::TVec3<f32> field_0x1c;
+ /* 0x28 */ JGeometry::TVec3<f32> field_0x28;
+};
+
+class JPAFieldAir : public JPAFieldBase {
+public:
+ /* 8027C07C */ void prepare(JPAEmitterWorkData*, JPAFieldBlock*);
+ /* 8027C1B8 */ void calc(JPAEmitterWorkData*, JPAFieldBlock*, JPABaseParticle*);
+ /* 8027D678 */ ~JPAFieldAir() {}
+};
+
+// unknown name
+class JPAFieldBlockData {
+public:
+ /* 0x00 */ u8 mMagic[4];
+ /* 0x04 */ u32 mSize;
+ /* 0x08 */ u32 mFlags;
+ /* 0x0C */ JGeometry::TVec3<f32> mPos;
+ /* 0x18 */ JGeometry::TVec3<f32> mDir;
+ /* 0x24 */ f32 mMag;
+ /* 0x28 */ f32 mMagRndm;
+ /* 0x2C */ f32 mVal1;
+ /* 0x30 */ f32 mFadeInTime;
+ /* 0x34 */ f32 mFadeOutTime;
+ /* 0x38 */ f32 mEnTime;
+ /* 0x3C */ f32 mDisTime;
+ /* 0x40 */ u8 mCycle;
+};
+
+class JPAFieldBlock {
+public:
+ /* 8027D088 */ JPAFieldBlock(u8 const*, JKRHeap*);
+ /* 8027D0C0 */ void init(JKRHeap*);
+
+ u32 getType() { return mpData->mFlags & 0xF; }
+ u32 getAddType() { return (mpData->mFlags >> 8) & 3; }
+ u32 getSttFlag() { return mpData->mFlags >> 16; }
+ bool checkStatus(u16 flag) { return flag & getSttFlag(); }
+ f32 getMagRndm() const { return mpData->mMagRndm; }
+ f32 getVal1() const { return mpData->mVal1; }
+ f32 getFadeInTime() { return mpData->mFadeInTime; }
+ f32 getFadeOutTime() { return mpData->mFadeOutTime; }
+ f32 getEnTime() { return mpData->mEnTime; }
+ f32 getDisTime() { return mpData->mDisTime; }
+ u8 getCycle() { return mpData->mCycle; }
+ f32 getFadeInRate() { return mFadeInRate; }
+ f32 getFadeOutRate() { return mFadeOutRate; }
+ JGeometry::TVec3<f32>& getPos() { return mPos; }
+ JGeometry::TVec3<f32>& getDir() { return mDir; }
+ f32 getMag() const { return mMag; }
+ void getPosOrig(JGeometry::TVec3<f32>* pos) { pos->set(mpData->mPos); }
+ void getDirOrig(JGeometry::TVec3<f32>* dir) { dir->set(mpData->mDir); }
+ f32 getMagOrig() { return mpData->mMag; }
+ void initOpParam() {
+ getPosOrig(&mPos);
+ getDirOrig(&mDir);
+ mMag = getMagOrig();
+ }
+ void prepare(JPAEmitterWorkData* work) { mpField->prepare(work, this); }
+ void calc(JPAEmitterWorkData* work, JPABaseParticle* ptcl) { mpField->calc(work, this, ptcl); }
+
+private:
+ /* 0x00 */ const JPAFieldBlockData* mpData;
+ /* 0x04 */ JPAFieldBase* mpField;
+ /* 0x08 */ f32 mFadeInRate;
+ /* 0x0C */ f32 mFadeOutRate;
+ /* 0x10 */ JGeometry::TVec3<f32> mPos;
+ /* 0x1C */ JGeometry::TVec3<f32> mDir;
+ /* 0x28 */ f32 mMag;
+
+ enum Type {
+ /* 0x0 */ FIELD_GRAVITY,
+ /* 0x1 */ FIELD_AIR,
+ /* 0x2 */ FIELD_MAGNET,
+ /* 0x3 */ FIELD_NEWTON,
+ /* 0x4 */ FIELD_VORTEX,
+ /* 0x5 */ FIELD_RANDOM,
+ /* 0x6 */ FIELD_DRAG,
+ /* 0x7 */ FIELD_CONVECTION,
+ /* 0x8 */ FIELD_SPIN,
+ };
+};
+
+#endif /* JPAFIELDBLOCK_H */
diff --git a/include/JSystem/JParticle/JPAKeyBlock.h b/include/JSystem/JParticle/JPAKeyBlock.h
new file mode 100644
index 00000000..3d79e854
--- /dev/null
+++ b/include/JSystem/JParticle/JPAKeyBlock.h
@@ -0,0 +1,21 @@
+#ifndef JPAKEYBLOCK_H
+#define JPAKEYBLOCK_H
+
+#include "dolphin/types.h"
+
+/**
+ * @ingroup jsystem-jparticle
+ *
+ */
+struct JPAKeyBlock {
+ /* 8027D730 */ JPAKeyBlock(u8 const*);
+ /* 8027D740 */ f32 calc(f32);
+
+ u8 getID() { return mDataStart[8]; }
+
+ const u8* mDataStart;
+ const f32* field_0x4;
+};
+
+
+#endif /* JPAKEYBLOCK_H */
diff --git a/include/JSystem/JParticle/JPAList.h b/include/JSystem/JParticle/JPAList.h
new file mode 100644
index 00000000..ab2e5a7f
--- /dev/null
+++ b/include/JSystem/JParticle/JPAList.h
@@ -0,0 +1,131 @@
+#ifndef JPALIST_H
+#define JPALIST_H
+
+#include "dolphin/types.h"
+
+/**
+ * @ingroup jsystem-jparticle
+ *
+ */
+template <class T>
+struct JPANode {
+ JPANode() : mpPrev(NULL), mpNext(NULL) {
+ }
+ ~JPANode() {}
+ JPANode<T>* getPrev() { return mpPrev; }
+ JPANode<T>* getNext() { return mpNext; }
+ T* getObject() { return &mData; }
+
+ /* 0x00 */ JPANode<T>* mpPrev;
+ /* 0x04 */ JPANode<T>* mpNext;
+ /* 0x08 */ T mData;
+};
+
+/**
+ * @ingroup jsystem-jparticle
+ *
+ */
+template <class T>
+struct JPAList {
+ /* 0x00 */ JPANode<T>* mpFirst;
+ /* 0x04 */ JPANode<T>* mpLast;
+ /* 0x08 */ u32 mNum;
+
+ JPAList() : mpFirst(NULL), mpLast(NULL), mNum() {}
+ ~JPAList() {}
+
+ JPANode<T>* getEnd() { return NULL; }
+ JPANode<T>* getFirst() const { return mpFirst; }
+ JPANode<T>* getLast() const { return mpLast; }
+ u32 getNum() const { return mNum; }
+
+ void push_front(JPANode<T>* node) {
+ if (mpFirst != NULL) {
+ node->mpPrev = NULL;
+ node->mpNext = mpFirst;
+ mpFirst->mpPrev = node;
+ mpFirst = node;
+ } else {
+ mpLast = node;
+ mpFirst = node;
+ node->mpPrev = NULL;
+ node->mpNext = NULL;
+ }
+
+ mNum++;
+ }
+
+ void push_back(JPANode<T>* node) {
+ if (mpLast != NULL) {
+ node->mpPrev = mpLast;
+ node->mpNext = NULL;
+ mpLast->mpNext = node;
+ mpLast = node;
+ } else {
+ mpFirst = node;
+ mpLast = node;
+ node->mpNext = node->mpPrev = NULL;
+ }
+
+ mNum++;
+ }
+
+ JPANode<T>* pop_front() {
+ JPANode<T>* ret = NULL;
+
+ if (mNum == 1) {
+ ret = mpFirst;
+ mpLast = NULL;
+ mpFirst = NULL;
+ mNum--;
+ } else if (mNum) {
+ ret = mpFirst;
+ ret->mpNext->mpPrev = NULL;
+ mpFirst = ret->mpNext;
+ mNum--;
+ }
+
+ return ret;
+ }
+
+ JPANode<T>* pop_back() {
+ JPANode<T>* ret = NULL;
+
+ if (mNum == 1) {
+ ret = mpLast;
+ mpLast = NULL;
+ mpFirst = NULL;
+ mNum--;
+ } else if (mNum) {
+ ret = mpLast;
+ ret->mpPrev->mpNext = NULL;
+ mpLast = ret->mpPrev;
+ mNum--;
+ }
+
+ return ret;
+ }
+
+ JPANode<T>* erase(JPANode<T>* node) {
+ if (node->mpNext != NULL && node->mpPrev != NULL) {
+ node->mpPrev->mpNext = node->mpNext;
+ node->mpNext->mpPrev = node->mpPrev;
+ mNum--;
+ } else if (node->mpNext != NULL) {
+ node->mpNext->mpPrev = NULL;
+ mpFirst = node->mpNext;
+ mNum--;
+ } else if (node->mpPrev != NULL) {
+ node->mpPrev->mpNext = NULL;
+ mpLast = node->mpPrev;
+ mNum--;
+ } else {
+ mpLast = NULL;
+ mpFirst = NULL;
+ mNum--;
+ }
+ return node;
+ }
+};
+
+#endif
diff --git a/include/JSystem/JParticle/JPAMath.h b/include/JSystem/JParticle/JPAMath.h
new file mode 100644
index 00000000..68701359
--- /dev/null
+++ b/include/JSystem/JParticle/JPAMath.h
@@ -0,0 +1,16 @@
+#ifndef JPAMATH_H
+#define JPAMATH_H
+
+#include "dolphin/mtx.h"
+#include "JSystem/JGeometry.h"
+
+void JPAGetDirMtx(JGeometry::TVec3<f32> const& param_0, f32 (*param_1)[4]);
+void JPAGetYZRotateMtx(s16 angleY, s16 angleZ, f32 (*param_2)[4]);
+void JPAGetXYZRotateMtx(s16 x, s16 y, s16 z, Mtx dst);
+void JPASetRMtxTVecfromMtx(f32 const (*param_0)[4], f32 (*param_1)[4],
+ JGeometry::TVec3<f32>* param_2);
+f32 JPACalcKeyAnmValue(f32 param_0, u16 param_1, f32 const* param_2);
+void JPASetRMtxSTVecfromMtx(f32 const (*param_0)[4], f32 (*param_1)[4],
+ JGeometry::TVec3<f32>* param_2, JGeometry::TVec3<f32>* param_3);
+
+#endif /* JPAMATH_H */
diff --git a/include/JSystem/JParticle/JPAParticle.h b/include/JSystem/JParticle/JPAParticle.h
new file mode 100644
index 00000000..2e67f8e8
--- /dev/null
+++ b/include/JSystem/JParticle/JPAParticle.h
@@ -0,0 +1,93 @@
+#ifndef JPAPARTICLE_H
+#define JPAPARTICLE_H
+
+#include <dolphin/gx.h>
+#include "JSystem/JGeometry.h"
+
+class JKRHeap;
+class JPABaseEmitter;
+class JPABaseParticle;
+class JPAEmitterCallBack;
+class JPAEmitterManager;
+class JPAParticleCallBack;
+class JPAResourceManager;
+struct JPAEmitterWorkData;
+
+/**
+ * @ingroup jsystem-jparticle
+ *
+ */
+class JPABaseParticle {
+public:
+ ~JPABaseParticle() {}
+ /* 8027EFEC */ void init_p(JPAEmitterWorkData*);
+ /* 8027F8C8 */ void init_c(JPAEmitterWorkData*, JPABaseParticle*);
+ /* 8027FFD0 */ bool calc_p(JPAEmitterWorkData*);
+ /* 80280260 */ bool calc_c(JPAEmitterWorkData*);
+ /* 802804C8 */ bool canCreateChild(JPAEmitterWorkData*);
+ /* 80280548 */ f32 getWidth(JPABaseEmitter const*) const;
+ /* 80280568 */ f32 getHeight(JPABaseEmitter const*) const;
+ int getAge() { return mAge; }
+ void setOffsetPosition(const JGeometry::TVec3<f32>& pos) { mOffsetPosition.set(pos); }
+ void setOffsetPosition(f32 x, f32 y, f32 z) { mOffsetPosition.set(x, y, z); }
+ void getOffsetPosition(JGeometry::TVec3<f32>& pos) { pos.set(mOffsetPosition); }
+ u16 getRotateAngle() const { return mRotateAngle; }
+ void getGlobalPosition(JGeometry::TVec3<f32>& pos) const { pos.set(mPosition); }
+ f32 getParticleScaleX() const { return mParticleScaleX; }
+ f32 getParticleScaleY() const { return mParticleScaleY; }
+ void setStatus(u32 flag) { mStatus |= flag; }
+ u32 checkStatus(u32 flag) { return mStatus & flag; }
+ void initStatus(u32 status) { mStatus = status; }
+ void setInvisibleParticleFlag() { setStatus(8); }
+ void setDeleteParticleFlag() { setStatus(2); }
+ void getVelVec(JGeometry::TVec3<f32>& vec) const { vec.set(mVelocity); }
+ void getLocalPosition(JGeometry::TVec3<f32>& vec) const { vec.set(mLocalPosition); }
+ void getBaseAxis(JGeometry::TVec3<f32>& vec) const { vec.set(mBaseAxis); }
+
+public:
+ /* 0x00 */ JGeometry::TVec3<f32> mPosition;
+ /* 0x0C */ JGeometry::TVec3<f32> mLocalPosition;
+ /* 0x18 */ JGeometry::TVec3<f32> mOffsetPosition;
+ /* 0x24 */ JGeometry::TVec3<f32> mVelocity;
+ /* 0x30 */ JGeometry::TVec3<f32> mVelType1;
+ /* 0x3C */ JGeometry::TVec3<f32> mVelType0;
+ /* 0x48 */ JGeometry::TVec3<f32> mVelType2;
+ /* 0x54 */ JGeometry::TVec3<f32> mBaseAxis;
+ /* 0x60 */ f32 mParticleScaleX;
+ /* 0x64 */ f32 mParticleScaleY;
+ /* 0x68 */ f32 mScaleOut;
+ /* 0x6C */ f32 mAlphaWaveRandom;
+ /* 0x70 */ f32 mMoment;
+ /* 0x74 */ f32 mDrag;
+ /* 0x78 */ u32 field_0x78;
+ /* 0x7C */ u32 mStatus;
+ /* 0x80 */ s16 mAge;
+ /* 0x82 */ s16 mLifeTime;
+ /* 0x84 */ f32 mTime;
+ /* 0x88 */ u16 mRotateAngle;
+ /* 0x8A */ s16 mRotateSpeed;
+ /* 0x8C */ GXColor mPrmClr;
+ /* 0x90 */ GXColor mEnvClr;
+ /* 0x94 */ u8 mTexAnmIdx;
+ /* 0x95 */ u8 mAnmRandom;
+ /* 0x96 */ u8 mPrmColorAlphaAnm;
+};
+
+/**
+ * @ingroup jsystem-jparticle
+ *
+ */
+class JPAParticleCallBack {
+public:
+ JPAParticleCallBack() {}
+ virtual ~JPAParticleCallBack() = 0;
+ virtual void execute(JPABaseEmitter*, JPABaseParticle*) {}
+ virtual void draw(JPABaseEmitter*, JPABaseParticle*) {}
+};
+
+// not sure where this belongs
+static inline u32 COLOR_MULTI(u32 a, u32 b) {
+ return ((a * (b + 1)) * 0x10000) >> 24;
+}
+
+#endif /* JPAPARTICLE_H */
diff --git a/include/JSystem/JParticle/JPARandom.h b/include/JSystem/JParticle/JPARandom.h
new file mode 100644
index 00000000..5ffb276d
--- /dev/null
+++ b/include/JSystem/JParticle/JPARandom.h
@@ -0,0 +1,43 @@
+#ifndef JPARANDOM_H
+#define JPARANDOM_H
+
+#include "dolphin/types.h"
+
+/**
+ * @ingroup jsystem-jparticle
+ *
+ */
+struct JPARandom {
+public:
+ JPARandom() { mSeed = 0; }
+ JPARandom(u32 seed) { mSeed = seed; }
+ ~JPARandom() {}
+ void set_seed(u32 seed) { mSeed = seed; }
+
+ u32 get_rndm_u() { return mSeed = mSeed * 0x19660du + 0x3c6ef35fu; }
+
+ f32 get_rndm_f() {
+ union {
+ u32 u;
+ f32 f;
+ } a;
+ a.u = ((get_rndm_u() >> 9) | 0x3f800000);
+ return a.f - 1.0f;
+ }
+
+ f32 get_rndm_zp() {
+ f32 f = get_rndm_f();
+ return (f + f) - 1.0f;
+ }
+
+ f32 get_rndm_zh() {
+ return get_rndm_f() - 0.5f;
+ }
+
+ s16 get_rndm_ss() { return (s16)(get_rndm_u() >> 16); }
+
+public:
+ u32 mSeed;
+};
+
+#endif
diff --git a/include/JSystem/JParticle/JPAResource.h b/include/JSystem/JParticle/JPAResource.h
new file mode 100644
index 00000000..4b953233
--- /dev/null
+++ b/include/JSystem/JParticle/JPAResource.h
@@ -0,0 +1,81 @@
+#ifndef JPARESOURCE_H
+#define JPARESOURCE_H
+
+#include "dolphin/types.h"
+
+class JKRHeap;
+class JPAEmitterWorkData;
+class JPABaseEmitter;
+class JPABaseParticle;
+
+class JPABaseShape;
+class JPAExtraShape;
+class JPAChildShape;
+class JPAExTexShape;
+class JPADynamicsBlock;
+class JPAFieldBlock;
+class JPAKeyBlock;
+
+/**
+ * @ingroup jsystem-jparticle
+ *
+ */
+class JPAResource {
+public:
+ /* 80274010 */ JPAResource();
+ /* 80274080 */ void init(JKRHeap*);
+ /* 802755E8 */ bool calc(JPAEmitterWorkData*, JPABaseEmitter*);
+ /* 80275A94 */ void draw(JPAEmitterWorkData*, JPABaseEmitter*);
+ /* 80275B74 */ void drawP(JPAEmitterWorkData*);
+ /* 80275EB0 */ void drawC(JPAEmitterWorkData*);
+ /* 802761A8 */ void setPTev();
+ /* 8027642C */ void setCTev(JPAEmitterWorkData*);
+ /* 8027658C */ void calc_p(JPAEmitterWorkData*, JPABaseParticle*);
+ /* 80276608 */ void calc_c(JPAEmitterWorkData*, JPABaseParticle*);
+ /* 80276684 */ void calcField(JPAEmitterWorkData*, JPABaseParticle*);
+ /* 80276700 */ void calcKey(JPAEmitterWorkData*);
+ /* 80276840 */ void calcWorkData_c(JPAEmitterWorkData*);
+ /* 80276A0C */ void calcWorkData_d(JPAEmitterWorkData*);
+
+ JPABaseShape* getBsp() const { return mpBaseShape; }
+ JPAExtraShape* getEsp() const { return mpExtraShape; }
+ JPAChildShape* getCsp() const { return mpChildShape; }
+ JPAExTexShape* getEts() const { return mpExTexShape; }
+ JPADynamicsBlock* getDyn() const { return mpDynamicsBlock; }
+
+ u32 getTexIdx(u32 idx) const { return mpTDB1[idx]; }
+ u16 getUsrIdx() const { return mUsrIdx; }
+
+public:
+ typedef void (*EmitterFunc)(JPAEmitterWorkData*);
+ typedef void (*ParticleFunc)(JPAEmitterWorkData*, JPABaseParticle*);
+ /* 0x00 */ EmitterFunc* mpCalcEmitterFuncList;
+ /* 0x04 */ EmitterFunc* mpDrawEmitterFuncList;
+ /* 0x08 */ EmitterFunc* mpDrawEmitterChildFuncList;
+ /* 0x0C */ ParticleFunc* mpCalcParticleFuncList;
+ /* 0x10 */ ParticleFunc* mpDrawParticleFuncList;
+ /* 0x14 */ ParticleFunc* mpCalcParticleChildFuncList;
+ /* 0x18 */ ParticleFunc* mpDrawParticleChildFuncList;
+
+ /* 0x1C */ JPABaseShape* mpBaseShape;
+ /* 0x20 */ JPAExtraShape* mpExtraShape;
+ /* 0x24 */ JPAChildShape* mpChildShape;
+ /* 0x28 */ JPAExTexShape* mpExTexShape;
+ /* 0x2C */ JPADynamicsBlock* mpDynamicsBlock;
+ /* 0x30 */ JPAFieldBlock** mpFieldBlocks;
+ /* 0x34 */ JPAKeyBlock** mpKeyBlocks;
+ /* 0x38 */ u16 const* mpTDB1;
+ /* 0x3C */ u16 mUsrIdx;
+ /* 0x3E */ u8 mFieldBlockNum;
+ /* 0x3F */ u8 mKeyBlockNum;
+ /* 0x40 */ u8 mTDB1Num;
+ /* 0x41 */ u8 mpCalcEmitterFuncListNum;
+ /* 0x42 */ u8 mpDrawEmitterFuncListNum;
+ /* 0x43 */ u8 mpDrawEmitterChildFuncListNum;
+ /* 0x44 */ u8 mpCalcParticleFuncListNum;
+ /* 0x45 */ u8 mpDrawParticleFuncListNum;
+ /* 0x46 */ u8 mpCalcParticleChildFuncListNum;
+ /* 0x47 */ u8 mpDrawParticleChildFuncListNum;
+};
+
+#endif /* JPARESOURCE_H */
diff --git a/include/JSystem/JParticle/JPAResourceLoader.h b/include/JSystem/JParticle/JPAResourceLoader.h
new file mode 100644
index 00000000..10ff1e38
--- /dev/null
+++ b/include/JSystem/JParticle/JPAResourceLoader.h
@@ -0,0 +1,14 @@
+#ifndef JPARESOURCELOADER_H
+#define JPARESOURCELOADER_H
+
+#include "dolphin/types.h"
+
+class JPAResourceManager;
+
+class JPAResourceLoader {
+public:
+ /* 8027D8A0 */ JPAResourceLoader(u8 const*, JPAResourceManager*);
+ /* 8027D8E0 */ void load_jpc(u8 const*, JPAResourceManager*);
+};
+
+#endif /* JPARESOURCELOADER_H */
diff --git a/include/JSystem/JParticle/JPAResourceManager.h b/include/JSystem/JParticle/JPAResourceManager.h
new file mode 100644
index 00000000..2820c810
--- /dev/null
+++ b/include/JSystem/JParticle/JPAResourceManager.h
@@ -0,0 +1,36 @@
+#ifndef JPARESOURCEMANAGER_H
+#define JPARESOURCEMANAGER_H
+
+#include "JSystem/JParticle/JPATexture.h"
+
+class JKRHeap;
+class JPAResource;
+struct ResTIMG;
+
+/**
+ * @ingroup jsystem-jparticle
+ *
+ */
+class JPAResourceManager {
+public:
+ /* 80273E10 */ JPAResourceManager(void const*, JKRHeap*);
+ /* 80273E68 */ JPAResource* getResource(u16) const;
+ /* 80273EA8 */ bool checkUserIndexDuplication(u16) const;
+ /* 80273EEC */ const ResTIMG* swapTexture(ResTIMG const*, char const*);
+ /* 80273F8C */ void registRes(JPAResource*);
+ /* 80273FAC */ void registTex(JPATexture*);
+ /* 80273FCC */ u32 getResUserWork(u16) const;
+
+ void load(u16 idx, GXTexMapID texMapID) { mpTexArr[idx]->load(texMapID); }
+
+public:
+ /* 0x00 */ JKRHeap* mpHeap;
+ /* 0x04 */ JPAResource** mpResArr;
+ /* 0x08 */ JPATexture** mpTexArr;
+ /* 0x0C */ u16 mResMax;
+ /* 0x0E */ u16 mResNum;
+ /* 0x10 */ u16 mTexMax;
+ /* 0x12 */ u16 mTexNum;
+};
+
+#endif /* JPARESOURCEMANAGER_H */
diff --git a/include/JSystem/JParticle/JPATexture.h b/include/JSystem/JParticle/JPATexture.h
new file mode 100644
index 00000000..19b3bed7
--- /dev/null
+++ b/include/JSystem/JParticle/JPATexture.h
@@ -0,0 +1,36 @@
+#ifndef JPATEXTURE_H
+#define JPATEXTURE_H
+
+#include "JSystem/JUtility/JUTTexture.h"
+
+/**
+ * @ingroup jsystem-jparticle
+ *
+ */
+struct JPATextureData {
+ // Probably magic / size / flags up top here, but they're unused.
+ /* 0x00 */ char field_0x00[0x0C];
+ /* 0x0C */ char mName[0x14];
+ /* 0x20 */ ResTIMG mResTIMG;
+};
+
+/**
+ * @ingroup jsystem-jparticle
+ *
+ */
+class JPATexture {
+public:
+ JPATexture(u8 const*);
+ virtual ~JPATexture();
+
+ void load(GXTexMapID texMapID) { mTexture.load(texMapID); }
+
+ JUTTexture* getJUTTexture() { return &mTexture; }
+ const char* getName() const { return mpData->mName; }
+
+public:
+ JUTTexture mTexture;
+ const JPATextureData* mpData;
+};
+
+#endif /* JPATEXTURE_H */
diff --git a/include/JSystem/JSupport/JSUList.h b/include/JSystem/JSupport/JSUList.h
new file mode 100644
index 00000000..884b8b9b
--- /dev/null
+++ b/include/JSystem/JSupport/JSUList.h
@@ -0,0 +1,254 @@
+#ifndef JSULIST_H
+#define JSULIST_H
+
+#include "dolphin/types.h"
+
+template <typename T>
+class JSUList;
+
+//
+// Link
+//
+
+class JSUPtrList;
+
+/**
+* @ingroup jsystem-jsupport
+*
+*/
+class JSUPtrLink {
+public:
+ JSUPtrLink(void* object);
+ ~JSUPtrLink();
+
+ void* getObjectPtr() const { return mObject; }
+
+ JSUPtrList* getList() const { return mList; }
+
+ JSUPtrLink* getNext() const { return mNext; }
+
+ JSUPtrLink* getPrev() const { return mPrev; }
+
+public:
+ void* mObject;
+ JSUPtrList* mList;
+ JSUPtrLink* mPrev;
+ JSUPtrLink* mNext;
+};
+
+/**
+* @ingroup jsystem-jsupport
+*
+*/
+template <typename T>
+class JSULink : public JSUPtrLink {
+public:
+ JSULink(T* object) : JSUPtrLink((void*)object) {}
+
+ T* getObject() const { return static_cast<T*>(mObject); }
+
+ JSUList<T>* getSupervisor() const { return static_cast<JSUList<T>*>(this->getList()); }
+
+ JSULink<T>* getNext() const { return static_cast<JSULink*>(mNext); }
+
+ JSULink<T>* getPrev() const { return static_cast<JSULink*>(mPrev); }
+};
+
+//
+// List
+//
+
+/**
+* @ingroup jsystem-jsupport
+*
+*/
+class JSUPtrList {
+public:
+ JSUPtrList() { this->initiate(); }
+ JSUPtrList(bool init);
+ ~JSUPtrList();
+
+ void initiate();
+ void setFirst(JSUPtrLink* first);
+ bool append(JSUPtrLink* ptr);
+ bool prepend(JSUPtrLink* ptr);
+ bool insert(JSUPtrLink* before, JSUPtrLink* ptr);
+ bool remove(JSUPtrLink* ptr);
+ JSUPtrLink* getNthLink(u32 i) const;
+
+ JSUPtrLink* getFirstLink() const { return mHead; }
+
+ JSUPtrLink* getLastLink() const { return mTail; }
+
+ u32 getNumLinks() const { return mLength; }
+
+private:
+ JSUPtrLink* mHead;
+ JSUPtrLink* mTail;
+ u32 mLength;
+};
+
+/**
+* @ingroup jsystem-jsupport
+*
+*/
+template <typename T>
+class JSUList : public JSUPtrList {
+public:
+ JSUList() : JSUPtrList() {}
+ JSUList(bool init) : JSUPtrList(init) {}
+
+ ~JSUList() {}
+
+ bool append(JSULink<T>* link) { return this->JSUPtrList::append((JSUPtrLink*)link); }
+
+ bool prepend(JSULink<T>* link) { return this->JSUPtrList::prepend((JSUPtrLink*)link); }
+
+ bool insert(JSULink<T>* before, JSULink<T>* link) {
+ return this->JSUPtrList::insert((JSUPtrLink*)before, (JSUPtrLink*)link);
+ }
+
+ bool remove(JSULink<T>* link) { return this->JSUPtrList::remove((JSUPtrLink*)link); }
+
+ JSULink<T>* getFirst() const { return (JSULink<T>*)getFirstLink(); }
+
+ JSULink<T>* getLast() const { return (JSULink<T>*)getLastLink(); }
+
+ JSULink<T>* getNth(int index) { return (JSULink<T>*)getNthLink(index); }
+
+ JSULink<T>* getEnd() const { return NULL; }
+
+ u32 getNumLinks() const { return this->JSUPtrList::getNumLinks(); }
+};
+
+/**
+* @ingroup jsystem-jsupport
+*
+*/
+template <typename T>
+class JSUListIterator {
+public:
+ JSUListIterator() : mLink(NULL) {}
+ JSUListIterator(JSULink<T>* link) : mLink(link) {}
+ JSUListIterator(JSUList<T>* list) : mLink(list->getFirst()) {}
+
+ JSUListIterator<T>& operator=(JSULink<T>* link) {
+ this->mLink = link;
+ return *this;
+ }
+
+ T* getObject() { return this->mLink->getObject(); }
+
+ bool operator==(JSULink<T> const* other) const { return this->mLink == other; }
+ bool operator!=(JSULink<T> const* other) const { return this->mLink != other; }
+ bool operator==(JSUListIterator<T> const& other) const { return this->mLink == other.mLink; }
+ bool operator!=(JSUListIterator<T> const& other) const { return this->mLink != other.mLink; }
+
+ JSUListIterator<T> operator++(int) {
+ JSUListIterator<T> prev = *this;
+ this->mLink = this->mLink->getNext();
+ return prev;
+ }
+
+ JSUListIterator<T>& operator++() {
+ this->mLink = this->mLink->getNext();
+ return *this;
+ }
+
+ JSUListIterator<T> operator--(int) {
+ JSUListIterator<T> prev = *this;
+ this->mLink = this->mLink->getPrev();
+ return prev;
+ }
+
+ JSUListIterator<T>& operator--() {
+ this->mLink = this->mLink->getPrev();
+ return *this;
+ }
+
+ T& operator*() { return *this->getObject(); }
+
+ T* operator->() const { return mLink->getObject(); }
+
+// private:
+ JSULink<T>* mLink;
+};
+
+//
+// Tree
+//
+
+/**
+* @ingroup jsystem-jsupport
+*
+*/
+template <typename T>
+class JSUTree : public JSUList<T>, public JSULink<T> {
+public:
+ JSUTree(T* owner) : JSUList<T>(), JSULink<T>(owner) {}
+ ~JSUTree() {}
+
+ bool appendChild(JSUTree<T>* child) { return this->append(child); }
+
+ bool removeChild(JSUTree<T>* child) { return this->remove(child); }
+
+ bool insertChild(JSUTree<T>* before, JSUTree<T>* child) { return this->insert(before, child); }
+
+ JSUTree<T>* getEndChild() const { return NULL; }
+
+ JSUTree<T>* getFirstChild() const { return (JSUTree<T>*)this->getFirst(); }
+
+ JSUTree<T>* getLastChild() const { return (JSUTree<T>*)this->getLast(); }
+
+ JSUTree<T>* getNextChild() const { return (JSUTree<T>*)this->getNext(); }
+
+ JSUTree<T>* getPrevChild() const { return (JSUTree<T>*)this->getPrev(); }
+
+ u32 getNumChildren() const { return this->getNumLinks(); }
+
+ T* getObject() const { return (T*)this->getObjectPtr(); }
+
+ JSUTree<T>* getParent() const { return (JSUTree<T>*)this->getList(); }
+};
+
+/**
+* @ingroup jsystem-jsupport
+*
+*/
+template <typename T>
+class JSUTreeIterator {
+public:
+ JSUTreeIterator() : mTree(NULL) {}
+ JSUTreeIterator(JSUTree<T>* tree) : mTree(tree) {}
+
+ JSUTreeIterator<T>& operator=(JSUTree<T>* tree) {
+ this->mTree = tree;
+ return *this;
+ }
+
+ T* getObject() { return this->mTree->getObject(); }
+
+ bool operator==(JSUTree<T>* other) { return this->mTree == other; }
+
+ bool operator!=(JSUTree<T>* other) { return this->mTree != other; }
+
+ JSUTreeIterator<T> operator++(int) {
+ JSUTreeIterator<T> prev = *this;
+ this->mTree = this->mTree->getNextChild();
+ return prev;
+ }
+
+ JSUTreeIterator<T>& operator++() {
+ this->mTree = this->mTree->getNextChild();
+ return *this;
+ }
+
+ T* operator*() { return this->getObject(); }
+
+ T* operator->() { return this->getObject(); }
+
+private:
+ JSUTree<T>* mTree;
+};
+
+#endif /* JSULIST_H */
diff --git a/include/JSystem/JSupport/JSupport.h b/include/JSystem/JSupport/JSupport.h
new file mode 100644
index 00000000..c4a47c61
--- /dev/null
+++ b/include/JSystem/JSupport/JSupport.h
@@ -0,0 +1,45 @@
+#ifndef JSUPPORT_H
+#define JSUPPORT_H
+
+#include <dolphin.h>
+
+/**
+* @ingroup jsystem-jsupport
+*
+*/
+template <typename T>
+T* JSUConvertOffsetToPtr(const void* ptr, u32 offset) {
+ if (offset == 0) {
+ return NULL;
+ } else {
+ return (T*)((s32)ptr + (s32)offset);
+ }
+}
+
+/**
+* @ingroup jsystem-jsupport
+*
+*/
+template <typename T>
+T* JSUConvertOffsetToPtr(const void* ptr, const void* offset) {
+ if (offset == NULL) {
+ return NULL;
+ } else {
+ return (T*)((s32)ptr + (s32)offset);
+ }
+}
+
+inline u8 JSULoNibble(u8 param_0) { return param_0 & 0x0f; }
+inline u8 JSUHiNibble(u8 param_0) {return param_0 >> 4; }
+
+inline u8 JSULoByte(u16 in) {
+ return in & 0xff;
+}
+
+inline u8 JSUHiByte(u16 in) {
+ return in >> 8;
+}
+
+inline u16 JSULoHalf(u32 param_0) {return param_0; }
+
+#endif
diff --git a/include/JSystem/JUtility/JUTAssert.h b/include/JSystem/JUtility/JUTAssert.h
new file mode 100644
index 00000000..5d469fb3
--- /dev/null
+++ b/include/JSystem/JUtility/JUTAssert.h
@@ -0,0 +1,64 @@
+#ifndef JUTASSERT_H
+#define JUTASSERT_H
+
+#include "dolphin/os.h"
+
+#ifdef DEBUG
+#define JUT_ASSERT(LINE, COND) \
+ (COND) ? (void)0 : (JUTAssertion::showAssert(JUTAssertion::getSDevice(), __FILE__, LINE, #COND), OSPanic(__FILE__, LINE, "Halt"));
+
+#define JUT_ASSERT_MSG(LINE, COND, MSG) \
+ (COND) ? (void)0 : (JUTAssertion::showAssert(JUTAssertion::getSDevice(), __FILE__, LINE, MSG), OSPanic(__FILE__, LINE, "Halt"));
+
+#define JUT_ASSERT_MSG_F(LINE, COND, MSG, ...) \
+ (COND) ? (void)0 : (JUTAssertion::showAssert_f(JUTAssertion::getSDevice(), __FILE__, LINE, MSG, __VA_ARGS__), OSPanic(__FILE__, LINE, "Halt"));
+
+#define J3D_ASSERT(LINE, COND, MSG) JUT_ASSERT_MSG(LINE, (COND) != 0, MSG)
+
+#define JUT_PANIC(LINE, TEXT) \
+ JUTAssertion::showAssert(JUTAssertion::getSDevice(), __FILE__, LINE, TEXT); \
+ OSPanic(__FILE__, LINE, "Halt");
+
+#define JUT_WARN_DEVICE(LINE, DEVICE, ...) \
+ JUTAssertion::setWarningMessage_f(DEVICE, __FILE__, LINE, __VA_ARGS__); \
+
+#define JUT_WARN(LINE, ...) \
+ JUT_WARN_DEVICE(LINE, JUTAssertion::getSDevice(), __VA_ARGS__)
+
+#define JUT_LOG(LINE, ...) \
+ JUTAssertion::setLogMessage_f(JUTAssertion::getSDevice(), __FILE__, LINE, __VA_ARGS__)
+
+#define JUT_CONFIRM(LINE, COND) \
+ JUTAssertion::setConfirmMessage(JUTAssertion::getSDevice(), __FILE__, LINE, COND, #COND)
+
+#else
+#define JUT_ASSERT(...) (void)0;
+#define JUT_ASSERT_MSG(...) (void)0;
+#define JUT_ASSERT_MSG_F(...) (void)0;
+#define J3D_ASSERT(...) (void)0;
+#define JUT_PANIC(...)
+#define JUT_WARN(...)
+#define JUT_WARN_DEVICE(...)
+#define JUT_LOG(...)
+#define JUT_CONFIRM(...)
+#endif
+
+namespace JUTAssertion {
+ /* 802E495C */ void create();
+ /* 802E4960 */ u32 flush_subroutine();
+ /* 802E499C */ void flushMessage();
+ /* 802E4A54 */ void flushMessage_dbPrint();
+ /* 802E4C34 */ void setVisible(bool);
+ /* 802E4C3C */ void setMessageCount(int);
+
+ u32 getSDevice();
+ void showAssert(u32 device, const char * file, int line, const char * assertion);
+ void showAssert_f(u32 device, const char* file, int line, const char* msg, ...);
+ void setWarningMessage_f(u32 device, char * file, int line, const char * fmt, ...);
+ void setLogMessage_f(u32 device, char* file, int line, const char* fmt, ...);
+ void setConfirmMessage(u32 param_1, char* file, int line, bool param_4, const char* msg);
+};
+
+extern bool sAssertVisible;
+
+#endif /* JUTASSERT_H */
diff --git a/include/JSystem/JUtility/JUTTexture.h b/include/JSystem/JUtility/JUTTexture.h
new file mode 100644
index 00000000..606cd581
--- /dev/null
+++ b/include/JSystem/JUtility/JUTTexture.h
@@ -0,0 +1,113 @@
+#ifndef JUTTEXTURE_H
+#define JUTTEXTURE_H
+
+#include <dolphin/gx.h>
+
+class JUTPalette;
+
+/**
+* @ingroup jsystem-jutility
+* @brief Image data header.
+*
+* Acts as the header to image data. Usually texture data immediately follows it,
+* so any pointer arithmetic to go past the end of this structure is so that a
+* variable sized allocated buffer can be accessed.
+*
+*/
+struct ResTIMG {
+ /* 0x00 */ u8 format;
+ /* 0x01 */ u8 alphaEnabled;
+ /* 0x02 */ u16 width;
+ /* 0x04 */ u16 height;
+ /* 0x06 */ u8 wrapS;
+ /* 0x07 */ u8 wrapT;
+ /* 0x08 */ u8 indexTexture;
+ /* 0x09 */ u8 colorFormat;
+ /* 0x0A */ u16 numColors;
+ /* 0x0C */ u32 paletteOffset;
+ /* 0x10 */ u8 mipmapEnabled;
+ /* 0x11 */ u8 doEdgeLOD;
+ /* 0x12 */ u8 biasClamp;
+ /* 0x13 */ u8 maxAnisotropy;
+ /* 0x14 */ u8 minFilter;
+ /* 0x15 */ u8 magFilter;
+ /* 0x16 */ s8 minLOD;
+ /* 0x17 */ s8 maxLOD;
+ /* 0x18 */ u8 mipmapCount;
+ /* 0x19 */ u8 unknown;
+ /* 0x1A */ s16 LODBias;
+ /* 0x1C */ u32 imageOffset;
+}; // Size: 0x20
+
+/**
+* @ingroup jsystem-jutility
+*
+*/
+class JUTTexture {
+public:
+ JUTTexture() {
+ setCaptureFlag(false);
+ mEmbPalette = NULL;
+ mTexInfo = NULL;
+ }
+
+ JUTTexture(const ResTIMG* p_timg, u8 param_1) {
+ mEmbPalette = NULL;
+ storeTIMG(p_timg, param_1);
+ setCaptureFlag(false);
+ }
+
+ ~JUTTexture();
+ void storeTIMG(ResTIMG const*, JUTPalette*, _GXTlut);
+ void storeTIMG(ResTIMG const*, u8);
+ void storeTIMG(ResTIMG const*, JUTPalette*);
+ void attachPalette(JUTPalette*);
+ void init();
+ void initTexObj(_GXTlut);
+ void initTexObj();
+ void load(_GXTexMapID);
+
+ const ResTIMG* getTexInfo() const { return mTexInfo; }
+ s32 getFormat() const { return mTexInfo->format; }
+ s32 getTransparency() { return mTexInfo->alphaEnabled; }
+ s32 getWidth() const { return mTexInfo->width; }
+ s32 getHeight() const { return mTexInfo->height; }
+ void setCaptureFlag(bool flag) { mFlags &= 2 | flag; }
+ u8 getCaptureFlag() const { return mFlags & 1; }
+ u8 getEmbPaletteDelFlag() const { return mFlags & 2; }
+ void setEmbPaletteDelFlag(bool flag) { mFlags = (mFlags & 1) | (flag << 1);}
+ u8 getTlutName() const { return mTlutName; }
+ bool operator==(const JUTTexture& other) {
+ return mTexInfo == other.mTexInfo
+ && field_0x2c == other.field_0x2c
+ && mWrapS == other.mWrapS
+ && mWrapT == other.mWrapT
+ && mMinFilter == other.mMinFilter
+ && mMagFilter == other.mMagFilter
+ && mMinLOD == other.mMinLOD
+ && mMinLOD == other.mMinLOD
+ && mLODBias == other.mLODBias;
+ }
+ bool operator!=(const JUTTexture& other) {
+ return !operator==(other);
+ }
+
+private:
+ /* 0x00 */ GXTexObj mTexObj;
+ /* 0x20 */ const ResTIMG* mTexInfo;
+ /* 0x24 */ void* mTexData;
+ /* 0x28 */ JUTPalette* mEmbPalette;
+ /* 0x2C */ JUTPalette* field_0x2c;
+ /* 0x30 */ u8 mWrapS;
+ /* 0x31 */ u8 mWrapT;
+ /* 0x32 */ u8 mMinFilter;
+ /* 0x33 */ u8 mMagFilter;
+ /* 0x34 */ u16 mMinLOD;
+ /* 0x36 */ u16 mMaxLOD;
+ /* 0x38 */ s16 mLODBias;
+ /* 0x3A */ u8 mTlutName;
+ /* 0x3B */ u8 mFlags;
+ /* 0x3C */ void* field_0x3c;
+};
+
+#endif /* JUTTEXTURE_H */
diff --git a/include/JSystem/TPosition3.h b/include/JSystem/TPosition3.h
new file mode 100644
index 00000000..807ce4fe
--- /dev/null
+++ b/include/JSystem/TPosition3.h
@@ -0,0 +1,86 @@
+#ifndef TPOSITION3_H
+#define TPOSITION3_H
+
+#include "dolphin/mtx.h"
+#include "JSystem/JMath/JMath.h"
+#include "JSystem/JGeometry.h"
+
+namespace JGeometry {
+
+template <typename T>
+struct SMatrix34C {
+ T data[3][4];
+};
+
+template <>
+struct SMatrix34C<f32> {
+ f32 data[3][4];
+
+ void identity() { MTXIdentity(data); }
+
+ typedef f32 ArrType[4];
+ void set(const ArrType* src) {
+ JMath::gekko_ps_copy12(data, src);
+ }
+
+ operator ArrType*() { return data; }
+ operator const ArrType*() const { return data; }
+};
+
+template <typename T>
+struct SMatrix33C {
+ T data[3][3];
+
+ inline T& ref(int i, int j) {
+ return data[i][j];
+ }
+
+ inline T at(int i, int j) const {
+ return data[i][j];
+ }
+
+ inline void set(T param_1, T param_2, T param_3, T param_4, T param_5,
+ T param_6, T param_7, T param_8, T param_9) {
+ ref(0,0) = param_1;
+ ref(0,1) = param_2;
+ ref(0,2) = param_3;
+ ref(1,0) = param_4;
+ ref(1,1) = param_5;
+ ref(1,2) = param_6;
+ ref(2,0) = param_7;
+ ref(2,1) = param_8;
+ ref(2,2) = param_9;
+ }
+};
+
+template <typename T>
+struct TMatrix34 : public T {};
+
+template <typename T>
+struct TRotation3 : public T {};
+
+template<typename T>
+struct TRotation3<SMatrix33C<T> > : public SMatrix33C<T> {
+ inline void getEulerXYZ(TVec3<T>* param_1) const {
+ if (at(2, 0) - TUtil<T>::one() >= -TUtil<T>::epsilon()) {
+ param_1->set(TUtil<T>::atan2(-at(0, 1), at(1, 1)), -TUtil<T>::halfPI(), 0.0);
+ } else {
+ if (at(2, 0) + TUtil<T>::one() <= TUtil<T>::epsilon()) {
+ param_1->set(TUtil<T>::atan2(at(0, 1), at(1, 1)), TUtil<T>::halfPI(), 0.0);
+ } else {
+ param_1->x = TUtil<T>::atan2(at(2, 1), at(2, 2));
+ param_1->z = TUtil<T>::atan2(at(1, 0), at(0, 0));
+ param_1->y = TUtil<T>::asin(-at(2, 0));
+ }
+ }
+ }
+};
+
+template <typename T>
+struct TPosition3 : public T {};
+
+typedef TPosition3<TRotation3<TMatrix34<SMatrix34C<f32> > > > TPosition3f32;
+
+} // namespace JGeometry
+
+#endif
diff --git a/src/JSystem/JParticle/JPABaseShape.cpp b/src/JSystem/JParticle/JPABaseShape.cpp
new file mode 100644
index 00000000..d869cd20
--- /dev/null
+++ b/src/JSystem/JParticle/JPABaseShape.cpp
@@ -0,0 +1,1449 @@
+//
+// Generated By: dol2asm
+// Translation Unit: JPABaseShape
+//
+
+#include "JSystem/JParticle/JPABaseShape.h"
+#include "JSystem/JKernel/JKRHeap.h"
+#include "JSystem/JParticle/JPAParticle.h"
+#include "JSystem/JParticle/JPAEmitter.h"
+#include "JSystem/JParticle/JPAResourceManager.h"
+#include "JSystem/JMath/JMATrigonometric.h"
+#include "dolphin/mtx.h"
+#include "dolphin/gx.h"
+
+/* 80276A90-80276ACC 2713D0 003C+00 0/0 1/1 0/0 .text JPASetPointSize__FP18JPAEmitterWorkData */
+void JPASetPointSize(JPAEmitterWorkData* work) {
+ GXSetPointSize((u8)(25.0f * work->mGlobalPtclScl.x), GX_TO_ONE);
+}
+
+/* 80276ACC-80276B08 27140C 003C+00 0/0 1/1 0/0 .text JPASetLineWidth__FP18JPAEmitterWorkData */
+void JPASetLineWidth(JPAEmitterWorkData* work) {
+ GXSetLineWidth((u8)(25.0f * work->mGlobalPtclScl.x), GX_TO_ONE);
+}
+
+/* 80276B08-80276B4C 271448 0044+00 0/0 1/1 0/0 .text
+ * JPASetPointSize__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPASetPointSize(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ GXSetPointSize((u8)(ptcl->mParticleScaleX * (25.0f * work->mGlobalPtclScl.x)), GX_TO_ONE);
+}
+
+/* 80276B4C-80276B90 27148C 0044+00 0/0 1/1 0/0 .text
+ * JPASetLineWidth__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPASetLineWidth(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ GXSetLineWidth((u8)(ptcl->mParticleScaleX * (25.0f * work->mGlobalPtclScl.x)), GX_TO_ONE);
+}
+
+/* 80276B90-80276C2C 2714D0 009C+00 0/0 1/1 0/0 .text JPARegistPrm__FP18JPAEmitterWorkData */
+void JPARegistPrm(JPAEmitterWorkData* work) {
+ JPABaseEmitter* emtr = work->mpEmtr;
+ GXColor prm = emtr->mPrmClr;
+ prm.r = COLOR_MULTI(prm.r, emtr->mGlobalPrmClr.r);
+ prm.g = COLOR_MULTI(prm.g, emtr->mGlobalPrmClr.g);
+ prm.b = COLOR_MULTI(prm.b, emtr->mGlobalPrmClr.b);
+ prm.a = COLOR_MULTI(prm.a, emtr->mGlobalPrmClr.a);
+ GXSetTevColor(GX_TEVREG0, prm);
+}
+
+/* 80276C2C-80276CB0 27156C 0084+00 0/0 1/1 0/0 .text JPARegistEnv__FP18JPAEmitterWorkData */
+void JPARegistEnv(JPAEmitterWorkData* work) {
+ JPABaseEmitter* emtr = work->mpEmtr;
+ GXColor env = emtr->mEnvClr;
+ env.r = COLOR_MULTI(env.r, emtr->mGlobalEnvClr.r);
+ env.g = COLOR_MULTI(env.g, emtr->mGlobalEnvClr.g);
+ env.b = COLOR_MULTI(env.b, emtr->mGlobalEnvClr.b);
+ GXSetTevColor(GX_TEVREG1, env);
+}
+
+/* 80276CB0-80276DB0 2715F0 0100+00 0/0 1/1 0/0 .text JPARegistPrmEnv__FP18JPAEmitterWorkData */
+void JPARegistPrmEnv(JPAEmitterWorkData* work) {
+ JPABaseEmitter* emtr = work->mpEmtr;
+ GXColor prm = emtr->mPrmClr;
+ GXColor env = emtr->mEnvClr;
+ prm.r = COLOR_MULTI(prm.r, emtr->mGlobalPrmClr.r);
+ prm.g = COLOR_MULTI(prm.g, emtr->mGlobalPrmClr.g);
+ prm.b = COLOR_MULTI(prm.b, emtr->mGlobalPrmClr.b);
+ prm.a = COLOR_MULTI(prm.a, emtr->mGlobalPrmClr.a);
+ env.r = COLOR_MULTI(env.r, emtr->mGlobalEnvClr.r);
+ env.g = COLOR_MULTI(env.g, emtr->mGlobalEnvClr.g);
+ env.b = COLOR_MULTI(env.b, emtr->mGlobalEnvClr.b);
+ GXSetTevColor(GX_TEVREG0, prm);
+ GXSetTevColor(GX_TEVREG1, env);
+}
+
+/* 80276DB0-80276E60 2716F0 00B0+00 0/0 1/1 0/0 .text
+ * JPARegistAlpha__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPARegistAlpha(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ JPABaseEmitter* emtr = work->mpEmtr;
+ GXColor prm = emtr->mPrmClr;
+ prm.r = COLOR_MULTI(prm.r, emtr->mGlobalPrmClr.r);
+ prm.g = COLOR_MULTI(prm.g, emtr->mGlobalPrmClr.g);
+ prm.b = COLOR_MULTI(prm.b, emtr->mGlobalPrmClr.b);
+ prm.a = COLOR_MULTI(prm.a, emtr->mGlobalPrmClr.a);
+ prm.a = COLOR_MULTI(prm.a, ptcl->mPrmColorAlphaAnm);
+ GXSetTevColor(GX_TEVREG0, prm);
+}
+
+/* 80276E60-80276F10 2717A0 00B0+00 0/0 1/1 0/0 .text
+ * JPARegistPrmAlpha__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPARegistPrmAlpha(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ JPABaseEmitter* emtr = work->mpEmtr;
+ GXColor prm = ptcl->mPrmClr;
+ prm.r = COLOR_MULTI(prm.r, emtr->mGlobalPrmClr.r);
+ prm.g = COLOR_MULTI(prm.g, emtr->mGlobalPrmClr.g);
+ prm.b = COLOR_MULTI(prm.b, emtr->mGlobalPrmClr.b);
+ prm.a = COLOR_MULTI(prm.a, emtr->mGlobalPrmClr.a);
+ prm.a = COLOR_MULTI(prm.a, ptcl->mPrmColorAlphaAnm);
+ GXSetTevColor(GX_TEVREG0, prm);
+}
+
+/* 80276F10-80277024 271850 0114+00 0/0 1/1 0/0 .text
+ * JPARegistPrmAlphaEnv__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPARegistPrmAlphaEnv(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ JPABaseEmitter* emtr = work->mpEmtr;
+ GXColor prm = ptcl->mPrmClr;
+ GXColor env = ptcl->mEnvClr;
+ prm.r = COLOR_MULTI(prm.r, emtr->mGlobalPrmClr.r);
+ prm.g = COLOR_MULTI(prm.g, emtr->mGlobalPrmClr.g);
+ prm.b = COLOR_MULTI(prm.b, emtr->mGlobalPrmClr.b);
+ prm.a = COLOR_MULTI(prm.a, emtr->mGlobalPrmClr.a);
+ prm.a = COLOR_MULTI(prm.a, ptcl->mPrmColorAlphaAnm);
+ env.r = COLOR_MULTI(env.r, emtr->mGlobalEnvClr.r);
+ env.g = COLOR_MULTI(env.g, emtr->mGlobalEnvClr.g);
+ env.b = COLOR_MULTI(env.b, emtr->mGlobalEnvClr.b);
+ GXSetTevColor(GX_TEVREG0, prm);
+ GXSetTevColor(GX_TEVREG1, env);
+}
+
+/* 80277024-80277138 271964 0114+00 0/0 1/1 0/0 .text
+ * JPARegistAlphaEnv__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPARegistAlphaEnv(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ JPABaseEmitter* emtr = work->mpEmtr;
+ GXColor prm = emtr->mPrmClr;
+ GXColor env = ptcl->mEnvClr;
+ prm.r = COLOR_MULTI(prm.r, emtr->mGlobalPrmClr.r);
+ prm.g = COLOR_MULTI(prm.g, emtr->mGlobalPrmClr.g);
+ prm.b = COLOR_MULTI(prm.b, emtr->mGlobalPrmClr.b);
+ prm.a = COLOR_MULTI(prm.a, emtr->mGlobalPrmClr.a);
+ prm.a = COLOR_MULTI(prm.a, ptcl->mPrmColorAlphaAnm);
+ env.r = COLOR_MULTI(env.r, emtr->mGlobalEnvClr.r);
+ env.g = COLOR_MULTI(env.g, emtr->mGlobalEnvClr.g);
+ env.b = COLOR_MULTI(env.b, emtr->mGlobalEnvClr.b);
+ GXSetTevColor(GX_TEVREG0, prm);
+ GXSetTevColor(GX_TEVREG1, env);
+}
+
+/* 80277138-802771BC 271A78 0084+00 0/0 1/1 0/0 .text
+ * JPARegistEnv__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPARegistEnv(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ JPABaseEmitter* emtr = work->mpEmtr;
+ GXColor env = ptcl->mEnvClr;
+ env.r = COLOR_MULTI(env.r, emtr->mGlobalEnvClr.r);
+ env.g = COLOR_MULTI(env.g, emtr->mGlobalEnvClr.g);
+ env.b = COLOR_MULTI(env.b, emtr->mGlobalEnvClr.b);
+ GXSetTevColor(GX_TEVREG1, env);
+}
+
+/* 802771BC-802771E8 271AFC 002C+00 0/0 1/1 0/0 .text JPACalcClrIdxNormal__FP18JPAEmitterWorkData
+ */
+void JPACalcClrIdxNormal(JPAEmitterWorkData* work) {
+ JPABaseShape* bsp = work->mpRes->getBsp();
+ s16 keyFrame;
+ if (work->mpEmtr->mTick < bsp->getClrAnmMaxFrm()) {
+ keyFrame = work->mpEmtr->mTick;
+ } else {
+ keyFrame = bsp->getClrAnmMaxFrm();
+ }
+ work->mClrKeyFrame = keyFrame;
+}
+
+/* 802771E8-80277210 271B28 0028+00 0/0 1/1 0/0 .text
+ * JPACalcClrIdxNormal__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPACalcClrIdxNormal(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
+ JPABaseShape* shape = work->mpRes->getBsp();
+ s16 age = param_1->mAge;
+ s16 maxFrm = shape->getClrAnmMaxFrm();
+ s16 keyFrame;
+ if (age < maxFrm) {
+ keyFrame = age;
+ } else {
+ keyFrame = maxFrm;
+ }
+ work->mClrKeyFrame = keyFrame;
+}
+
+/* 80277210-80277240 271B50 0030+00 0/0 1/1 0/0 .text JPACalcClrIdxRepeat__FP18JPAEmitterWorkData
+ */
+void JPACalcClrIdxRepeat(JPAEmitterWorkData* work) {
+ JPABaseShape* shape = work->mpRes->getBsp();
+ work->mClrKeyFrame = work->mpEmtr->mTick % (shape->getClrAnmMaxFrm() + 1);
+}
+
+/* 80277240-8027727C 271B80 003C+00 0/0 1/1 0/0 .text
+ * JPACalcClrIdxRepeat__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPACalcClrIdxRepeat(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
+ JPABaseShape* shape = work->mpRes->getBsp();
+ s32 tick = shape->getClrLoopOfst(param_1->mAnmRandom);
+ tick = param_1->mAge + tick;
+ work->mClrKeyFrame = tick % (shape->getClrAnmMaxFrm() + 1);
+}
+
+/* 8027727C-802772BC 271BBC 0040+00 0/0 1/1 0/0 .text JPACalcClrIdxReverse__FP18JPAEmitterWorkData
+ */
+void JPACalcClrIdxReverse(JPAEmitterWorkData* work) {
+ JPABaseShape* shape = work->mpRes->getBsp();
+ int maxFrm = shape->getClrAnmMaxFrm();
+ u32 tick = work->mpEmtr->mTick;
+ u32 uVar1 = tick / maxFrm;
+ tick = tick % maxFrm;
+ uVar1 &= 1;
+ work->mClrKeyFrame = tick + (uVar1) * (maxFrm - tick * 2);
+}
+
+/* 802772BC-80277308 271BFC 004C+00 0/0 1/1 0/0 .text
+ * JPACalcClrIdxReverse__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPACalcClrIdxReverse(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
+ JPABaseShape* shape = work->mpRes->getBsp();
+ s32 tick = param_1->mAge + shape->getClrLoopOfst(param_1->mAnmRandom);
+ s32 maxFrm = shape->getClrAnmMaxFrm();
+ s32 rem = tick % maxFrm;
+ work->mClrKeyFrame = rem + ((tick / maxFrm) & 1) * (maxFrm - rem * 2);
+}
+
+/* 80277308-80277314 271C48 000C+00 0/0 1/1 0/0 .text JPACalcClrIdxMerge__FP18JPAEmitterWorkData
+ */
+void JPACalcClrIdxMerge(JPAEmitterWorkData* work) {
+ work->mClrKeyFrame = 0;
+}
+
+/* 80277314-80277384 271C54 0070+00 0/0 1/1 0/0 .text
+ * JPACalcClrIdxMerge__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPACalcClrIdxMerge(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
+ JPABaseShape* shape = work->mpRes->getBsp();
+ s32 maxFrm = shape->getClrAnmMaxFrm() + 1;
+ s32 tick = (s32)(param_1->mTime * maxFrm) + shape->getClrLoopOfst(param_1->mAnmRandom);
+ work->mClrKeyFrame = tick % maxFrm;
+}
+
+/* 80277384-80277390 271CC4 000C+00 0/0 1/1 0/0 .text JPACalcClrIdxRandom__FP18JPAEmitterWorkData
+ */
+void JPACalcClrIdxRandom(JPAEmitterWorkData* work) {
+ work->mClrKeyFrame = 0;
+}
+
+/* 80277390-802773C4 271CD0 0034+00 0/0 1/1 0/0 .text
+ * JPACalcClrIdxRandom__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPACalcClrIdxRandom(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
+ JPABaseShape* shape = work->mpRes->getBsp();
+ s32 tick = shape->getClrLoopOfst(param_1->mAnmRandom);
+ s32 maxFrm = shape->getClrAnmMaxFrm() + 1;
+ work->mClrKeyFrame = tick % maxFrm;
+}
+
+/* 802773C4-80277404 271D04 0040+00 0/0 1/1 0/0 .text JPACalcPrm__FP18JPAEmitterWorkData
+ */
+void JPACalcPrm(JPAEmitterWorkData* work) {
+ work->mpRes->getBsp()->getPrmClr(work->mClrKeyFrame, &work->mpEmtr->mPrmClr);
+}
+
+/* 80277404-80277440 271D44 003C+00 0/0 1/1 0/0 .text
+ * JPACalcPrm__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPACalcPrm(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ work->mpRes->getBsp()->getPrmClr(work->mClrKeyFrame, &ptcl->mPrmClr);
+}
+
+/* 80277440-80277480 271D80 0040+00 0/0 1/1 0/0 .text JPACalcEnv__FP18JPAEmitterWorkData
+ */
+void JPACalcEnv(JPAEmitterWorkData* work) {
+ work->mpRes->getBsp()->getEnvClr(work->mClrKeyFrame, &work->mpEmtr->mEnvClr);
+}
+
+/* 80277480-802774BC 271DC0 003C+00 0/0 1/1 0/0 .text
+ * JPACalcEnv__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPACalcEnv(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ work->mpRes->getBsp()->getEnvClr(work->mClrKeyFrame, &ptcl->mEnvClr);
+}
+
+/* 802774BC-80277504 271DFC 0048+00 0/0 1/1 0/0 .text
+ * JPACalcColorCopy__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPACalcColorCopy(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ JPABaseEmitter* emtr = work->mpEmtr;
+ ptcl->mPrmClr = emtr->mPrmClr;
+ ptcl->mEnvClr = emtr->mEnvClr;
+}
+
+/* 80277504-8027753C 271E44 0038+00 0/0 1/1 0/0 .text JPAGenTexCrdMtxIdt__FP18JPAEmitterWorkData
+ */
+void JPAGenTexCrdMtxIdt(JPAEmitterWorkData* param_0) {
+ GXSetTexCoordGen2(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY, GX_FALSE, GX_PTIDENTITY);
+}
+
+/* 8027753C-80277574 271E7C 0038+00 0/0 1/1 0/0 .text JPAGenTexCrdMtxAnm__FP18JPAEmitterWorkData
+ */
+void JPAGenTexCrdMtxAnm(JPAEmitterWorkData* param_0) {
+ GXSetTexCoordGen2(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_TEXMTX0, GX_FALSE, GX_PTIDENTITY);
+}
+
+/* 80277574-802775AC 271EB4 0038+00 0/0 1/1 0/0 .text JPAGenTexCrdMtxPrj__FP18JPAEmitterWorkData
+ */
+void JPAGenTexCrdMtxPrj(JPAEmitterWorkData* param_0) {
+ GXSetTexCoordGen2(GX_TEXCOORD0, GX_TG_MTX3x4, GX_TG_POS, GX_TEXMTX0, GX_FALSE, GX_PTIDENTITY);
+}
+
+/* 802775AC-80277758 271EEC 01AC+00 0/0 1/1 0/0 .text
+ * JPAGenCalcTexCrdMtxAnm__FP18JPAEmitterWorkData */
+void JPAGenCalcTexCrdMtxAnm(JPAEmitterWorkData* work) {
+ JPABaseShape* shape = work->mpRes->getBsp();
+ f32 dVar16 = work->mpEmtr->mTick;
+ f32 dVar15 = 0.5f * (1.0f + shape->getTilingS());
+ f32 dVar14 = 0.5f * (1.0f + shape->getTilingT());
+ f32 dVar11 = (dVar16 * shape->getIncTransX()) + shape->getInitTransX();
+ f32 dVar10 = (dVar16 * shape->getIncTransY()) + shape->getInitTransY();
+ f32 dVar13 = (dVar16 * shape->getIncScaleX()) + shape->getInitScaleX();
+ f32 dVar12 = (dVar16 * shape->getIncScaleY()) + shape->getInitScaleY();
+ s32 local_c0 = (dVar16 * shape->getIncRot()) + shape->getInitRot();
+ f32 dVar8 = JMASSin(local_c0);
+ f32 dVar9 = JMASCos(local_c0);
+ Mtx local_108;
+ local_108[0][0] = dVar13 * dVar9;
+ local_108[0][1] = -dVar13 * dVar8;
+ local_108[0][2] = 0.0f;
+ local_108[0][3] =
+ (dVar15 + (dVar13 * ((dVar8 * (dVar14 + dVar10)) - (dVar9 * (dVar15 + dVar11)))));
+ local_108[1][0] = dVar12 * dVar8;
+ local_108[1][1] = dVar12 * dVar9;
+ local_108[1][2] = 0.0f;
+ local_108[1][3] =
+ (dVar14 + (-dVar12 * ((dVar8 * (dVar15 + dVar11)) + (dVar9 * (dVar14 + dVar10)))));
+ local_108[2][0] = 0.0f;
+ local_108[2][1] = 0.0f;
+ local_108[2][2] = 1.0f;
+ local_108[2][3] = 0.0f;
+ GXLoadTexMtxImm(local_108, 0x1e, GX_MTX2x4);
+ GXSetTexCoordGen2(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, 0x1e, false, 0x7d);
+}
+
+/* 80277758-802778EC 272098 0194+00 0/0 1/1 0/0 .text
+ * JPALoadCalcTexCrdMtxAnm__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPALoadCalcTexCrdMtxAnm(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
+ JPABaseShape* shape = work->mpRes->getBsp();
+ f32 dVar16 = param_1->mAge;
+ f32 dVar15 = 0.5f * (1.0f + shape->getTilingS());
+ f32 dVar14 = 0.5f * (1.0f + shape->getTilingT());
+ f32 dVar11 = (dVar16 * shape->getIncTransX()) + shape->getInitTransX();
+ f32 dVar10 = (dVar16 * shape->getIncTransY()) + shape->getInitTransY();
+ f32 dVar13 = (dVar16 * shape->getIncScaleX()) + shape->getInitScaleX();
+ f32 dVar12 = (dVar16 * shape->getIncScaleY()) + shape->getInitScaleY();
+ s32 local_c0 = (dVar16 * shape->getIncRot()) + shape->getInitRot();
+ f32 dVar8 = JMASSin(local_c0);
+ f32 dVar9 = JMASCos(local_c0);
+ Mtx local_108;
+ local_108[0][0] = dVar13 * dVar9;
+ local_108[0][1] = -dVar13 * dVar8;
+ local_108[0][2] = 0.0f;
+ local_108[0][3] =
+ (dVar15 + (dVar13 * ((dVar8 * (dVar14 + dVar10)) - (dVar9 * (dVar15 + dVar11)))));
+ local_108[1][0] = dVar12 * dVar8;
+ local_108[1][1] = dVar12 * dVar9;
+ local_108[1][2] = 0.0f;
+ local_108[1][3] =
+ (dVar14 + (-dVar12 * ((dVar8 * (dVar15 + dVar11)) + (dVar9 * (dVar14 + dVar10)))));
+ local_108[2][0] = 0.0f;
+ local_108[2][1] = 0.0f;
+ local_108[2][2] = 1.0f;
+ local_108[2][3] = 0.0f;
+ GXLoadTexMtxImm(local_108, 0x1e, GX_MTX2x4);
+}
+
+/* 802778EC-80277940 27222C 0054+00 0/0 1/1 0/0 .text JPALoadTex__FP18JPAEmitterWorkData
+ */
+void JPALoadTex(JPAEmitterWorkData* work) {
+ work->mpResMgr->load(work->mpRes->getTexIdx(work->mpRes->getBsp()->getTexIdx()), GX_TEXMAP0);
+}
+
+/* 80277940-80277990 272280 0050+00 0/0 1/1 0/0 .text JPALoadTexAnm__FP18JPAEmitterWorkData */
+void JPALoadTexAnm(JPAEmitterWorkData* work) {
+ work->mpResMgr->load(work->mpRes->getTexIdx(work->mpEmtr->mTexAnmIdx), GX_TEXMAP0);
+}
+
+/* 80277990-802779DC 2722D0 004C+00 0/0 1/1 0/0 .text
+ * JPALoadTexAnm__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPALoadTexAnm(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ work->mpResMgr->load(work->mpRes->getTexIdx(ptcl->mTexAnmIdx), GX_TEXMAP0);
+}
+
+/* 802779DC-80277A18 27231C 003C+00 0/0 1/1 0/0 .text JPACalcTexIdxNormal__FP18JPAEmitterWorkData
+ */
+void JPACalcTexIdxNormal(JPAEmitterWorkData* work) {
+ JPABaseShape* shape = work->mpRes->getBsp();
+ u8 tick = shape->getTexAnmKeyNum() - 1 < work->mpEmtr->mTick
+ ? shape->getTexAnmKeyNum() - 1 : work->mpEmtr->mTick;
+ work->mpEmtr->mTexAnmIdx = shape->getTexIdx(tick);
+}
+
+/* 80277A18-80277A50 272358 0038+00 0/0 1/1 0/0 .text
+ * JPACalcTexIdxNormal__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPACalcTexIdxNormal(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
+ JPABaseShape* shape = work->mpRes->getBsp();
+ u8 tick = shape->getTexAnmKeyNum() - 1 < param_1->mAge
+ ? shape->getTexAnmKeyNum() - 1 : param_1->mAge;
+ param_1->mTexAnmIdx = shape->getTexIdx(tick);
+}
+
+/* 80277A50-80277A88 272390 0038+00 0/0 1/1 0/0 .text JPACalcTexIdxRepeat__FP18JPAEmitterWorkData
+ */
+void JPACalcTexIdxRepeat(JPAEmitterWorkData* work) {
+ JPABaseShape* shape = work->mpRes->getBsp();
+ work->mpEmtr->mTexAnmIdx = shape->getTexIdx(work->mpEmtr->mTick % shape->getTexAnmKeyNum());
+}
+
+/* 80277A88-80277ACC 2723C8 0044+00 0/0 1/1 0/0 .text
+ * JPACalcTexIdxRepeat__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPACalcTexIdxRepeat(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
+ JPABaseShape* shape = work->mpRes->getBsp();
+ param_1->mTexAnmIdx = shape->getTexIdx(
+ ((int)shape->getTexLoopOfst(param_1->mAnmRandom) + param_1->mAge)
+ % shape->getTexAnmKeyNum());
+}
+
+/* 80277ACC-80277B1C 27240C 0050+00 0/0 1/1 0/0 .text JPACalcTexIdxReverse__FP18JPAEmitterWorkData
+ */
+void JPACalcTexIdxReverse(JPAEmitterWorkData* work) {
+ JPABaseShape* shape = work->mpRes->getBsp();
+ int tick = work->mpEmtr->mTick;
+ int keyNum = (int)shape->getTexAnmKeyNum() - 1;
+ int div = tick / keyNum;
+ int rem = tick % keyNum;
+ work->mpEmtr->mTexAnmIdx = shape->getTexIdx(rem + (div & 1) * (keyNum - rem * 2));
+}
+
+/* 80277B1C-80277B78 27245C 005C+00 0/0 1/1 0/0 .text
+ * JPACalcTexIdxReverse__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPACalcTexIdxReverse(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
+ JPABaseShape* shape = work->mpRes->getBsp();
+ s32 tick = shape->getTexLoopOfst(param_1->mAnmRandom) + param_1->mAge;
+ int keyNum = (int)shape->getTexAnmKeyNum() - 1;
+ int div = tick / keyNum;
+ int rem = tick % keyNum;
+ param_1->mTexAnmIdx = shape->getTexIdx(rem + (div & 1) * (keyNum - rem * 2));
+}
+
+/* 80277B78-80277B94 2724B8 001C+00 0/0 1/1 0/0 .text JPACalcTexIdxMerge__FP18JPAEmitterWorkData
+ */
+void JPACalcTexIdxMerge(JPAEmitterWorkData* work) {
+ work->mpEmtr->mTexAnmIdx = work->mpRes->getBsp()->getTexIdx();
+}
+
+/* 80277B94-80277C0C 2724D4 0078+00 0/0 1/1 0/0 .text
+ * JPACalcTexIdxMerge__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPACalcTexIdxMerge(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
+ JPABaseShape* shape = work->mpRes->getBsp();
+ s32 maxFrm = shape->getTexAnmKeyNum();
+ s32 tick = (s32)(maxFrm * param_1->mTime) + shape->getTexLoopOfst(param_1->mAnmRandom);
+ param_1->mTexAnmIdx = shape->getTexIdx(tick % maxFrm);
+}
+
+/* 80277C0C-80277C28 27254C 001C+00 0/0 1/1 0/0 .text JPACalcTexIdxRandom__FP18JPAEmitterWorkData
+ */
+void JPACalcTexIdxRandom(JPAEmitterWorkData* work) {
+ work->mpEmtr->mTexAnmIdx = work->mpRes->getBsp()->getTexIdx();
+}
+
+/* 80277C28-80277C64 272568 003C+00 0/0 1/1 0/0 .text
+ * JPACalcTexIdxRandom__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPACalcTexIdxRandom(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
+ JPABaseShape* shape = work->mpRes->getBsp();
+ param_1->mTexAnmIdx = shape->getTexIdx(((int)shape->getTexLoopOfst(param_1->mAnmRandom))
+ % shape->getTexAnmKeyNum());
+}
+
+/* 80277C64-80277C8C 2725A4 0028+00 0/0 1/1 0/0 .text JPALoadPosMtxCam__FP18JPAEmitterWorkData */
+void JPALoadPosMtxCam(JPAEmitterWorkData* work) {
+ GXLoadPosMtxImm(work->mPosCamMtx, GX_PNMTX0);
+}
+
+/* 80277C8C-80277C90 2725CC 0004+00 1/0 0/0 0/0 .text noLoadPrj__FPC18JPAEmitterWorkDataPA4_Cf */
+static void noLoadPrj(JPAEmitterWorkData const* work, const Mtx srt) {
+ /* empty function */
+}
+
+/* 80277C90-80277CC8 2725D0 0038+00 1/0 0/0 0/0 .text loadPrj__FPC18JPAEmitterWorkDataPA4_Cf */
+void loadPrj(JPAEmitterWorkData const* work, const Mtx srt) {
+ Mtx mtx;
+ MTXConcat(work->mPrjMtx, srt, mtx);
+ GXLoadTexMtxImm(mtx, GX_TEXMTX0, GX_MTX3x4);
+}
+
+/* 80277CC8-80277E88 272608 01C0+00 1/0 0/0 0/0 .text loadPrjAnm__FPC18JPAEmitterWorkDataPA4_Cf */
+static void loadPrjAnm(JPAEmitterWorkData const* work, const Mtx srt) {
+ JPABaseShape* shape = work->mpRes->getBsp();
+ f32 dVar16 = work->mpEmtr->getAge();
+ f32 dVar15 = 0.5f * (1.0f + shape->getTilingS());
+ f32 dVar14 = 0.5f * (1.0f + shape->getTilingT());
+ f32 dVar11 = (dVar16 * shape->getIncTransX()) + shape->getInitTransX();
+ f32 dVar10 = (dVar16 * shape->getIncTransY()) + shape->getInitTransY();
+ f32 dVar13 = (dVar16 * shape->getIncScaleX()) + shape->getInitScaleX();
+ f32 dVar12 = (dVar16 * shape->getIncScaleY()) + shape->getInitScaleY();
+ s32 local_c0 = (dVar16 * shape->getIncRot()) + shape->getInitRot();
+ f32 dVar8 = JMASSin(local_c0);
+ f32 dVar9 = JMASCos(local_c0);
+ Mtx local_108;
+ local_108[0][0] = dVar13 * dVar9;
+ local_108[0][1] = -dVar13 * dVar8;
+ local_108[0][2] =
+ (dVar15 + (dVar13 * ((dVar8 * (dVar14 + dVar10)) - (dVar9 * (dVar15 + dVar11)))));
+ local_108[0][3] = 0.0f;
+ local_108[1][0] = dVar12 * dVar8;
+ local_108[1][1] = dVar12 * dVar9;
+ local_108[1][2] =
+ (dVar14 + (-dVar12 * ((dVar8 * (dVar15 + dVar11)) + (dVar9 * (dVar14 + dVar10)))));
+ local_108[1][3] = 0.0f;
+ local_108[2][0] = 0.0f;
+ local_108[2][1] = 0.0f;
+ local_108[2][2] = 1.0f;
+ local_108[2][3] = 0.0f;
+ MTXConcat(local_108, work->mPrjMtx, local_108);
+ MTXConcat(local_108, srt, local_108);
+ GXLoadTexMtxImm(local_108, 0x1e, GX_MTX3x4);
+}
+
+/* 803C42E0-803C4300 021400 0020+00 10/9 0/0 0/0 .data jpa_dl */
+static u8 jpa_dl[32] = {
+ 0x80, 0x00, 0x04, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+/* 803C4300-803C4320 021420 0020+00 1/0 0/0 0/0 .data jpa_dl_x */
+static u8 jpa_dl_x[32] = {
+ 0x80, 0x00, 0x08, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x48, 0x00, 0x49, 0x01, 0x4A,
+ 0x02, 0x4B, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+typedef void (*projectionFunc)(JPAEmitterWorkData const*, const Mtx);
+
+/* 803C4320-803C432C -00001 000C+00 6/10 0/0 0/0 .data p_prj */
+static projectionFunc p_prj[3] = {
+ noLoadPrj,
+ loadPrj,
+ loadPrjAnm,
+};
+
+/* 80277E88-80277F70 2727C8 00E8+00 0/0 1/1 0/0 .text
+ * JPADrawBillboard__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPADrawBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
+ if (param_1->checkStatus(8) == 0) {
+ JGeometry::TVec3<f32> local_48;
+ MTXMultVec(work->mPosCamMtx, param_1->mPosition, local_48);
+ Mtx local_38;
+ local_38[0][0] = work->mGlobalPtclScl.x * param_1->mParticleScaleX;
+ local_38[0][3] = local_48.x;
+ local_38[1][1] = work->mGlobalPtclScl.y * param_1->mParticleScaleY;
+ local_38[1][3] = local_48.y;
+ local_38[2][2] = 1.0f;
+ local_38[2][3] = local_48.z;
+ local_38[2][1] = 0.0f;
+ local_38[2][0] = 0.0f;
+ local_38[1][2] = 0.0f;
+ local_38[1][0] = 0.0f;
+ local_38[0][2] = 0.0f;
+ local_38[0][1] = 0.0f;
+ GXLoadPosMtxImm(local_38, 0);
+ p_prj[work->mPrjType](work, local_38);
+ GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
+ }
+}
+
+/* 80277F70-80278088 2728B0 0118+00 0/0 1/1 0/0 .text
+ * JPADrawRotBillboard__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPADrawRotBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
+ if (param_1->checkStatus(8) == 0) {
+ JGeometry::TVec3<f32> local_48;
+ MTXMultVec(work->mPosCamMtx, param_1->mPosition, local_48);
+ f32 sinRot = JMASSin(param_1->mRotateAngle);
+ f32 cosRot = JMASCos(param_1->mRotateAngle);
+ f32 particleX = work->mGlobalPtclScl.x * param_1->mParticleScaleX;
+ f32 particleY = work->mGlobalPtclScl.y * param_1->mParticleScaleY;
+
+ Mtx local_38;
+ local_38[0][0] = cosRot * particleX;
+ local_38[0][1] = -sinRot * particleY;
+ local_38[0][3] = local_48.x;
+ local_38[1][0] = sinRot * particleX;
+ local_38[1][1] = cosRot * particleY;
+ local_38[1][3] = local_48.y;
+ local_38[2][2] = 1.0f;
+ local_38[2][3] = local_48.z;
+ local_38[2][1] = 0.0f;
+ local_38[2][0] = 0.0f;
+ local_38[1][2] = 0.0f;
+ local_38[0][2] = 0.0f;
+ GXLoadPosMtxImm(local_38, 0);
+ p_prj[work->mPrjType](work, local_38);
+ GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
+ }
+}
+
+/* 80278088-80278184 2729C8 00FC+00 0/0 1/1 0/0 .text
+ * JPADrawYBillboard__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPADrawYBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
+ if (param_1->checkStatus(8) == 0) {
+ JGeometry::TVec3<f32> local_48;
+ MTXMultVec(work->mPosCamMtx, param_1->mPosition, local_48);
+ Mtx local_38;
+ f32 particleY = work->mGlobalPtclScl.y * param_1->mParticleScaleY;
+ local_38[0][0] = work->mGlobalPtclScl.x * param_1->mParticleScaleX;
+ local_38[0][3] = local_48.x;
+ local_38[1][1] = work->mYBBCamMtx[1][1] * particleY;
+ local_38[1][2] = work->mYBBCamMtx[1][2];
+ local_38[1][3] = local_48.y;
+ local_38[2][1] = work->mYBBCamMtx[2][1] * particleY;
+ local_38[2][2] = work->mYBBCamMtx[2][2];
+ local_38[2][3] = local_48.z;
+ local_38[2][0] = 0.0f;
+ local_38[1][0] = 0.0f;
+ local_38[0][2] = 0.0f;
+ local_38[0][1] = 0.0f;
+ GXLoadPosMtxImm(local_38, 0);
+ p_prj[work->mPrjType](work, local_38);
+ GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
+ }
+}
+
+/* 80278184-802782B4 272AC4 0130+00 0/0 1/1 0/0 .text
+ * JPADrawRotYBillboard__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPADrawRotYBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
+ if (param_1->checkStatus(8) == 0) {
+ JGeometry::TVec3<f32> local_48;
+ MTXMultVec(work->mPosCamMtx, param_1->mPosition, local_48);
+ f32 sinRot = JMASSin(param_1->mRotateAngle);
+ f32 cosRot = JMASCos(param_1->mRotateAngle);
+ Mtx local_38;
+ f32 particleX = work->mGlobalPtclScl.x * param_1->mParticleScaleX;
+ f32 particleY = work->mGlobalPtclScl.y * param_1->mParticleScaleY;
+ f32 local_98 = (float)(sinRot * particleX);
+ f32 local_94 = (float)(cosRot * particleY);
+ f32 local_90 = work->mYBBCamMtx[1][1];
+ f32 fVar1 = work->mYBBCamMtx[2][1];
+ local_38[0][0] = (float)(cosRot * particleX);
+ local_38[0][1] = (float)(-sinRot * particleY);
+ local_38[0][2] = 0.0f;
+ local_38[0][3] = local_48.x;
+ local_38[1][0] = local_98 * local_90;
+ local_38[1][1] = local_94 * local_90;
+ local_38[1][2] = -fVar1;
+ local_38[1][3] = local_48.y;
+ local_38[2][0] = local_98 * fVar1;
+ local_38[2][1] = local_94 * fVar1;
+ local_38[2][2] = local_90;
+ local_38[2][3] = local_48.z;
+ GXLoadPosMtxImm(local_38, 0);
+ p_prj[work->mPrjType](work, local_38);
+ GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
+ }
+}
+
+/* 802782B4-802782D0 272BF4 001C+00 1/0 0/0 0/0 .text
+ * dirTypeVel__FPC18JPAEmitterWorkDataPC15JPABaseParticlePQ29JGeometry8TVec3<f> */
+void dirTypeVel(JPAEmitterWorkData const* work, JPABaseParticle const* param_1,
+ JGeometry::TVec3<f32>* param_2) {
+ param_1->getVelVec(*param_2);
+}
+
+/* 802782D0-802782EC 272C10 001C+00 1/0 0/0 0/0 .text
+ * dirTypePos__FPC18JPAEmitterWorkDataPC15JPABaseParticlePQ29JGeometry8TVec3<f> */
+void dirTypePos(JPAEmitterWorkData const* work, JPABaseParticle const* param_1,
+ JGeometry::TVec3<f32>* param_2) {
+ param_1->getLocalPosition(*param_2);
+}
+
+/* 802782EC-80278320 272C2C 0034+00 1/0 0/0 0/0 .text
+ * dirTypePosInv__FPC18JPAEmitterWorkDataPC15JPABaseParticlePQ29JGeometry8TVec3<f> */
+void dirTypePosInv(JPAEmitterWorkData const* work, JPABaseParticle const* param_1,
+ JGeometry::TVec3<f32>* param_2) {
+ param_1->getLocalPosition(*param_2);
+ param_2->negate();
+}
+
+/* 80278320-8027833C 272C60 001C+00 1/0 0/0 0/0 .text
+ * dirTypeEmtrDir__FPC18JPAEmitterWorkDataPC15JPABaseParticlePQ29JGeometry8TVec3<f> */
+void dirTypeEmtrDir(JPAEmitterWorkData const* work, JPABaseParticle const* param_1,
+ JGeometry::TVec3<f32>* param_2) {
+ param_2->set(work->mGlobalEmtrDir);
+}
+
+/* 8027833C-802783D4 272C7C 0098+00 1/0 0/0 0/0 .text
+ * dirTypePrevPtcl__FPC18JPAEmitterWorkDataPC15JPABaseParticlePQ29JGeometry8TVec3<f> */
+void dirTypePrevPtcl(JPAEmitterWorkData const* work, JPABaseParticle const* param_1,
+ JGeometry::TVec3<f32>* param_2) {
+ JGeometry::TVec3<f32> aTStack_24;
+ param_1->getGlobalPosition(aTStack_24);
+ JPANode<JPABaseParticle>* end = work->mpAlivePtcl->getEnd();
+ JPANode<JPABaseParticle>* prev = work->mpCurNode->getPrev();
+
+ if (end != prev) {
+ JPABaseParticle* particle = work->mpCurNode->getPrev()->getObject();
+ particle->getGlobalPosition(*param_2);
+ } else {
+ work->mpEmtr->calcEmitterGlobalPosition(param_2);
+ }
+ param_2->sub(aTStack_24);
+}
+
+/* 802783D4-80278414 272D14 0040+00 1/0 0/0 0/0 .text rotTypeY__FffRA3_A4_f */
+static void rotTypeY(f32 param_0, f32 param_1, Mtx& param_2) {
+ param_2[0][0] = param_1;
+ param_2[0][1] = 0.0f;
+ param_2[0][2] = -param_0;
+ param_2[0][3] = 0.0f;
+ param_2[1][0] = 0.0f;
+ param_2[1][1] = 1.0f;
+ param_2[1][2] = 0.0f;
+ param_2[1][3] = 0.0f;
+ param_2[2][0] = param_0;
+ param_2[2][1] = 0.0f;
+ param_2[2][2] = param_1;
+ param_2[2][3] = 0.0f;
+}
+
+/* 80278414-80278454 272D54 0040+00 1/0 0/0 0/0 .text rotTypeX__FffRA3_A4_f */
+static void rotTypeX(f32 param_0, f32 param_1, Mtx& param_2) {
+ param_2[0][0] = 1.0f;
+ param_2[0][1] = 0.0f;
+ param_2[0][2] = 0.0f;
+ param_2[0][3] = 0.0f;
+ param_2[1][0] = 0.0f;
+ param_2[1][1] = param_1;
+ param_2[1][2] = -param_0;
+ param_2[1][3] = 0.0f;
+ param_2[2][0] = 0.0f;
+ param_2[2][1] = param_0;
+ param_2[2][2] = param_1;
+ param_2[2][3] = 0.0f;
+}
+
+/* 80278454-80278494 272D94 0040+00 1/0 0/0 0/0 .text rotTypeZ__FffRA3_A4_f */
+static void rotTypeZ(f32 param_0, f32 param_1, Mtx& param_2) {
+ param_2[0][0] = param_1;
+ param_2[0][1] = -param_0;
+ param_2[0][2] = 0.0f;
+ param_2[0][3] = 0.0f;
+ param_2[1][0] = param_0;
+ param_2[1][1] = param_1;
+ param_2[1][2] = 0.0f;
+ param_2[1][3] = 0.0f;
+ param_2[2][0] = 0.0f;
+ param_2[2][1] = 0.0f;
+ param_2[2][2] = 1.0f;
+ param_2[2][3] = 0.0f;
+}
+
+/* 80278494-802784F0 272DD4 005C+00 1/0 0/0 0/0 .text rotTypeXYZ__FffRA3_A4_f */
+static void rotTypeXYZ(f32 param_0, f32 param_1, Mtx& param_2) {
+ f32 f3 = 0.33333298563957214f * (1.0f - param_1);
+ f32 fVar1;
+ f32 f4;
+ f4 = f3 + 0.5773500204086304f * param_0;
+ fVar1 = f3 - 0.5773500204086304f * param_0;
+ f3 += param_1;
+ param_2[0][0] = f3;
+ param_2[0][1] = fVar1;
+ param_2[0][2] = f4;
+ param_2[0][3] = 0.0f;
+ param_2[1][0] = f4;
+ param_2[1][1] = f3;
+ param_2[1][2] = fVar1;
+ param_2[1][3] = 0.0f;
+ param_2[2][0] = fVar1;
+ param_2[2][1] = f4;
+ param_2[2][2] = f3;
+ param_2[2][3] = 0.0f;
+}
+
+/* 802784F0-8027853C 272E30 004C+00 1/0 0/0 0/0 .text basePlaneTypeXY__FPA4_fff */
+static void basePlaneTypeXY(MtxP param_0, f32 param_1, f32 param_2) {
+ param_0[0][0] *= param_1;
+ param_0[1][0] *= param_1;
+ param_0[2][0] *= param_1;
+ param_0[0][1] *= param_2;
+ param_0[1][1] *= param_2;
+ param_0[2][1] *= param_2;
+}
+
+/* 8027853C-80278588 272E7C 004C+00 1/0 0/0 0/0 .text basePlaneTypeXZ__FPA4_fff */
+static void basePlaneTypeXZ(MtxP param_0, f32 param_1, f32 param_2) {
+ param_0[0][0] *= param_1;
+ param_0[1][0] *= param_1;
+ param_0[2][0] *= param_1;
+ param_0[0][2] *= param_2;
+ param_0[1][2] *= param_2;
+ param_0[2][2] *= param_2;
+}
+
+/* 80278588-802785F8 272EC8 0070+00 1/0 0/0 0/0 .text basePlaneTypeX__FPA4_fff */
+static void basePlaneTypeX(MtxP param_0, f32 param_1, f32 param_2) {
+ param_0[0][0] *= param_1;
+ param_0[1][0] *= param_1;
+ param_0[2][0] *= param_1;
+ param_0[0][1] *= param_2;
+ param_0[1][1] *= param_2;
+ param_0[2][1] *= param_2;
+ param_0[0][2] *= param_1;
+ param_0[1][2] *= param_1;
+ param_0[2][2] *= param_1;
+}
+
+/* 803C432C-803C4340 -00001 0014+00 2/5 0/0 0/0 .data p_direction */
+typedef void (*dirTypeFunc)(JPAEmitterWorkData const*, JPABaseParticle const*,
+ JGeometry::TVec3<f32>*);
+static dirTypeFunc p_direction[5] = {
+ dirTypeVel, dirTypePos, dirTypePosInv,
+ dirTypeEmtrDir, dirTypePrevPtcl,
+};
+
+/* 803C4340-803C4354 -00001 0014+00 0/2 0/0 0/0 .data p_rot */
+typedef void (*rotTypeFunc)(f32, f32, Mtx&);
+#pragma push
+#pragma force_active on
+static rotTypeFunc p_rot[5] = {
+ rotTypeY, rotTypeX, rotTypeZ,
+ rotTypeXYZ, rotTypeY,
+};
+#pragma pop
+
+/* 803C4354-803C4360 -00001 000C+00 0/3 0/0 0/0 .data p_plane */
+
+typedef void (*planeFunc)(MtxP, f32, f32);
+
+static planeFunc p_plane[3] = {
+ basePlaneTypeXY,
+ basePlaneTypeXZ,
+ basePlaneTypeX,
+};
+
+/* 804507A0-804507A8 -00001 0008+00 3/3 0/0 0/0 .sdata p_dl */
+static u8* p_dl[2] = {
+ jpa_dl,
+ jpa_dl_x,
+};
+
+/* 802785F8-80278994 272F38 039C+00 0/0 1/1 0/0 .text
+ * JPADrawDirection__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPADrawDirection(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) {
+ if (param_1->checkStatus(8) == 0) {
+ JGeometry::TVec3<f32> local_6c;
+ JGeometry::TVec3<f32> local_78;
+ p_direction[param_0->mDirType](param_0, param_1, &local_6c);
+ if (!local_6c.isZero()) {
+ local_6c.normalize();
+ local_78.cross(param_1->mBaseAxis, local_6c);
+ if (!local_78.isZero()) {
+ local_78.normalize();
+ param_1->mBaseAxis.cross(local_6c, local_78);
+ param_1->mBaseAxis.normalize();
+ Mtx local_60;
+ f32 fVar1 = param_0->mGlobalPtclScl.x * param_1->mParticleScaleX;
+ f32 fVar2 = param_0->mGlobalPtclScl.y * param_1->mParticleScaleY;
+ local_60[0][0] = param_1->mBaseAxis.x;
+ local_60[0][1] = local_6c.x;
+ local_60[0][2] = local_78.x;
+ local_60[0][3] = param_1->mPosition.x;
+ local_60[1][0] = param_1->mBaseAxis.y;
+ local_60[1][1] = local_6c.y;
+ local_60[1][2] = local_78.y;
+ local_60[1][3] = param_1->mPosition.y;
+ local_60[2][0] = param_1->mBaseAxis.z;
+ local_60[2][1] = local_6c.z;
+ local_60[2][2] = local_78.z;
+ local_60[2][3] = param_1->mPosition.z;
+ p_plane[param_0->mPlaneType](local_60, fVar1, fVar2);
+ MTXConcat(param_0->mPosCamMtx, local_60, local_60);
+ GXLoadPosMtxImm(local_60, 0);
+ p_prj[param_0->mPrjType](param_0, local_60);
+ GXCallDisplayList(p_dl[param_0->mDLType], sizeof(jpa_dl));
+ }
+ }
+ }
+}
+
+/* 80278994-80278DA8 2732D4 0414+00 0/0 1/1 0/0 .text
+ * JPADrawRotDirection__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPADrawRotDirection(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) {
+ if (param_1->checkStatus(8) == 0) {
+ f32 sinRot = JMASSin(param_1->mRotateAngle);
+ f32 cosRot = JMASCos(param_1->mRotateAngle);
+ JGeometry::TVec3<f32> local_6c;
+ JGeometry::TVec3<f32> local_78;
+ p_direction[param_0->mDirType](param_0, param_1, &local_6c);
+ if (!local_6c.isZero()) {
+ local_6c.normalize();
+ local_78.cross(param_1->mBaseAxis, local_6c);
+ if (!local_78.isZero()) {
+ local_78.normalize();
+ param_1->mBaseAxis.cross(local_6c, local_78);
+ param_1->mBaseAxis.normalize();
+ f32 particleX = param_0->mGlobalPtclScl.x * param_1->mParticleScaleX;
+ f32 particleY = param_0->mGlobalPtclScl.y * param_1->mParticleScaleY;
+ Mtx auStack_80;
+ Mtx local_60;
+ p_rot[param_0->mRotType](sinRot, cosRot, auStack_80);
+ p_plane[param_0->mPlaneType](auStack_80, particleX, particleY);
+ local_60[0][0] = param_1->mBaseAxis.x;
+ local_60[0][1] = local_6c.x;
+ local_60[0][2] = local_78.x;
+ local_60[0][3] = param_1->mPosition.x;
+ local_60[1][0] = param_1->mBaseAxis.y;
+ local_60[1][1] = local_6c.y;
+ local_60[1][2] = local_78.y;
+ local_60[1][3] = param_1->mPosition.y;
+ local_60[2][0] = param_1->mBaseAxis.z;
+ local_60[2][1] = local_6c.z;
+ local_60[2][2] = local_78.z;
+ local_60[2][3] = param_1->mPosition.z;
+ MTXConcat(local_60, auStack_80, auStack_80);
+ MTXConcat(param_0->mPosCamMtx, auStack_80, local_60);
+ GXLoadPosMtxImm(local_60, 0);
+ p_prj[param_0->mPrjType](param_0, local_60);
+ GXCallDisplayList(p_dl[param_0->mDLType], sizeof(jpa_dl));
+ }
+ }
+ }
+}
+
+/* 80278DA8-80278FC8 2736E8 0220+00 0/0 1/1 0/0 .text
+ * JPADrawDBillboard__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPADrawDBillboard(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) {
+ if (param_1->checkStatus(8) == 0) {
+ JGeometry::TVec3<f32> local_70;
+ p_direction[param_0->mDirType](param_0, param_1, &local_70);
+ JGeometry::TVec3<f32> aTStack_7c;
+ aTStack_7c.set(param_0->mPosCamMtx[2][0], param_0->mPosCamMtx[2][1],
+ param_0->mPosCamMtx[2][2]);
+ local_70.cross(local_70, aTStack_7c);
+ if (!local_70.isZero()) {
+ local_70.normalize();
+ MTXMultVecSR(param_0->mPosCamMtx, local_70, local_70);
+ JGeometry::TVec3<f32> local_88;
+ MTXMultVec(param_0->mPosCamMtx, param_1->mPosition, local_88);
+ f32 particleX = param_0->mGlobalPtclScl.x * param_1->mParticleScaleX;
+ f32 particleY = param_0->mGlobalPtclScl.y * param_1->mParticleScaleY;
+ Mtx local_60;
+ local_60[0][0] = local_70.x * particleX;
+ local_60[0][1] = -local_70.y * particleY;
+ local_60[0][3] = local_88.x;
+ local_60[1][0] = local_70.y * particleX;
+ local_60[1][1] = local_70.x * particleY;
+ local_60[1][3] = local_88.y;
+ local_60[2][2] = 1.0f;
+ local_60[2][3] = local_88.z;
+ local_60[2][1] = 0.0f;
+ local_60[2][0] = 0.0f;
+ local_60[1][2] = 0.0f;
+ local_60[0][2] = 0.0f;
+ GXLoadPosMtxImm(local_60, 0);
+ p_prj[param_0->mPrjType](param_0, local_60);
+ GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
+ }
+ }
+}
+
+/* 80278FC8-80279110 273908 0148+00 0/0 1/1 0/0 .text
+ * JPADrawRotation__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPADrawRotation(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) {
+ if (param_1->checkStatus(8) == 0) {
+ f32 sinRot = JMASSin(param_1->mRotateAngle);
+ f32 cosRot = JMASCos(param_1->mRotateAngle);
+ f32 particleX = param_0->mGlobalPtclScl.x * param_1->mParticleScaleX;
+ f32 particleY = param_0->mGlobalPtclScl.y * param_1->mParticleScaleY;
+ Mtx auStack_88;
+ p_rot[param_0->mRotType](sinRot, cosRot, auStack_88);
+ p_plane[param_0->mPlaneType](auStack_88, particleX, particleY);
+ auStack_88[0][3] = param_1->mPosition.x;
+ auStack_88[1][3] = param_1->mPosition.y;
+ auStack_88[2][3] = param_1->mPosition.z;
+ MTXConcat(param_0->mPosCamMtx, auStack_88, auStack_88);
+ GXLoadPosMtxImm(auStack_88, 0);
+ p_prj[param_0->mPrjType](param_0, auStack_88);
+ GXCallDisplayList(p_dl[param_0->mDLType], sizeof(jpa_dl));
+ }
+}
+
+/* 80279110-802791B0 273A50 00A0+00 0/0 1/1 0/0 .text
+ * JPADrawPoint__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPADrawPoint(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ if (!!(ptcl->mStatus & JPAPtclStts_Invisible))
+ return;
+
+ GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
+ GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
+ GXBegin(GX_POINTS, GX_VTXFMT1, 1);
+ GXPosition3f32(ptcl->mPosition.x, ptcl->mPosition.y, ptcl->mPosition.z);
+ GXTexCoord2f32(0.0f, 0.0f);
+ GXEnd();
+ GXSetVtxDesc(GX_VA_POS, GX_INDEX8);
+ GXSetVtxDesc(GX_VA_TEX0, GX_INDEX8);
+}
+
+/* 802791B0-80279364 273AF0 01B4+00 0/0 1/1 0/0 .text
+ * JPADrawLine__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPADrawLine(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) {
+ if (param_1->checkStatus(8) == 0) {
+ JGeometry::TVec3<f32> local_1c;
+ JGeometry::setTVec3f(&param_1->mPosition.x, &local_1c.x);
+ JGeometry::TVec3<f32> local_28;
+ param_1->getVelVec(local_28);
+ if (!local_28.isZero()) {
+ local_28.setLength(param_0->mGlobalPtclScl.y * (25.0f * param_1->mParticleScaleY));
+ local_28.sub(local_1c, local_28);
+ GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
+ GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
+ GXBegin(GX_LINES, GX_VTXFMT1, 2);
+ GXPosition3f32(local_1c.x, local_1c.y, local_1c.z);
+ GXTexCoord2f32(0.0f, 0.0f);
+ GXPosition3f32(local_28.x, local_28.y, local_28.z);
+ GXTexCoord2f32(0.0f, 1.0f);
+ GXEnd();
+ GXSetVtxDesc(GX_VA_POS, GX_INDEX8);
+ GXSetVtxDesc(GX_VA_TEX0, GX_INDEX8);
+ }
+ }
+}
+
+/* 80279364-8027936C 273CA4 0008+00 2/2 0/0 0/0 .text getNext__FP26JPANode<15JPABaseParticle> */
+JPANode<JPABaseParticle>* getNext(JPANode<JPABaseParticle>* param_0) {
+ return param_0->getNext();
+}
+
+/* 8027936C-80279374 273CAC 0008+00 2/2 0/0 0/0 .text getPrev__FP26JPANode<15JPABaseParticle> */
+JPANode<JPABaseParticle>* getPrev(JPANode<JPABaseParticle>* param_0) {
+ return param_0->getPrev();
+}
+
+typedef JPANode<JPABaseParticle>* (*getNodeFunc)(JPANode<JPABaseParticle>*);
+
+/* 80279374-8027996C 273CB4 05F8+00 0/0 1/1 0/0 .text JPADrawStripe__FP18JPAEmitterWorkData */
+void JPADrawStripe(JPAEmitterWorkData* param_0) {
+ JPABaseShape* shape = param_0->mpRes->getBsp();
+ u32 ptcl_num = param_0->mpAlivePtcl->getNum();
+ if (ptcl_num < 2) {
+ return;
+ }
+
+ f32 coord = 0.0f;
+ f32 step = 1.0f / (ptcl_num - 1.0f);
+ f32 dVar14 = (1.0f + param_0->mPivot.x) * (25.0f * param_0->mGlobalPtclScl.x);
+ f32 dVar13 = (1.0f - param_0->mPivot.x) * (25.0f * param_0->mGlobalPtclScl.x);
+ Mtx local_c8;
+ f32 dVar11;
+ f32 dVar12;
+ JGeometry::TVec3<f32> local_ec;
+ JGeometry::TVec3<f32> local_e0[2];
+ JGeometry::TVec3<f32> local_f8;
+ JGeometry::TVec3<f32> local_104;
+ getNodeFunc node_func;
+ JPANode<JPABaseParticle>* startNode;
+ if (shape->isDrawFwdAhead()) {
+ startNode = param_0->mpAlivePtcl->getLast();
+ node_func = getPrev;
+ coord = 1.0f;
+ step = -step;
+ } else {
+ startNode = param_0->mpAlivePtcl->getFirst();
+ node_func = getNext;
+ }
+
+ GXLoadPosMtxImm(param_0->mPosCamMtx, 0);
+ p_prj[param_0->mPrjType](param_0, param_0->mPosCamMtx);
+ GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
+ GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
+ GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT1, ptcl_num << 1);
+ for (JPANode<JPABaseParticle>* node = startNode; node != param_0->mpAlivePtcl->getEnd();
+ node = node_func(node), coord += step) {
+ param_0->mpCurNode = node;
+ JPABaseParticle* particle = node->getObject();
+ local_ec.set(particle->mPosition);
+ dVar11 = JMASSin(particle->mRotateAngle);
+ dVar12 = JMASCos(particle->mRotateAngle);
+ local_e0[0].set(-particle->mParticleScaleX * dVar14, 0.0f, 0.0f);
+ local_e0[0].set(local_e0[0].x * dVar12, 0.0f, local_e0[0].x * dVar11);
+ local_e0[1].set(particle->mParticleScaleX * dVar13, 0.0f, 0.0f);
+ local_e0[1].set(local_e0[1].x * dVar12, 0.0f, local_e0[1].x * dVar11);
+ p_direction[param_0->mDirType](param_0, particle, &local_f8);
+ if (local_f8.isZero()) {
+ local_f8.set(0.0f, 1.0f, 0.0f);
+ } else {
+ local_f8.normalize();
+ }
+ local_104.cross(particle->mBaseAxis, local_f8);
+ if (local_104.isZero()) {
+ local_104.set(1.0f, 0.0f, 0.0f);
+ } else {
+ local_104.normalize();
+ }
+ particle->mBaseAxis.cross(local_f8, local_104);
+ particle->mBaseAxis.normalize();
+
+ local_c8[0][0] = local_104.x;
+ local_c8[0][1] = local_f8.x;
+ local_c8[0][2] = particle->mBaseAxis.x;
+ local_c8[0][3] = 0.0f;
+ local_c8[1][0] = local_104.y;
+ local_c8[1][1] = local_f8.y;
+ local_c8[1][2] = particle->mBaseAxis.y;
+ local_c8[1][3] = 0.0f;
+ local_c8[2][0] = local_104.z;
+ local_c8[2][1] = local_f8.z;
+ local_c8[2][2] = particle->mBaseAxis.z;
+ local_c8[2][3] = 0.0f;
+ MTXMultVecArraySR(local_c8, (Vec*)local_e0, (Vec*)local_e0, 2);
+ GXPosition3f32(local_e0[0].x + local_ec.x, local_e0[0].y + local_ec.y,
+ local_e0[0].z + local_ec.z);
+ GXTexCoord2f32(0.0f, coord);
+ GXPosition3f32(local_e0[1].x + local_ec.x, local_e0[1].y + local_ec.y,
+ local_e0[1].z + local_ec.z);
+ GXTexCoord2f32(1.0f, coord);
+ }
+ GXEnd();
+ GXSetVtxDesc(GX_VA_POS, GX_INDEX8);
+ GXSetVtxDesc(GX_VA_TEX0, GX_INDEX8);
+}
+
+/* 8027996C-8027A3D8 2742AC 0A6C+00 0/0 1/1 0/0 .text JPADrawStripeX__FP18JPAEmitterWorkData */
+void JPADrawStripeX(JPAEmitterWorkData* param_0) {
+ JPABaseShape* shape = param_0->mpRes->getBsp();
+ u32 ptcl_num = param_0->mpAlivePtcl->getNum();
+ if (ptcl_num < 2) {
+ return;
+ }
+
+ f32 start_coord = 0.0f;
+ f32 coord = 0.0f;
+ f32 step = 1.0f / (ptcl_num - 1.0f);
+ f32 local_154 = (1.0f + param_0->mPivot.x) * (25.0f * param_0->mGlobalPtclScl.x);
+ f32 local_158 = (1.0f - param_0->mPivot.x) * (25.0f * param_0->mGlobalPtclScl.x);
+ f32 local_15c = (1.0f + param_0->mPivot.y) * (25.0f * param_0->mGlobalPtclScl.y);
+ f32 local_160 = (1.0f - param_0->mPivot.y) * (25.0f * param_0->mGlobalPtclScl.y);
+ Mtx local_90;
+ f32 dVar11;
+ f32 dVar12;
+ JGeometry::TVec3<f32> local_b4;
+ JGeometry::TVec3<f32> local_a8[2];
+ JGeometry::TVec3<f32> local_c0;
+ JGeometry::TVec3<f32> local_cc;
+ JPANode<JPABaseParticle>* startNode;
+ getNodeFunc node_func;
+ if (shape->isDrawFwdAhead()) {
+ startNode = param_0->mpAlivePtcl->getLast();
+ node_func = getPrev;
+ start_coord = coord = 1.0f;
+ step = -step;
+ } else {
+ startNode = param_0->mpAlivePtcl->getFirst();
+ node_func = getNext;
+ }
+
+ GXLoadPosMtxImm(param_0->mPosCamMtx, 0);
+ p_prj[param_0->mPrjType](param_0, param_0->mPosCamMtx);
+ GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
+ GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
+ GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT1, ptcl_num << 1);
+ for (JPANode<JPABaseParticle>* node = startNode; node != param_0->mpAlivePtcl->getEnd();
+ node = node_func(node), coord += step) {
+ param_0->mpCurNode = node;
+ JPABaseParticle* particle = node->getObject();
+ local_b4.set(particle->mPosition);
+ dVar11 = JMASSin(particle->mRotateAngle);
+ dVar12 = JMASCos(particle->mRotateAngle);
+ local_a8[0].set(-particle->mParticleScaleX * local_154, 0.0f, 0.0f);
+ local_a8[0].set(local_a8[0].x * dVar12, 0.0f, local_a8[0].x * dVar11);
+ local_a8[1].set(particle->mParticleScaleX * local_158, 0.0f, 0.0f);
+ local_a8[1].set(local_a8[1].x * dVar12, 0.0f, local_a8[1].x * dVar11);
+ p_direction[param_0->mDirType](param_0, particle, &local_c0);
+ if (local_c0.isZero()) {
+ local_c0.set(0.0f, 1.0f, 0.0f);
+ } else {
+ local_c0.normalize();
+ }
+ local_cc.cross(particle->mBaseAxis, local_c0);
+ if (local_cc.isZero()) {
+ local_cc.set(1.0f, 0.0f, 0.0f);
+ } else {
+ local_cc.normalize();
+ }
+ particle->mBaseAxis.cross(local_c0, local_cc);
+ particle->mBaseAxis.normalize();
+
+ local_90[0][0] = local_cc.x;
+ local_90[0][1] = local_c0.x;
+ local_90[0][2] = particle->mBaseAxis.x;
+ local_90[0][3] = 0.0f;
+ local_90[1][0] = local_cc.y;
+ local_90[1][1] = local_c0.y;
+ local_90[1][2] = particle->mBaseAxis.y;
+ local_90[1][3] = 0.0f;
+ local_90[2][0] = local_cc.z;
+ local_90[2][1] = local_c0.z;
+ local_90[2][2] = particle->mBaseAxis.z;
+ local_90[2][3] = 0.0f;
+ MTXMultVecArraySR(local_90, (Vec*)local_a8, (Vec*)local_a8, 2);
+ GXPosition3f32(local_a8[0].x + local_b4.x, local_a8[0].y + local_b4.y,
+ local_a8[0].z + local_b4.z);
+ GXTexCoord2f32(0.0f, coord);
+ GXPosition3f32(local_a8[1].x + local_b4.x, local_a8[1].y + local_b4.y,
+ local_a8[1].z + local_b4.z);
+ GXTexCoord2f32(1.0f, coord);
+ }
+ GXEnd();
+
+ coord = start_coord;
+ GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT1, ptcl_num << 1);
+ for (JPANode<JPABaseParticle>* node = startNode; node != param_0->mpAlivePtcl->getEnd();
+ node = node_func(node), coord += step) {
+ param_0->mpCurNode = node;
+ JPABaseParticle* particle = node->getObject();
+ local_b4.set(particle->mPosition);
+ dVar11 = JMASCos(particle->mRotateAngle);
+ dVar12 = -JMASSin(particle->mRotateAngle);
+ local_a8[0].set(-particle->mParticleScaleY * local_15c, 0.0f, 0.0f);
+ local_a8[0].set(local_a8[0].x * dVar12, 0.0f, local_a8[0].x * dVar11);
+ local_a8[1].set(particle->mParticleScaleY * local_160, 0.0f, 0.0f);
+ local_a8[1].set(local_a8[1].x * dVar12, 0.0f, local_a8[1].x * dVar11);
+ p_direction[param_0->mDirType](param_0, particle, &local_c0);
+ if (local_c0.isZero()) {
+ local_c0.set(0.0f, 1.0f, 0.0f);
+ } else {
+ local_c0.normalize();
+ }
+ local_cc.cross(particle->mBaseAxis, local_c0);
+ if (local_cc.isZero()) {
+ local_cc.set(1.0f, 0.0f, 0.0f);
+ } else {
+ local_cc.normalize();
+ }
+ particle->mBaseAxis.cross(local_c0, local_cc);
+ particle->mBaseAxis.normalize();
+
+ local_90[0][0] = local_cc.x;
+ local_90[0][1] = local_c0.x;
+ local_90[0][2] = particle->mBaseAxis.x;
+ local_90[0][3] = 0.0f;
+ local_90[1][0] = local_cc.y;
+ local_90[1][1] = local_c0.y;
+ local_90[1][2] = particle->mBaseAxis.y;
+ local_90[1][3] = 0.0f;
+ local_90[2][0] = local_cc.z;
+ local_90[2][1] = local_c0.z;
+ local_90[2][2] = particle->mBaseAxis.z;
+ local_90[2][3] = 0.0f;
+ MTXMultVecArraySR(local_90, (Vec*)local_a8, (Vec*)local_a8, 2);
+ GXPosition3f32(local_a8[0].x + local_b4.x, local_a8[0].y + local_b4.y,
+ local_a8[0].z + local_b4.z);
+ GXTexCoord2f32(0.0f, coord);
+ GXPosition3f32(local_a8[1].x + local_b4.x, local_a8[1].y + local_b4.y,
+ local_a8[1].z + local_b4.z);
+ GXTexCoord2f32(1.0f, coord);
+ }
+ GXEnd();
+ GXSetVtxDesc(GX_VA_POS, GX_INDEX8);
+ GXSetVtxDesc(GX_VA_TEX0, GX_INDEX8);
+}
+
+/* 8027A3D8-8027A414 274D18 003C+00 0/0 1/1 0/0 .text
+ * JPADrawEmitterCallBackB__FP18JPAEmitterWorkData */
+void JPADrawEmitterCallBackB(JPAEmitterWorkData* work) {
+ if (work->mpEmtr->mpEmtrCallBack == NULL)
+ return;
+
+ work->mpEmtr->mpEmtrCallBack->draw(work->mpEmtr);
+}
+
+/* 8027A414-8027A454 274D54 0040+00 0/0 1/1 0/0 .text
+ * JPADrawParticleCallBack__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPADrawParticleCallBack(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ if (work->mpEmtr->mpPtclCallBack == NULL)
+ return;
+
+ work->mpEmtr->mpPtclCallBack->draw(work->mpEmtr, ptcl);
+}
+
+/* 8027A454-8027A6DC 274D94 0288+00 1/1 0/0 0/0 .text
+ * makeColorTable__FPP8_GXColorPC16JPAClrAnmKeyDataUcsP7JKRHeap */
+static void makeColorTable(GXColor** o_color_table, JPAClrAnmKeyData const* i_data, u8 param_2,
+ s16 i_size, JKRHeap* i_heap) {
+ GXColor* color_table = (GXColor*)JKRAllocFromHeap(i_heap, (i_size + 1) * 4, 4);
+ f32 r_step, g_step, b_step, a_step;
+ r_step = g_step = b_step = a_step = 0.0f;
+ f32 r = i_data[0].color.r;
+ f32 g = i_data[0].color.g;
+ f32 b = i_data[0].color.b;
+ f32 a = i_data[0].color.a;
+ int j = 0;
+ for (s16 i = 0; i < i_size + 1; i++) {
+ if (i == i_data[j].index) {
+ color_table[i] = i_data[j].color;
+ r = i_data[j].color.r;
+ g = i_data[j].color.g;
+ b = i_data[j].color.b;
+ a = i_data[j].color.a;
+ j++;
+ if (j < param_2) {
+ f32 base_step = 1.0f / (i_data[j].index - i_data[j - 1].index);
+ r_step = base_step * ((f32)i_data[j].color.r - r);
+ g_step = base_step * ((f32)i_data[j].color.g - g);
+ b_step = base_step * ((f32)i_data[j].color.b - b);
+ a_step = base_step * ((f32)i_data[j].color.a - a);
+ } else {
+ r_step = g_step = b_step = a_step = 0.0f;
+ }
+ } else {
+ r += r_step;
+ color_table[i].r = r;
+ g += g_step;
+ color_table[i].g = g;
+ b += b_step;
+ color_table[i].b = b;
+ a += a_step;
+ color_table[i].a = a;
+ }
+ }
+ *o_color_table = color_table;
+}
+
+/* 8027A6DC-8027A7E8 27501C 010C+00 0/0 1/1 0/0 .text __ct__12JPABaseShapeFPCUcP7JKRHeap
+ */
+JPABaseShape::JPABaseShape(u8 const* pData, JKRHeap* pHeap) {
+ mpData = (const JPABaseShapeData*)pData;
+
+ if (isTexCrdAnm()) {
+ mpTexCrdMtxAnmTbl = (const void*)(pData + sizeof(JPABaseShapeData));
+ } else {
+ mpTexCrdMtxAnmTbl = NULL;
+ }
+
+ if (isTexAnm()) {
+ u32 offs = sizeof(JPABaseShapeData);
+ if (isTexCrdAnm())
+ offs = sizeof(JPABaseShapeData) + 0x28;
+ mpTexIdxAnimTbl = (const u8*)(pData + offs);
+ } else {
+ mpTexIdxAnimTbl = NULL;
+ }
+
+ if (isPrmAnm()) {
+ makeColorTable(&mpPrmClrAnmTbl, (JPAClrAnmKeyData*)(pData + mpData->mClrPrmAnmOffset),
+ mpData->mClrPrmKeyNum, mpData->mClrAnmFrmMax, pHeap);
+ } else {
+ mpPrmClrAnmTbl = NULL;
+ }
+
+ if (isEnvAnm()) {
+ makeColorTable(&mpEnvClrAnmTbl, (JPAClrAnmKeyData*)(pData + mpData->mClrEnvAnmOffset),
+ mpData->mClrEnvKeyNum, mpData->mClrAnmFrmMax, pHeap);
+ } else {
+ mpEnvClrAnmTbl = NULL;
+ }
+}
+
+/* 803C4360-803C436C 021480 000C+00 0/1 0/0 0/0 .data st_bm__12JPABaseShape */
+GXBlendMode JPABaseShape::st_bm[3] = {
+ GX_BM_NONE,
+ GX_BM_BLEND,
+ GX_BM_LOGIC,
+};
+
+/* 803C436C-803C4394 02148C 0028+00 0/1 0/0 0/0 .data st_bf__12JPABaseShape */
+GXBlendFactor JPABaseShape::st_bf[10] = {
+ GX_BL_ZERO, GX_BL_ONE, GX_BL_SRCCLR, GX_BL_INVSRCCLR,
+ GX_BL_SRCCLR, GX_BL_INVSRCCLR, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA,
+ GX_BL_DSTALPHA, GX_BL_INVDSTALPHA,
+};
+
+/* 803C4394-803C43D4 0214B4 0040+00 0/1 0/0 0/0 .data st_lo__12JPABaseShape */
+GXLogicOp JPABaseShape::st_lo[16] = {
+ GX_LO_CLEAR, GX_LO_SET, GX_LO_COPY, GX_LO_INVCOPY, GX_LO_NOOP, GX_LO_INV,
+ GX_LO_AND, GX_LO_NAND, GX_LO_OR, GX_LO_NOR, GX_LO_XOR, GX_LO_EQUIV,
+ GX_LO_REVAND, GX_LO_INVAND, GX_LO_REVOR, GX_LO_INVOR,
+};
+
+/* 803C43D4-803C43F4 0214F4 0020+00 0/1 0/0 0/0 .data st_c__12JPABaseShape */
+GXCompare JPABaseShape::st_c[8] = {
+ GX_NEVER, GX_LESS, GX_LEQUAL, GX_EQUAL, GX_NEQUAL, GX_GEQUAL, GX_GREATER, GX_ALWAYS,
+};
+
+/* 803C43F4-803C4404 021514 0010+00 0/1 0/0 0/0 .data st_ao__12JPABaseShape */
+GXAlphaOp JPABaseShape::st_ao[4] = {
+ GX_AOP_AND,
+ GX_AOP_OR,
+ GX_AOP_XOR,
+ GX_AOP_XNOR,
+};
+
+/* 803C4404-803C4464 021524 0060+00 0/1 0/0 0/0 .data st_ca__12JPABaseShape */
+GXTevColorArg JPABaseShape::st_ca[6][4] = {
+ {
+ GX_CC_ZERO,
+ GX_CC_TEXC,
+ GX_CC_ONE,
+ GX_CC_ZERO,
+ },
+ {
+ GX_CC_ZERO,
+ GX_CC_C0,
+ GX_CC_TEXC,
+ GX_CC_ZERO,
+ },
+ {
+ GX_CC_C0,
+ GX_CC_ONE,
+ GX_CC_TEXC,
+ GX_CC_ZERO,
+ },
+ {
+ GX_CC_C1,
+ GX_CC_C0,
+ GX_CC_TEXC,
+ GX_CC_ZERO,
+ },
+ {
+ GX_CC_ZERO,
+ GX_CC_TEXC,
+ GX_CC_C0,
+ GX_CC_C1,
+ },
+ {
+ GX_CC_ZERO,
+ GX_CC_ZERO,
+ GX_CC_ZERO,
+ GX_CC_C0,
+ },
+};
+
+/* 803C4464-803C4488 021584 0020+04 0/1 0/0 0/0 .data st_aa__12JPABaseShape */
+GXTevAlphaArg JPABaseShape::st_aa[2][4] = {
+ {
+ GX_CA_ZERO,
+ GX_CA_TEXA,
+ GX_CA_A0,
+ GX_CA_ZERO,
+ },
+ {
+ GX_CA_ZERO,
+ GX_CA_ZERO,
+ GX_CA_ZERO,
+ GX_CA_A0,
+ },
+};
+
+/* 8027A7E8-8027A918 275128 0130+00 0/0 1/1 0/0 .text setGX__12JPABaseShapeCFP18JPAEmitterWorkData
+ */
+void JPABaseShape::setGX(JPAEmitterWorkData* work) const {
+ const GXTevColorArg* colorArg = getTevColorArg();
+ const GXTevAlphaArg* alphaArg = getTevAlphaArg();
+ GXSetBlendMode(getBlendMode(), getBlendSrc(), getBlendDst(), getLogicOp());
+ GXSetZMode(getZEnable(), getZCmp(), getZUpd());
+ GXSetAlphaCompare(getAlphaCmp0(), getAlphaRef0(), getAlphaOp(), getAlphaCmp1(), getAlphaRef1());
+ GXSetTevColorIn(GX_TEVSTAGE0, colorArg[0], colorArg[1], colorArg[2], colorArg[3]);
+ GXSetTevAlphaIn(GX_TEVSTAGE0, alphaArg[0], alphaArg[1], alphaArg[2], alphaArg[3]);
+ GXSetTevDirect(GX_TEVSTAGE0);
+ GXSetTevDirect(GX_TEVSTAGE1);
+ GXSetZCompLoc(getZCompLoc());
+}
diff --git a/src/JSystem/JParticle/JPAChildShape.cpp b/src/JSystem/JParticle/JPAChildShape.cpp
new file mode 100644
index 00000000..cbc24cbb
--- /dev/null
+++ b/src/JSystem/JParticle/JPAChildShape.cpp
@@ -0,0 +1,48 @@
+//
+// Generated By: dol2asm
+// Translation Unit: JPAChildShape
+//
+
+#include "JSystem/JParticle/JPAChildShape.h"
+#include "JSystem/JParticle/JPAParticle.h"
+#include "JSystem/JParticle/JPAEmitter.h"
+#include "dolphin/gx.h"
+#include "dolphin/os.h"
+
+/* 8027AEBC-8027AFDC 2757FC 0120+00 0/0 1/1 0/0 .text JPARegistChildPrmEnv__FP18JPAEmitterWorkData
+ */
+void JPARegistChildPrmEnv(JPAEmitterWorkData* work) {
+ JPAChildShape* csp = work->mpRes->getCsp();
+ JPABaseEmitter* emtr = work->mpEmtr;
+ GXColor prm, env;
+ csp->getPrmClr(&prm);
+ csp->getEnvClr(&env);
+ prm.r = COLOR_MULTI(prm.r, emtr->mGlobalPrmClr.r);
+ prm.g = COLOR_MULTI(prm.g, emtr->mGlobalPrmClr.g);
+ prm.b = COLOR_MULTI(prm.b, emtr->mGlobalPrmClr.b);
+ prm.a = COLOR_MULTI(prm.a, emtr->mGlobalPrmClr.a);
+ env.r = COLOR_MULTI(env.r, emtr->mGlobalEnvClr.r);
+ env.g = COLOR_MULTI(env.g, emtr->mGlobalEnvClr.g);
+ env.b = COLOR_MULTI(env.b, emtr->mGlobalEnvClr.b);
+ GXSetTevColor(GX_TEVREG0, prm);
+ GXSetTevColor(GX_TEVREG1, env);
+}
+
+/* 8027AFDC-8027B008 27591C 002C+00 0/0 1/1 0/0 .text
+ * JPACalcChildAlphaOut__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPACalcChildAlphaOut(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ f32 anm = (1.0f - ptcl->mTime) * 255.0f;
+ OSf32tou8(&anm, &ptcl->mPrmColorAlphaAnm);
+}
+
+/* 8027B008-8027B038 275948 0030+00 0/0 1/1 0/0 .text
+ * JPACalcChildScaleOut__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPACalcChildScaleOut(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ ptcl->mParticleScaleX = ptcl->mScaleOut * (1.0f - ptcl->mTime);
+ ptcl->mParticleScaleY = ptcl->mAlphaWaveRandom * (1.0f - ptcl->mTime);
+}
+
+/* 8027B038-8027B040 -00001 0008+00 0/0 0/0 0/0 .text __ct__13JPAChildShapeFPCUc */
+JPAChildShape::JPAChildShape(u8 const* pData) {
+ mpData = (JPAChildShapeData*)pData;
+}
diff --git a/src/JSystem/JParticle/JPADynamicsBlock.cpp b/src/JSystem/JParticle/JPADynamicsBlock.cpp
new file mode 100644
index 00000000..672c8413
--- /dev/null
+++ b/src/JSystem/JParticle/JPADynamicsBlock.cpp
@@ -0,0 +1,233 @@
+//
+// Generated By: dol2asm
+// Translation Unit: JPADynamicsBlock
+//
+
+#include "JSystem/JParticle/JPADynamicsBlock.h"
+#include "JSystem/JMath/JMATrigonometric.h"
+#include "JSystem/JParticle/JPAEmitter.h"
+
+/* 8027B144-8027B220 275A84 00DC+00 1/1 0/0 0/0 .text JPAVolumePoint__FP18JPAEmitterWorkData */
+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);
+}
+
+/* 8027B220-8027B33C 275B60 011C+00 1/1 0/0 0/0 .text JPAVolumeLine */
+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);
+}
+
+/* 8027B33C-8027B4E8 275C7C 01AC+00 1/1 0/0 0/0 .text JPAVolumeCircle */
+// 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);
+}
+
+/* 8027B4E8-8027B5F0 275E28 0108+00 1/1 0/0 0/0 .text JPAVolumeCube */
+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);
+}
+
+/* 8027B5F0-8027B87C 275F30 028C+00 1/1 0/0 0/0 .text JPAVolumeSphere__FP18JPAEmitterWorkData */
+static void JPAVolumeSphere(JPAEmitterWorkData* work) {
+ s16 phi, theta;
+ if (work->mpEmtr->checkFlag(JPADynFlag_FixedInterval)) {
+ phi = (u16)(work->mVolumeX * 0x8000 / (work->mDivNumber - 1) + 0x4000);
+ f32 tmp = (u16)(work->mVolumeAngleNum * 0x10000 / (work->mVolumeAngleMax - 1));
+ theta = tmp * 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;
+ theta = work->mVolumeSweep * work->mpEmtr->get_r_ss();
+ }
+
+ f32 rnd = work->mpEmtr->get_r_f();
+ if (work->mpEmtr->checkFlag(JPADynFlag_FixedDensity)) {
+ rnd = 1.0f - rnd * rnd * rnd;
+ }
+ f32 rad = work->mVolumeSize * (work->mVolumeMinRad + rnd * (1.0f - work->mVolumeMinRad));
+ work->mVolumeCalcData.mVolumePos.set(rad * JMASCos(phi) * JMASSin(theta), -rad * JMASSin(phi),
+ rad * JMASCos(phi) * 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);
+}
+
+/* 8027B87C-8027B9F8 2761BC 017C+00 1/1 0/0 0/0 .text JPAVolumeCylinder__FP18JPAEmitterWorkData */
+static void JPAVolumeCylinder(JPAEmitterWorkData* work) {
+ s16 theta = work->mVolumeSweep * work->mpEmtr->get_r_ss();
+ f32 rnd = work->mpEmtr->get_r_f();
+ if (work->mpEmtr->checkFlag(JPADynFlag_FixedDensity)) {
+ rnd = 1.0f - rnd * rnd;
+ }
+ f32 rad = work->mVolumeSize * (work->mVolumeMinRad + rnd * (1.0f - work->mVolumeMinRad));
+ work->mVolumeCalcData.mVolumePos.set(
+ rad * JMASSin(theta), work->mVolumeSize * work->mpEmtr->get_r_zp(), rad * 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);
+}
+
+/* 8027B9F8-8027BB18 276338 0120+00 1/1 0/0 0/0 .text JPAVolumeTorus__FP18JPAEmitterWorkData */
+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);
+}
+
+/* 8027BB18-8027BB4C 276458 0034+00 0/0 1/1 0/0 .text __ct__16JPADynamicsBlockFPCUc */
+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,
+};
+
+/* 8027BB4C-8027BBE8 27648C 009C+00 2/1 0/0 0/0 .text init__16JPADynamicsBlockFv */
+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;
+ }
+}
+
+/* 8027BBE8-8027BDEC 276528 0204+00 0/0 1/1 0/0 .text
+ * create__16JPADynamicsBlockFP18JPAEmitterWorkData */
+void JPADynamicsBlock::create(JPAEmitterWorkData* work) {
+ if (work->mpEmtr->checkStatus(JPAEmtrStts_RateStepEmit)) {
+ s32 emitCount;
+ s32 createCount;
+
+ // Probably an inlined function.
+ if (work->mpEmtr->checkFlag(JPADynFlag_FixedInterval)) {
+ s32 count;
+ if (getVolumeType() == VOL_Sphere) {
+ count = 4 * getDivNumber() * getDivNumber() + 2;
+ } else {
+ count = getDivNumber();
+ }
+ emitCount = count;
+
+ work->mVolumeEmitIdx = 0;
+ } else {
+ f32 newPtclCount =
+ work->mpEmtr->mRate * (getRateRndm() * work->mpEmtr->get_r_zp() + 1.0f);
+ f32 newEmitCount = work->mpEmtr->mEmitCount + newPtclCount;
+ work->mpEmtr->mEmitCount = newEmitCount;
+ emitCount = (s32)newEmitCount;
+ 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;
+ }
+
+ // Probably an inlined function.
+ createCount = emitCount;
+ while (createCount > 0) {
+ JPABaseParticle* 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);
+}
diff --git a/src/JSystem/JParticle/JPAEmitter.cpp b/src/JSystem/JParticle/JPAEmitter.cpp
new file mode 100644
index 00000000..517421c8
--- /dev/null
+++ b/src/JSystem/JParticle/JPAEmitter.cpp
@@ -0,0 +1,183 @@
+//
+// Generated By: dol2asm
+// Translation Unit: JPAEmitter
+//
+
+#include "JSystem/JParticle/JPAEmitter.h"
+#include "JSystem/JParticle/JPAEmitterManager.h"
+#include "JSystem/JParticle/JPAParticle.h"
+#include "JSystem/JParticle/JPAResourceManager.h"
+#include "JSystem/JParticle/JPABaseShape.h"
+#include "dolphin/types.h"
+
+//
+// Types:
+//
+
+//
+// Forward References:
+//
+
+//
+// External References:
+//
+
+//
+// Declarations:
+//
+
+/* 8027E6A4-8027E6EC 278FE4 0048+00 0/0 14/14 16/16 .text __dt__18JPAEmitterCallBackFv */
+JPAEmitterCallBack::~JPAEmitterCallBack() {
+}
+
+/* 8027E6EC-8027EA40 27902C 0354+00 0/0 1/1 0/0 .text
+ * init__14JPABaseEmitterFP17JPAEmitterManagerP11JPAResource */
+void JPABaseEmitter::init(JPAEmitterManager* param_0, JPAResource* param_1) {
+ mpEmtrMgr = param_0;
+ mpRes = param_1;
+ mpRes->getDyn()->getEmitterScl(&mLocalScl);
+ mpRes->getDyn()->getEmitterTrs(&mLocalTrs);
+ mpRes->getDyn()->getEmitterDir(&mLocalDir);
+ mLocalDir.normalize();
+ mpRes->getDyn()->getEmitterRot(&mLocalRot);
+ mMaxFrame = mpRes->getDyn()->getMaxFrame();
+ mLifeTime = mpRes->getDyn()->getLifetime();
+ mVolumeSize = mpRes->getDyn()->getVolumeSize();
+ mRate = mpRes->getDyn()->getRate();
+ mRateStep = mpRes->getDyn()->getRateStep();
+ mVolumeSweep = mpRes->getDyn()->getVolumeSweep();
+ mVolumeMinRad = mpRes->getDyn()->getVolumeMinRad();
+ mAwayFromCenterSpeed = mpRes->getDyn()->getInitVelOmni();
+ mAwayFromAxisSpeed = mpRes->getDyn()->getInitVelAxis();
+ mDirSpeed = mpRes->getDyn()->getInitVelDir();
+ mSpread = mpRes->getDyn()->getInitVelDirSp();
+ mRndmDirSpeed = mpRes->getDyn()->getInitVelRndm();
+ mAirResist = mpRes->getDyn()->getAirRes();
+ mRndm.set_seed(mpEmtrMgr->pWd->mRndm.get_rndm_u());
+ MTXIdentity(mGlobalRot);
+ mGlobalScl.set(1.0f, 1.0f, 1.0f);
+ mGlobalTrs.zero();
+ mGlobalPScl.set(1.0f, 1.0f);
+ mGlobalEnvClr.a = 0xff;
+ mGlobalEnvClr.b = 0xff;
+ mGlobalEnvClr.g = 0xff;
+ mGlobalEnvClr.r = 0xff;
+ mGlobalPrmClr.a = 0xff;
+ mGlobalPrmClr.b = 0xff;
+ mGlobalPrmClr.g = 0xff;
+ mGlobalPrmClr.r = 0xff;
+ param_1->getBsp()->getPrmClr(&mPrmClr);
+ param_1->getBsp()->getEnvClr(&mEnvClr);
+ mpUserWork = NULL;
+ mScaleOut = 1.0f;
+ mEmitCount = 0.0f;
+ initStatus(0x30);
+ mDrawTimes = 1;
+ mTick = 0;
+ mWaitTime = 0;
+ mRateStepTimer = 0;
+ mTexAnmIdx = 0;
+}
+
+/* 8027EA40-8027EB60 279380 0120+00 0/0 3/3 0/0 .text createParticle__14JPABaseEmitterFv
+ */
+JPABaseParticle* JPABaseEmitter::createParticle() {
+ if (mpPtclPool->getNum() != 0) {
+ JPANode<JPABaseParticle>* node = mpPtclPool->pop_front();
+ mAlivePtclBase.push_front(node);
+ mpRes->getDyn()->calc(mpEmtrMgr->pWd);
+ node->mData.init_p(mpEmtrMgr->pWd);
+ return &node->mData;
+ }
+
+ return NULL;
+}
+
+/* 8027EB60-8027EC60 2794A0 0100+00 0/0 1/1 0/0 .text
+ * createChild__14JPABaseEmitterFP15JPABaseParticle */
+JPABaseParticle* JPABaseEmitter::createChild(JPABaseParticle* parent) {
+ if (mpPtclPool->getNum() != 0) {
+ JPANode<JPABaseParticle>* node = mpPtclPool->pop_front();
+ mAlivePtclChld.push_front(node);
+ node->mData.init_c(mpEmtrMgr->pWd, parent);
+ return &node->mData;
+ }
+
+ return NULL;
+}
+
+/* 8027EC60-8027EDD4 2795A0 0174+00 0/0 2/2 21/21 .text deleteAllParticle__14JPABaseEmitterFv */
+void JPABaseEmitter::deleteAllParticle() {
+ while (mAlivePtclBase.getNum())
+ mpPtclPool->push_front(mAlivePtclBase.pop_back());
+ while (mAlivePtclChld.getNum())
+ mpPtclPool->push_front(mAlivePtclChld.pop_back());
+}
+
+/* 8027EDD4-8027EE14 279714 0040+00 0/0 1/1 0/0 .text processTillStartFrame__14JPABaseEmitterFv */
+bool JPABaseEmitter::processTillStartFrame() {
+ JPADynamicsBlock* dyn = mpRes->getDyn();
+ s16 startFrame = dyn->getStartFrame();
+
+ if (mWaitTime >= startFrame)
+ return true;
+
+ if (!(mStatus & 2))
+ mWaitTime++;
+
+ return false;
+}
+
+/* 8027EE14-8027EEB0 279754 009C+00 0/0 1/1 0/0 .text processTermination__14JPABaseEmitterFv */
+bool JPABaseEmitter::processTermination() {
+ if (checkStatus(0x100)) {
+ return true;
+ }
+
+ if (mMaxFrame == 0) {
+ return false;
+ }
+ if (mMaxFrame < 0) {
+ setStatus(8);
+ return getParticleNumber() == 0;
+ }
+ if (mTick >= mMaxFrame) {
+ setStatus(8);
+ if (checkStatus(0x40)) {
+ return 0;
+ }
+ return getParticleNumber() == 0;
+ }
+ return false;
+}
+
+/* 8027EEB0-8027EF30 2797F0 0080+00 0/0 1/1 0/0 .text
+ * calcEmitterGlobalPosition__14JPABaseEmitterCFPQ29JGeometry8TVec3<f> */
+void JPABaseEmitter::calcEmitterGlobalPosition(JGeometry::TVec3<f32>* dst) const {
+ Mtx mtx;
+ MTXScale(mtx, mGlobalScl.x, mGlobalScl.y, mGlobalScl.z);
+ MTXConcat(mGlobalRot, mtx, mtx);
+ mtx[0][3] = mGlobalTrs.x;
+ mtx[1][3] = mGlobalTrs.y;
+ mtx[2][3] = mGlobalTrs.z;
+ MTXMultVec(mtx, mLocalTrs, *dst);
+}
+
+/* 8027EF30-8027EF40 279870 0010+00 0/0 1/1 0/0 .text getCurrentCreateNumber__14JPABaseEmitterCFv
+ */
+u32 JPABaseEmitter::getCurrentCreateNumber() const {
+ return mpEmtrMgr->pWd->mEmitCount;
+}
+
+/* 8027EF40-8027EF50 279880 0010+00 0/0 3/3 0/0 .text getDrawCount__14JPABaseEmitterCFv
+ */
+u8 JPABaseEmitter::getDrawCount() const {
+ return mpEmtrMgr->pWd->mDrawCount;
+}
+
+/* 8027EF50-8027EFA4 279890 0054+00 0/0 1/1 0/0 .text
+ * loadTexture__14JPABaseEmitterFUc11_GXTexMapID */
+bool JPABaseEmitter::loadTexture(u8 idx, GXTexMapID texMapID) {
+ mpEmtrMgr->pWd->mpResMgr->load(mpRes->getTexIdx(idx), texMapID);
+ return true;
+}
diff --git a/src/JSystem/JParticle/JPAEmitterManager.cpp b/src/JSystem/JParticle/JPAEmitterManager.cpp
new file mode 100644
index 00000000..649f4226
--- /dev/null
+++ b/src/JSystem/JParticle/JPAEmitterManager.cpp
@@ -0,0 +1,203 @@
+//
+// Generated By: dol2asm
+// Translation Unit: JPAEmitterManager
+//
+
+#include "JSystem/JParticle/JPAEmitterManager.h"
+#include "JSystem/JKernel/JKRHeap.h"
+#include "JSystem/JParticle/JPAEmitter.h"
+#include "JSystem/JParticle/JPAParticle.h"
+#include "JSystem/JParticle/JPAResourceManager.h"
+#include "JSystem/JUtility/JUTAssert.h"
+#include "dolphin/gx.h"
+
+/* 8027DCA0-8027DEBC 2785E0 021C+00 0/0 1/1 0/0 .text __ct__17JPAEmitterManagerFUlUlP7JKRHeapUcUc
+ */
+JPAEmitterManager::JPAEmitterManager(u32 i_ptclNum, u32 i_emtrNum, JKRHeap* pHeap, u8 i_gidMax,
+ u8 i_ridMax) {
+ emtrNum = i_emtrNum;
+ ptclNum = i_ptclNum;
+ gidMax = i_gidMax;
+ ridMax = i_ridMax;
+
+ JUT_ASSERT(40, emtrNum && ptclNum && gidMax && ridMax);
+
+ JPABaseEmitter* p_emtr_link = new (pHeap, 0) JPABaseEmitter[emtrNum];
+ JUT_ASSERT(44, p_emtr_link);
+ for (u32 i = 0; i < emtrNum; i++)
+ mFreeEmtrList.prepend(&p_emtr_link[i].mLink);
+
+ JPANode<JPABaseParticle>* p_ptcl_node = new (pHeap, 0) JPANode<JPABaseParticle>[ptclNum];
+ JUT_ASSERT(51, p_ptcl_node);
+ for (u32 i = 0; i < ptclNum; i++)
+ mPtclPool.push_back(&p_ptcl_node[i]);
+
+ pEmtrUseList = new (pHeap, 0) JSUList<JPABaseEmitter>[gidMax];
+ JUT_ASSERT(58, pEmtrUseList);
+ pResMgrAry = new (pHeap, 0) JPAResourceManager*[ridMax];
+ JUT_ASSERT(62, pResMgrAry)
+ for (int i = 0; i < ridMax; i++) {
+ pResMgrAry[i] = NULL;
+ }
+
+ pWd = new (pHeap, 0) JPAEmitterWorkData();
+ JUT_ASSERT(67, pWd);
+}
+
+/* 8027DEBC-8027DFA0 2787FC 00E4+00 0/0 3/3 0/0 .text
+ * createSimpleEmitterID__17JPAEmitterManagerFRCQ29JGeometry8TVec3<f>UsUcUcP18JPAEmitterCallBackP19JPAParticleCallBack
+ */
+JPABaseEmitter* JPAEmitterManager::createSimpleEmitterID(JGeometry::TVec3<f32> const& pos,
+ u16 resID, u8 group_id, u8 res_mgr_id,
+ JPAEmitterCallBack* emtrCB,
+ JPAParticleCallBack* ptclCB) {
+ JUT_ASSERT(88, group_id < gidMax);
+ JUT_ASSERT(89, res_mgr_id < ridMax);
+ JUT_ASSERT(90, pResMgrAry[res_mgr_id] != 0);
+ JPAResource* pRes = pResMgrAry[res_mgr_id]->getResource(resID);
+
+ if (pRes == NULL) {
+ JUT_WARN_DEVICE(94, 3, "JPA : User Index %d is NOT exist\n", resID);
+ } else if (mFreeEmtrList.getNumLinks() == 0) {
+ JUT_WARN_DEVICE(97, 3, "JPA : Can NOT create emitter more\n");
+ } else {
+ JSULink<JPABaseEmitter>* pLink = mFreeEmtrList.getFirst();
+ mFreeEmtrList.remove(pLink);
+ pEmtrUseList[group_id].append(pLink);
+ JPABaseEmitter* emtr = pLink->getObject();
+ emtr->init(this, pRes);
+ emtr->mpPtclPool = &mPtclPool;
+ emtr->mpEmtrCallBack = emtrCB;
+ emtr->mpPtclCallBack = ptclCB;
+ emtr->mGroupID = group_id;
+ emtr->mResMgrID = res_mgr_id;
+ emtr->mGlobalTrs.set(pos);
+ return emtr;
+ }
+
+ return NULL;
+}
+
+/* 8027DFA0-8027E028 2788E0 0088+00 0/0 3/3 0/0 .text calc__17JPAEmitterManagerFUc */
+void JPAEmitterManager::calc(u8 group_id) {
+ JUT_ASSERT(154, group_id < gidMax);
+ JSULink<JPABaseEmitter>* pNext = NULL;
+ for (JSULink<JPABaseEmitter>* pLink = pEmtrUseList[group_id].getFirst();
+ pLink != pEmtrUseList[group_id].getEnd(); pLink = pNext) {
+ pNext = pLink->getNext();
+
+ JPABaseEmitter* emtr = pLink->getObject();
+
+ if (emtr->mpRes->calc(pWd, emtr) && !emtr->checkStatus(0x200))
+ forceDeleteEmitter(emtr);
+ }
+}
+
+/* 8027E028-8027E220 278968 01F8+00 0/0 1/1 0/0 .text draw__17JPAEmitterManagerFPC11JPADrawInfoUc
+ */
+void JPAEmitterManager::draw(JPADrawInfo const* drawInfo, u8 group_id) {
+ JUT_ASSERT(192, group_id < gidMax);
+ drawInfo->getCamMtx(pWd->mPosCamMtx);
+ drawInfo->getPrjMtx(pWd->mPrjMtx);
+ calcYBBCam();
+ GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
+ GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
+ GXEnableTexOffsets(GX_TEXCOORD0, GX_TRUE, GX_TRUE);
+ GXEnableTexOffsets(GX_TEXCOORD1, GX_TRUE, GX_TRUE);
+ GXEnableTexOffsets(GX_TEXCOORD2, GX_TRUE, GX_TRUE);
+ GXSetCullMode(GX_CULL_NONE);
+ GXSetCoPlanar(GX_FALSE);
+ GXClearVtxDesc();
+ GXSetVtxDesc(GX_VA_POS, GX_INDEX8);
+ GXSetVtxDesc(GX_VA_TEX0, GX_INDEX8);
+ GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_S8, 0);
+ GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_S8, 0);
+ GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
+ GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
+ GXSetCurrentMtx(GX_PNMTX0);
+ GXSetChanCtrl(GX_COLOR0A0, GX_FALSE, GX_SRC_REG, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_NONE,
+ GX_AF_NONE);
+ GXSetChanCtrl(GX_COLOR1A1, GX_FALSE, GX_SRC_REG, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_NONE,
+ GX_AF_NONE);
+ GXSetNumChans(0);
+
+ for (JSULink<JPABaseEmitter>* pLink = pEmtrUseList[group_id].getFirst();
+ pLink != pEmtrUseList[group_id].getEnd(); pLink = pLink->getNext()) {
+ JPABaseEmitter* emtr = pLink->getObject();
+ if (!emtr->checkStatus(0x04)) {
+ pWd->mpResMgr = pResMgrAry[emtr->mResMgrID];
+ emtr->mpRes->draw(pWd, emtr);
+ }
+ }
+}
+
+/* 8027E220-8027E278 278B60 0058+00 0/0 1/1 0/0 .text forceDeleteAllEmitter__17JPAEmitterManagerFv
+ */
+void JPAEmitterManager::forceDeleteAllEmitter() {
+ for (u8 i = 0; i < gidMax; i++)
+ forceDeleteGroupEmitter(i);
+}
+
+/* 8027E278-8027E2D8 278BB8 0060+00 1/1 0/0 0/0 .text
+ * forceDeleteGroupEmitter__17JPAEmitterManagerFUc */
+void JPAEmitterManager::forceDeleteGroupEmitter(u8 group_id) {
+ JUT_ASSERT(288, group_id < gidMax);
+ while (pEmtrUseList[group_id].getNumLinks())
+ forceDeleteEmitter(pEmtrUseList[group_id].getLast()->getObject());
+}
+
+/* 8027E2D8-8027E344 278C18 006C+00 3/3 1/1 0/0 .text
+ * forceDeleteEmitter__17JPAEmitterManagerFP14JPABaseEmitter */
+void JPAEmitterManager::forceDeleteEmitter(JPABaseEmitter* emtr) {
+ emtr->deleteAllParticle();
+ emtr->setStatus(0x300);
+ pEmtrUseList[emtr->getGroupID()].remove(&emtr->mLink);
+ mFreeEmtrList.prepend(&emtr->mLink);
+}
+
+/* 8027E344-8027E354 278C84 0010+00 0/0 2/2 0/0 .text
+ * entryResourceManager__17JPAEmitterManagerFP18JPAResourceManagerUc */
+void JPAEmitterManager::entryResourceManager(JPAResourceManager* resMgr, u8 resMgrID) {
+ JUT_ASSERT_MSG_F(325, resMgrID < ridMax && (pResMgrAry[resMgrID]) == 0,
+ "res_id %d res_id_max %d array[%d] = %x", resMgrID, ridMax, resMgrID,
+ pResMgrAry[resMgrID]);
+ pResMgrAry[resMgrID] = resMgr;
+}
+
+/* 8027E354-8027E3F4 278C94 00A0+00 0/0 1/1 0/0 .text clearResourceManager__17JPAEmitterManagerFUc
+ */
+void JPAEmitterManager::clearResourceManager(u8 res_mgr_id) {
+ JUT_ASSERT(339, res_mgr_id < ridMax);
+ for (u8 i = 0; i < gidMax; i++) {
+ JSULink<JPABaseEmitter>* pNext = NULL;
+ for (JSULink<JPABaseEmitter>* pLink = pEmtrUseList[i].getFirst();
+ pLink != pEmtrUseList[i].getEnd(); pLink = pNext) {
+ pNext = pLink->getNext();
+
+ if (res_mgr_id == pLink->getObject()->getResourceManagerID())
+ forceDeleteEmitter(pLink->getObject());
+ }
+ }
+
+ pResMgrAry[res_mgr_id] = NULL;
+}
+
+/* 8027E3F4-8027E51C 278D34 0128+00 1/1 0/0 0/0 .text calcYBBCam__17JPAEmitterManagerFv
+ */
+void JPAEmitterManager::calcYBBCam() {
+ JGeometry::TVec3<float> v(0.0f, pWd->mPosCamMtx[1][1], pWd->mPosCamMtx[2][1]);
+ JUT_ASSERT(367, !v.isZero());
+ v.normalize();
+ pWd->mYBBCamMtx[0][0] = 1.0f;
+ pWd->mYBBCamMtx[0][1] = 0.0f;
+ pWd->mYBBCamMtx[0][2] = 0.0f;
+ pWd->mYBBCamMtx[0][3] = pWd->mPosCamMtx[0][3];
+ pWd->mYBBCamMtx[1][0] = 0.0f;
+ pWd->mYBBCamMtx[1][1] = v.y;
+ pWd->mYBBCamMtx[1][2] = -v.z;
+ pWd->mYBBCamMtx[1][3] = pWd->mPosCamMtx[1][3];
+ pWd->mYBBCamMtx[2][0] = 0.0f;
+ pWd->mYBBCamMtx[2][1] = v.z;
+ pWd->mYBBCamMtx[2][2] = v.y;
+ pWd->mYBBCamMtx[2][3] = pWd->mPosCamMtx[2][3];
+}
diff --git a/src/JSystem/JParticle/JPAExTexShape.cpp b/src/JSystem/JParticle/JPAExTexShape.cpp
new file mode 100644
index 00000000..4763459a
--- /dev/null
+++ b/src/JSystem/JParticle/JPAExTexShape.cpp
@@ -0,0 +1,35 @@
+//
+// Generated By: dol2asm
+// Translation Unit: JPAExTexShape
+//
+
+#include "JSystem/JParticle/JPAExTexShape.h"
+#include "JSystem/JParticle/JPAResourceManager.h"
+#include "JSystem/JParticle/JPAEmitter.h"
+#include "dolphin/gx.h"
+
+/* 8027B040-8027B13C 275980 00FC+00 0/0 1/1 0/0 .text JPALoadExTex__FP18JPAEmitterWorkData */
+void JPALoadExTex(JPAEmitterWorkData* work) {
+ JPAExTexShape* ets = work->mpRes->getEts();
+
+ GXTexCoordID secTexCoordID = GX_TEXCOORD1;
+ if (ets->isUseIndirect()) {
+ GXSetTexCoordGen2(GX_TEXCOORD1, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY, GX_FALSE,
+ GX_PTIDENTITY);
+ u8 texIdx = ets->getIndTexIdx();
+ work->mpResMgr->load(work->mpRes->getTexIdx(texIdx), GX_TEXMAP2);
+ secTexCoordID = GX_TEXCOORD2;
+ }
+
+ if (ets->isUseSecTex()) {
+ GXSetTexCoordGen2(secTexCoordID, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY, GX_FALSE,
+ GX_PTIDENTITY);
+ u8 texIdx = ets->getSecTexIdx();
+ work->mpResMgr->load(work->mpRes->getTexIdx(texIdx), GX_TEXMAP3);
+ }
+}
+
+/* 8027B13C-8027B144 -00001 0008+00 0/0 0/0 0/0 .text __ct__13JPAExTexShapeFPCUc */
+JPAExTexShape::JPAExTexShape(u8 const* data) {
+ mpData = (const JPAExTexShapeData*)data;
+} \ No newline at end of file
diff --git a/src/JSystem/JParticle/JPAExtraShape.cpp b/src/JSystem/JParticle/JPAExtraShape.cpp
new file mode 100644
index 00000000..2c269a31
--- /dev/null
+++ b/src/JSystem/JParticle/JPAExtraShape.cpp
@@ -0,0 +1,152 @@
+//
+// Generated By: dol2asm
+// Translation Unit: JPAExtraShape
+//
+
+#include "JSystem/JParticle/JPAExtraShape.h"
+#include "JSystem/JMath/JMATrigonometric.h"
+#include "JSystem/JParticle/JPAParticle.h"
+#include "JSystem/JParticle/JPAEmitter.h"
+#include "dolphin/os.h"
+
+/* 8027A918-8027A990 275258 0078+00 0/0 1/1 0/0 .text
+ * JPACalcScaleX__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPACalcScaleX(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ JPAExtraShape* esp = work->mpRes->getEsp();
+ if (work->mScaleAnm < esp->getScaleInTiming()) {
+ ptcl->mParticleScaleX =
+ ptcl->mScaleOut * (esp->getScaleIncRateX() * work->mScaleAnm + esp->getScaleInValueX());
+ } else if (work->mScaleAnm > esp->getScaleOutTiming()) {
+ ptcl->mParticleScaleX =
+ ptcl->mScaleOut *
+ (esp->getScaleDecRateX() * (work->mScaleAnm - esp->getScaleOutTiming()) + 1.0f);
+ } else {
+ ptcl->mParticleScaleX = ptcl->mScaleOut;
+ }
+}
+
+/* 8027A990-8027AA08 2752D0 0078+00 0/0 1/1 0/0 .text
+ * JPACalcScaleY__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPACalcScaleY(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ JPAExtraShape* esp = work->mpRes->getEsp();
+ if (work->mScaleAnm < esp->getScaleInTiming()) {
+ ptcl->mParticleScaleY =
+ ptcl->mScaleOut * (esp->getScaleIncRateY() * work->mScaleAnm + esp->getScaleInValueY());
+ } else if (work->mScaleAnm > esp->getScaleOutTiming()) {
+ ptcl->mParticleScaleY =
+ ptcl->mScaleOut *
+ (esp->getScaleDecRateY() * (work->mScaleAnm - esp->getScaleOutTiming()) + 1.0f);
+ } else {
+ ptcl->mParticleScaleY = ptcl->mScaleOut;
+ }
+}
+
+/* 8027AA08-8027AA14 275348 000C+00 0/0 1/1 0/0 .text
+ * JPACalcScaleCopy__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPACalcScaleCopy(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ JPAExtraShape* esp = work->mpRes->getEsp();
+ ptcl->mParticleScaleY = ptcl->mParticleScaleX;
+}
+
+/* 8027AA14-8027AA20 275354 000C+00 0/0 1/1 0/0 .text
+ * JPACalcScaleAnmNormal__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPACalcScaleAnmNormal(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ work->mScaleAnm = ptcl->mTime;
+}
+
+/* 8027AA20-8027AA84 275360 0064+00 0/0 1/1 0/0 .text
+ * JPACalcScaleAnmRepeatX__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPACalcScaleAnmRepeatX(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ JPAExtraShape* esp = work->mpRes->getEsp();
+ work->mScaleAnm = (ptcl->mAge % esp->getScaleAnmCycleX()) / (f32)esp->getScaleAnmCycleX();
+}
+
+/* 8027AA84-8027AAE8 2753C4 0064+00 0/0 1/1 0/0 .text
+ * JPACalcScaleAnmRepeatY__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPACalcScaleAnmRepeatY(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ JPAExtraShape* esp = work->mpRes->getEsp();
+ work->mScaleAnm = (ptcl->mAge % esp->getScaleAnmCycleY()) / (f32)esp->getScaleAnmCycleY();
+}
+
+/* 8027AAE8-8027AB7C 275428 0094+00 0/0 1/1 0/0 .text
+ * JPACalcScaleAnmReverseX__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPACalcScaleAnmReverseX(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ JPAExtraShape* esp = work->mpRes->getEsp();
+ s32 cycle = ptcl->mAge / esp->getScaleAnmCycleX();
+ f32 base = (ptcl->mAge % esp->getScaleAnmCycleX()) / (f32)esp->getScaleAnmCycleX();
+ work->mScaleAnm = base + ((cycle & 1) * (1.0f - base * 2.0f));
+}
+
+/* 8027AB7C-8027AC10 2754BC 0094+00 0/0 1/1 0/0 .text
+ * JPACalcScaleAnmReverseY__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPACalcScaleAnmReverseY(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ JPAExtraShape* esp = work->mpRes->getEsp();
+ s32 cycle = ptcl->mAge / esp->getScaleAnmCycleY();
+ f32 base = (ptcl->mAge % esp->getScaleAnmCycleY()) / (f32)esp->getScaleAnmCycleY();
+ work->mScaleAnm = base + ((cycle & 1) * (1.0f - base * 2.0f));
+}
+
+/* 8027AC10-8027AC98 275550 0088+00 0/0 1/1 0/0 .text
+ * JPACalcAlphaAnm__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPACalcAlphaAnm(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ JPAExtraShape* esp = work->mpRes->getEsp();
+ f32 alpha;
+ if (ptcl->mTime < esp->getAlphaInTiming()) {
+ alpha = 255.0f * (esp->getAlphaInValue() + esp->getAlphaIncRate() * ptcl->mTime);
+ } else if (ptcl->mTime > esp->getAlphaOutTiming()) {
+ alpha = 255.0f * ((ptcl->mTime - esp->getAlphaOutTiming()) * esp->getAlphaDecRate() +
+ esp->getAlphaBaseValue());
+ } else {
+ alpha = 255.0f * esp->getAlphaBaseValue();
+ }
+ OSf32tou8(&alpha, &ptcl->mPrmColorAlphaAnm);
+}
+
+/* 8027AC98-8027AD88 2755D8 00F0+00 0/0 1/1 0/0 .text
+ * JPACalcAlphaFlickAnm__FP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPACalcAlphaFlickAnm(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ JPAExtraShape* esp = work->mpRes->getEsp();
+ f32 alpha;
+ if (ptcl->mTime < esp->getAlphaInTiming()) {
+ alpha = (esp->getAlphaInValue() + esp->getAlphaIncRate() * ptcl->mTime);
+ } else if (ptcl->mTime > esp->getAlphaOutTiming()) {
+ alpha = ((ptcl->mTime - esp->getAlphaOutTiming()) * esp->getAlphaDecRate() +
+ esp->getAlphaBaseValue());
+ } else {
+ alpha = esp->getAlphaBaseValue();
+ }
+ s32 theta = ptcl->mAlphaWaveRandom * ptcl->mAge * 16384.0f * (1.0f - esp->getAlphaFreq());
+ f32 wave = JMASSin(theta);
+ alpha *= (1.0f + esp->getAlphaAmp() * (wave - 1.0f) * 0.5f) * 255.0f;
+ OSf32tou8(&alpha, &ptcl->mPrmColorAlphaAnm);
+}
+
+/* 8027AD88-8027ADBC 2756C8 0034+00 0/0 1/1 0/0 .text __ct__13JPAExtraShapeFPCUc */
+JPAExtraShape::JPAExtraShape(u8 const* data) {
+ mpData = (const JPAExtraShapeData*)data;
+ init();
+}
+
+/* 8027ADBC-8027AEBC 2756FC 0100+00 1/1 0/0 0/0 .text init__13JPAExtraShapeFv */
+void JPAExtraShape::init() {
+ mAlphaIncRate = (getAlphaInTiming() != 0.0f) ?
+ (getAlphaBaseValue() - getAlphaInValue()) / getAlphaInTiming() :
+ 1.0f;
+ mAlphaDecRate = (getAlphaOutTiming() != 1.0f) ?
+ (getAlphaOutValue() - getAlphaBaseValue()) / (1.0f - getAlphaOutTiming()) :
+ 1.0f;
+
+ if (getScaleInTiming() != 0.0f) {
+ mScaleIncRateX = (1.0f - getScaleInValueX()) / getScaleInTiming();
+ mScaleIncRateY = (1.0f - getScaleInValueY()) / getScaleInTiming();
+ } else {
+ mScaleIncRateX = mScaleIncRateY = 1.0f;
+ }
+
+ if (getScaleOutTiming() != 1.0f) {
+ mScaleDecRateX = (getScaleOutValueX() - 1.0f) / (1.0f - getScaleOutTiming());
+ mScaleDecRateY = (getScaleOutValueY() - 1.0f) / (1.0f - getScaleOutTiming());
+ } else {
+ mScaleDecRateX = mScaleDecRateY = 1.0f;
+ }
+}
diff --git a/src/JSystem/JParticle/JPAFieldBlock.cpp b/src/JSystem/JParticle/JPAFieldBlock.cpp
new file mode 100644
index 00000000..c9a4c038
--- /dev/null
+++ b/src/JSystem/JParticle/JPAFieldBlock.cpp
@@ -0,0 +1,299 @@
+//
+// Generated By: dol2asm
+// Translation Unit: JPAFieldBlock
+//
+
+#include "JSystem/JParticle/JPAFieldBlock.h"
+#include "JSystem/JKernel/JKRHeap.h"
+#include "JSystem/JParticle/JPAEmitter.h"
+#include "JSystem/JParticle/JPAParticle.h"
+
+/* 8027BDEC-8027BF18 27672C 012C+00 8/8 0/0 0/0 .text
+ * calcAffect__12JPAFieldBaseFP13JPAFieldBlockP15JPABaseParticle */
+void JPAFieldBase::calcAffect(JPAFieldBlock* block, JPABaseParticle* ptcl) {
+ JGeometry::TVec3<f32> vec = mAccel;
+ if (!ptcl->checkStatus(4) && block->checkStatus(0x78)) {
+ vec.scale(calcFadeAffect(block, ptcl->mTime));
+ }
+
+ switch (block->getAddType()) {
+ case 0:
+ ptcl->mVelType0.add(vec);
+ break;
+ case 1:
+ ptcl->mVelType1.add(vec);
+ break;
+ case 2:
+ ptcl->mVelType2.add(vec);
+ break;
+ }
+}
+
+/* 8027BF18-8027BFB4 276858 009C+00 2/2 0/0 0/0 .text
+ * calcFadeAffect__12JPAFieldBaseCFP13JPAFieldBlockf */
+f32 JPAFieldBase::calcFadeAffect(JPAFieldBlock* block, f32 time) const {
+ f32 fade = 1.0f;
+ if ((block->checkStatus(8) && time < block->getEnTime())
+ || (block->checkStatus(0x10) && time >= block->getDisTime()))
+ {
+ fade = 0.0f;
+ } else if (block->checkStatus(0x40) && time >= block->getFadeOutTime()) {
+ fade = (block->getDisTime() - time) * block->getFadeOutRate();
+ } else if (block->checkStatus(0x20) && time < block->getFadeInTime()) {
+ fade = (time - block->getEnTime()) * block->getFadeInRate();
+ }
+ return fade;
+}
+
+/* 8027BFB4-8027C054 2768F4 00A0+00 1/0 0/0 0/0 .text
+ * prepare__15JPAFieldGravityFP18JPAEmitterWorkDataP13JPAFieldBlock */
+void JPAFieldGravity::prepare(JPAEmitterWorkData* work, JPAFieldBlock* block) {
+ if (block->checkStatus(2)) {
+ mAccel.scale(block->getMag(), block->getDir());
+ } else {
+ MTXMultVecSR(work->mRotationMtx, &block->getDir(), &mAccel);
+ mAccel.scale(block->getMag());
+ }
+}
+
+/* 8027C054-8027C07C 276994 0028+00 1/0 0/0 0/0 .text
+ * calc__15JPAFieldGravityFP18JPAEmitterWorkDataP13JPAFieldBlockP15JPABaseParticle */
+void JPAFieldGravity::calc(JPAEmitterWorkData* work, JPAFieldBlock* block, JPABaseParticle* ptcl) {
+ calcAffect(block, ptcl);
+}
+
+/* 8027C07C-8027C1B8 2769BC 013C+00 1/0 0/0 0/0 .text
+ * prepare__11JPAFieldAirFP18JPAEmitterWorkDataP13JPAFieldBlock */
+void JPAFieldAir::prepare(JPAEmitterWorkData* work, JPAFieldBlock* block) {
+ JGeometry::TVec3<f32> vec;
+ vec.normalize(block->getDir());
+ if (block->checkStatus(2)) {
+ mAccel.scale(block->getMag(), vec);
+ } else {
+ MTXMultVecSR(work->mRotationMtx, vec, mAccel);
+ mAccel.scale(block->getMag());
+ }
+}
+
+/* 8027C1B8-8027C24C 276AF8 0094+00 1/0 0/0 0/0 .text
+ * calc__11JPAFieldAirFP18JPAEmitterWorkDataP13JPAFieldBlockP15JPABaseParticle */
+void JPAFieldAir::calc(JPAEmitterWorkData* work, JPAFieldBlock* block, JPABaseParticle* ptcl) {
+ calcAffect(block, ptcl);
+ if (block->checkStatus(4)) {
+ f32 len = ptcl->mVelType1.length();
+ if (len > block->getMagRndm()) {
+ ptcl->mVelType1.scale(block->getMagRndm() / len);
+ }
+ }
+}
+
+/* 8027C24C-8027C29C 276B8C 0050+00 1/0 0/0 0/0 .text
+ * prepare__14JPAFieldMagnetFP18JPAEmitterWorkDataP13JPAFieldBlock */
+void JPAFieldMagnet::prepare(JPAEmitterWorkData* work, JPAFieldBlock* block) {
+ mDir.sub(block->getPos(), work->mEmitterPos);
+ MTXMultVecSR(work->mRotationMtx, &mDir, &mDir);
+}
+
+/* 8027C29C-8027C36C 276BDC 00D0+00 1/0 0/0 0/0 .text
+ * calc__14JPAFieldMagnetFP18JPAEmitterWorkDataP13JPAFieldBlockP15JPABaseParticle */
+void JPAFieldMagnet::calc(JPAEmitterWorkData* work, JPAFieldBlock* block, JPABaseParticle* ptcl) {
+ mAccel.sub(mDir, ptcl->mLocalPosition);
+ mAccel.setLength(block->getMag());
+ calcAffect(block, ptcl);
+}
+
+/* 8027C36C-8027C3E0 276CAC 0074+00 1/0 0/0 0/0 .text
+ * prepare__14JPAFieldNewtonFP18JPAEmitterWorkDataP13JPAFieldBlock */
+void JPAFieldNewton::prepare(JPAEmitterWorkData* work, JPAFieldBlock* block) {
+ mDir.sub(block->getPos(), work->mEmitterPos);
+ MTXMultVecSR(work->mRotationMtx, &mDir, &mDir);
+ mCutoff = block->getVal1() * block->getVal1();
+}
+
+/* 8027C3E0-8027C56C 276D20 018C+00 1/0 0/0 0/0 .text
+ * calc__14JPAFieldNewtonFP18JPAEmitterWorkDataP13JPAFieldBlockP15JPABaseParticle */
+void JPAFieldNewton::calc(JPAEmitterWorkData* work, JPAFieldBlock* block, JPABaseParticle* ptcl) {
+ mAccel.sub(mDir, ptcl->mLocalPosition);
+ f32 len_sq = mAccel.squared();
+ if (len_sq > mCutoff) {
+ mAccel.setLength(mCutoff * (block->getMag() * 10.0f) / len_sq);
+ } else {
+ mAccel.setLength(block->getMag() * 10.0f);
+ }
+ calcAffect(block, ptcl);
+}
+
+/* 8027C56C-8027C674 276EAC 0108+00 1/0 0/0 0/0 .text
+ * prepare__14JPAFieldVortexFP18JPAEmitterWorkDataP13JPAFieldBlock */
+void JPAFieldVortex::prepare(JPAEmitterWorkData* work, JPAFieldBlock* block) {
+ MTXMultVecSR(work->mGlobalRot, &block->getDir(), &field_0x10);
+ field_0x10.normalize();
+ field_0x1c = block->getPos().z * block->getPos().z;
+ field_0x20 = 1.0f / field_0x1c;
+}
+
+/* 8027C674-8027C814 276FB4 01A0+00 1/0 0/0 0/0 .text
+ * calc__14JPAFieldVortexFP18JPAEmitterWorkDataP13JPAFieldBlockP15JPABaseParticle */
+void JPAFieldVortex::calc(JPAEmitterWorkData* work, JPAFieldBlock* block, JPABaseParticle* ptcl) {
+ JGeometry::TVec3<f32> vec;
+ vec.scale(field_0x10.dot(ptcl->mLocalPosition), field_0x10);
+ vec.sub(ptcl->mLocalPosition, vec);
+ f32 mag = vec.squared();
+ if (mag > field_0x1c) {
+ mag = block->getMagRndm();
+ } else {
+ mag *= field_0x20;
+ mag = (1.0f - mag) * block->getMag() + mag * block->getMagRndm();
+ }
+ vec.normalize();
+ mAccel.cross(vec, field_0x10);
+ mAccel.scale(mag);
+ calcAffect(block, ptcl);
+}
+
+/* 8027C814-8027CA94 277154 0280+00 1/0 0/0 0/0 .text
+ * prepare__18JPAFieldConvectionFP18JPAEmitterWorkDataP13JPAFieldBlock */
+void JPAFieldConvection::prepare(JPAEmitterWorkData* work, JPAFieldBlock* block) {
+ JGeometry::TVec3<f32> vec1, vec2;
+ vec2.cross(block->getPos(), block->getDir());
+ vec1.cross(block->getDir(), vec2);
+ MTXMultVecSR(work->mGlobalRot, &vec1, &field_0x10);
+ MTXMultVecSR(work->mGlobalRot, &block->getDir(), field_0x1c);
+ MTXMultVecSR(work->mGlobalRot, &vec2, &field_0x28);
+ field_0x10.normalize();
+ field_0x1c.normalize();
+ field_0x28.normalize();
+}
+
+/* 8027CA94-8027CCCC 2773D4 0238+00 1/0 0/0 0/0 .text
+ * calc__18JPAFieldConvectionFP18JPAEmitterWorkDataP13JPAFieldBlockP15JPABaseParticle */
+void JPAFieldConvection::calc(JPAEmitterWorkData* work, JPAFieldBlock* block,
+ JPABaseParticle* ptcl) {
+ JGeometry::TVec3<f32> vec1, vec2, vec3;
+ vec1.scale(field_0x10.dot(ptcl->mLocalPosition), field_0x10);
+ vec3.scale(field_0x28.dot(ptcl->mLocalPosition), field_0x28);
+ vec1.add(vec3);
+ vec1.setLength(vec1, block->getVal1());
+ vec2.sub(ptcl->mLocalPosition, vec1);
+ vec3.cross(field_0x1c, vec1);
+ mAccel.cross(vec3, vec2);
+ mAccel.setLength(block->getMag());
+ calcAffect(block, ptcl);
+}
+
+/* 8027CCCC-8027CDE4 27760C 0118+00 1/0 0/0 0/0 .text
+ * calc__14JPAFieldRandomFP18JPAEmitterWorkDataP13JPAFieldBlockP15JPABaseParticle */
+void JPAFieldRandom::calc(JPAEmitterWorkData* work, JPAFieldBlock* block, JPABaseParticle* ptcl) {
+ if (ptcl->mAge == 0 || (block->getCycle() != 0 && ptcl->mAge % block->getCycle() == 0)) {
+ JPABaseEmitter* emtr = work->mpEmtr;
+ mAccel.set(emtr->get_r_zh(), emtr->get_r_zh(), emtr->get_r_zh());
+ mAccel.scale(block->getMag());
+ calcAffect(block, ptcl);
+ }
+}
+
+/* 8027CDE4-8027CE64 277724 0080+00 1/0 0/0 0/0 .text
+ * calc__12JPAFieldDragFP18JPAEmitterWorkDataP13JPAFieldBlockP15JPABaseParticle */
+void JPAFieldDrag::calc(JPAEmitterWorkData* work, JPAFieldBlock* block, JPABaseParticle* ptcl) {
+ if (!ptcl->checkStatus(4)) {
+ f32 fade = calcFadeAffect(block, ptcl->mTime);
+ ptcl->mDrag *= 1.0f - fade * (1.0f - block->getMag());
+ } else {
+ ptcl->mDrag *= block->getMag();
+ }
+}
+
+/* 8027CE64-8027CFA8 2777A4 0144+00 1/0 0/0 0/0 .text
+ * prepare__12JPAFieldSpinFP18JPAEmitterWorkDataP13JPAFieldBlock */
+void JPAFieldSpin::prepare(JPAEmitterWorkData* work, JPAFieldBlock* block) {
+ JGeometry::TVec3<f32> axis;
+ MTXMultVecSR(work->mGlobalRot, &block->getDir(), &axis);
+ axis.normalize();
+ Mtx mtx;
+ MTXRotAxisRad(mtx, &axis, block->getMag());
+ field_0x10.set(mtx[0][0], mtx[1][0], mtx[2][0]);
+ field_0x1c.set(mtx[0][1], mtx[1][1], mtx[2][1]);
+ field_0x28.set(mtx[0][2], mtx[1][2], mtx[2][2]);
+}
+
+/* 8027CFA8-8027D088 2778E8 00E0+00 1/0 0/0 0/0 .text
+ * calc__12JPAFieldSpinFP18JPAEmitterWorkDataP13JPAFieldBlockP15JPABaseParticle */
+void JPAFieldSpin::calc(JPAEmitterWorkData* work, JPAFieldBlock* block, JPABaseParticle* ptcl) {
+ Mtx mtx;
+ mtx[0][0] = field_0x10.x;
+ mtx[1][0] = field_0x10.y;
+ mtx[2][0] = field_0x10.z;
+ mtx[0][1] = field_0x1c.x;
+ mtx[1][1] = field_0x1c.y;
+ mtx[2][1] = field_0x1c.z;
+ mtx[0][2] = field_0x28.x;
+ mtx[1][2] = field_0x28.y;
+ mtx[2][2] = field_0x28.z;
+ mtx[0][3] = mtx[1][3] = mtx[2][3] = 0.0f;
+ Vec vec;
+ MTXMultVecSR(mtx, &ptcl->mLocalPosition, &vec);
+ mAccel.set(vec.x - ptcl->mLocalPosition.x, vec.y - ptcl->mLocalPosition.y,
+ vec.z - ptcl->mLocalPosition.z);
+ calcAffect(block, ptcl);
+}
+
+/* 8027D088-8027D0C0 2779C8 0038+00 0/0 1/1 0/0 .text __ct__13JPAFieldBlockFPCUcP7JKRHeap
+ */
+JPAFieldBlock::JPAFieldBlock(u8 const* data, JKRHeap* heap)
+ : mpData((const JPAFieldBlockData*)data) {
+ init(heap);
+}
+
+/* 8027D0C0-8027D3AC 277A00 02EC+00 2/1 0/0 0/0 .text init__13JPAFieldBlockFP7JKRHeap */
+void JPAFieldBlock::init(JKRHeap* heap) {
+ mFadeInRate = getFadeInTime() - getEnTime();
+ if (mFadeInRate == 0.0f) {
+ mFadeInRate = 1.0f;
+ } else {
+ mFadeInRate = 1.0f / mFadeInRate;
+ }
+
+ mFadeOutRate = getDisTime() - getFadeOutTime();
+ if (mFadeOutRate == 0.0f) {
+ mFadeOutRate = 1.0f;
+ } else {
+ mFadeOutRate = 1.0f / mFadeOutRate;
+ }
+
+ getPosOrig(&mPos);
+ getDirOrig(&mDir);
+ mMag = getMagOrig();
+
+ switch (getType()) {
+ case FIELD_GRAVITY:
+ mpField = new (heap, 0) JPAFieldGravity();
+ break;
+ case FIELD_AIR:
+ mpField = new (heap, 0) JPAFieldAir();
+ break;
+ case FIELD_MAGNET:
+ mpField = new (heap, 0) JPAFieldMagnet();
+ break;
+ case FIELD_NEWTON:
+ mpField = new (heap, 0) JPAFieldNewton();
+ break;
+ case FIELD_VORTEX:
+ mpField = new (heap, 0) JPAFieldVortex();
+ break;
+ case FIELD_RANDOM:
+ mpField = new (heap, 0) JPAFieldRandom();
+ break;
+ case FIELD_DRAG:
+ mpField = new (heap, 0) JPAFieldDrag();
+ break;
+ case FIELD_CONVECTION:
+ mpField = new (heap, 0) JPAFieldConvection();
+ break;
+ case FIELD_SPIN:
+ mpField = new (heap, 0) JPAFieldSpin();
+ break;
+ default:
+ mpField = NULL;
+ break;
+ }
+}
diff --git a/src/JSystem/JParticle/JPAKeyBlock.cpp b/src/JSystem/JParticle/JPAKeyBlock.cpp
new file mode 100644
index 00000000..fdb1e8e6
--- /dev/null
+++ b/src/JSystem/JParticle/JPAKeyBlock.cpp
@@ -0,0 +1,25 @@
+//
+// Generated By: dol2asm
+// Translation Unit: JPAKeyBlock
+//
+
+#include "JSystem/JParticle/JPAKeyBlock.h"
+#include "JSystem/JParticle/JPAMath.h"
+
+/* 8027D730-8027D740 278070 0010+00 0/0 1/1 0/0 .text __ct__11JPAKeyBlockFPCUc */
+JPAKeyBlock::JPAKeyBlock(const u8* data)
+ : mDataStart(data)
+ , field_0x4(reinterpret_cast<const float*>(&data[0xC]))
+{
+}
+
+/* 8027D740-8027D7D4 278080 0094+00 0/0 1/1 0/0 .text calc__11JPAKeyBlockFf */
+f32 JPAKeyBlock::calc(float p1) {
+ if (mDataStart[0xB] != '\0') {
+ int v1 = (int)field_0x4[(mDataStart[9] - 1) * 4] + 1;
+ // p1 -= (v1 * ((int)p1 / v1));
+ int v2 = ((int)p1 / v1);
+ p1 = p1 - (v2 * v1);
+ }
+ return JPACalcKeyAnmValue(p1, mDataStart[9], field_0x4);
+}
diff --git a/src/JSystem/JParticle/JPAMath.cpp b/src/JSystem/JParticle/JPAMath.cpp
new file mode 100644
index 00000000..c8686038
--- /dev/null
+++ b/src/JSystem/JParticle/JPAMath.cpp
@@ -0,0 +1,182 @@
+//
+// Generated By: dol2asm
+// Translation Unit: JPAMath
+//
+
+#include "JSystem/JParticle/JPAMath.h"
+#include "JSystem/JMath/JMATrigonometric.h"
+#include "JSystem/J2DGraph/J2DAnimation.h"
+
+//
+// Types:
+//
+
+//
+// Forward References:
+//
+
+extern "C" void func_80280588();
+extern "C" void JPAGetYZRotateMtx__FssPA4_f();
+extern "C" void JPAGetXYZRotateMtx__FsssPA4_f();
+extern "C" void func_802807E0();
+extern "C" void func_80280808();
+extern "C" void JPACalcKeyAnmValue__FfUsPCf();
+
+//
+// External References:
+//
+
+extern "C" void _savegpr_28();
+extern "C" void _restgpr_28();
+extern "C" u8 sincosTable___5JMath[65536];
+
+//
+// Declarations:
+//
+
+/* ############################################################################################## */
+// Probably some local function needed to change float literal order
+static f32 floatDummyFunc() {
+ return 1.0f;
+}
+
+/* 80280588-802806C0 27AEC8 0138+00 0/0 1/1 0/0 .text JPAGetDirMtx__FRCQ29JGeometry8TVec3<f>PA4_f
+ */
+void JPAGetDirMtx(JGeometry::TVec3<f32> const& param_0, f32 (*param_1)[4]) {
+ JGeometry::TVec3<float> local_78(param_0.y, -param_0.x, 0.0f);
+ f32 len = local_78.length();
+
+ if (len <= JGeometry::TUtil<f32>::epsilon()) {
+ local_78.zero();
+ } else {
+ local_78.scale(1.0f / len);
+ }
+ f32 xsquared = local_78.x * local_78.x;
+ f32 ysquared = local_78.y * local_78.y;
+ f32 xlen = local_78.x * len;
+ f32 ylen = local_78.y * len;
+ f32 fVar5 = (1.0f - param_0.z) * (local_78.x * local_78.y);
+ param_1[0][0] = xsquared + param_0.z * (1.0f - xsquared);
+ param_1[0][1] = fVar5;
+ param_1[0][2] = -ylen;
+ param_1[0][3] = 0.0f;
+ param_1[1][0] = fVar5;
+ param_1[1][1] = ysquared + param_0.z * (1.0f - ysquared);
+ param_1[1][2] = xlen;
+ param_1[1][3] = 0.0f;
+ param_1[2][0] = ylen;
+ param_1[2][1] = -xlen;
+ param_1[2][2] = param_0.z;
+ param_1[2][3] = 0.0f;
+}
+
+/* 802806C0-80280734 27B000 0074+00 0/0 1/1 0/0 .text JPAGetYZRotateMtx__FssPA4_f */
+void JPAGetYZRotateMtx(s16 angleY, s16 angleZ, f32 (*param_2)[4]) {
+ f32 cosy = JMASCos(angleY);
+ f32 cosz = JMASCos(angleZ);
+ f32 siny = JMASSin(angleY);
+ f32 sinz = JMASSin(angleZ);
+ param_2[0][0] = (cosy * cosz);
+ param_2[0][1] = -sinz;
+ param_2[0][2] = (siny * cosz);
+ param_2[1][0] = (cosy * sinz);
+ param_2[1][1] = cosz;
+ param_2[1][2] = (siny * sinz);
+ param_2[2][0] = -siny;
+ param_2[2][2] = cosy;
+ param_2[2][3] = 0.0f;
+ param_2[2][1] = 0.0f;
+ param_2[1][3] = 0.0f;
+ param_2[0][3] = 0.0f;
+}
+
+/* 80280734-802807E0 27B074 00AC+00 0/0 6/6 11/11 .text JPAGetXYZRotateMtx__FsssPA4_f */
+void JPAGetXYZRotateMtx(s16 x, s16 y, s16 z, Mtx mtx) {
+ f32 cosx = JMASCos(x);
+ f32 cosy = JMASCos(y);
+ f32 cosz = JMASCos(z);
+ f32 sinx = JMASSin(x);
+ f32 siny = JMASSin(y);
+ f32 sinz = JMASSin(z);
+ mtx[0][0] = cosy * cosz;
+ mtx[1][0] = cosy * sinz;
+ mtx[2][0] = -siny;
+ mtx[2][1] = sinx * cosy;
+ mtx[2][2] = cosx * cosy;
+ f32 cosxsinz = cosx * sinz;
+ f32 sinxcosz = sinx * cosz;
+ mtx[0][1] = sinxcosz * siny - cosxsinz;
+ mtx[1][2] = cosxsinz * siny - sinxcosz;
+ f32 sinxsinz = sinx * sinz;
+ f32 cosxcosz = cosx * cosz;
+ mtx[0][2] = sinxsinz + cosxcosz * siny;
+ mtx[1][1] = cosxcosz + sinxsinz * siny;
+ mtx[2][3] = 0.0f;
+ mtx[1][3] = 0.0f;
+ mtx[0][3] = 0.0f;
+}
+
+/* 802807E0-80280808 27B120 0028+00 0/0 11/11 71/71 .text
+ * JPASetRMtxTVecfromMtx__FPA4_CfPA4_fPQ29JGeometry8TVec3<f> */
+void JPASetRMtxTVecfromMtx(f32 const (*param_0)[4], f32 (*param_1)[4],
+ JGeometry::TVec3<f32>* param_2) {
+ JGeometry::TVec3<f32> dummy;
+ JPASetRMtxSTVecfromMtx(param_0, param_1, &dummy, param_2);
+}
+
+/* 80280808-80280984 27B148 017C+00 1/1 1/1 53/53 .text
+ * JPASetRMtxSTVecfromMtx__FPA4_CfPA4_fPQ29JGeometry8TVec3<f>PQ29JGeometry8TVec3<f> */
+void JPASetRMtxSTVecfromMtx(f32 const (*param_0)[4], f32 (*param_1)[4],
+ JGeometry::TVec3<f32>* param_2, JGeometry::TVec3<f32>* param_3) {
+ JGeometry::TVec3<float> aTStack_54;
+ aTStack_54.set(param_0[0][0], param_0[1][0], param_0[2][0]);
+ param_2->x = aTStack_54.length();
+ aTStack_54.set(param_0[0][1], param_0[1][1], param_0[2][1]);
+ param_2->y = aTStack_54.length();
+ aTStack_54.set(param_0[0][2], param_0[1][2], param_0[2][2]);
+ param_2->z = aTStack_54.length();
+ MTXIdentity(param_1);
+ if (param_2->x != 0.0f) {
+ f32 fVar5 = 1.0f / param_2->x;
+ param_1[0][0] = param_0[0][0] * fVar5;
+ param_1[1][0] = param_0[1][0] * fVar5;
+ param_1[2][0] = param_0[2][0] * fVar5;
+ }
+ if (param_2->y != 0.0f) {
+ f32 fVar5 = 1.0f / param_2->y;
+ param_1[0][1] = param_0[0][1] * fVar5;
+ param_1[1][1] = param_0[1][1] * fVar5;
+ param_1[2][1] = param_0[2][1] * fVar5;
+ }
+ if (param_2->z != 0.0f) {
+ f32 fVar5 = 1.0f / param_2->z;
+ param_1[0][2] = param_0[0][2] * fVar5;
+ param_1[1][2] = param_0[1][2] * fVar5;
+ param_1[2][2] = param_0[2][2] * fVar5;
+ }
+ param_3->set(param_0[0][3], param_0[1][3], param_0[2][3]);
+}
+
+/* 80280984-80280A48 27B2C4 00C4+00 0/0 2/1 0/0 .text JPACalcKeyAnmValue__FfUsPCf */
+f32 JPACalcKeyAnmValue(f32 param_0, u16 param_1, f32 const* param_2) {
+ if (param_0 < param_2[0]) {
+ return param_2[1];
+ }
+ int ind = param_1 - 1;
+ if (param_2[ind * 4] <= param_0) {
+ return param_2[ind * 4 + 1];
+ }
+ int x = param_1;
+ while (x > 1) {
+ u32 uVar3 = x / 2;
+ if (param_0 >= param_2[uVar3 * 4]) {
+ param_2 += uVar3 * 4;
+ x -= uVar3;
+ } else {
+ x = uVar3;
+ }
+ }
+ return JMAHermiteInterpolation(param_0, param_2[0], param_2[1],
+ param_2[3], param_2[4],
+ param_2[5], param_2[6]);
+}
diff --git a/src/JSystem/JParticle/JPAParticle.cpp b/src/JSystem/JParticle/JPAParticle.cpp
new file mode 100644
index 00000000..c06c62b9
--- /dev/null
+++ b/src/JSystem/JParticle/JPAParticle.cpp
@@ -0,0 +1,331 @@
+//
+// Generated By: dol2asm
+// Translation Unit: JPAParticle
+//
+
+#include "JSystem/JParticle/JPAParticle.h"
+#include "JSystem/JParticle/JPABaseShape.h"
+#include "JSystem/JParticle/JPAChildShape.h"
+#include "JSystem/JParticle/JPAEmitter.h"
+#include "JSystem/JParticle/JPAEmitterManager.h"
+#include "JSystem/JParticle/JPAExtraShape.h"
+
+/* 8027EFA4-8027EFEC 2798E4 0048+00 0/0 11/11 1/1 .text __dt__19JPAParticleCallBackFv */
+JPAParticleCallBack::~JPAParticleCallBack() {
+ /* empty function */
+}
+
+/* 8027EFEC-8027F8C8 27992C 08DC+00 0/0 1/1 0/0 .text
+ * init_p__15JPABaseParticleFP18JPAEmitterWorkData */
+void JPABaseParticle::init_p(JPAEmitterWorkData* work) {
+ JPABaseEmitter* emtr = work->mpEmtr;
+ JPAExtraShape* esp = work->mpRes->getEsp();
+ JPABaseShape* bsp = work->mpRes->getBsp();
+ JPADynamicsBlock* dyn = work->mpRes->getDyn();
+
+ mAge = -1;
+ mLifeTime = (1.0f - dyn->getLifetimeRndm() * emtr->get_r_f()) * emtr->mLifeTime;
+ mTime = 0.0f;
+
+ initStatus(0);
+ MTXMultVecSR(work->mGlobalSR, &work->mVolumeCalcData.mVolumePos, &mLocalPosition);
+ if (emtr->checkFlag(8)) {
+ setStatus(0x20);
+ }
+
+ mOffsetPosition.set(work->mGlobalPos);
+ mPosition.set(mOffsetPosition.x + mLocalPosition.x * work->mPublicScale.x,
+ mOffsetPosition.y + mLocalPosition.y * work->mPublicScale.y,
+ mOffsetPosition.z + mLocalPosition.z * work->mPublicScale.z);
+
+ JGeometry::TVec3<f32> velOmni;
+ if (emtr->mAwayFromCenterSpeed) {
+ velOmni.setLength(work->mVolumeCalcData.mVelOmni, emtr->mAwayFromCenterSpeed);
+ } else {
+ velOmni.zero();
+ }
+
+ JGeometry::TVec3<f32> velAxis;
+ if (emtr->mAwayFromAxisSpeed) {
+ velAxis.setLength(work->mVolumeCalcData.mVelAxis, emtr->mAwayFromAxisSpeed);
+ } else {
+ velAxis.zero();
+ }
+
+ JGeometry::TVec3<f32> velDir;
+ if (emtr->mDirSpeed) {
+ Mtx mtx;
+ JPAGetYZRotateMtx(emtr->get_r_zp() * 0x8000 * emtr->mSpread, emtr->get_r_ss(), mtx);
+ MTXConcat(work->mDirectionMtx, mtx, mtx);
+ velDir.set(emtr->mDirSpeed * mtx[0][2],
+ emtr->mDirSpeed * mtx[1][2],
+ emtr->mDirSpeed * mtx[2][2]);
+ } else {
+ velDir.zero();
+ }
+
+ JGeometry::TVec3<f32> velRndm;
+ if (emtr->mRndmDirSpeed) {
+ velRndm.set(emtr->mRndmDirSpeed * emtr->get_r_zh(),
+ emtr->mRndmDirSpeed * emtr->get_r_zh(),
+ emtr->mRndmDirSpeed * emtr->get_r_zh());
+ } else {
+ velRndm.zero();
+ }
+
+ f32 ratio = emtr->get_r_zp() * dyn->getInitVelRatio() + 1.0f;
+ mVelType1.set(ratio * (velOmni.x + velAxis.x + velDir.x + velRndm.x),
+ ratio * (velOmni.y + velAxis.y + velDir.y + velRndm.y),
+ ratio * (velOmni.z + velAxis.z + velDir.z + velRndm.z));
+
+ if (emtr->checkFlag(4)) {
+ mVelType1.mul(emtr->mLocalScl);
+ }
+ MTXMultVecSR(work->mGlobalRot, &mVelType1, &mVelType1);
+
+ mVelType0.zero();
+
+ mMoment = 1.0f - dyn->getMomentRndm() * emtr->get_r_f();
+ mDrag = 1.0f;
+ field_0x78 = 0;
+
+ mBaseAxis.set(work->mGlobalRot[0][1], work->mGlobalRot[1][1], work->mGlobalRot[2][1]);
+
+ mPrmClr = emtr->mPrmClr;
+ mEnvClr = emtr->mEnvClr;
+
+ mAnmRandom = emtr->get_r_f() * bsp->getLoopOfstValue();
+
+ if (esp != NULL && esp->isEnableScaleAnm()) {
+ mParticleScaleX = mParticleScaleY = mScaleOut = emtr->mScaleOut * (emtr->get_r_zp() * esp->getScaleRndm() + 1.0f);
+ } else {
+ mParticleScaleX = mParticleScaleY = mScaleOut = emtr->mScaleOut;
+ }
+
+ mPrmColorAlphaAnm = 0xff;
+
+ if (esp != NULL && esp->isEnableAlphaFlick()) {
+ mAlphaWaveRandom = emtr->get_r_zp() * esp->getAlphaFreqRndm() + 1.0f;
+ } else {
+ mAlphaWaveRandom = 1.0f;
+ }
+
+ if (esp != NULL) {
+ if (esp->isEnableRotateAnm()) {
+ mRotateAngle = esp->getRotateInitAngle() + esp->getRotateRndmAngle() * emtr->get_r_zh();
+ mRotateSpeed = esp->getRotateInitSpeed() *
+ (esp->getRotateRndmSpeed() * emtr->get_r_zp() + 1.0f);
+ mRotateSpeed = emtr->get_r_zp() < esp->getRotateDirection() ?
+ mRotateSpeed : (s16)-mRotateSpeed;
+ } else {
+ mRotateAngle = 0;
+ mRotateSpeed = 0;
+ }
+ } else {
+ mRotateAngle = 0;
+ mRotateSpeed = 0;
+ }
+}
+
+/* 8027F8C8-8027FFD0 27A208 0708+00 0/0 1/1 0/0 .text
+ * init_c__15JPABaseParticleFP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPABaseParticle::init_c(JPAEmitterWorkData* work, JPABaseParticle* parent) {
+ JPABaseEmitter* emtr = work->mpEmtr;
+ JPAChildShape* csp = work->mpRes->getCsp();
+
+ mAge = -1;
+ mLifeTime = csp->getLife();
+ mTime = 0.0f;
+ initStatus(4);
+ mLocalPosition.set(parent->mLocalPosition);
+
+ f32 pos_rndm = csp->getPosRndm();
+ if (pos_rndm != 0.0f) {
+ JGeometry::TVec3<f32> rnd(emtr->get_r_zh(), emtr->get_r_zh(), emtr->get_r_zh());
+ rnd.setLength(pos_rndm * emtr->get_r_f());
+ mLocalPosition.add(rnd);
+ }
+
+ if (emtr->checkFlag(0x10)) {
+ setStatus(0x20);
+ }
+
+ mOffsetPosition.set(parent->mOffsetPosition);
+
+ f32 base_speed = csp->getBaseVel() * (csp->getBaseVelRndm() * emtr->get_r_zp() + 1.0f);
+ JGeometry::TVec3<f32> base_vel(emtr->get_r_zp(), emtr->get_r_zp(), emtr->get_r_zp());
+ base_vel.setLength(base_speed);
+ mVelType1.scaleAdd(csp->getVelInhRate(), parent->mVelType1, base_vel);
+ mVelType0.scale(csp->getVelInhRate(), parent->mVelType2);
+
+ mMoment = parent->mMoment;
+ if (csp->isFieldAffected()) {
+ mDrag = parent->mDrag;
+ } else {
+ setStatus(0x40);
+ mDrag = 1.0f;
+ }
+ field_0x78 = parent->field_0x78;
+
+ mVelType2.set(mVelType0);
+ f32 ratio = mMoment * mDrag;
+ mVelocity.set(ratio * (mVelType1.x + mVelType2.x),
+ ratio * (mVelType1.y + mVelType2.y),
+ ratio * (mVelType1.z + mVelType2.z));
+
+ mBaseAxis.set(parent->mBaseAxis);
+
+ if (csp->isScaleInherited()) {
+ mParticleScaleX = mScaleOut = parent->mParticleScaleX * csp->getScaleInhRate();
+ mParticleScaleY = mAlphaWaveRandom = parent->mParticleScaleY * csp->getScaleInhRate();
+ } else {
+ mParticleScaleX = mScaleOut = mParticleScaleY = mAlphaWaveRandom = 1.0f;
+ }
+
+ if (csp->isColorInherited()) {
+ mPrmClr.r = parent->mPrmClr.r * csp->getColorInhRate();
+ mPrmClr.g = parent->mPrmClr.g * csp->getColorInhRate();
+ mPrmClr.b = parent->mPrmClr.b * csp->getColorInhRate();
+ mEnvClr.r = parent->mEnvClr.r * csp->getColorInhRate();
+ mEnvClr.g = parent->mEnvClr.g * csp->getColorInhRate();
+ mEnvClr.b = parent->mEnvClr.b * csp->getColorInhRate();
+ } else {
+ csp->getPrmClr(&mPrmClr);
+ csp->getEnvClr(&mEnvClr);
+ }
+
+ mPrmColorAlphaAnm = 0xff;
+ if (csp->isAlphaInherited()) {
+ mPrmClr.a = COLOR_MULTI(parent->mPrmClr.a, parent->mPrmColorAlphaAnm)
+ * csp->getAlphaInhRate();
+ } else {
+ mPrmClr.a = csp->getPrmAlpha();
+ }
+
+ mRotateAngle = parent->mRotateAngle;
+ if (csp->isRotateOn()) {
+ mRotateSpeed = csp->getRotInitSpeed();
+ } else {
+ mRotateSpeed = 0;
+ }
+
+ mTexAnmIdx = 0;
+}
+
+/* 8027FFD0-80280260 27A910 0290+00 0/0 1/1 0/0 .text
+ * calc_p__15JPABaseParticleFP18JPAEmitterWorkData */
+bool JPABaseParticle::calc_p(JPAEmitterWorkData* work) {
+ if (++mAge >= mLifeTime) {
+ return true;
+ }
+ mTime = (f32)mAge / (f32)mLifeTime;
+
+ if (checkStatus(0x20)) {
+ mOffsetPosition.set(work->mGlobalPos);
+ }
+
+ mVelType2.zero();
+ if (!checkStatus(0x40)) {
+ work->mpRes->calcField(work, this);
+ }
+ mVelType2.add(mVelType0);
+ mVelType1.scale(work->mpEmtr->mAirResist);
+ f32 ratio = mMoment * mDrag;
+ mVelocity.set(ratio * (mVelType1.x + mVelType2.x),
+ ratio * (mVelType1.y + mVelType2.y),
+ ratio * (mVelType1.z + mVelType2.z));
+
+ if (work->mpEmtr->mpPtclCallBack != NULL) {
+ work->mpEmtr->mpPtclCallBack->execute(work->mpEmtr, this);
+ }
+
+ if (checkStatus(2)) {
+ return true;
+ }
+
+ work->mpRes->calc_p(work, this);
+ mRotateAngle += mRotateSpeed;
+
+ if (work->mpRes->getCsp() != NULL && canCreateChild(work)) {
+ for (int i = work->mpRes->getCsp()->getRate(); i > 0; i--) {
+ work->mpEmtr->createChild(this);
+ }
+ }
+
+ mLocalPosition.add(mVelocity);
+ mPosition.set(mOffsetPosition.x + mLocalPosition.x * work->mPublicScale.x,
+ mOffsetPosition.y + mLocalPosition.y * work->mPublicScale.y,
+ mOffsetPosition.z + mLocalPosition.z * work->mPublicScale.z);
+
+ return false;
+}
+
+/* 80280260-802804C8 27ABA0 0268+00 0/0 1/1 0/0 .text
+ * calc_c__15JPABaseParticleFP18JPAEmitterWorkData */
+bool JPABaseParticle::calc_c(JPAEmitterWorkData* work) {
+ if (++mAge >= mLifeTime) {
+ return true;
+ }
+ mTime = (f32)mAge / (f32)mLifeTime;
+
+ if (mAge != 0) {
+ if (checkStatus(0x20)) {
+ mOffsetPosition.set(work->mGlobalPos);
+ }
+
+ mVelType1.y -= work->mpRes->getCsp()->getGravity();
+ mVelType2.zero();
+ if (!checkStatus(0x40)) {
+ work->mpRes->calcField(work, this);
+ }
+ mVelType2.add(mVelType0);
+ mVelType1.scale(work->mpEmtr->mAirResist);
+ f32 ratio = mMoment * mDrag;
+ mVelocity.set(ratio * (mVelType1.x + mVelType2.x),
+ ratio * (mVelType1.y + mVelType2.y),
+ ratio * (mVelType1.z + mVelType2.z));
+ }
+
+ if (work->mpEmtr->mpPtclCallBack != NULL) {
+ work->mpEmtr->mpPtclCallBack->execute(work->mpEmtr, this);
+ }
+
+ if (checkStatus(2)) {
+ return true;
+ }
+
+ work->mpRes->calc_c(work, this);
+ mRotateAngle += mRotateSpeed;
+ mLocalPosition.add(mVelocity);
+ mPosition.set(mOffsetPosition.x + mLocalPosition.x * work->mPublicScale.x,
+ mOffsetPosition.y + mLocalPosition.y * work->mPublicScale.y,
+ mOffsetPosition.z + mLocalPosition.z * work->mPublicScale.z);
+
+ return false;
+}
+
+/* 802804C8-80280548 27AE08 0080+00 1/1 0/0 0/0 .text
+ * canCreateChild__15JPABaseParticleFP18JPAEmitterWorkData */
+bool JPABaseParticle::canCreateChild(JPAEmitterWorkData* work) {
+ JPAChildShape* csp = work->mpRes->getCsp();
+ bool ret = false;
+ int time = mAge - (int)((mLifeTime - 1) * csp->getTiming());
+ if (time >= 0 && time % (csp->getStep() + 1) == 0) {
+ ret = true;
+ }
+ return ret;
+}
+
+/* 80280548-80280568 27AE88 0020+00 0/0 3/3 0/0 .text
+ * getWidth__15JPABaseParticleCFPC14JPABaseEmitter */
+f32 JPABaseParticle::getWidth(JPABaseEmitter const* emtr) const {
+ f32 scale = 2.0f * mParticleScaleX;
+ return scale * emtr->mpEmtrMgr->pWd->mGlobalPtclScl.x;
+}
+
+/* 80280568-80280588 27AEA8 0020+00 0/0 3/3 0/0 .text
+ * getHeight__15JPABaseParticleCFPC14JPABaseEmitter */
+f32 JPABaseParticle::getHeight(JPABaseEmitter const* emtr) const {
+ f32 scale = 2.0f * mParticleScaleY;
+ return scale * emtr->mpEmtrMgr->pWd->mGlobalPtclScl.y;
+}
diff --git a/src/JSystem/JParticle/JPAResource.cpp b/src/JSystem/JParticle/JPAResource.cpp
new file mode 100644
index 00000000..01bba7d2
--- /dev/null
+++ b/src/JSystem/JParticle/JPAResource.cpp
@@ -0,0 +1,1124 @@
+//
+// Generated By: dol2asm
+// Translation Unit: JPAResource
+//
+
+#include "JSystem/JParticle/JPAResource.h"
+#include "JSystem/JKernel/JKRHeap.h"
+#include "JSystem/JParticle/JPABaseShape.h"
+#include "JSystem/JParticle/JPAChildShape.h"
+#include "JSystem/JParticle/JPAEmitter.h"
+#include "JSystem/JParticle/JPAExTexShape.h"
+#include "JSystem/JParticle/JPAExtraShape.h"
+#include "JSystem/JParticle/JPAFieldBlock.h"
+#include "JSystem/JParticle/JPAKeyBlock.h"
+#include "JSystem/JParticle/JPAParticle.h"
+#include "JSystem/JParticle/JPAResourceManager.h"
+#include "dolphin/gx.h"
+#include "global.h"
+
+/* 80274010-80274080 26E950 0070+00 0/0 1/1 0/0 .text __ct__11JPAResourceFv */
+JPAResource::JPAResource() {
+ mpDrawEmitterChildFuncList = NULL;
+ mpDrawEmitterFuncList = NULL;
+ mpCalcEmitterFuncList = NULL;
+ mpDrawParticleChildFuncList = NULL;
+ mpCalcParticleChildFuncList = NULL;
+ mpDrawParticleFuncList = NULL;
+ mpCalcParticleFuncList = NULL;
+ mpBaseShape = NULL;
+ mpExtraShape = NULL;
+ mpChildShape = NULL;
+ mpExTexShape = NULL;
+ mpDynamicsBlock = NULL;
+ mpFieldBlocks = NULL;
+ mpKeyBlocks = NULL;
+ mpTDB1 = NULL;
+ mpDrawParticleChildFuncListNum = 0;
+ mpCalcParticleChildFuncListNum = 0;
+ mpDrawParticleFuncListNum = 0;
+ mpCalcParticleFuncListNum = 0;
+ mpDrawEmitterChildFuncListNum = 0;
+ mpDrawEmitterFuncListNum = 0;
+ mpCalcEmitterFuncListNum = 0;
+ mTDB1Num = 0;
+ mKeyBlockNum = 0;
+ mFieldBlockNum = 0;
+ mUsrIdx = 0;
+}
+
+/* 803C40C0-803C4220 0211E0 0144+1C 2/2 0/0 0/0 .data jpa_pos */
+static u8 jpa_pos[324] ALIGN_DECL(32) = {
+ 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x32, 0xCE, 0x00, 0x00, 0xCE, 0x00, 0xE7, 0x00, 0x00, 0x19,
+ 0x00, 0x00, 0x19, 0xCE, 0x00, 0xE7, 0xCE, 0x00, 0xCE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE,
+ 0x00, 0xCE, 0xCE, 0x00, 0x00, 0x19, 0x00, 0x32, 0x19, 0x00, 0x32, 0xE7, 0x00, 0x00, 0xE7, 0x00,
+ 0xE7, 0x19, 0x00, 0x19, 0x19, 0x00, 0x19, 0xE7, 0x00, 0xE7, 0xE7, 0x00, 0xCE, 0x19, 0x00, 0x00,
+ 0x19, 0x00, 0x00, 0xE7, 0x00, 0xCE, 0xE7, 0x00, 0x00, 0x32, 0x00, 0x32, 0x32, 0x00, 0x32, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xE7, 0x32, 0x00, 0x19, 0x32, 0x00, 0x19, 0x00, 0x00, 0xE7, 0x00, 0x00,
+ 0xCE, 0x32, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32,
+ 0x00, 0x00, 0x32, 0x00, 0x32, 0x00, 0x00, 0x32, 0xE7, 0x00, 0x00, 0x19, 0x00, 0x00, 0x19, 0x00,
+ 0x32, 0xE7, 0x00, 0x32, 0xCE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xCE, 0x00, 0x32,
+ 0x00, 0x00, 0xE7, 0x32, 0x00, 0xE7, 0x32, 0x00, 0x19, 0x00, 0x00, 0x19, 0xE7, 0x00, 0xE7, 0x19,
+ 0x00, 0xE7, 0x19, 0x00, 0x19, 0xE7, 0x00, 0x19, 0xCE, 0x00, 0xE7, 0x00, 0x00, 0xE7, 0x00, 0x00,
+ 0x19, 0xCE, 0x00, 0x19, 0x00, 0x00, 0xCE, 0x32, 0x00, 0xCE, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xE7, 0x00, 0xCE, 0x19, 0x00, 0xCE, 0x19, 0x00, 0x00, 0xE7, 0x00, 0x00, 0xCE, 0x00, 0xCE, 0x00,
+ 0x00, 0xCE, 0x00, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0xCE,
+ 0x32, 0x00, 0xCE, 0x00, 0x00, 0x00, 0xE7, 0x00, 0x00, 0x19, 0x00, 0xCE, 0x19, 0x00, 0xCE, 0xE7,
+ 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x00, 0x00, 0xCE, 0xCE, 0x00, 0x19, 0x00, 0x00,
+ 0x19, 0x32, 0x00, 0xE7, 0x32, 0x00, 0xE7, 0x00, 0x00, 0x19, 0xE7, 0x00, 0x19, 0x19, 0x00, 0xE7,
+ 0x19, 0x00, 0xE7, 0xE7, 0x00, 0x19, 0xCE, 0x00, 0x19, 0x00, 0x00, 0xE7, 0x00, 0x00, 0xE7, 0xCE,
+ 0x00, 0x32, 0x00, 0x00, 0x32, 0x32, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x32, 0xE7, 0x00,
+ 0x32, 0x19, 0x00, 0x00, 0x19, 0x00, 0x00, 0xE7, 0x00, 0x32, 0xCE, 0x00, 0x32, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xCE,
+};
+
+/* 803C4220-803C4240 021340 0020+00 2/2 0/0 0/0 .data jpa_crd */
+static u8 jpa_crd[32] ALIGN_DECL(32) = {
+ 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x02, 0x01, 0x00, 0x01,
+ 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02,
+};
+
+/* 80274080-802755E8 26E9C0 1568+00 2/0 1/1 0/0 .text init__11JPAResourceFP7JKRHeap */
+void JPAResource::init(JKRHeap* heap) {
+ BOOL is_glbl_clr_anm = mpBaseShape->isGlblClrAnm();
+ BOOL is_glbl_tex_anm = mpBaseShape->isGlblTexAnm();
+ BOOL is_prm_anm = mpBaseShape->isPrmAnm();
+ BOOL is_env_anm = mpBaseShape->isEnvAnm();
+ BOOL is_tex_anm = mpBaseShape->isTexAnm();
+ BOOL is_tex_crd_anm = mpBaseShape->isTexCrdAnm();
+ BOOL is_prj_tex = mpBaseShape->isPrjTex();
+ BOOL is_enable_scale_anm = mpExtraShape != NULL && mpExtraShape->isEnableScaleAnm();
+ BOOL is_enable_alpha_anm = mpExtraShape != NULL && mpExtraShape->isEnableAlphaAnm();
+ BOOL is_enable_alpha_flick = mpExtraShape != NULL && mpExtraShape->isEnableAlphaAnm()
+ && mpExtraShape->isEnableAlphaFlick();
+ BOOL is_enable_rotate_anm = mpExtraShape != NULL && mpExtraShape->isEnableRotateAnm();
+ BOOL is_rotate_on = is_enable_rotate_anm
+ || (mpChildShape != NULL && mpChildShape->isRotateOn());
+ BOOL base_type_5_6 = mpBaseShape->getType() == 5 || mpBaseShape->getType() == 6;
+ BOOL base_type_0 = mpBaseShape->getType() == 0;
+ BOOL base_type_0_1 = mpBaseShape->getType() == 0 || mpBaseShape->getType() == 1;
+ BOOL child_type_5_6 = mpChildShape != NULL
+ && (mpChildShape->getType() == 5 || mpChildShape->getType() == 6);
+ BOOL child_type_0 = mpChildShape != NULL && mpChildShape->getType() == 0;
+ BOOL child_type_0_1 = mpChildShape != NULL
+ && (mpChildShape->getType() == 0 || mpChildShape->getType() == 1);
+ BOOL is_draw_parent = !mpBaseShape->isNoDrawParent();
+ BOOL is_draw_child = !mpBaseShape->isNoDrawChild();
+
+ if (is_glbl_tex_anm && is_tex_anm) {
+ mpCalcEmitterFuncListNum++;
+ }
+
+ if (is_glbl_clr_anm) {
+ if (is_prm_anm) {
+ mpCalcEmitterFuncListNum++;
+ }
+ if (is_env_anm) {
+ mpCalcEmitterFuncListNum++;
+ }
+ if (is_prm_anm || is_env_anm) {
+ mpCalcEmitterFuncListNum++;
+ }
+ }
+
+ if (mpCalcEmitterFuncListNum != 0) {
+ mpCalcEmitterFuncList =
+ (EmitterFunc*)JKRAllocFromHeap(heap, mpCalcEmitterFuncListNum * 4, 4);
+ }
+
+ int func_no = 0;
+
+ if (is_glbl_tex_anm && is_tex_anm) {
+ switch (mpBaseShape->getTexAnmType()) {
+ case 0:
+ mpCalcEmitterFuncList[func_no] = &JPACalcTexIdxNormal;
+ break;
+ case 1:
+ mpCalcEmitterFuncList[func_no] = &JPACalcTexIdxRepeat;
+ break;
+ case 2:
+ mpCalcEmitterFuncList[func_no] = &JPACalcTexIdxReverse;
+ break;
+ case 3:
+ mpCalcEmitterFuncList[func_no] = &JPACalcTexIdxMerge;
+ break;
+ case 4:
+ mpCalcEmitterFuncList[func_no] = &JPACalcTexIdxRandom;
+ break;
+ }
+ func_no++;
+ }
+
+ if (is_glbl_clr_anm) {
+ if (is_prm_anm) {
+ mpCalcEmitterFuncList[func_no] = &JPACalcPrm;
+ func_no++;
+ }
+ if (is_env_anm) {
+ mpCalcEmitterFuncList[func_no] = &JPACalcEnv;
+ func_no++;
+ }
+ if (is_prm_anm || is_env_anm) {
+ switch (mpBaseShape->getClrAnmType()) {
+ case 0:
+ mpCalcEmitterFuncList[func_no] = &JPACalcClrIdxNormal;
+ break;
+ case 1:
+ mpCalcEmitterFuncList[func_no] = &JPACalcClrIdxRepeat;
+ break;
+ case 2:
+ mpCalcEmitterFuncList[func_no] = &JPACalcClrIdxReverse;
+ break;
+ case 3:
+ mpCalcEmitterFuncList[func_no] = &JPACalcClrIdxMerge;
+ break;
+ case 4:
+ mpCalcEmitterFuncList[func_no] = &JPACalcClrIdxRandom;
+ break;
+ }
+ }
+ }
+
+ if (!is_glbl_tex_anm && is_tex_anm) {
+ mpCalcParticleFuncListNum++;
+ }
+
+ if (!base_type_5_6 && (is_enable_alpha_anm || is_enable_alpha_flick)) {
+ mpCalcParticleFuncListNum++;
+ }
+
+ if (!is_glbl_clr_anm) {
+ if (is_prm_anm) {
+ mpCalcParticleFuncListNum++;
+ }
+ if (is_env_anm) {
+ mpCalcParticleFuncListNum++;
+ }
+ if (is_prm_anm || is_env_anm) {
+ mpCalcParticleFuncListNum++;
+ }
+ } else {
+ mpCalcParticleFuncListNum++;
+ }
+
+ if (is_enable_scale_anm) {
+ if (mpBaseShape->getType() != 0) {
+ if (mpExtraShape->isScaleXYDiff()) {
+ if (mpExtraShape->getScaleAnmTypeX() == 0 && mpExtraShape->getScaleAnmTypeY() == 0) {
+ mpCalcParticleFuncListNum++;
+ } else {
+ mpCalcParticleFuncListNum++;
+ mpCalcParticleFuncListNum++;
+ }
+ } else {
+ mpCalcParticleFuncListNum++;
+ }
+ }
+ mpCalcParticleFuncListNum++;
+ mpCalcParticleFuncListNum++;
+ }
+
+ if (mpCalcParticleFuncListNum != 0) {
+ mpCalcParticleFuncList =
+ (ParticleFunc*)JKRAllocFromHeap(heap, mpCalcParticleFuncListNum * 4, 4);
+ }
+
+ func_no = 0;
+
+ if (!is_glbl_tex_anm && is_tex_anm) {
+ switch (mpBaseShape->getTexAnmType()) {
+ case 0:
+ mpCalcParticleFuncList[func_no] = &JPACalcTexIdxNormal;
+ break;
+ case 1:
+ mpCalcParticleFuncList[func_no] = &JPACalcTexIdxRepeat;
+ break;
+ case 2:
+ mpCalcParticleFuncList[func_no] = &JPACalcTexIdxReverse;
+ break;
+ case 3:
+ mpCalcParticleFuncList[func_no] = &JPACalcTexIdxMerge;
+ break;
+ case 4:
+ mpCalcParticleFuncList[func_no] = &JPACalcTexIdxRandom;
+ break;
+ }
+ func_no++;
+ }
+
+ if (!base_type_5_6 && (is_enable_alpha_anm || is_enable_alpha_flick)) {
+ if (is_enable_alpha_flick) {
+ mpCalcParticleFuncList[func_no] = &JPACalcAlphaFlickAnm;
+ func_no++;
+ } else {
+ mpCalcParticleFuncList[func_no] = &JPACalcAlphaAnm;
+ func_no++;
+ }
+ }
+
+ if (!is_glbl_clr_anm) {
+ if (is_prm_anm) {
+ mpCalcParticleFuncList[func_no] = &JPACalcPrm;
+ func_no++;
+ }
+ if (is_env_anm) {
+ mpCalcParticleFuncList[func_no] = &JPACalcEnv;
+ func_no++;
+ }
+ if (is_prm_anm || is_env_anm) {
+ switch (mpBaseShape->getClrAnmType()) {
+ case 0:
+ mpCalcParticleFuncList[func_no] = &JPACalcClrIdxNormal;
+ break;
+ case 1:
+ mpCalcParticleFuncList[func_no] = &JPACalcClrIdxRepeat;
+ break;
+ case 2:
+ mpCalcParticleFuncList[func_no] = &JPACalcClrIdxReverse;
+ break;
+ case 3:
+ mpCalcParticleFuncList[func_no] = &JPACalcClrIdxMerge;
+ break;
+ case 4:
+ mpCalcParticleFuncList[func_no] = &JPACalcClrIdxRandom;
+ break;
+ }
+ func_no++;
+ }
+ } else {
+ mpCalcParticleFuncList[func_no] = &JPACalcColorCopy;
+ func_no++;
+ }
+
+ if (is_enable_scale_anm) {
+ if (mpBaseShape->getType() != 0) {
+ if (mpExtraShape->isScaleXYDiff()) {
+ mpCalcParticleFuncList[func_no] = &JPACalcScaleY;
+ func_no++;
+ if (mpExtraShape->getScaleAnmTypeY() != 0 || mpExtraShape->getScaleAnmTypeX() != 0) {
+ switch (mpExtraShape->getScaleAnmTypeY()) {
+ case 0:
+ mpCalcParticleFuncList[func_no] = &JPACalcScaleAnmNormal;
+ break;
+ case 1:
+ mpCalcParticleFuncList[func_no] = &JPACalcScaleAnmRepeatY;
+ break;
+ case 2:
+ mpCalcParticleFuncList[func_no] = &JPACalcScaleAnmReverseY;
+ break;
+ }
+ func_no++;
+ }
+ } else {
+ mpCalcParticleFuncList[func_no] = &JPACalcScaleCopy;
+ func_no++;
+ }
+ }
+ mpCalcParticleFuncList[func_no] = &JPACalcScaleX;
+ func_no++;
+ switch (mpExtraShape->getScaleAnmTypeX()) {
+ case 0:
+ mpCalcParticleFuncList[func_no] = &JPACalcScaleAnmNormal;
+ break;
+ case 1:
+ mpCalcParticleFuncList[func_no] = &JPACalcScaleAnmRepeatX;
+ break;
+ case 2:
+ mpCalcParticleFuncList[func_no] = &JPACalcScaleAnmReverseX;
+ break;
+ }
+ }
+
+ if (mpChildShape != NULL && mpChildShape->isScaleOutOn()) {
+ mpCalcParticleChildFuncListNum++;
+ }
+
+ if (mpChildShape != NULL && mpChildShape->isAlphaOutOn()) {
+ mpCalcParticleChildFuncListNum++;
+ }
+
+ if (mpCalcParticleChildFuncListNum != 0) {
+ mpCalcParticleChildFuncList =
+ (ParticleFunc*)JKRAllocFromHeap(heap, mpCalcParticleChildFuncListNum * 4, 4);
+ }
+
+ func_no = 0;
+
+ if (mpChildShape != NULL && mpChildShape->isScaleOutOn()) {
+ mpCalcParticleChildFuncList[func_no] = &JPACalcChildScaleOut;
+ func_no++;
+ }
+
+ if (mpChildShape != NULL && mpChildShape->isAlphaOutOn()) {
+ mpCalcParticleChildFuncList[func_no] = &JPACalcChildAlphaOut;
+ }
+
+ if (is_draw_parent && base_type_5_6) {
+ mpDrawEmitterFuncListNum++;
+ }
+
+ mpDrawEmitterFuncListNum++;
+
+ if (mpExTexShape != NULL) {
+ mpDrawEmitterFuncListNum++;
+ }
+
+ if (is_glbl_tex_anm || !is_tex_anm) {
+ mpDrawEmitterFuncListNum++;
+ }
+
+ mpDrawEmitterFuncListNum++;
+
+ if (base_type_0_1) {
+ mpDrawEmitterFuncListNum++;
+ }
+
+ if (base_type_0_1 && !is_enable_scale_anm) {
+ mpDrawEmitterFuncListNum++;
+ }
+
+ if (is_glbl_clr_anm || (!is_prm_anm && !is_enable_alpha_anm) || !is_env_anm) {
+ mpDrawEmitterFuncListNum++;
+ }
+
+ if (mpDrawEmitterFuncListNum != 0) {
+ mpDrawEmitterFuncList =
+ (EmitterFunc*)JKRAllocFromHeap(heap, mpDrawEmitterFuncListNum * 4, 4);
+ }
+
+ func_no = 0;
+
+ if (is_draw_parent && base_type_5_6) {
+ if (mpBaseShape->getType() == 5) {
+ mpDrawEmitterFuncList[func_no] = &JPADrawStripe;
+ func_no++;
+ } else {
+ mpDrawEmitterFuncList[func_no] = &JPADrawStripeX;
+ func_no++;
+ }
+ }
+
+ mpDrawEmitterFuncList[func_no] = &JPADrawEmitterCallBackB;
+ func_no++;
+
+ if (mpExTexShape != NULL) {
+ mpDrawEmitterFuncList[func_no] = &JPALoadExTex;
+ func_no++;
+ }
+
+ if (!is_tex_anm) {
+ mpDrawEmitterFuncList[func_no] = &JPALoadTex;
+ func_no++;
+ } else if (is_glbl_tex_anm) {
+ mpDrawEmitterFuncList[func_no] = &JPALoadTexAnm;
+ func_no++;
+ }
+
+ if (base_type_0_1) {
+ mpDrawEmitterFuncList[func_no] = &JPAGenTexCrdMtxIdt;
+ func_no++;
+ } else if (is_prj_tex) {
+ mpDrawEmitterFuncList[func_no] = &JPAGenTexCrdMtxPrj;
+ func_no++;
+ } else if (is_tex_crd_anm) {
+ if (base_type_5_6) {
+ mpDrawEmitterFuncList[func_no] = &JPAGenCalcTexCrdMtxAnm;
+ func_no++;
+ } else {
+ mpDrawEmitterFuncList[func_no] = &JPAGenTexCrdMtxAnm;
+ func_no++;
+ }
+ } else {
+ mpDrawEmitterFuncList[func_no] = &JPAGenTexCrdMtxIdt;
+ func_no++;
+ }
+
+ if (base_type_0_1) {
+ mpDrawEmitterFuncList[func_no] = &JPALoadPosMtxCam;
+ func_no++;
+ }
+
+ if (base_type_0_1 && !is_enable_scale_anm) {
+ if (base_type_0) {
+ mpDrawEmitterFuncList[func_no] = &JPASetPointSize;
+ func_no++;
+ } else {
+ mpDrawEmitterFuncList[func_no] = &JPASetLineWidth;
+ func_no++;
+ }
+ }
+
+ if (is_glbl_clr_anm) {
+ if (base_type_5_6 || !is_enable_alpha_anm) {
+ mpDrawEmitterFuncList[func_no] = &JPARegistPrmEnv;
+ } else if (is_enable_alpha_anm) {
+ mpDrawEmitterFuncList[func_no] = &JPARegistEnv;
+ }
+ } else if (!is_prm_anm && !is_enable_alpha_anm) {
+ if (!is_env_anm) {
+ mpDrawEmitterFuncList[func_no] = &JPARegistPrmEnv;
+ } else {
+ mpDrawEmitterFuncList[func_no] = &JPARegistPrm;
+ }
+ } else if (!is_env_anm) {
+ mpDrawEmitterFuncList[func_no] = &JPARegistEnv;
+ }
+
+ if (is_draw_child && child_type_5_6) {
+ mpDrawEmitterChildFuncListNum++;
+ }
+
+ mpDrawEmitterChildFuncListNum++;
+
+ if (child_type_0_1) {
+ mpDrawEmitterChildFuncListNum++;
+ }
+
+ if (mpChildShape != NULL && !mpChildShape->isAlphaOutOn() && !mpChildShape->isAlphaInherited()
+ && !mpChildShape->isColorInherited()) {
+ mpDrawEmitterChildFuncListNum++;
+ }
+
+ if (mpDrawEmitterChildFuncListNum != 0) {
+ mpDrawEmitterChildFuncList =
+ (EmitterFunc*)JKRAllocFromHeap(heap, mpDrawEmitterChildFuncListNum * 4, 4);
+ }
+
+ func_no = 0;
+
+ if (is_draw_child && child_type_5_6) {
+ if (mpChildShape->getType() == 5) {
+ mpDrawEmitterChildFuncList[func_no] = &JPADrawStripe;
+ func_no++;
+ } else {
+ mpDrawEmitterChildFuncList[func_no] = &JPADrawStripeX;
+ func_no++;
+ }
+ }
+
+ mpDrawEmitterChildFuncList[func_no] = &JPADrawEmitterCallBackB;
+ func_no++;
+
+ if (child_type_0_1) {
+ mpDrawEmitterChildFuncList[func_no] = &JPALoadPosMtxCam;
+ func_no++;
+ }
+
+ if (mpChildShape != NULL && !mpChildShape->isAlphaOutOn() && !mpChildShape->isAlphaInherited()
+ && !mpChildShape->isColorInherited()) {
+ mpDrawEmitterChildFuncList[func_no] = &JPARegistChildPrmEnv;
+ }
+
+ if (is_draw_parent && !base_type_5_6) {
+ mpDrawParticleFuncListNum++;
+ }
+
+ mpDrawParticleFuncListNum++;
+
+ if (!is_glbl_tex_anm && is_tex_anm) {
+ mpDrawParticleFuncListNum++;
+ }
+
+ if ((base_type_0_1 && is_enable_scale_anm) || (is_tex_crd_anm && !is_prj_tex)) {
+ mpDrawParticleFuncListNum++;
+ }
+
+ if ((!is_glbl_clr_anm && (is_prm_anm || is_env_anm || is_enable_alpha_anm))
+ || (is_glbl_clr_anm && is_enable_alpha_anm && !base_type_5_6)) {
+ mpDrawParticleFuncListNum++;
+ }
+
+ if (mpDrawParticleFuncListNum != 0) {
+ mpDrawParticleFuncList =
+ (ParticleFunc*)JKRAllocFromHeap(heap, mpDrawParticleFuncListNum * 4, 4);
+ }
+
+ func_no = 0;
+
+ if (is_draw_parent && !base_type_5_6) {
+ switch (mpBaseShape->getType()) {
+ case 2:
+ if (is_enable_rotate_anm) {
+ mpDrawParticleFuncList[func_no] = &JPADrawRotBillboard;
+ } else {
+ mpDrawParticleFuncList[func_no] = &JPADrawBillboard;
+ }
+ break;
+ case 10:
+ if (is_enable_rotate_anm) {
+ mpDrawParticleFuncList[func_no] = &JPADrawRotYBillboard;
+ } else {
+ mpDrawParticleFuncList[func_no] = &JPADrawYBillboard;
+ }
+ break;
+ case 3:
+ case 4:
+ if (is_enable_rotate_anm) {
+ mpDrawParticleFuncList[func_no] = &JPADrawRotDirection;
+ } else {
+ mpDrawParticleFuncList[func_no] = &JPADrawDirection;
+ }
+ break;
+ case 9:
+ mpDrawParticleFuncList[func_no] = &JPADrawDBillboard;
+ break;
+ case 7:
+ case 8:
+ mpDrawParticleFuncList[func_no] = &JPADrawRotation;
+ break;
+ case 0:
+ mpDrawParticleFuncList[func_no] = &JPADrawPoint;
+ break;
+ case 1:
+ mpDrawParticleFuncList[func_no] = &JPADrawLine;
+ break;
+ }
+ func_no++;
+ }
+
+ mpDrawParticleFuncList[func_no] = &JPADrawParticleCallBack;
+ func_no++;
+
+ if (!is_glbl_tex_anm && is_tex_anm) {
+ mpDrawParticleFuncList[func_no] = &JPALoadTexAnm;
+ func_no++;
+ }
+
+ if (base_type_0_1 && is_enable_scale_anm) {
+ if (base_type_0) {
+ mpDrawParticleFuncList[func_no] = &JPASetPointSize;
+ func_no++;
+ } else {
+ mpDrawParticleFuncList[func_no] = &JPASetLineWidth;
+ func_no++;
+ }
+ } else if (is_tex_crd_anm && !is_prj_tex) {
+ mpDrawParticleFuncList[func_no] = &JPALoadCalcTexCrdMtxAnm;
+ func_no++;
+ }
+
+ if (!is_glbl_clr_anm) {
+ if (is_prm_anm) {
+ if (is_env_anm) {
+ mpDrawParticleFuncList[func_no] = &JPARegistPrmAlphaEnv;
+ } else {
+ mpDrawParticleFuncList[func_no] = &JPARegistPrmAlpha;
+ }
+ } else if (is_enable_alpha_anm) {
+ if (is_env_anm) {
+ mpDrawParticleFuncList[func_no] = &JPARegistAlphaEnv;
+ } else {
+ mpDrawParticleFuncList[func_no] = &JPARegistAlpha;
+ }
+ } else if (is_env_anm) {
+ mpDrawParticleFuncList[func_no] = &JPARegistEnv;
+ }
+ } else if (is_enable_alpha_anm && !base_type_5_6) {
+ mpDrawParticleFuncList[func_no] = &JPARegistAlpha;
+ }
+
+ if (is_draw_child && mpChildShape != NULL && !child_type_5_6) {
+ mpDrawParticleChildFuncListNum++;
+ }
+
+ mpDrawParticleChildFuncListNum++;
+
+ if (child_type_0_1) {
+ mpDrawParticleChildFuncListNum++;
+ }
+
+ if (mpChildShape != NULL && (mpChildShape->isAlphaOutOn() || mpChildShape->isAlphaInherited()
+ || mpChildShape->isColorInherited())) {
+ mpDrawParticleChildFuncListNum++;
+ }
+
+ if (mpDrawParticleChildFuncListNum != 0) {
+ mpDrawParticleChildFuncList =
+ (ParticleFunc*)JKRAllocFromHeap(heap, mpDrawParticleChildFuncListNum * 4, 4);
+ }
+
+ func_no = 0;
+
+ if (is_draw_child && mpChildShape != NULL && !child_type_5_6) {
+ switch (mpChildShape->getType()) {
+ case 2:
+ if (is_rotate_on) {
+ mpDrawParticleChildFuncList[func_no] = &JPADrawRotBillboard;
+ } else {
+ mpDrawParticleChildFuncList[func_no] = &JPADrawBillboard;
+ }
+ break;
+ case 10:
+ if (is_rotate_on) {
+ mpDrawParticleChildFuncList[func_no] = &JPADrawRotYBillboard;
+ } else {
+ mpDrawParticleChildFuncList[func_no] = &JPADrawYBillboard;
+ }
+ break;
+ case 3:
+ case 4:
+ if (is_rotate_on) {
+ mpDrawParticleChildFuncList[func_no] = &JPADrawRotDirection;
+ } else {
+ mpDrawParticleChildFuncList[func_no] = &JPADrawDirection;
+ }
+ break;
+ case 9:
+ mpDrawParticleChildFuncList[func_no] = &JPADrawDBillboard;
+ break;
+ case 7:
+ case 8:
+ mpDrawParticleChildFuncList[func_no] = &JPADrawRotation;
+ break;
+ case 0:
+ mpDrawParticleChildFuncList[func_no] = &JPADrawPoint;
+ break;
+ case 1:
+ mpDrawParticleChildFuncList[func_no] = &JPADrawLine;
+ break;
+ }
+ func_no++;
+ }
+
+ mpDrawParticleChildFuncList[func_no] = &JPADrawParticleCallBack;
+ func_no++;
+
+ if (child_type_0_1) {
+ if (child_type_0) {
+ mpDrawParticleChildFuncList[func_no] = &JPASetPointSize;
+ func_no++;
+ } else {
+ mpDrawParticleChildFuncList[func_no] = &JPASetLineWidth;
+ func_no++;
+ }
+ }
+
+ if (mpChildShape != NULL && (mpChildShape->isAlphaOutOn() || mpChildShape->isAlphaInherited()
+ || mpChildShape->isColorInherited())) {
+ mpDrawParticleChildFuncList[func_no] = &JPARegistPrmAlphaEnv;
+ }
+}
+
+/* 802755E8-80275A94 26FF28 04AC+00 0/0 1/1 0/0 .text
+ * calc__11JPAResourceFP18JPAEmitterWorkDataP14JPABaseEmitter */
+bool JPAResource::calc(JPAEmitterWorkData* work, JPABaseEmitter* emtr) {
+ work->mpEmtr = emtr;
+ work->mpRes = this;
+ work->mEmitCount = 0;
+
+ if (!emtr->processTillStartFrame()) {
+ return false;
+ }
+
+ if (emtr->processTermination()) {
+ return true;
+ }
+
+ if (emtr->checkStatus(2)) {
+ if (emtr->mpEmtrCallBack != NULL) {
+ emtr->mpEmtrCallBack->execute(emtr);
+ if (emtr->checkStatus(0x100)) {
+ return true;
+ }
+ emtr->mpEmtrCallBack->executeAfter(emtr);
+ if (emtr->checkStatus(0x100)) {
+ return true;
+ }
+ }
+
+ } else {
+ calcKey(work);
+
+ for (int i = mFieldBlockNum - 1; i >= 0; i--) {
+ mpFieldBlocks[i]->initOpParam();
+ }
+
+ if (emtr->mpEmtrCallBack != NULL) {
+ emtr->mpEmtrCallBack->execute(emtr);
+ if (emtr->checkStatus(0x100)) {
+ return true;
+ }
+ }
+
+ calcWorkData_c(work);
+
+ for (int i = mpCalcEmitterFuncListNum - 1; i >= 0; i--) {
+ (*mpCalcEmitterFuncList[i])(work);
+ }
+
+ for (int i = mFieldBlockNum - 1; i >= 0; i--) {
+ mpFieldBlocks[i]->prepare(work);
+ }
+
+ if (!emtr->checkStatus(8)) {
+ mpDynamicsBlock->create(work);
+ }
+
+ if (emtr->mpEmtrCallBack != NULL) {
+ emtr->mpEmtrCallBack->executeAfter(emtr);
+ if (emtr->checkStatus(0x100)) {
+ return true;
+ }
+ }
+
+ JPANode<JPABaseParticle>* node = emtr->mAlivePtclBase.getFirst();
+ JPANode<JPABaseParticle>* next;
+ while (node != emtr->mAlivePtclBase.getEnd()) {
+ next = node->getNext();
+ if (node->getObject()->calc_p(work)) {
+ emtr->mpPtclPool->push_front(emtr->mAlivePtclBase.erase(node));
+ }
+ node = next;
+ }
+
+ node = emtr->mAlivePtclChld.getFirst();
+ while (node != emtr->mAlivePtclChld.getEnd()) {
+ next = node->getNext();
+ if (node->getObject()->calc_c(work)) {
+ emtr->mpPtclPool->push_front(emtr->mAlivePtclChld.erase(node));
+ }
+ node = next;
+ }
+
+ emtr->mTick++;
+ }
+
+ return false;
+}
+
+/* 80275A94-80275B74 2703D4 00E0+00 0/0 1/1 0/0 .text
+ * draw__11JPAResourceFP18JPAEmitterWorkDataP14JPABaseEmitter */
+void JPAResource::draw(JPAEmitterWorkData* work, JPABaseEmitter* emtr) {
+ work->mpEmtr = emtr;
+ work->mpRes = this;
+ work->mDrawCount = 0;
+ calcWorkData_d(work);
+ mpBaseShape->setGX(work);
+ for (s32 i = 1; i <= emtr->getDrawTimes(); i++) {
+ work->mDrawCount++;
+ if (mpBaseShape->isDrawPrntAhead() && mpChildShape != NULL)
+ drawC(work);
+ drawP(work);
+ if (!mpBaseShape->isDrawPrntAhead() && mpChildShape != NULL)
+ drawC(work);
+ }
+}
+
+/* 80275B74-80275EB0 2704B4 033C+00 1/1 0/0 0/0 .text drawP__11JPAResourceFP18JPAEmitterWorkData
+ */
+void JPAResource::drawP(JPAEmitterWorkData* work) {
+ work->mpEmtr->clearStatus(0x80);
+
+ work->mGlobalPtclScl.x = work->mpEmtr->mGlobalPScl.x * mpBaseShape->getBaseSizeX();
+ work->mGlobalPtclScl.y = work->mpEmtr->mGlobalPScl.y * mpBaseShape->getBaseSizeY();
+
+ if (mpBaseShape->getType() == 0) {
+ work->mGlobalPtclScl.x *= 1.02f;
+ } else if (mpBaseShape->getType() == 1) {
+ work->mGlobalPtclScl.x *= 1.02f;
+ work->mGlobalPtclScl.y *= 0.4f;
+ }
+
+ if (mpExtraShape != NULL && mpExtraShape->isEnableScaleAnm()) {
+ work->mPivot.x = mpExtraShape->getScaleCenterX() - 1.0f;
+ work->mPivot.y = mpExtraShape->getScaleCenterY() - 1.0f;
+ } else {
+ work->mPivot.x = work->mPivot.y = 0.0f;
+ }
+
+ work->mDirType = mpBaseShape->getDirType();
+ work->mRotType = mpBaseShape->getRotType();
+ work->mDLType = mpBaseShape->getType() == 4 || mpBaseShape->getType() == 8;
+ work->mPlaneType = work->mDLType ? 2 : mpBaseShape->getBasePlaneType();
+ work->mPrjType = mpBaseShape->isPrjTex() ? (mpBaseShape->isTexCrdAnm() ? 2 : 1) : 0;
+
+ work->mpAlivePtcl = &work->mpEmtr->mAlivePtclBase;
+ setPTev();
+
+ for (int i = mpDrawEmitterFuncListNum - 1; i >= 0; i--) {
+ (*mpDrawEmitterFuncList[i])(work);
+ }
+
+ if (mpBaseShape->isDrawFwdAhead()) {
+ JPANode<JPABaseParticle>* node = work->mpEmtr->mAlivePtclBase.getLast();
+ for (; node != work->mpEmtr->mAlivePtclBase.getEnd(); node = node->getPrev()) {
+ work->mpCurNode = node;
+ if (mpDrawParticleFuncList != NULL) {
+ for (int i = mpDrawParticleFuncListNum - 1; i >= 0; i--) {
+ (*mpDrawParticleFuncList[i])(work, node->getObject());
+ }
+ }
+ }
+ } else {
+ JPANode<JPABaseParticle>* node = work->mpEmtr->mAlivePtclBase.getFirst();
+ for (; node != work->mpEmtr->mAlivePtclBase.getEnd(); node = node->getNext()) {
+ work->mpCurNode = node;
+ if (mpDrawParticleFuncList != NULL) {
+ for (int i = mpDrawParticleFuncListNum - 1; i >= 0; i--) {
+ (*mpDrawParticleFuncList[i])(work, node->getObject());
+ }
+ }
+ }
+ }
+
+ GXSetMisc(GX_MT_XF_FLUSH, 0);
+
+ if (work->mpEmtr->mpEmtrCallBack != NULL) {
+ work->mpEmtr->mpEmtrCallBack->drawAfter(work->mpEmtr);
+ }
+}
+
+/* 80275EB0-802761A8 2707F0 02F8+00 1/1 0/0 0/0 .text drawC__11JPAResourceFP18JPAEmitterWorkData
+ */
+void JPAResource::drawC(JPAEmitterWorkData* work) {
+ work->mpEmtr->setStatus(0x80);
+
+ if (mpChildShape->isScaleInherited()) {
+ work->mGlobalPtclScl.x = work->mpEmtr->mGlobalPScl.x * mpBaseShape->getBaseSizeX();
+ work->mGlobalPtclScl.y = work->mpEmtr->mGlobalPScl.y * mpBaseShape->getBaseSizeY();
+ } else {
+ work->mGlobalPtclScl.x = work->mpEmtr->mGlobalPScl.x * mpChildShape->getScaleX();
+ work->mGlobalPtclScl.y = work->mpEmtr->mGlobalPScl.y * mpChildShape->getScaleY();
+ }
+
+ if (mpChildShape->getType() == 0) {
+ work->mGlobalPtclScl.x *= 1.02f;
+ } else if (mpChildShape->getType() == 1) {
+ work->mGlobalPtclScl.x *= 1.02f;
+ work->mGlobalPtclScl.y *= 0.4f;
+ }
+
+ work->mPivot.x = work->mPivot.y = 0.0f;
+
+ work->mDirType = mpChildShape->getDirType();
+ work->mRotType = mpChildShape->getRotType();
+ work->mDLType = mpChildShape->getType() == 4 || mpChildShape->getType() == 8;
+ work->mPlaneType = work->mDLType ? 2 : mpChildShape->getBasePlaneType();
+ work->mPrjType = 0;
+
+ work->mpAlivePtcl = &work->mpEmtr->mAlivePtclChld;
+ setCTev(work);
+
+ for (int i = mpDrawEmitterChildFuncListNum - 1; i >= 0; i--) {
+ (*mpDrawEmitterChildFuncList[i])(work);
+ }
+
+ if (mpBaseShape->isDrawFwdAhead()) {
+ JPANode<JPABaseParticle>* node = work->mpEmtr->mAlivePtclChld.getLast();
+ for (; node != work->mpEmtr->mAlivePtclChld.getEnd(); node = node->getPrev()) {
+ work->mpCurNode = node;
+ if (mpDrawParticleChildFuncList != NULL) {
+ for (int i = mpDrawParticleChildFuncListNum - 1; i >= 0; i--) {
+ (*mpDrawParticleChildFuncList[i])(work, node->getObject());
+ }
+ }
+ }
+ } else {
+ JPANode<JPABaseParticle>* node = work->mpEmtr->mAlivePtclChld.getFirst();
+ for (; node != work->mpEmtr->mAlivePtclChld.getEnd(); node = node->getNext()) {
+ work->mpCurNode = node;
+ if (mpDrawParticleChildFuncList != NULL) {
+ for (int i = mpDrawParticleChildFuncListNum - 1; i >= 0; i--) {
+ (*mpDrawParticleChildFuncList[i])(work, node->getObject());
+ }
+ }
+ }
+ }
+
+ GXSetMisc(GX_MT_XF_FLUSH, 0);
+
+ if (work->mpEmtr->mpEmtrCallBack != NULL) {
+ work->mpEmtr->mpEmtrCallBack->drawAfter(work->mpEmtr);
+ }
+}
+
+/* 802761A8-8027642C 270AE8 0284+00 1/1 0/0 0/0 .text setPTev__11JPAResourceFv */
+void JPAResource::setPTev() {
+ GXTexCoordID tex_coord = GX_TEXCOORD1;
+ u8 tev_stages = 1;
+ u8 tex_gens = 1;
+ u8 ind_stages = 0;
+
+ int base_plane_type = (mpBaseShape->getType() == 3 || mpBaseShape->getType() == 7) ?
+ mpBaseShape->getBasePlaneType() : 0;
+ int center_offset;
+ if (mpExtraShape != NULL) {
+ center_offset =
+ (mpExtraShape->getScaleCenterX() + 3 * mpExtraShape->getScaleCenterY()) * 0xC;
+ } else {
+ center_offset = 0x30;
+ }
+ int pos_offset = center_offset + base_plane_type * 0x6C;
+ int crd_offset = (mpBaseShape->getTilingS() + 2 * mpBaseShape->getTilingT()) * 8;
+ GXSetArray(GX_VA_POS, jpa_pos + pos_offset, 3);
+ GXSetArray(GX_VA_TEX0, jpa_crd + crd_offset, 2);
+ GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL);
+
+ if (mpExTexShape != NULL) {
+ if (mpExTexShape->isUseIndirect()) {
+ GXSetIndTexOrder(GX_INDTEXSTAGE0, GX_TEXCOORD1, GX_TEXMAP2);
+ GXSetIndTexCoordScale(GX_INDTEXSTAGE0, GX_ITS_1, GX_ITS_1);
+ GXSetIndTexMtx(GX_ITM_0, (f32(*)[3])mpExTexShape->getIndTexMtx(), mpExTexShape->getExpScale());
+ GXSetTevIndirect(GX_TEVSTAGE0, GX_INDTEXSTAGE0, GX_ITF_8, GX_ITB_STU, GX_ITM_0,
+ GX_ITW_OFF, GX_ITW_OFF, 0, 0, GX_ITBA_OFF);
+ ind_stages++;
+ tex_gens++;
+ tex_coord = GX_TEXCOORD2;
+ }
+ if (mpExTexShape->isUseSecTex()) {
+ GXSetTevOrder(GX_TEVSTAGE1, tex_coord, GX_TEXMAP3, GX_COLOR_NULL);
+ GXSetTevColorIn(GX_TEVSTAGE1, GX_CC_ZERO, GX_CC_TEXC, GX_CC_CPREV, GX_CC_ZERO);
+ GXSetTevAlphaIn(GX_TEVSTAGE1, GX_CA_ZERO, GX_CA_TEXA, GX_CA_APREV, GX_CA_ZERO);
+ GXSetTevColorOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE,
+ GX_TEVPREV);
+ GXSetTevAlphaOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE,
+ GX_TEVPREV);
+ tev_stages++;
+ tex_gens++;
+ }
+ }
+
+ GXSetNumTevStages(tev_stages);
+ GXSetNumIndStages(ind_stages);
+ if (mpBaseShape->isClipOn()) {
+ GXSetMisc(GX_MT_XF_FLUSH, 8);
+ GXSetClipMode(GX_CLIP_ENABLE);
+ } else {
+ GXSetClipMode(GX_CLIP_DISABLE);
+ }
+ GXSetNumTexGens(tex_gens);
+}
+
+/* 8027642C-8027658C 270D6C 0160+00 1/1 0/0 0/0 .text setCTev__11JPAResourceFP18JPAEmitterWorkData
+ */
+void JPAResource::setCTev(JPAEmitterWorkData* work) {
+ int base_plane_type = (mpChildShape->getType() == 3 || mpChildShape->getType() == 7) ?
+ mpChildShape->getBasePlaneType() : 0;
+ int pos_offset = 0x30 + base_plane_type * 0x6C;
+ GXSetArray(GX_VA_POS, jpa_pos + pos_offset, 3);
+ GXSetArray(GX_VA_TEX0, jpa_crd, 2);
+ GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP1, GX_COLOR_NULL);
+ GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, 0x3C);
+ GXSetTevDirect(GX_TEVSTAGE0);
+ GXSetNumTevStages(1);
+ GXSetNumIndStages(0);
+ if (mpChildShape->isClipOn()) {
+ GXSetMisc(GX_MT_XF_FLUSH, 8);
+ GXSetClipMode(GX_CLIP_ENABLE);
+ } else {
+ GXSetClipMode(GX_CLIP_DISABLE);
+ }
+ GXSetNumTexGens(1);
+ work->mpResMgr->load(work->mpRes->getTexIdx(mpChildShape->getTexIdx()), GX_TEXMAP1);
+}
+
+/* 8027658C-80276608 270ECC 007C+00 0/0 1/1 0/0 .text
+ * calc_p__11JPAResourceFP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPAResource::calc_p(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ if (mpCalcParticleFuncList != NULL) {
+ for (int i = mpCalcParticleFuncListNum - 1; i >= 0; i--) {
+ (*mpCalcParticleFuncList[i])(work, ptcl);
+ }
+ }
+}
+
+/* 80276608-80276684 270F48 007C+00 0/0 1/1 0/0 .text
+ * calc_c__11JPAResourceFP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPAResource::calc_c(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ if (mpCalcParticleChildFuncList != NULL) {
+ for (int i = mpCalcParticleChildFuncListNum - 1; i >= 0; i--) {
+ (*mpCalcParticleChildFuncList[i])(work, ptcl);
+ }
+ }
+}
+
+/* 80276684-80276700 270FC4 007C+00 0/0 2/2 0/0 .text
+ * calcField__11JPAResourceFP18JPAEmitterWorkDataP15JPABaseParticle */
+void JPAResource::calcField(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ for (int i = mFieldBlockNum - 1; i >= 0; i--) {
+ mpFieldBlocks[i]->calc(work, ptcl);
+ }
+}
+
+/* 80276700-80276840 271040 0140+00 2/1 0/0 0/0 .text calcKey__11JPAResourceFP18JPAEmitterWorkData
+ */
+void JPAResource::calcKey(JPAEmitterWorkData* work) {
+ for (int i = mKeyBlockNum - 1; i >= 0; i--) {
+ f32 val = mpKeyBlocks[i]->calc(work->mpEmtr->mTick);
+ switch (mpKeyBlocks[i]->getID()) {
+ case 0:
+ work->mpEmtr->mRate = val;
+ break;
+ case 1:
+ work->mpEmtr->mVolumeSize = val;
+ break;
+ case 3:
+ work->mpEmtr->mVolumeMinRad = val;
+ break;
+ case 4:
+ work->mpEmtr->mLifeTime = val;
+ break;
+ case 6:
+ work->mpEmtr->mAwayFromCenterSpeed = val;
+ break;
+ case 7:
+ work->mpEmtr->mAwayFromAxisSpeed = val;
+ break;
+ case 8:
+ work->mpEmtr->mDirSpeed = val;
+ break;
+ case 9:
+ work->mpEmtr->mSpread = val;
+ break;
+ case 10:
+ work->mpEmtr->mScaleOut = val;
+ break;
+ }
+ }
+}
+
+/* 80276840-80276A0C 271180 01CC+00 1/1 0/0 0/0 .text
+ * calcWorkData_c__11JPAResourceFP18JPAEmitterWorkData */
+void JPAResource::calcWorkData_c(JPAEmitterWorkData* work) {
+ work->mVolumeSize = work->mpEmtr->mVolumeSize;
+ work->mVolumeMinRad = work->mpEmtr->mVolumeMinRad;
+ work->mVolumeSweep = work->mpEmtr->mVolumeSweep;
+ work->mVolumeX = 0;
+ work->mVolumeAngleNum = 0;
+ work->mVolumeAngleMax = 1;
+ work->mDivNumber = mpDynamicsBlock->getDivNumber() * 2 + 1;
+ Mtx local_scl_mtx, local_rot_mtx, global_mtx;
+ MTXScale(local_scl_mtx, work->mpEmtr->mLocalScl.x, work->mpEmtr->mLocalScl.y,
+ work->mpEmtr->mLocalScl.z);
+ JPAGetXYZRotateMtx(work->mpEmtr->mLocalRot.x * 182, work->mpEmtr->mLocalRot.y * 182,
+ work->mpEmtr->mLocalRot.z * 182, local_rot_mtx);
+ MTXScale(global_mtx, work->mpEmtr->mGlobalScl.x, work->mpEmtr->mGlobalScl.y,
+ work->mpEmtr->mGlobalScl.z);
+ MTXConcat(work->mpEmtr->mGlobalRot, global_mtx, global_mtx);
+ global_mtx[0][3] = work->mpEmtr->mGlobalTrs.x;
+ global_mtx[1][3] = work->mpEmtr->mGlobalTrs.y;
+ global_mtx[2][3] = work->mpEmtr->mGlobalTrs.z;
+ MTXCopy(work->mpEmtr->mGlobalRot, work->mRotationMtx);
+ MTXConcat(work->mRotationMtx, local_rot_mtx, work->mGlobalRot);
+ MTXConcat(work->mGlobalRot, local_scl_mtx, work->mGlobalSR);
+ work->mEmitterPos.set(work->mpEmtr->mLocalTrs);
+ work->mGlobalScl.mul(work->mpEmtr->mGlobalScl, work->mpEmtr->mLocalScl);
+ JPAGetDirMtx(work->mpEmtr->mLocalDir, work->mDirectionMtx);
+ work->mPublicScale.set(work->mpEmtr->mGlobalScl);
+ MTXMultVec(global_mtx, &work->mpEmtr->mLocalTrs, &work->mGlobalPos);
+}
+
+/* 80276A0C-80276A8C 27134C 0080+00 1/1 0/0 0/0 .text
+ * calcWorkData_d__11JPAResourceFP18JPAEmitterWorkData */
+void JPAResource::calcWorkData_d(JPAEmitterWorkData* work) {
+ Mtx mtx;
+ JPAGetXYZRotateMtx(work->mpEmtr->mLocalRot.x * 0xB6, work->mpEmtr->mLocalRot.y * 0xB6,
+ work->mpEmtr->mLocalRot.z * 0xB6, mtx);
+ MTXConcat(work->mpEmtr->mGlobalRot, mtx, work->mGlobalRot);
+ MTXMultVecSR(work->mGlobalRot, &work->mpEmtr->mLocalDir, &work->mGlobalEmtrDir);
+}
+
+#pragma push
+#pragma force_active on
+static u8 jpa_resource_padding[28] = {0};
+#pragma pop
diff --git a/src/JSystem/JParticle/JPAResourceLoader.cpp b/src/JSystem/JParticle/JPAResourceLoader.cpp
new file mode 100644
index 00000000..580e913a
--- /dev/null
+++ b/src/JSystem/JParticle/JPAResourceLoader.cpp
@@ -0,0 +1,106 @@
+//
+// Generated By: dol2asm
+// Translation Unit: JPAResourceLoader
+//
+
+#include "JSystem/JParticle/JPAResourceLoader.h"
+#include "JSystem/JKernel/JKRHeap.h"
+#include "JSystem/JParticle/JPABaseShape.h"
+#include "JSystem/JParticle/JPAChildShape.h"
+#include "JSystem/JParticle/JPADynamicsBlock.h"
+#include "JSystem/JParticle/JPAExTexShape.h"
+#include "JSystem/JParticle/JPAExtraShape.h"
+#include "JSystem/JParticle/JPAFieldBlock.h"
+#include "JSystem/JParticle/JPAKeyBlock.h"
+#include "JSystem/JParticle/JPAResource.h"
+#include "JSystem/JParticle/JPAResourceManager.h"
+
+/* 8027D8A0-8027D8E0 2781E0 0040+00 0/0 1/1 0/0 .text
+ * __ct__17JPAResourceLoaderFPCUcP18JPAResourceManager */
+JPAResourceLoader::JPAResourceLoader(u8 const* data, JPAResourceManager* mgr) {
+ if (*(u32*)(data + 4) == '2-10') {
+ load_jpc(data, mgr);
+ }
+}
+
+struct JPAResourceHeader {
+ /* 0x0 */ u16 mUsrIdx;
+ /* 0x2 */ u16 mBlockNum;
+ /* 0x4 */ u8 mFieldBlockNum;
+ /* 0x5 */ u8 mKeyBlockNum;
+ /* 0x6 */ u8 mTDB1Num;
+};
+
+/* 8027D8E0-8027DCA0 278220 03C0+00 1/1 0/0 0/0 .text
+ * load_jpc__17JPAResourceLoaderFPCUcP18JPAResourceManager */
+void JPAResourceLoader::load_jpc(u8 const* data, JPAResourceManager* mgr) {
+ JKRHeap* heap = mgr->mpHeap;
+ mgr->mResMax = *(u16*)(data + 8);
+ mgr->mTexMax = *(u16*)(data + 0xA);
+ mgr->mpResArr = new (heap, 0) JPAResource*[mgr->mResMax];
+ mgr->mpTexArr = new (heap, 0) JPATexture*[mgr->mTexMax];
+
+ u32 offset = 0x10;
+ for (int i = 0; i < *(u16*)(data + 8); i++) {
+ JPAResourceHeader* header = (JPAResourceHeader*)(data + offset);
+ JPAResource* res = new (heap, 0) JPAResource();
+ res->mFieldBlockNum = header->mFieldBlockNum;
+ res->mpFieldBlocks = res->mFieldBlockNum != 0 ?
+ new (heap, 0) JPAFieldBlock*[res->mFieldBlockNum] : NULL;
+ res->mKeyBlockNum = header->mKeyBlockNum;
+ res->mpKeyBlocks = res->mKeyBlockNum != 0 ?
+ new (heap, 0) JPAKeyBlock*[res->mKeyBlockNum] : NULL;
+ res->mTDB1Num = header->mTDB1Num;
+ res->mpTDB1 = NULL;
+ res->mUsrIdx = header->mUsrIdx;
+
+ offset += 8;
+ u32 field_idx = 0;
+ u32 key_idx = 0;
+
+ for (int j = 0; j < header->mBlockNum; j++) {
+ u32 magic = *(u32*)(data + offset);
+ u32 size = *(u32*)(data + offset + 4);
+ switch (magic) {
+ case 'FLD1':
+ res->mpFieldBlocks[field_idx] = new (heap, 0) JPAFieldBlock(data + offset, heap);
+ field_idx++;
+ break;
+ case 'KFA1':
+ res->mpKeyBlocks[key_idx] = new (heap, 0) JPAKeyBlock(data + offset);
+ key_idx++;
+ break;
+ case 'BEM1':
+ res->mpDynamicsBlock = new (heap, 0) JPADynamicsBlock(data + offset);
+ break;
+ case 'BSP1':
+ res->mpBaseShape = new (heap, 0) JPABaseShape(data + offset, heap);
+ break;
+ case 'ESP1':
+ res->mpExtraShape = new (heap, 0) JPAExtraShape(data + offset);
+ break;
+ case 'SSP1':
+ res->mpChildShape = new (heap, 0) JPAChildShape(data + offset);
+ break;
+ case 'ETX1':
+ res->mpExTexShape = new (heap, 0) JPAExTexShape(data + offset);
+ break;
+ case 'TDB1':
+ res->mpTDB1 = (const u16*)(data + offset + 8);
+ break;
+ }
+ offset += size;
+ }
+
+ res->init(heap);
+ mgr->registRes(res);
+ }
+
+ offset = *(u32*)(data + 0xC);
+ for (int i = 0; i < *(u16*)(data + 0xA); i++) {
+ u32 size = *(u32*)(data + offset + 4);
+ JPATexture* tex = new (heap, 0) JPATexture(data + offset);
+ mgr->registTex(tex);
+ offset += size;
+ }
+}
diff --git a/src/JSystem/JParticle/JPAResourceManager.cpp b/src/JSystem/JParticle/JPAResourceManager.cpp
new file mode 100644
index 00000000..e06be753
--- /dev/null
+++ b/src/JSystem/JParticle/JPAResourceManager.cpp
@@ -0,0 +1,84 @@
+//
+// Generated By: dol2asm
+// Translation Unit: JPAResourceManager
+//
+
+#include "JSystem/JParticle/JPAResourceManager.h"
+#include "JSystem/JParticle/JPADynamicsBlock.h"
+#include "JSystem/JParticle/JPAResource.h"
+#include "string.h"
+
+struct JPAResourceLoader {
+ /* 8027D8A0 */ JPAResourceLoader(u8 const*, JPAResourceManager*);
+};
+
+/* 80273E10-80273E68 26E750 0058+00 0/0 2/2 0/0 .text __ct__18JPAResourceManagerFPCvP7JKRHeap */
+JPAResourceManager::JPAResourceManager(void const* pData, JKRHeap* pHeap) {
+ mpResArr = NULL;
+ mpTexArr = NULL;
+ mResMax = 0;
+ mResNum = 0;
+ mTexMax = 0;
+ mTexNum = 0;
+ mpHeap = pHeap;
+ JPAResourceLoader loader((u8 const*)pData, this);
+}
+
+/* 80273E68-80273EA8 26E7A8 0040+00 1/1 1/1 0/0 .text getResource__18JPAResourceManagerCFUs */
+JPAResource* JPAResourceManager::getResource(u16 usrIdx) const {
+ for (u16 i = 0; i < mResNum; i++)
+ if (mpResArr[i]->getUsrIdx() == usrIdx)
+ return mpResArr[i];
+ return NULL;
+}
+
+/* 80273EA8-80273EEC 26E7E8 0044+00 0/0 2/2 0/0 .text
+ * checkUserIndexDuplication__18JPAResourceManagerCFUs */
+bool JPAResourceManager::checkUserIndexDuplication(u16 usrIdx) const {
+ for (s32 i = 0; i < mResNum; i++)
+ if (mpResArr[i]->getUsrIdx() == usrIdx)
+ return true;
+ return false;
+}
+
+/* 80273EEC-80273F8C 26E82C 00A0+00 0/0 2/2 0/0 .text
+ * swapTexture__18JPAResourceManagerFPC7ResTIMGPCc */
+const ResTIMG* JPAResourceManager::swapTexture(ResTIMG const* img, char const* swapName) {
+ const ResTIMG* ret = NULL;
+
+ for (s32 i = 0; i < mTexNum; i++) {
+ if (strcmp(swapName, mpTexArr[i]->getName()) == 0) {
+ JUTTexture* tex = mpTexArr[i]->getJUTTexture();
+ ret = tex->getTexInfo();
+ tex->storeTIMG(img, (u8)0);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/* 80273F8C-80273FAC 26E8CC 0020+00 0/0 1/1 0/0 .text
+ * registRes__18JPAResourceManagerFP11JPAResource */
+void JPAResourceManager::registRes(JPAResource* res) {
+ mpResArr[mResNum] = res;
+ mResNum++;
+}
+
+/* 80273FAC-80273FCC 26E8EC 0020+00 0/0 1/1 0/0 .text
+ * registTex__18JPAResourceManagerFP10JPATexture */
+void JPAResourceManager::registTex(JPATexture* tex) {
+ mpTexArr[mTexNum] = tex;
+ mTexNum++;
+}
+
+/* 80273FCC-80274010 26E90C 0044+00 0/0 6/6 0/0 .text getResUserWork__18JPAResourceManagerCFUs */
+u32 JPAResourceManager::getResUserWork(u16 usrIdx) const {
+ u32 ret = 0;
+
+ JPAResource* res = getResource(usrIdx);
+ if (res != NULL)
+ ret = res->getDyn()->getResUserWork();
+
+ return ret;
+} \ No newline at end of file
diff --git a/src/JSystem/JParticle/JPATexture.cpp b/src/JSystem/JParticle/JPATexture.cpp
new file mode 100644
index 00000000..17aac802
--- /dev/null
+++ b/src/JSystem/JParticle/JPATexture.cpp
@@ -0,0 +1,15 @@
+//
+// Generated By: dol2asm
+// Translation Unit: JPATexture
+//
+
+#include "JSystem/JParticle/JPATexture.h"
+
+/* 8027D7D4-8027D83C 278114 0068+00 0/0 1/1 0/0 .text __ct__10JPATextureFPCUc */
+JPATexture::JPATexture(u8 const* pData) {
+ mpData = (const JPATextureData*)pData;
+ mTexture.storeTIMG(&mpData->mResTIMG, (u8)0);
+}
+
+/* 8027D83C-8027D8A0 27817C 0064+00 1/0 0/0 0/0 .text __dt__10JPATextureFv */
+JPATexture::~JPATexture() {} \ No newline at end of file
diff --git a/src/JSystem/JSupport/JSUList.cpp b/src/JSystem/JSupport/JSUList.cpp
new file mode 100644
index 00000000..eb906508
--- /dev/null
+++ b/src/JSystem/JSupport/JSUList.cpp
@@ -0,0 +1,162 @@
+//
+// Generated By: dol2asm
+// Translation Unit: JSUList
+//
+
+#include "JSystem/JSupport/JSUList.h"
+
+JSUPtrLink::JSUPtrLink(void* object) {
+ mList = NULL;
+ mObject = object;
+ mPrev = NULL;
+ mNext = NULL;
+}
+
+JSUPtrLink::~JSUPtrLink() {
+ if (mList != NULL) {
+ mList->remove(this);
+ }
+}
+
+JSUPtrList::JSUPtrList(bool init) {
+ if (init) {
+ initiate();
+ }
+}
+
+JSUPtrList::~JSUPtrList() {
+ JSUPtrLink* node = mHead;
+ s32 removed = 0;
+ while (mLength > removed) {
+ node->mList = NULL;
+ node = node->getNext();
+ removed += 1;
+ }
+}
+
+void JSUPtrList::initiate() {
+ mHead = NULL;
+ mTail = NULL;
+ mLength = 0;
+}
+
+void JSUPtrList::setFirst(JSUPtrLink* first) {
+ first->mList = this;
+ first->mPrev = NULL;
+ first->mNext = NULL;
+ mTail = first;
+ mHead = first;
+ mLength = 1;
+}
+
+bool JSUPtrList::append(JSUPtrLink* ptr) {
+ JSUPtrList* list = ptr->mList;
+ bool result = (NULL == list);
+ if (!result) {
+ result = list->remove(ptr);
+ }
+
+ if (result) {
+ if (mLength == 0) {
+ setFirst(ptr);
+ } else {
+ ptr->mList = this;
+ ptr->mPrev = mTail;
+ ptr->mNext = NULL;
+ mTail->mNext = ptr;
+ mTail = ptr;
+ mLength++;
+ }
+ }
+
+ return result;
+}
+
+bool JSUPtrList::prepend(JSUPtrLink* ptr) {
+ JSUPtrList* list = ptr->mList;
+ bool result = (NULL == list);
+ if (!result) {
+ result = list->remove(ptr);
+ }
+
+ if (result) {
+ if (mLength == 0) {
+ setFirst(ptr);
+ } else {
+ ptr->mList = this;
+ ptr->mPrev = NULL;
+ ptr->mNext = mHead;
+ mHead->mPrev = ptr;
+ mHead = ptr;
+ mLength++;
+ }
+ }
+
+ return result;
+}
+
+bool JSUPtrList::insert(JSUPtrLink* before, JSUPtrLink* ptr) {
+ if (before == mHead) {
+ return prepend(ptr);
+ } else if (before == NULL) {
+ return append(ptr);
+ }
+
+ if (before->mList != this) {
+ return false;
+ }
+
+ bool result = (NULL == ptr->mList);
+ if (!result) {
+ result = ptr->mList->remove(ptr);
+ }
+
+ if (result) {
+ JSUPtrLink* prev = before->mPrev;
+ ptr->mList = this;
+ ptr->mPrev = prev;
+ ptr->mNext = before;
+ prev->mNext = ptr;
+ before->mPrev = ptr;
+ mLength++;
+ }
+
+ return result;
+}
+
+bool JSUPtrList::remove(JSUPtrLink* ptr) {
+ bool is_parent = (ptr->mList == this);
+ if (is_parent) {
+ if (mLength == 1) {
+ mHead = NULL;
+ mTail = NULL;
+ } else if (ptr == mHead) {
+ ptr->mNext->mPrev = NULL;
+ mHead = ptr->mNext;
+ } else if (ptr == mTail) {
+ ptr->mPrev->mNext = NULL;
+ mTail = ptr->mPrev;
+ } else {
+ ptr->mPrev->mNext = ptr->mNext;
+ ptr->mNext->mPrev = ptr->mPrev;
+ }
+
+ ptr->mList = NULL;
+ mLength--;
+ }
+
+ return is_parent;
+}
+
+JSUPtrLink* JSUPtrList::getNthLink(u32 index) const {
+ if (index >= mLength) {
+ return NULL;
+ }
+
+ JSUPtrLink* node = mHead;
+ for (u32 i = 0; i < index; i++) {
+ node = node->getNext();
+ }
+
+ return node;
+} \ No newline at end of file