mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-06-10 20:28:19 -04:00
Implement JPA particle batching
This commit is contained in:
Vendored
+1
-1
Submodule extern/aurora updated: 9bc79d649c...5143394381
@@ -3,6 +3,20 @@
|
||||
|
||||
#include <gx.h>
|
||||
|
||||
#if TARGET_PC
|
||||
#include <mtx.h>
|
||||
|
||||
struct ParticleDrawCtx {
|
||||
bool batch; // off = immediate mode
|
||||
bool useTexMtx; // UVs transformed by texMtx
|
||||
bool useClr0; // prm color in GX_VA_CLR0
|
||||
bool useClr1; // env color in GX_VA_CLR1
|
||||
Mtx texMtx;
|
||||
GXColor clr0;
|
||||
GXColor clr1;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct JPAEmitterWorkData;
|
||||
class JPABaseParticle;
|
||||
class JKRHeap;
|
||||
@@ -75,6 +89,9 @@ public:
|
||||
|
||||
const GXTevColorArg* getTevColorArg() const { return st_ca[(pBsd->mFlags >> 0x0F) & 0x07]; }
|
||||
const GXTevAlphaArg* getTevAlphaArg() const { return st_aa[(pBsd->mFlags >> 0x12) & 0x01]; }
|
||||
#if TARGET_PC
|
||||
u32 getTevColorArgSel() const { return (pBsd->mFlags >> 0x0F) & 0x07; }
|
||||
#endif
|
||||
|
||||
u32 getType() const { return (pBsd->mFlags >> 0) & 0x0F; }
|
||||
u32 getDirType() const { return (pBsd->mFlags >> 4) & 0x07; }
|
||||
@@ -186,26 +203,34 @@ 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*);
|
||||
#if TARGET_PC
|
||||
#define JPA_DRAW_PARTICLE_ARGS JPAEmitterWorkData*, JPABaseParticle*, ParticleDrawCtx*
|
||||
#else
|
||||
#define JPA_DRAW_PARTICLE_ARGS JPAEmitterWorkData*, JPABaseParticle*
|
||||
#endif
|
||||
|
||||
void JPADrawPoint(JPA_DRAW_PARTICLE_ARGS);
|
||||
void JPADrawLine(JPA_DRAW_PARTICLE_ARGS);
|
||||
void JPADrawRotBillboard(JPA_DRAW_PARTICLE_ARGS);
|
||||
void JPADrawBillboard(JPA_DRAW_PARTICLE_ARGS);
|
||||
void JPADrawRotDirection(JPA_DRAW_PARTICLE_ARGS);
|
||||
void JPADrawDirection(JPA_DRAW_PARTICLE_ARGS);
|
||||
void JPADrawRotation(JPA_DRAW_PARTICLE_ARGS);
|
||||
void JPADrawDBillboard(JPA_DRAW_PARTICLE_ARGS);
|
||||
void JPADrawRotYBillboard(JPA_DRAW_PARTICLE_ARGS);
|
||||
void JPADrawYBillboard(JPA_DRAW_PARTICLE_ARGS);
|
||||
void JPADrawParticleCallBack(JPA_DRAW_PARTICLE_ARGS);
|
||||
void JPALoadTexAnm(JPA_DRAW_PARTICLE_ARGS);
|
||||
void JPASetPointSize(JPA_DRAW_PARTICLE_ARGS);
|
||||
void JPASetLineWidth(JPA_DRAW_PARTICLE_ARGS);
|
||||
void JPALoadCalcTexCrdMtxAnm(JPA_DRAW_PARTICLE_ARGS);
|
||||
void JPARegistAlpha(JPA_DRAW_PARTICLE_ARGS);
|
||||
void JPARegistEnv(JPA_DRAW_PARTICLE_ARGS);
|
||||
void JPARegistAlphaEnv(JPA_DRAW_PARTICLE_ARGS);
|
||||
void JPARegistPrmAlpha(JPA_DRAW_PARTICLE_ARGS);
|
||||
void JPARegistPrmAlphaEnv(JPA_DRAW_PARTICLE_ARGS);
|
||||
|
||||
#undef JPA_DRAW_PARTICLE_ARGS
|
||||
|
||||
#if TARGET_PC
|
||||
void JPAInterpBillboard(JPAEmitterWorkData*, JPABaseParticle*);
|
||||
|
||||
@@ -17,6 +17,10 @@ class JPADynamicsBlock;
|
||||
class JPAFieldBlock;
|
||||
class JPAKeyBlock;
|
||||
|
||||
#if TARGET_PC
|
||||
struct ParticleDrawCtx;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @ingroup jsystem-jparticle
|
||||
*
|
||||
@@ -50,13 +54,19 @@ public:
|
||||
public:
|
||||
typedef void (*EmitterFunc)(JPAEmitterWorkData*);
|
||||
typedef void (*ParticleFunc)(JPAEmitterWorkData*, JPABaseParticle*);
|
||||
#if TARGET_PC
|
||||
typedef void (*DrawParticleFunc)(JPAEmitterWorkData*, JPABaseParticle*,
|
||||
ParticleDrawCtx*);
|
||||
#else
|
||||
typedef ParticleFunc DrawParticleFunc;
|
||||
#endif
|
||||
/* 0x00 */ EmitterFunc* mpCalcEmitterFuncList;
|
||||
/* 0x04 */ EmitterFunc* mpDrawEmitterFuncList;
|
||||
/* 0x08 */ EmitterFunc* mpDrawEmitterChildFuncList;
|
||||
/* 0x0C */ ParticleFunc* mpCalcParticleFuncList;
|
||||
/* 0x10 */ ParticleFunc* mpDrawParticleFuncList;
|
||||
/* 0x10 */ DrawParticleFunc* mpDrawParticleFuncList;
|
||||
/* 0x14 */ ParticleFunc* mpCalcParticleChildFuncList;
|
||||
/* 0x18 */ ParticleFunc* mpDrawParticleChildFuncList;
|
||||
/* 0x18 */ DrawParticleFunc* mpDrawParticleChildFuncList;
|
||||
|
||||
/* 0x1C */ JPABaseShape* pBsp;
|
||||
/* 0x20 */ JPAExtraShape* pEsp;
|
||||
@@ -77,6 +87,20 @@ public:
|
||||
/* 0x45 */ u8 mpDrawParticleFuncListNum;
|
||||
/* 0x46 */ u8 mpCalcParticleChildFuncListNum;
|
||||
/* 0x47 */ u8 mpDrawParticleChildFuncListNum;
|
||||
|
||||
#if TARGET_PC
|
||||
struct BatchInfo {
|
||||
f32 vtxPos[8][3];
|
||||
f32 vtxUv[8][2];
|
||||
u8 vtxCount; // 4 (quad) or 8 (cross)
|
||||
bool supported; // draw func list contains only batchable funcs
|
||||
bool hasPtclColor; // per-particle JPARegist* func is present
|
||||
bool hasPtclTexMtx; // JPALoadCalcTexCrdMtxAnm is present
|
||||
};
|
||||
BatchInfo mBatchInfo;
|
||||
|
||||
void initBatchInfo();
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* JPARESOURCE_H */
|
||||
|
||||
@@ -14,6 +14,33 @@
|
||||
#endif
|
||||
#include "tracy/Tracy.hpp"
|
||||
|
||||
#if TARGET_PC
|
||||
#define JPA_DRAW_CTX_PARAM , ParticleDrawCtx* ctx
|
||||
|
||||
namespace {
|
||||
GXColor emitter_prm_color(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);
|
||||
return prm;
|
||||
}
|
||||
|
||||
GXColor emitter_env_color(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);
|
||||
return env;
|
||||
}
|
||||
} // namespace
|
||||
#else
|
||||
#define JPA_DRAW_CTX_PARAM
|
||||
#endif
|
||||
|
||||
void JPASetPointSize(JPAEmitterWorkData* work) {
|
||||
GXSetPointSize((u8)(25.0f * work->mGlobalPtclScl.x), GX_TO_ONE);
|
||||
}
|
||||
@@ -22,15 +49,16 @@ void JPASetLineWidth(JPAEmitterWorkData* work) {
|
||||
GXSetLineWidth((u8)(25.0f * work->mGlobalPtclScl.x), GX_TO_ONE);
|
||||
}
|
||||
|
||||
void JPASetPointSize(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
void JPASetPointSize(JPAEmitterWorkData* work, JPABaseParticle* ptcl JPA_DRAW_CTX_PARAM) {
|
||||
GXSetPointSize((u8)(ptcl->mParticleScaleX * (25.0f * work->mGlobalPtclScl.x)), GX_TO_ONE);
|
||||
}
|
||||
|
||||
void JPASetLineWidth(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
void JPASetLineWidth(JPAEmitterWorkData* work, JPABaseParticle* ptcl JPA_DRAW_CTX_PARAM) {
|
||||
GXSetLineWidth((u8)(ptcl->mParticleScaleX * (25.0f * work->mGlobalPtclScl.x)), GX_TO_ONE);
|
||||
}
|
||||
|
||||
void JPARegistPrm(JPAEmitterWorkData* work) {
|
||||
ZoneScoped;
|
||||
JPABaseEmitter* emtr = work->mpEmtr;
|
||||
GXColor prm = emtr->mPrmClr;
|
||||
prm.r = COLOR_MULTI(prm.r, emtr->mGlobalPrmClr.r);
|
||||
@@ -41,6 +69,7 @@ void JPARegistPrm(JPAEmitterWorkData* work) {
|
||||
}
|
||||
|
||||
void JPARegistEnv(JPAEmitterWorkData* work) {
|
||||
ZoneScoped;
|
||||
JPABaseEmitter* emtr = work->mpEmtr;
|
||||
GXColor env = emtr->mEnvClr;
|
||||
env.r = COLOR_MULTI(env.r, emtr->mGlobalEnvClr.r);
|
||||
@@ -50,6 +79,7 @@ void JPARegistEnv(JPAEmitterWorkData* work) {
|
||||
}
|
||||
|
||||
void JPARegistPrmEnv(JPAEmitterWorkData* work) {
|
||||
ZoneScoped;
|
||||
JPABaseEmitter* emtr = work->mpEmtr;
|
||||
GXColor prm = emtr->mPrmClr;
|
||||
GXColor env = emtr->mEnvClr;
|
||||
@@ -64,7 +94,8 @@ void JPARegistPrmEnv(JPAEmitterWorkData* work) {
|
||||
GXSetTevColor(GX_TEVREG1, env);
|
||||
}
|
||||
|
||||
void JPARegistAlpha(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
void JPARegistAlpha(JPAEmitterWorkData* work, JPABaseParticle* ptcl JPA_DRAW_CTX_PARAM) {
|
||||
ZoneScoped;
|
||||
JPABaseEmitter* emtr = work->mpEmtr;
|
||||
GXColor prm = emtr->mPrmClr;
|
||||
prm.r = COLOR_MULTI(prm.r, emtr->mGlobalPrmClr.r);
|
||||
@@ -72,10 +103,19 @@ void JPARegistAlpha(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
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);
|
||||
#if TARGET_PC
|
||||
if (ctx->batch) {
|
||||
ctx->clr0 = prm;
|
||||
if (ctx->useClr1) {
|
||||
ctx->clr1 = emitter_env_color(work);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
GXSetTevColor(GX_TEVREG0, prm);
|
||||
}
|
||||
|
||||
void JPARegistPrmAlpha(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
void JPARegistPrmAlpha(JPAEmitterWorkData* work, JPABaseParticle* ptcl JPA_DRAW_CTX_PARAM) {
|
||||
ZoneScoped;
|
||||
JPABaseEmitter* emtr = work->mpEmtr;
|
||||
GXColor prm = ptcl->mPrmClr;
|
||||
@@ -84,10 +124,19 @@ void JPARegistPrmAlpha(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
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);
|
||||
#if TARGET_PC
|
||||
if (ctx->batch) {
|
||||
ctx->clr0 = prm;
|
||||
if (ctx->useClr1) {
|
||||
ctx->clr1 = emitter_env_color(work);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
GXSetTevColor(GX_TEVREG0, prm);
|
||||
}
|
||||
|
||||
void JPARegistPrmAlphaEnv(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
void JPARegistPrmAlphaEnv(JPAEmitterWorkData* work, JPABaseParticle* ptcl JPA_DRAW_CTX_PARAM) {
|
||||
ZoneScoped;
|
||||
JPABaseEmitter* emtr = work->mpEmtr;
|
||||
GXColor prm = ptcl->mPrmClr;
|
||||
@@ -100,11 +149,19 @@ void JPARegistPrmAlphaEnv(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
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);
|
||||
#if TARGET_PC
|
||||
if (ctx->batch) {
|
||||
ctx->clr0 = prm;
|
||||
ctx->clr1 = env;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
GXSetTevColor(GX_TEVREG0, prm);
|
||||
GXSetTevColor(GX_TEVREG1, env);
|
||||
}
|
||||
|
||||
void JPARegistAlphaEnv(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
void JPARegistAlphaEnv(JPAEmitterWorkData* work, JPABaseParticle* ptcl JPA_DRAW_CTX_PARAM) {
|
||||
ZoneScoped;
|
||||
JPABaseEmitter* emtr = work->mpEmtr;
|
||||
GXColor prm = emtr->mPrmClr;
|
||||
GXColor env = ptcl->mEnvClr;
|
||||
@@ -116,16 +173,31 @@ void JPARegistAlphaEnv(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
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);
|
||||
#if TARGET_PC
|
||||
if (ctx->batch) {
|
||||
ctx->clr0 = prm;
|
||||
ctx->clr1 = env;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
GXSetTevColor(GX_TEVREG0, prm);
|
||||
GXSetTevColor(GX_TEVREG1, env);
|
||||
}
|
||||
|
||||
void JPARegistEnv(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
void JPARegistEnv(JPAEmitterWorkData* work, JPABaseParticle* ptcl JPA_DRAW_CTX_PARAM) {
|
||||
ZoneScoped;
|
||||
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);
|
||||
#if TARGET_PC
|
||||
if (ctx->batch) {
|
||||
ctx->clr0 = emitter_prm_color(work);
|
||||
ctx->clr1 = env;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
GXSetTevColor(GX_TEVREG1, env);
|
||||
}
|
||||
|
||||
@@ -258,7 +330,7 @@ void JPAGenCalcTexCrdMtxAnm(JPAEmitterWorkData* work) {
|
||||
GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_TEXMTX0);
|
||||
}
|
||||
|
||||
void JPALoadCalcTexCrdMtxAnm(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
|
||||
void JPALoadCalcTexCrdMtxAnm(JPAEmitterWorkData* work, JPABaseParticle* param_1 JPA_DRAW_CTX_PARAM) {
|
||||
ZoneScoped;
|
||||
JPABaseShape* shape = work->mpRes->getBsp();
|
||||
f32 dVar16 = param_1->mAge;
|
||||
@@ -286,6 +358,12 @@ void JPALoadCalcTexCrdMtxAnm(JPAEmitterWorkData* work, JPABaseParticle* param_1)
|
||||
local_108[2][1] = 0.0f;
|
||||
local_108[2][2] = 1.0f;
|
||||
local_108[2][3] = 0.0f;
|
||||
#if TARGET_PC
|
||||
if (ctx->batch) {
|
||||
MTXCopy(local_108, ctx->texMtx);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
GXLoadTexMtxImm(local_108, 0x1e, GX_MTX2x4);
|
||||
}
|
||||
|
||||
@@ -299,7 +377,7 @@ void JPALoadTexAnm(JPAEmitterWorkData* work) {
|
||||
work->mpResMgr->load(work->mpRes->getTexIdx(work->mpEmtr->mTexAnmIdx), GX_TEXMAP0);
|
||||
}
|
||||
|
||||
void JPALoadTexAnm(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
void JPALoadTexAnm(JPAEmitterWorkData* work, JPABaseParticle* ptcl JPA_DRAW_CTX_PARAM) {
|
||||
ZoneScoped;
|
||||
work->mpResMgr->load(work->mpRes->getTexIdx(ptcl->mTexAnmIdx), GX_TEXMAP0);
|
||||
}
|
||||
@@ -429,6 +507,47 @@ static projectionFunc p_prj[3] = {
|
||||
};
|
||||
|
||||
#if TARGET_PC
|
||||
static void emit_batch_quad(JPAEmitterWorkData* work, const ParticleDrawCtx* ctx,
|
||||
const Mtx posMtx) {
|
||||
const JPAResource::BatchInfo& info = work->mpRes->mBatchInfo;
|
||||
|
||||
for (int i = 0; i < info.vtxCount; i++) {
|
||||
Vec localPos = {info.vtxPos[i][0], info.vtxPos[i][1], info.vtxPos[i][2]};
|
||||
Vec drawPos;
|
||||
MTXMultVec(posMtx, &localPos, &drawPos);
|
||||
|
||||
f32 texS = info.vtxUv[i][0];
|
||||
f32 texT = info.vtxUv[i][1];
|
||||
if (ctx->useTexMtx) {
|
||||
f32 srcS = texS;
|
||||
f32 srcT = texT;
|
||||
texS = ctx->texMtx[0][0] * srcS + ctx->texMtx[0][1] * srcT + ctx->texMtx[0][3];
|
||||
texT = ctx->texMtx[1][0] * srcS + ctx->texMtx[1][1] * srcT + ctx->texMtx[1][3];
|
||||
}
|
||||
|
||||
GXPosition3f32(drawPos.x, drawPos.y, drawPos.z);
|
||||
if (ctx->useClr0) {
|
||||
GXColor4u8(ctx->clr0.r, ctx->clr0.g, ctx->clr0.b, ctx->clr0.a);
|
||||
}
|
||||
if (ctx->useClr1) {
|
||||
GXColor4u8(ctx->clr1.r, ctx->clr1.g, ctx->clr1.b, ctx->clr1.a);
|
||||
}
|
||||
GXTexCoord2f32(texS, texT);
|
||||
}
|
||||
}
|
||||
|
||||
static void submit_particle_quad(
|
||||
JPAEmitterWorkData* work, ParticleDrawCtx* ctx, const Mtx posMtx, const u8* dl, u32 dlSize) {
|
||||
if (ctx->batch) {
|
||||
emit_batch_quad(work, ctx, posMtx);
|
||||
return;
|
||||
}
|
||||
|
||||
GXLoadPosMtxImm(posMtx, GX_PNMTX0);
|
||||
p_prj[work->mPrjType](work, posMtx);
|
||||
GXCallDisplayList(dl, dlSize);
|
||||
}
|
||||
|
||||
void JPAInterpBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
Mtx ptclPosMtx;
|
||||
MTXTrans(ptclPosMtx, ptcl->mPosition.x, ptcl->mPosition.y, ptcl->mPosition.z);
|
||||
@@ -448,7 +567,7 @@ void JPAInterpRotBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
}
|
||||
#endif
|
||||
|
||||
void JPADrawBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
void JPADrawBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl JPA_DRAW_CTX_PARAM) {
|
||||
if (ptcl->checkStatus(JPAPtclStts_Invisible)) {
|
||||
return;
|
||||
}
|
||||
@@ -473,12 +592,16 @@ void JPADrawBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
posMtx[2][2] = 1.0f;
|
||||
posMtx[2][3] = pos.z;
|
||||
posMtx[0][1] = posMtx[0][2] = posMtx[1][0] = posMtx[1][2] = posMtx[2][0] = posMtx[2][1] = 0.0f;
|
||||
#if TARGET_PC
|
||||
submit_particle_quad(work, ctx, posMtx, jpa_dl, sizeof(jpa_dl));
|
||||
#else
|
||||
GXLoadPosMtxImm(posMtx, GX_PNMTX0);
|
||||
p_prj[work->mPrjType](work, posMtx);
|
||||
GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
|
||||
#endif
|
||||
}
|
||||
|
||||
void JPADrawRotBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
void JPADrawRotBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl JPA_DRAW_CTX_PARAM) {
|
||||
if (ptcl->checkStatus(JPAPtclStts_Invisible)) {
|
||||
return;
|
||||
}
|
||||
@@ -517,12 +640,16 @@ void JPADrawRotBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
posMtx[2][2] = 1.0f;
|
||||
posMtx[2][3] = pos.z;
|
||||
posMtx[0][2] = posMtx[1][2] = posMtx[2][0] = posMtx[2][1] = 0.0f;
|
||||
#if TARGET_PC
|
||||
submit_particle_quad(work, ctx, posMtx, jpa_dl, sizeof(jpa_dl));
|
||||
#else
|
||||
GXLoadPosMtxImm(posMtx, GX_PNMTX0);
|
||||
p_prj[work->mPrjType](work, posMtx);
|
||||
GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
|
||||
#endif
|
||||
}
|
||||
|
||||
void JPADrawYBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
|
||||
void JPADrawYBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1 JPA_DRAW_CTX_PARAM) {
|
||||
if (param_1->checkStatus(JPAPtclStts_Invisible)) {
|
||||
return;
|
||||
}
|
||||
@@ -542,12 +669,16 @@ void JPADrawYBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
|
||||
local_38[2][2] = work->mYBBCamMtx[2][2];
|
||||
local_38[2][3] = local_48.z;
|
||||
local_38[0][1] = local_38[0][2] = local_38[1][0] = local_38[2][0] = 0.0f;
|
||||
#if TARGET_PC
|
||||
submit_particle_quad(work, ctx, local_38, jpa_dl, sizeof(jpa_dl));
|
||||
#else
|
||||
GXLoadPosMtxImm(local_38, GX_PNMTX0);
|
||||
p_prj[work->mPrjType](work, local_38);
|
||||
GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
|
||||
#endif
|
||||
}
|
||||
|
||||
void JPADrawRotYBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
|
||||
void JPADrawRotYBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1 JPA_DRAW_CTX_PARAM) {
|
||||
if (param_1->checkStatus(JPAPtclStts_Invisible)) {
|
||||
return;
|
||||
}
|
||||
@@ -576,9 +707,13 @@ void JPADrawRotYBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
|
||||
local_38[2][1] = local_94 * fVar1;
|
||||
local_38[2][2] = local_90;
|
||||
local_38[2][3] = local_48.z;
|
||||
#if TARGET_PC
|
||||
submit_particle_quad(work, ctx, local_38, jpa_dl, sizeof(jpa_dl));
|
||||
#else
|
||||
GXLoadPosMtxImm(local_38, GX_PNMTX0);
|
||||
p_prj[work->mPrjType](work, local_38);
|
||||
GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
|
||||
#endif
|
||||
}
|
||||
|
||||
void dirTypeVel(JPAEmitterWorkData const* work, JPABaseParticle const* param_1,
|
||||
@@ -741,6 +876,88 @@ static u8* p_dl[2] = {
|
||||
};
|
||||
|
||||
#if TARGET_PC
|
||||
static bool make_direction_mtx(JPAEmitterWorkData* work, JPABaseParticle* ptcl, Mtx posMtx) {
|
||||
JGeometry::TVec3<f32> axisY;
|
||||
JGeometry::TVec3<f32> axisZ;
|
||||
JGeometry::TVec3<f32> baseAxis(ptcl->mBaseAxis);
|
||||
p_direction[work->mDirType](work, ptcl, &axisY);
|
||||
if (axisY.isZero()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
axisY.normalize();
|
||||
axisZ.cross(baseAxis, axisY);
|
||||
if (axisZ.isZero()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
axisZ.normalize();
|
||||
baseAxis.cross(axisY, axisZ);
|
||||
baseAxis.normalize();
|
||||
ptcl->mBaseAxis.set(baseAxis);
|
||||
|
||||
f32 scaleX = work->mGlobalPtclScl.x * ptcl->mParticleScaleX;
|
||||
f32 scaleY = work->mGlobalPtclScl.y * ptcl->mParticleScaleY;
|
||||
posMtx[0][0] = baseAxis.x;
|
||||
posMtx[0][1] = axisY.x;
|
||||
posMtx[0][2] = axisZ.x;
|
||||
posMtx[0][3] = ptcl->mPosition.x;
|
||||
posMtx[1][0] = baseAxis.y;
|
||||
posMtx[1][1] = axisY.y;
|
||||
posMtx[1][2] = axisZ.y;
|
||||
posMtx[1][3] = ptcl->mPosition.y;
|
||||
posMtx[2][0] = baseAxis.z;
|
||||
posMtx[2][1] = axisY.z;
|
||||
posMtx[2][2] = axisZ.z;
|
||||
posMtx[2][3] = ptcl->mPosition.z;
|
||||
p_plane[work->mPlaneType](posMtx, scaleX, scaleY);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool make_rot_direction_mtx(JPAEmitterWorkData* work, JPABaseParticle* ptcl, Mtx posMtx) {
|
||||
f32 sinRot = JMASSin(ptcl->mRotateAngle);
|
||||
f32 cosRot = JMASCos(ptcl->mRotateAngle);
|
||||
JGeometry::TVec3<f32> axisY;
|
||||
JGeometry::TVec3<f32> axisZ;
|
||||
JGeometry::TVec3<f32> baseAxis(ptcl->mBaseAxis);
|
||||
p_direction[work->mDirType](work, ptcl, &axisY);
|
||||
if (axisY.isZero()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
axisY.normalize();
|
||||
axisZ.cross(baseAxis, axisY);
|
||||
if (axisZ.isZero()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
axisZ.normalize();
|
||||
baseAxis.cross(axisY, axisZ);
|
||||
baseAxis.normalize();
|
||||
ptcl->mBaseAxis.set(baseAxis);
|
||||
|
||||
f32 scaleX = work->mGlobalPtclScl.x * ptcl->mParticleScaleX;
|
||||
f32 scaleY = work->mGlobalPtclScl.y * ptcl->mParticleScaleY;
|
||||
Mtx rotMtx;
|
||||
Mtx dirMtx;
|
||||
p_rot[work->mRotType](sinRot, cosRot, rotMtx);
|
||||
p_plane[work->mPlaneType](rotMtx, scaleX, scaleY);
|
||||
dirMtx[0][0] = baseAxis.x;
|
||||
dirMtx[0][1] = axisY.x;
|
||||
dirMtx[0][2] = axisZ.x;
|
||||
dirMtx[0][3] = ptcl->mPosition.x;
|
||||
dirMtx[1][0] = baseAxis.y;
|
||||
dirMtx[1][1] = axisY.y;
|
||||
dirMtx[1][2] = axisZ.y;
|
||||
dirMtx[1][3] = ptcl->mPosition.y;
|
||||
dirMtx[2][0] = baseAxis.z;
|
||||
dirMtx[2][1] = axisY.z;
|
||||
dirMtx[2][2] = axisZ.z;
|
||||
dirMtx[2][3] = ptcl->mPosition.z;
|
||||
MTXConcat(dirMtx, rotMtx, posMtx);
|
||||
return true;
|
||||
}
|
||||
|
||||
void JPAInterpDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
JGeometry::TVec3<f32> axisY;
|
||||
JGeometry::TVec3<f32> axisZ;
|
||||
@@ -823,7 +1040,7 @@ void JPAInterpRotDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
}
|
||||
#endif
|
||||
|
||||
void JPADrawDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
void JPADrawDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl JPA_DRAW_CTX_PARAM) {
|
||||
if (ptcl->checkStatus(JPAPtclStts_Invisible)) {
|
||||
return;
|
||||
}
|
||||
@@ -832,8 +1049,12 @@ void JPADrawDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
|
||||
Mtx posMtx;
|
||||
#if TARGET_PC
|
||||
if (!dusk::frame_interp::lookup_replacement(ptcl, posMtx))
|
||||
#endif
|
||||
if (!dusk::frame_interp::lookup_replacement(ptcl, posMtx) &&
|
||||
!make_direction_mtx(work, ptcl, posMtx))
|
||||
{
|
||||
return;
|
||||
}
|
||||
#else
|
||||
{
|
||||
JGeometry::TVec3<f32> axisY;
|
||||
JGeometry::TVec3<f32> axisZ;
|
||||
@@ -869,14 +1090,19 @@ void JPADrawDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
posMtx[2][3] = ptcl->mPosition.z;
|
||||
p_plane[work->mPlaneType](posMtx, scaleX, scaleY);
|
||||
}
|
||||
#endif
|
||||
|
||||
MTXConcat(work->mPosCamMtx, posMtx, posMtx);
|
||||
#if TARGET_PC
|
||||
submit_particle_quad(work, ctx, posMtx, p_dl[work->mDLType], sizeof(jpa_dl));
|
||||
#else
|
||||
GXLoadPosMtxImm(posMtx, GX_PNMTX0);
|
||||
p_prj[work->mPrjType](work, posMtx);
|
||||
GXCallDisplayList(p_dl[work->mDLType], sizeof(jpa_dl));
|
||||
#endif
|
||||
}
|
||||
|
||||
void JPADrawRotDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
void JPADrawRotDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl JPA_DRAW_CTX_PARAM) {
|
||||
if (ptcl->checkStatus(JPAPtclStts_Invisible)) {
|
||||
return;
|
||||
}
|
||||
@@ -886,8 +1112,12 @@ void JPADrawRotDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
Mtx mtx1;
|
||||
Mtx mtx2;
|
||||
#if TARGET_PC
|
||||
if (!dusk::frame_interp::lookup_replacement(ptcl, mtx1))
|
||||
#endif
|
||||
if (!dusk::frame_interp::lookup_replacement(ptcl, mtx1) &&
|
||||
!make_rot_direction_mtx(work, ptcl, mtx1))
|
||||
{
|
||||
return;
|
||||
}
|
||||
#else
|
||||
{
|
||||
f32 sinRot = JMASSin(ptcl->mRotateAngle);
|
||||
f32 cosRot = JMASCos(ptcl->mRotateAngle);
|
||||
@@ -927,13 +1157,18 @@ void JPADrawRotDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
mtx2[2][3] = ptcl->mPosition.z;
|
||||
MTXConcat(mtx2, mtx1, mtx1);
|
||||
}
|
||||
#endif
|
||||
MTXConcat(work->mPosCamMtx, mtx1, mtx2);
|
||||
#if TARGET_PC
|
||||
submit_particle_quad(work, ctx, mtx2, p_dl[work->mDLType], sizeof(jpa_dl));
|
||||
#else
|
||||
GXLoadPosMtxImm(mtx2, GX_PNMTX0);
|
||||
p_prj[work->mPrjType](work, mtx2);
|
||||
GXCallDisplayList(p_dl[work->mDLType], sizeof(jpa_dl));
|
||||
#endif
|
||||
}
|
||||
|
||||
void JPADrawDBillboard(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) {
|
||||
void JPADrawDBillboard(JPAEmitterWorkData* param_0, JPABaseParticle* param_1 JPA_DRAW_CTX_PARAM) {
|
||||
if (param_1->checkStatus(JPAPtclStts_Invisible)) {
|
||||
return;
|
||||
}
|
||||
@@ -970,7 +1205,7 @@ void JPADrawDBillboard(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) {
|
||||
GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
|
||||
}
|
||||
|
||||
void JPADrawRotation(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) {
|
||||
void JPADrawRotation(JPAEmitterWorkData* param_0, JPABaseParticle* param_1 JPA_DRAW_CTX_PARAM) {
|
||||
if (param_1->checkStatus(JPAPtclStts_Invisible)) {
|
||||
return;
|
||||
}
|
||||
@@ -988,12 +1223,16 @@ void JPADrawRotation(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) {
|
||||
auStack_88[1][3] = param_1->mPosition.y;
|
||||
auStack_88[2][3] = param_1->mPosition.z;
|
||||
MTXConcat(param_0->mPosCamMtx, auStack_88, auStack_88);
|
||||
#if TARGET_PC
|
||||
submit_particle_quad(param_0, ctx, auStack_88, p_dl[param_0->mDLType], sizeof(jpa_dl));
|
||||
#else
|
||||
GXLoadPosMtxImm(auStack_88, 0);
|
||||
p_prj[param_0->mPrjType](param_0, auStack_88);
|
||||
GXCallDisplayList(p_dl[param_0->mDLType], sizeof(jpa_dl));
|
||||
#endif
|
||||
}
|
||||
|
||||
void JPADrawPoint(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
void JPADrawPoint(JPAEmitterWorkData* work, JPABaseParticle* ptcl JPA_DRAW_CTX_PARAM) {
|
||||
if (ptcl->checkStatus(JPAPtclStts_Invisible)) {
|
||||
return;
|
||||
}
|
||||
@@ -1010,7 +1249,7 @@ void JPADrawPoint(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
GXSetVtxDesc(GX_VA_TEX0, GX_INDEX8);
|
||||
}
|
||||
|
||||
void JPADrawLine(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) {
|
||||
void JPADrawLine(JPAEmitterWorkData* param_0, JPABaseParticle* param_1 JPA_DRAW_CTX_PARAM) {
|
||||
if (param_1->checkStatus(JPAPtclStts_Invisible)) {
|
||||
return;
|
||||
}
|
||||
@@ -1086,7 +1325,7 @@ void JPADrawStripe(JPAEmitterWorkData* param_0) {
|
||||
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();
|
||||
for (JPANode<JPABaseParticle>* node = startNode; node != param_0->mpAlivePtcl->getEnd();
|
||||
node = node_func(node), coord += step) {
|
||||
param_0->mpCurNode = node;
|
||||
JPABaseParticle* particle = node->getObject();
|
||||
@@ -1111,7 +1350,7 @@ void JPADrawStripe(JPAEmitterWorkData* param_0) {
|
||||
}
|
||||
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;
|
||||
@@ -1177,7 +1416,7 @@ void JPADrawStripeX(JPAEmitterWorkData* param_0) {
|
||||
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();
|
||||
for (JPANode<JPABaseParticle>* node = startNode; node != param_0->mpAlivePtcl->getEnd();
|
||||
node = node_func(node), coord += step) {
|
||||
param_0->mpCurNode = node;
|
||||
JPABaseParticle* particle = node->getObject();
|
||||
@@ -1202,7 +1441,7 @@ void JPADrawStripeX(JPAEmitterWorkData* param_0) {
|
||||
}
|
||||
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;
|
||||
@@ -1227,7 +1466,7 @@ void JPADrawStripeX(JPAEmitterWorkData* param_0) {
|
||||
|
||||
coord = start_coord;
|
||||
GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT1, ptcl_num << 1);
|
||||
for (JPANode<JPABaseParticle>* node = startNode; node != param_0->mpAlivePtcl->getEnd();
|
||||
for (JPANode<JPABaseParticle>* node = startNode; node != param_0->mpAlivePtcl->getEnd();
|
||||
node = node_func(node), coord += step) {
|
||||
param_0->mpCurNode = node;
|
||||
JPABaseParticle* particle = node->getObject();
|
||||
@@ -1252,7 +1491,7 @@ void JPADrawStripeX(JPAEmitterWorkData* param_0) {
|
||||
}
|
||||
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;
|
||||
@@ -1289,7 +1528,7 @@ void JPADrawEmitterCallBackB(JPAEmitterWorkData* work) {
|
||||
emtr->mpEmtrCallBack->draw(emtr);
|
||||
}
|
||||
|
||||
void JPADrawParticleCallBack(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
void JPADrawParticleCallBack(JPAEmitterWorkData* work, JPABaseParticle* ptcl JPA_DRAW_CTX_PARAM) {
|
||||
JPABaseEmitter* emtr = work->mpEmtr;
|
||||
if (emtr->mpPtclCallBack == NULL) {
|
||||
return;
|
||||
|
||||
@@ -18,9 +18,21 @@
|
||||
#include "global.h"
|
||||
#include "tracy/Tracy.hpp"
|
||||
|
||||
#if TARGET_PC
|
||||
#define JPA_DRAW_CTX_ARG , &ctx
|
||||
#else
|
||||
#define JPA_DRAW_CTX_ARG
|
||||
#endif
|
||||
|
||||
JPAResource::JPAResource() {
|
||||
mpCalcEmitterFuncList = mpDrawEmitterFuncList = mpDrawEmitterChildFuncList = NULL;
|
||||
#if TARGET_PC
|
||||
mpCalcParticleFuncList = mpCalcParticleChildFuncList = NULL;
|
||||
mpDrawParticleFuncList = mpDrawParticleChildFuncList = NULL;
|
||||
mBatchInfo = {};
|
||||
#else
|
||||
mpCalcParticleFuncList = mpDrawParticleFuncList = mpCalcParticleChildFuncList = mpDrawParticleChildFuncList = NULL;
|
||||
#endif
|
||||
pBsp = NULL;
|
||||
pEsp = NULL;
|
||||
pCsp = NULL;
|
||||
@@ -61,6 +73,60 @@ static u8 jpa_crd[32] ATTRIBUTE_ALIGN(32) = {
|
||||
0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02,
|
||||
};
|
||||
|
||||
#if TARGET_PC
|
||||
void JPAResource::initBatchInfo() {
|
||||
mBatchInfo = {};
|
||||
|
||||
bool hasDrawFunc = false;
|
||||
for (int i = 0; i < mpDrawParticleFuncListNum; i++) {
|
||||
DrawParticleFunc func = mpDrawParticleFuncList[i];
|
||||
if (func == JPADrawBillboard || func == JPADrawRotBillboard ||
|
||||
func == JPADrawYBillboard || func == JPADrawRotYBillboard ||
|
||||
func == JPADrawDirection || func == JPADrawRotDirection || func == JPADrawRotation)
|
||||
{
|
||||
hasDrawFunc = true;
|
||||
} else if (func == JPADrawParticleCallBack) {
|
||||
// Batchable only for emitters without a particle callback; checked per draw
|
||||
} else if (func == JPALoadCalcTexCrdMtxAnm) {
|
||||
mBatchInfo.hasPtclTexMtx = true;
|
||||
} else if (func == JPARegistAlpha || func == JPARegistPrmAlpha ||
|
||||
func == JPARegistPrmAlphaEnv || func == JPARegistAlphaEnv ||
|
||||
func == static_cast<DrawParticleFunc>(JPARegistEnv)) // overloaded
|
||||
{
|
||||
mBatchInfo.hasPtclColor = true;
|
||||
} else {
|
||||
// JPADrawPoint, JPADrawLine, JPADrawDBillboard, JPALoadTexAnm,
|
||||
// JPASetPointSize, JPASetLineWidth
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!hasDrawFunc) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Template array offsets, same math as setPTev
|
||||
int base_plane_type = (pBsp->getType() == 3 || pBsp->getType() == 7) ?
|
||||
pBsp->getBasePlaneType() : 0;
|
||||
int center_offset = pEsp != nullptr ? (pEsp->getScaleCenterX() + 3 * pEsp->getScaleCenterY()) * 0xC : 0x30;
|
||||
const s8* pos = reinterpret_cast<const s8*>(jpa_pos) + center_offset + base_plane_type * 0x6C;
|
||||
const s8* crd = reinterpret_cast<const s8*>(jpa_crd) + (pBsp->getTilingS() + 2 * pBsp->getTilingT()) * 8;
|
||||
|
||||
bool cross = pBsp->getType() == 4 || pBsp->getType() == 8;
|
||||
mBatchInfo.vtxCount = cross ? 8 : 4;
|
||||
for (int i = 0; i < mBatchInfo.vtxCount; i++) {
|
||||
int posIdx = i < 4 ? i : 72 + (i - 4);
|
||||
int crdIdx = i & 3;
|
||||
mBatchInfo.vtxPos[i][0] = pos[posIdx * 3 + 0];
|
||||
mBatchInfo.vtxPos[i][1] = pos[posIdx * 3 + 1];
|
||||
mBatchInfo.vtxPos[i][2] = pos[posIdx * 3 + 2];
|
||||
mBatchInfo.vtxUv[i][0] = crd[crdIdx * 2 + 0];
|
||||
mBatchInfo.vtxUv[i][1] = crd[crdIdx * 2 + 1];
|
||||
}
|
||||
|
||||
mBatchInfo.supported = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void JPAResource::init(JKRHeap* heap) {
|
||||
BOOL is_glbl_clr_anm = pBsp->isGlblClrAnm();
|
||||
BOOL is_glbl_tex_anm = pBsp->isGlblTexAnm();
|
||||
@@ -525,7 +591,10 @@ void JPAResource::init(JKRHeap* heap) {
|
||||
|
||||
if (mpDrawParticleFuncListNum != 0) {
|
||||
mpDrawParticleFuncList =
|
||||
(ParticleFunc*)JKRAllocFromHeap(heap, mpDrawParticleFuncListNum * sizeof(ParticleFunc), alignof(ParticleFunc));
|
||||
(DrawParticleFunc*)JKRAllocFromHeap(
|
||||
heap,
|
||||
mpDrawParticleFuncListNum * sizeof(DrawParticleFunc),
|
||||
alignof(DrawParticleFunc));
|
||||
}
|
||||
|
||||
func_no = 0;
|
||||
@@ -635,7 +704,10 @@ void JPAResource::init(JKRHeap* heap) {
|
||||
|
||||
if (mpDrawParticleChildFuncListNum != 0) {
|
||||
mpDrawParticleChildFuncList =
|
||||
(ParticleFunc*)JKRAllocFromHeap(heap, mpDrawParticleChildFuncListNum * sizeof(ParticleFunc), sizeof(EmitterFunc));
|
||||
(DrawParticleFunc*)JKRAllocFromHeap(
|
||||
heap,
|
||||
mpDrawParticleChildFuncListNum * sizeof(DrawParticleFunc),
|
||||
alignof(DrawParticleFunc));
|
||||
}
|
||||
|
||||
func_no = 0;
|
||||
@@ -699,6 +771,10 @@ void JPAResource::init(JKRHeap* heap) {
|
||||
mpDrawParticleChildFuncList[func_no] = &JPARegistPrmAlphaEnv;
|
||||
func_no++;
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
initBatchInfo();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool JPAResource::calc(JPAEmitterWorkData* work, JPABaseEmitter* emtr) {
|
||||
@@ -808,6 +884,183 @@ void JPAResource::draw(JPAEmitterWorkData* work, JPABaseEmitter* emtr) {
|
||||
}
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
static GXTevAlphaArg to_vtx_alpha_arg(GXTevAlphaArg arg) {
|
||||
return arg == GX_CA_A0 ? GX_CA_RASA : arg;
|
||||
}
|
||||
|
||||
static void batch_set_tev_op(GXTevStageID stage) {
|
||||
GXSetTevColorOp(stage, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
||||
GXSetTevAlphaOp(stage, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
||||
}
|
||||
|
||||
static void batch_setup_tev(JPAEmitterWorkData* work, bool useClr1) {
|
||||
JPABaseShape* shape = work->mpRes->getBsp();
|
||||
JPAExTexShape* ets = work->mpRes->getEts();
|
||||
bool useIndirect = ets != nullptr && ets->isUseIndirect();
|
||||
|
||||
// JPAEmitterManager::draw configures both channels to pass vertex color through
|
||||
GXSetNumChans(useClr1 ? 2 : 1);
|
||||
|
||||
const GXTevAlphaArg* alphaArg = shape->getTevAlphaArg();
|
||||
GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
|
||||
GXSetTevAlphaIn(GX_TEVSTAGE0, to_vtx_alpha_arg(alphaArg[0]), to_vtx_alpha_arg(alphaArg[1]),
|
||||
to_vtx_alpha_arg(alphaArg[2]), to_vtx_alpha_arg(alphaArg[3]));
|
||||
batch_set_tev_op(GX_TEVSTAGE0);
|
||||
if (!useIndirect) {
|
||||
GXSetTevDirect(GX_TEVSTAGE0);
|
||||
}
|
||||
GXTevStageID nextStage = GX_TEVSTAGE1;
|
||||
|
||||
switch (shape->getTevColorArgSel()) {
|
||||
case 0: // TEXC
|
||||
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_TEXC, GX_CC_ONE, GX_CC_ZERO);
|
||||
break;
|
||||
case 1: // C0 * TEXC
|
||||
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_RASC, GX_CC_TEXC, GX_CC_ZERO);
|
||||
break;
|
||||
case 2: // lerp(C0, 1, TEXC)
|
||||
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_RASC, GX_CC_ONE, GX_CC_TEXC, GX_CC_ZERO);
|
||||
break;
|
||||
case 3: // lerp(C1, C0, TEXC) = C0 * TEXC (stage 0) + C1 * (1 - TEXC) (stage 1)
|
||||
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_RASC, GX_CC_TEXC, GX_CC_ZERO);
|
||||
GXSetTevOrder(nextStage, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR1A1);
|
||||
GXSetTevColorIn(nextStage, GX_CC_RASC, GX_CC_ZERO, GX_CC_TEXC, GX_CC_CPREV);
|
||||
GXSetTevAlphaIn(nextStage, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_APREV);
|
||||
batch_set_tev_op(nextStage);
|
||||
GXSetTevDirect(nextStage);
|
||||
nextStage = static_cast<GXTevStageID>(nextStage + 1);
|
||||
break;
|
||||
case 4: // TEXC * C0 + C1: C0 * TEXC (stage 0), + C1 (stage 1)
|
||||
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_RASC, GX_CC_TEXC, GX_CC_ZERO);
|
||||
GXSetTevOrder(nextStage, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR1A1);
|
||||
GXSetTevColorIn(nextStage, GX_CC_CPREV, GX_CC_ZERO, GX_CC_ZERO, GX_CC_RASC);
|
||||
GXSetTevAlphaIn(nextStage, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_APREV);
|
||||
batch_set_tev_op(nextStage);
|
||||
GXSetTevDirect(nextStage);
|
||||
nextStage = static_cast<GXTevStageID>(nextStage + 1);
|
||||
break;
|
||||
case 5: // C0
|
||||
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_RASC);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ets != nullptr && ets->isUseSecTex()) {
|
||||
// Mirrors setPTev's secondary texture stage, at the next free stage
|
||||
GXTexCoordID texCoord = useIndirect ? GX_TEXCOORD2 : GX_TEXCOORD1;
|
||||
GXSetTevOrder(nextStage, texCoord, GX_TEXMAP3, GX_COLOR_NULL);
|
||||
GXSetTevColorIn(nextStage, GX_CC_ZERO, GX_CC_TEXC, GX_CC_CPREV, GX_CC_ZERO);
|
||||
GXSetTevAlphaIn(nextStage, GX_CA_ZERO, GX_CA_TEXA, GX_CA_APREV, GX_CA_ZERO);
|
||||
batch_set_tev_op(nextStage);
|
||||
GXSetTevDirect(nextStage);
|
||||
nextStage = static_cast<GXTevStageID>(nextStage + 1);
|
||||
}
|
||||
|
||||
GXSetNumTevStages(nextStage);
|
||||
}
|
||||
|
||||
static void batch_setup_vtx_desc(bool useClr0, bool useClr1) {
|
||||
static Mtx identityMtx = {
|
||||
{1.0f, 0.0f, 0.0f, 0.0f},
|
||||
{0.0f, 1.0f, 0.0f, 0.0f},
|
||||
{0.0f, 0.0f, 1.0f, 0.0f},
|
||||
};
|
||||
|
||||
GXLoadPosMtxImm(identityMtx, GX_PNMTX0);
|
||||
GXSetCurrentMtx(GX_PNMTX0);
|
||||
GXClearVtxDesc();
|
||||
GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
|
||||
if (useClr0) {
|
||||
GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT);
|
||||
}
|
||||
if (useClr1) {
|
||||
GXSetVtxDesc(GX_VA_CLR1, GX_DIRECT);
|
||||
}
|
||||
GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
|
||||
GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
|
||||
if (useClr0) {
|
||||
GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
|
||||
}
|
||||
if (useClr1) {
|
||||
GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_CLR1, GX_CLR_RGBA, GX_RGBA8, 0);
|
||||
}
|
||||
GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
|
||||
}
|
||||
|
||||
static void batch_restore_gx(JPAEmitterWorkData* work, bool changedTev, bool changedTexMtx) {
|
||||
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);
|
||||
|
||||
if (changedTexMtx) {
|
||||
GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_TEXMTX0);
|
||||
}
|
||||
|
||||
if (changedTev) {
|
||||
GXSetNumChans(0);
|
||||
work->mpRes->getBsp()->setGX(work);
|
||||
work->mpRes->setPTev();
|
||||
}
|
||||
}
|
||||
|
||||
static bool draw_particle_batch(JPAEmitterWorkData* work) {
|
||||
ZoneScoped;
|
||||
|
||||
JPAResource* res = work->mpRes;
|
||||
const JPAResource::BatchInfo& info = res->mBatchInfo;
|
||||
if (!info.supported || work->mPrjType != 0 || work->mpEmtr->mpPtclCallBack != nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool useClr0 = false;
|
||||
bool useClr1 = false;
|
||||
if (info.hasPtclColor) {
|
||||
u32 colorSel = res->getBsp()->getTevColorArgSel();
|
||||
if (colorSel >= 6) {
|
||||
return false;
|
||||
}
|
||||
useClr0 = true;
|
||||
useClr1 = colorSel == 3 || colorSel == 4;
|
||||
batch_setup_tev(work, useClr1);
|
||||
}
|
||||
|
||||
if (info.hasPtclTexMtx) {
|
||||
// UVs are CPU-transformed; drop the texgen
|
||||
GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
|
||||
}
|
||||
|
||||
batch_setup_vtx_desc(useClr0, useClr1);
|
||||
|
||||
ParticleDrawCtx ctx{};
|
||||
ctx.batch = true;
|
||||
ctx.useTexMtx = info.hasPtclTexMtx;
|
||||
ctx.useClr0 = useClr0;
|
||||
ctx.useClr1 = useClr1;
|
||||
|
||||
bool fwdAhead = res->getBsp()->isDrawFwdAhead();
|
||||
JPANode<JPABaseParticle>* node = fwdAhead ? work->mpEmtr->mAlivePtclBase.getLast() :
|
||||
work->mpEmtr->mAlivePtclBase.getFirst();
|
||||
|
||||
GXBegin(GX_QUADS, GX_VTXFMT1, GX_AUTO);
|
||||
while (node != work->mpEmtr->mAlivePtclBase.getEnd()) {
|
||||
work->mpCurNode = node;
|
||||
for (int i = res->mpDrawParticleFuncListNum - 1; i >= 0; i--) {
|
||||
(*res->mpDrawParticleFuncList[i])(work, node->getObject(), &ctx);
|
||||
}
|
||||
node = fwdAhead ? node->getPrev() : node->getNext();
|
||||
}
|
||||
GXEnd();
|
||||
|
||||
batch_restore_gx(work, useClr0, info.hasPtclTexMtx);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void JPAResource::drawP(JPAEmitterWorkData* work) {
|
||||
ZoneScoped;
|
||||
work->mpEmtr->clearStatus(0x80);
|
||||
@@ -842,13 +1095,25 @@ void JPAResource::drawP(JPAEmitterWorkData* work) {
|
||||
(*mpDrawEmitterFuncList[i])(work);
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
if (draw_particle_batch(work)) {
|
||||
GXSetMisc(GX_MT_XF_FLUSH, 0);
|
||||
if (work->mpEmtr->mpEmtrCallBack != nullptr) {
|
||||
work->mpEmtr->mpEmtrCallBack->drawAfter(work->mpEmtr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ParticleDrawCtx ctx{}; // immediate mode
|
||||
#endif
|
||||
|
||||
if (pBsp->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());
|
||||
(*mpDrawParticleFuncList[i])(work, node->getObject() JPA_DRAW_CTX_ARG);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -858,7 +1123,7 @@ void JPAResource::drawP(JPAEmitterWorkData* work) {
|
||||
work->mpCurNode = node;
|
||||
if (mpDrawParticleFuncList != NULL) {
|
||||
for (int i = mpDrawParticleFuncListNum - 1; i >= 0; i--) {
|
||||
(*mpDrawParticleFuncList[i])(work, node->getObject());
|
||||
(*mpDrawParticleFuncList[i])(work, node->getObject() JPA_DRAW_CTX_ARG);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -905,13 +1170,17 @@ void JPAResource::drawC(JPAEmitterWorkData* work) {
|
||||
(*mpDrawEmitterChildFuncList[i])(work);
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
ParticleDrawCtx ctx{}; // immediate mode
|
||||
#endif
|
||||
|
||||
if (pBsp->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());
|
||||
(*mpDrawParticleChildFuncList[i])(work, node->getObject() JPA_DRAW_CTX_ARG);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -921,7 +1190,7 @@ void JPAResource::drawC(JPAEmitterWorkData* work) {
|
||||
work->mpCurNode = node;
|
||||
if (mpDrawParticleChildFuncList != NULL) {
|
||||
for (int i = mpDrawParticleChildFuncListNum - 1; i >= 0; i--) {
|
||||
(*mpDrawParticleChildFuncList[i])(work, node->getObject());
|
||||
(*mpDrawParticleChildFuncList[i])(work, node->getObject() JPA_DRAW_CTX_ARG);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user