diff --git a/configure.py b/configure.py index 9abc5144..d78a5981 100644 --- a/configure.py +++ b/configure.py @@ -568,7 +568,7 @@ def MatchingFor(*versions): Object(NonMatching, "SB/Core/x/xNPCBasic.cpp"), Object(NonMatching, "SB/Game/zEntPlayerBungeeState.cpp", extra_cflags=["-sym on"]), Object(NonMatching, "SB/Game/zCollGeom.cpp"), - Object(NonMatching, "SB/Core/x/xParSys.cpp"), + Object(NonMatching, "SB/Core/x/xParSys.cpp", extra_cflags=["-sym on"]), Object(NonMatching, "SB/Core/x/xParEmitter.cpp"), Object(Matching, "SB/Core/x/xVolume.cpp"), Object(NonMatching, "SB/Core/x/xParEmitterType.cpp"), diff --git a/src/SB/Core/gc/iParMgr.h b/src/SB/Core/gc/iParMgr.h index 4168278c..e13f769e 100644 --- a/src/SB/Core/gc/iParMgr.h +++ b/src/SB/Core/gc/iParMgr.h @@ -42,8 +42,12 @@ void iRenderSetCameraViewMatrix(xMat4x3* m); void iRenderFlush(); void iRenderTrianglesImmediate(S32 vertType, S32 vertTypeSize, void* data, S32 dataSize, U16* index, S32 indexSize); +void iParMgrRenderParSys_Streak(void* data, xParGroup* ps); void iParMgrRenderParSys_QuadStreak(void* data, xParGroup* ps); +void iParMgrRenderParSys_InvStreak(void* data, xParGroup* ps); void iParMgrRenderParSys_Flat(void* data, xParGroup* ps); +void iParMgrRenderParSys_Static(void* data, xParGroup* ps); +void iParMgrRenderParSys_Ground(void* data, xParGroup* ps); void iParMgrRenderParSys_Sprite(void* data, xParGroup* ps); #endif diff --git a/src/SB/Core/x/xParCmd.h b/src/SB/Core/x/xParCmd.h index 2f6660eb..301fbb00 100644 --- a/src/SB/Core/x/xParCmd.h +++ b/src/SB/Core/x/xParCmd.h @@ -54,8 +54,6 @@ struct xParCmd xParCmdAsset* tasset; }; -struct xParGroup; - typedef void (*xParCmdUpdateFunc)(xParCmd* c, xParGroup* ps, F32 dt); void xParCmdInit(); diff --git a/src/SB/Core/x/xParSys.cpp b/src/SB/Core/x/xParSys.cpp index 5c106bec..a2adf1b8 100644 --- a/src/SB/Core/x/xParSys.cpp +++ b/src/SB/Core/x/xParSys.cpp @@ -1,22 +1,132 @@ #include "xParSys.h" -#include #include "zScene.h" +#include "xRenderState.h" +#include "zRenderState.h" +#include "zGlobals.h" +#include "xPtankPool.h" + +#include static xVec3 par_offset_right; static xVec3 par_offset_up; -static xParSysInfo sParSysInfo[7]; +static void render_par_sprite(void* data, xParGroup* ps); -static S32 sBlendTable[11] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; +static xParSysInfo sParSysInfo[7] = { + { XPARSYSINFO_TYPE_SPRITE, render_par_sprite }, + { XPARSYSINFO_TYPE_STREAK, iParMgrRenderParSys_Streak }, + { XPARSYSINFO_TYPE_FLAT, iParMgrRenderParSys_Flat }, + { XPARSYSINFO_TYPE_STATIC, iParMgrRenderParSys_Static }, + { XPARSYSINFO_TYPE_GROUND, iParMgrRenderParSys_Ground }, + { XPARSYSINFO_TYPE_QUADSTREAK, iParMgrRenderParSys_QuadStreak }, + { XPARSYSINFO_TYPE_INVSTREAK, iParMgrRenderParSys_InvStreak } +}; + +static const S32 sBlendTable[11] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; static void par_sprite_begin() { + par_offset_right = globals.camera.mat.right * 0.5f; + par_offset_up = globals.camera.mat.up * 0.5f; +} + +static void par_sprite_update(xParSys& sys, xParGroup& group) +{ + if (!using_ptank_render(*sys.tasset)) + { + return; + } + + U32 pivot = sys.tasset->parFlags; + xVec3 offset_right; + if (pivot & 0x8) + { + offset_right = par_offset_right; + } + else if (pivot & 0x20) + { + offset_right = -par_offset_right; + } + else + { + offset_right = 0.0f; + } + + xVec3 offset_up; + if (pivot & 0x10) + { + offset_up = -par_offset_up; + } + else if (pivot & 0x40) + { + offset_up = par_offset_up; + } + else + { + offset_up = 0.0f; + } + + ptank_pool__pos_color_size_uv2 pool; + pool.rs.texture = sys.txtr_particle; + pool.rs.src_blend = sBlendTable[sys.tasset->renderSrcBlendMode]; + pool.rs.dst_blend = sBlendTable[sys.tasset->renderDstBlendMode]; + pool.rs.flags = 0x0; + pool.reset(); + + xParCmdTex* tex = group.m_cmdTex; + xPar* p = group.m_root; + while (p != NULL) + { + RwSphere testSphere; + testSphere.center = *(RwV3d*)&p->m_pos; + testSphere.radius = p->m_size; + + if (RwCameraFrustumTestSphere(globals.camera.lo_cam, &testSphere)) + { + pool.next(); + + if (!pool.valid()) + { + break; + } + + xVec3& loc = *pool.pos; + loc = p->m_pos; + loc += offset_right * p->m_size; + loc += offset_up * p->m_size; + + pool.color->r = p->m_c[0]; + pool.color->g = p->m_c[1]; + pool.color->b = p->m_c[2]; + pool.color->a = p->m_c[3]; + + pool.size->assign(p->m_size, p->m_size); + + if (tex) + { + pool.uv[0].x = p->m_texIdx[0] * tex->unit_width + tex->x1; + pool.uv[0].y = p->m_texIdx[1] * tex->unit_height + tex->y1; + + pool.uv[1].x = (p->m_texIdx[0] + 1) * tex->unit_width + tex->x1; + pool.uv[1].y = (p->m_texIdx[1] + 1) * tex->unit_height + tex->y1; + } + else + { + pool.uv[0].assign(0.0f, 0.0f); + pool.uv[1].assign(1.0f, 1.0f); + } + } + + p = p->m_next; + } + + pool.flush(); } static void render_par_sprite(void* data, xParGroup* ps) { - if (using_ptank_render((*(xParSysAsset*)&ps->m_culled)) == 0) + if (!using_ptank_render(*((xParSys*)data)->tasset)) { iParMgrRenderParSys_Sprite(data, ps); } @@ -36,14 +146,234 @@ void xParSysInit(void* b, void* tasset) void xParSysInit(xBase* b, xParSysAsset* tasset) { + xParSys* t = (xParSys*)b; + + xBaseInit(b, tasset); + t->eventFunc = &xParSysEventCB; + t->tasset = tasset; + + if (t->linkCount > 0) + { + t->link = (xLinkAsset*)((char*)&t->tasset[1] + tasset->cmdSize); + } + else + { + t->link = NULL; + } + + t->visible = tasset->parFlags & 0x1; + t->cmdCount = tasset->cmdCount; + if (t->cmdCount) + { + t->cmd = (xParCmd*)xMemAlloc(gActiveHeap, t->cmdCount * sizeof(xParCmd), FALSE); + } + else + { + t->cmd = NULL; + } + + // Some arcane magic required due to how the asset command data is packed + U32 i; + U8* cmdPtr = (U8*)&tasset[1]; + for (i = 0; i < t->cmdCount; i++) + { + *(U32*)(&t->cmd[i]) = TRUE; + *(U32*)(&t->cmd[i].tasset) = (U32)cmdPtr; + cmdPtr += xParCmdGetSize(*(U32*)cmdPtr); + } + + t->group = (xParGroup*)xMemAlloc(gActiveHeap, sizeof(xParGroup), FALSE); + xParGroupInit(t->group); + xParGroupSetPriority(t->group, tasset->priority); + xParGroupRegister(t->group); + xParGroupSetAging(t->group, (((tasset->parFlags >> 1) & 0x1) ^ 0x1) & 0xFF); + xParGroupSetVisibility(t->group, t->visible); + xParGroupSetBack2Life(t->group,(((tasset->parFlags >> 2) & 0x1) ^ 0x1) & 0xFF); + t->parent = NULL; + + for (i = 0; i < t->cmdCount; i++) + { + if (t->cmd[i].tasset->type == XPARCMD_TYPE_TEX) + { + t->group->m_cmdTex = (xParCmdTex*)t->cmd[i].tasset; + xParCmdTexInit(t->group->m_cmdTex); + break; + } + } + + t->group->draw = sParSysInfo[t->tasset->renderFunc].func; } void xParSysSetup(xParSys* t) { - if (t != 0 && t->link != 0 && t->link->param[1]) + if (t != NULL && t->tasset != NULL && t->tasset->parentParSysID != 0x0) + { + t->parent = (xParSys*)zSceneFindObject(t->tasset->parentParSysID); + } + t->txtr_particle = (RwTexture*)xSTFindAsset(t->tasset->textureID, 0); +} + +void xParSysReset(xParSys* t) +{ + xBaseReset(t, t->tasset); + + if (t->group != NULL) { - t->parent = (xParSys*)zSceneFindObject(t->cmd->flag); + xParGroupKillAllParticles(t->group); + + t->visible = t->tasset->parFlags & 0x1; + + xParGroupSetAging(t->group, (((t->tasset->parFlags >> 1) & 0x1) ^ 0x1) & 0xFF); + xParGroupSetVisibility(t->group, t->visible); + xParGroupSetBack2Life(t->group,(((t->tasset->parFlags >> 2) & 0x1) ^ 0x1) & 0xFF); + } +} + +void xParSysExit(xParSys* t) +{ + if (t->group != NULL) + { + xParGroupKillAllParticles(t->group); + xParGroupUnregister(t->group); + } +} + +S32 xParSysEventCB(xBase* from, xBase* to, U32 toEvent, const F32* toParam, xBase* toParamWidget) +{ + xParSys* t = (xParSys*)to; + + switch (toEvent) + { + case eEventReset: + xParSysReset(t); + break; + case eEventVisible: + t->visible = TRUE; + if (t->group != NULL) + { + xParGroupSetVisibility(t->group, t->visible); + } + break; + case eEventInvisible: + t->visible = FALSE; + if (t->group != NULL) + { + xParGroupSetVisibility(t->group, t->visible); + } + break; + case eEventOn: + if (t->group != NULL) + { + xParGroupSetActive(t->group, TRUE); + } + break; + case eEventOff: + if (t->group != NULL) + { + xParGroupSetActive(t->group, FALSE); + } + break; + } + + return TRUE; +} + +static void xParGroupUpdateR(xParSys* s, xParGroup* g, F32 dt); +static void xParGroupUpdate(xParSys* s, xParGroup* g, F32 dt); +void xParSysUpdate(xBase* to, xScene* scn, F32 dt) +{ + xParSys* s = (xParSys*)to; + xParSys* parent = s->parent; + if (s->tasset->renderFunc == NULL) + { + par_sprite_begin(); + } + + xParGroup* g = s->group; + while (g != NULL) + { + if (g->m_active) + { + if (parent) + { + xParGroupUpdateR(parent, g, dt); + } + + if (g->m_alive) + { + xParGroupUpdate(s, g, dt); + } + } + + xParGroupAnimate(g, dt); + if (g->m_num_of_particles > 0 && !s->tasset->renderFunc) + { + par_sprite_update(*s, *g); + } + + g = g->m_next; + } +} + +static void xParGroupUpdateR(xParSys* s, xParGroup* g, F32 dt) +{ + if (s->parent != NULL) + { + xParGroupUpdateR(s->parent, g, dt); + } + + if (!s->group->m_active) + { + return; + } + + for (U32 i = 0; i < s->cmdCount; i++) + { + xParCmd* cmd = &s->cmd[i]; + if (cmd != NULL && cmd->tasset != NULL) + { + void (*func)(xParCmd*, xParGroup*, F32) = xParCmdGetUpdateFunc(cmd->tasset->type); + if (func != NULL) + { + func(cmd, g, dt); + } + } + } +} + +static void xParGroupUpdate(xParSys* s, xParGroup* g, F32 dt) +{ + for (U32 i = 0; i < s->cmdCount; i++) + { + xParCmd* cmd = &s->cmd[i]; + if (cmd != NULL && cmd->tasset != NULL) + { + void (*func)(xParCmd*, xParGroup*, F32) = xParCmdGetUpdateFunc(cmd->tasset->type); + if (func != NULL) + { + func(cmd, g, dt); + } + } + } +} + +void xParSysRender(xBase* b) +{ + xParGroup* g; + xParSys* s = (xParSys*)b; + zRenderState(SDRS_Particles); + + g = s->group; + while (g != NULL) + { + if (g->m_active && g->m_visible && g->m_alive && !g->m_culled && g->draw != NULL) + { + xRenderStateSetTexture(s->txtr_particle); + xRenderStateSetSrcBlendMode(s->tasset->renderSrcBlendMode); + xRenderStateSetDstBlendMode(s->tasset->renderDstBlendMode); + g->draw(s, g); + } + + g = g->m_next; } - t->parent = (xParSys*)xSTFindAsset(t->cmd->flag, 0); - t->parent = t->parent; } diff --git a/src/SB/Core/x/xParSys.h b/src/SB/Core/x/xParSys.h index 4ee1b7ee..9fc48034 100644 --- a/src/SB/Core/x/xParSys.h +++ b/src/SB/Core/x/xParSys.h @@ -6,10 +6,17 @@ #include "xParGroup.h" #include "iParMgr.h" #include "xstransvc.h" +#include "xScene.h" #include -struct xScene; +#define XPARSYSINFO_TYPE_SPRITE 0 +#define XPARSYSINFO_TYPE_STREAK 1 +#define XPARSYSINFO_TYPE_FLAT 2 +#define XPARSYSINFO_TYPE_STATIC 3 +#define XPARSYSINFO_TYPE_GROUND 4 +#define XPARSYSINFO_TYPE_QUADSTREAK 5 +#define XPARSYSINFO_TYPE_INVSTREAK 6 struct xParSysAsset : xBaseAsset { @@ -47,11 +54,15 @@ void xParCmdTexInit(xParCmdTex* tex); void xParSysInit(void* b, void* tasset); void xParSysInit(xBase* b, xParSysAsset* tasset); void xParSysSetup(xParSys* t); +void xParSysReset(xParSys* t); void xParSysExit(xParSys* t); void xParSysRender(xBase* b); -S32 xParSysEventCB(xBase*, xBase*, U32, F32*, xBase*); +S32 xParSysEventCB(xBase*, xBase*, U32, const F32*, xBase*); void xParSysUpdate(xBase* to, xScene*, F32 dt); -U8 using_ptank_render(const xParSysAsset&); +inline bool using_ptank_render(const xParSysAsset& tasset) +{ + return (tasset.parFlags >> 7) & 0x1; +} #endif diff --git a/src/SB/Core/x/xPtankPool.h b/src/SB/Core/x/xPtankPool.h index 4c5c5205..c2100936 100644 --- a/src/SB/Core/x/xPtankPool.h +++ b/src/SB/Core/x/xPtankPool.h @@ -48,12 +48,32 @@ struct ptank_pool U32 size; } hide; - bool valid() const; - void reset(); + bool valid() const + { + return ptank != NULL; + } + + bool at_block_end() const + { + return (used & 0x3F) == 0; + } + + void unlock_block() + { + RpPTankAtomicUnlock(ptank); + RPATOMICPTANKPLUGINDATA(ptank)->instFlags |= 0x800000; + RPATOMICPTANKPLUGINDATA(ptank)->actPCount = used; + used = 0; + } + + void reset() + { + ptank = NULL; + used = 0; + } + void flush(); void grab_block(ptank_group_type type); - bool at_block_end() const; - void unlock_block(); void lock_block(); }; @@ -117,7 +137,7 @@ struct ptank_pool__color_mat_uv2 : ptank_pool { }; // total size: 0x38 -struct ptank_pool__pos_color_size_uv2 : public ptank_pool +struct ptank_pool__pos_color_size_uv2 : ptank_pool { xVec3* pos; iColor_tag* color; @@ -125,8 +145,61 @@ struct ptank_pool__pos_color_size_uv2 : public ptank_pool xVec2* uv; S32 stride; - void next(); - void flush(); + void next() + { + if (at_block_end()) + { + if (valid()) + { + unlock_block(); + } + + grab_block(PGT_POS_COLOR_SIZE_UV2); + + if (!valid()) + { + return; + } + + lock_block(); + } + else + { + pos = (xVec3*)((char*)pos + stride); + color = (iColor_tag*)((char*)color + stride); + size = (xVec2*)((char*)size + stride); + uv = (xVec2*)((char*)uv + stride); + } + + used += 1; + } + + void lock_block() + { + RpPTankLockStruct ls_color; + RpPTankLockStruct ls_pos; + RpPTankLockStruct ls_size; + RpPTankLockStruct ls_uv; + + RpPTankAtomicLock(ptank, &ls_pos, rpPTANKLFLAGPOSITION, rpPTANKLOCKWRITE); + RpPTankAtomicLock(ptank, &ls_color, rpPTANKLFLAGCOLOR, rpPTANKLOCKWRITE); + RpPTankAtomicLock(ptank, &ls_size, rpPTANKLFLAGSIZE, rpPTANKLOCKWRITE); + RpPTankAtomicLock(ptank, &ls_uv, rpPTANKLFLAGVTX2TEXCOORDS, rpPTANKLOCKWRITE); + + pos = (xVec3*)ls_pos.data; + color = (iColor_tag*)ls_color.data; + size = (xVec2*)ls_size.data; + uv = (xVec2*)ls_uv.data; + stride = ls_pos.stride; + } + + void flush() + { + hide.data = (U8*)size + stride; + hide.stride = stride; + hide.size = 4; + ptank_pool::flush(); + } }; void xPTankPoolSceneEnter(); diff --git a/src/SB/Core/x/xVec3.h b/src/SB/Core/x/xVec3.h index 7eb08a53..fbfe67d0 100644 --- a/src/SB/Core/x/xVec3.h +++ b/src/SB/Core/x/xVec3.h @@ -26,6 +26,7 @@ struct xVec3 xVec3& operator=(const xVec3&); xVec3 operator+(const xVec3&) const; xVec3 operator-(const xVec3&) const; + xVec3 operator-() const; xVec3 operator*(F32) const; xVec3 operator/(F32) const; xVec3& operator+=(const xVec3&);