diff --git a/src/SB/Core/x/xMath2.h b/src/SB/Core/x/xMath2.h index 66ac08cae..7a71d7e5a 100644 --- a/src/SB/Core/x/xMath2.h +++ b/src/SB/Core/x/xMath2.h @@ -81,6 +81,12 @@ struct xVec2 xVec2 operator-(const xVec2&) const; }; +struct _xMat2x2 +{ + xVec2 right; + xVec2 up; +}; + F32 xVec2Dist(F32 x1, F32 y1, F32 x2, F32 y2); F32 xVec2Dot(const xVec2* a, const xVec2* b); void xVec2Init(xVec2* v, F32 _x, F32 _y); diff --git a/src/SB/Core/x/xParEmitter.cpp b/src/SB/Core/x/xParEmitter.cpp index 2f46c7f22..710027849 100644 --- a/src/SB/Core/x/xParEmitter.cpp +++ b/src/SB/Core/x/xParEmitter.cpp @@ -9,6 +9,15 @@ #include #include #include +#include + +#include + +static xParEmitterAsset sSaveEmmiterSettings; +static xParEmitterPropsAsset sSaveEmmiterPropSettings; +static xParEmitterPropsAsset sDummyProp; + +static U32 xParEmitterCull(xParEmitter* t, xPar* p); void add_tweaks(xParEmitter& pe) { @@ -16,41 +25,39 @@ void add_tweaks(xParEmitter& pe) S32 xParInterpConvertInterpMode(xParInterp* p) { - U32 interp_val = p->interp; - - if (interp_val < 8) + if (p->interp < 8) { - return interp_val; + return p->interp; } - if (interp_val == xStrHash("ConstA")) + if (p->interp == xStrHash("ConstA")) { return 0; } - if (interp_val == xStrHash("ConstB")) + if (p->interp == xStrHash("ConstB")) { return 1; } - if (interp_val == xStrHash("Sine")) + if (p->interp == xStrHash("Sine")) { return 4; } - if (interp_val == xStrHash("Cosine")) + if (p->interp == xStrHash("Cosine")) { return 5; } - if (interp_val == xStrHash("Linear")) + if (p->interp == xStrHash("Linear")) { return 3; } - if (interp_val == xStrHash("Step")) + if (p->interp == xStrHash("Step")) { return 7; } - if (interp_val == xStrHash("Random")) + if (p->interp == xStrHash("Random")) { return 2; } - return interp_val; + return 0; } void xParEmitterInit(void* b, void* tasset) @@ -60,107 +67,79 @@ void xParEmitterInit(void* b, void* tasset) void xParEmitterInit(xBase* b, xParEmitterAsset* pea) { - xLinkAsset* prop; - xLinkAsset* t; + xParEmitterPropsAsset* prop; + xParEmitter* t; S32 i; - F32 vec_length; - F32 temp_rate; - F32 temp_oocull; - U32 temp_psi; - xParEmitter* bEmitter = (xParEmitter*)b; + t = (xParEmitter*)b; - xBaseInit(bEmitter, (xBaseAsset*)pea); - bEmitter->eventFunc = (xBaseEventCB)xParEmitterEventCB; - bEmitter->tasset = pea; - bEmitter->prop = (xParEmitterPropsAsset*)xSTFindAsset(pea->propID, NULL); - if (bEmitter->prop == NULL) + xBaseInit(t, pea); + t->eventFunc = xParEmitterEventCB; + t->tasset = pea; + t->prop = (xParEmitterPropsAsset*)xSTFindAsset(pea->propID, NULL); + if (t->prop == NULL) { - bEmitter->prop = 0; + t->prop = &sDummyProp; } - if (bEmitter->linkCount != 0) + if (t->linkCount != 0) { - bEmitter->link = bEmitter->link; + t->link = (xLinkAsset*)(t->tasset + 1); } else { - bEmitter->link = NULL; - } - prop = (xLinkAsset*)bEmitter->prop; - bEmitter->emit_flags = pea->emit_flags; - temp_psi = bEmitter->prop->parSysID; - if (temp_psi != 0) - { - bEmitter->parSys = (xParSys*)zSceneFindObject(temp_psi); + t->link = NULL; } - else - { - bEmitter->parSys = NULL; - } - t = prop; - bEmitter->attachTo = 0; - bEmitter->emit_volume = 0; + prop = t->prop; + t->emit_flags = pea->emit_flags; + t->parSys = (t->prop->parSysID != 0) ? (xParSys*)zSceneFindObject(t->prop->parSysID) : NULL; + t->attachTo = NULL; + t->emit_volume = NULL; for (i = 0; i < 14; i++) { - if (t->param[1] == t->param[2]) + if (prop->value[i].val[0] == prop->value[i].val[1]) { - t->param[3] = 0U; + prop->value[i].interp = 0; } else { - t->param[3] = (F32)xParInterpConvertInterpMode((xParInterp*)(t->param + 1)); + prop->value[i].interp = xParInterpConvertInterpMode(&prop->value[i]); } - t += 0x14; - } - bEmitter->rate_mode = (U8)prop->param[3]; - if (((U8)bEmitter->eventFunc == 2) && (prop->param[1] == prop->param[2])) - { - bEmitter->rate_mode = 0; - } - if (bEmitter->rate_mode == 2) - { - (bEmitter->prop->life).order(); - } - if (bEmitter->rate_mode == 2) - { - temp_rate = ((prop->param[1] - prop->param[2]) * xurand()) + prop->param[2]; } - else + t->rate_mode = prop->rate.interp; + if ((t->rate_mode == 2) && (prop->rate.val[0] == prop->rate.val[1])) { - temp_rate = prop->param[1]; + t->rate_mode = 0; } - bEmitter->rate = temp_rate; - bEmitter->rate_time = 0.0f; - bEmitter->rate_fraction = 0.0f; - bEmitter->rate_fraction_cull = 0.0f; - if (pea->emit_flags & 2) - { - temp_oocull = 1.0f / pea->cull_dist_sqr; - } - else + if (t->rate_mode == 2) { - temp_oocull = 0.0f; + prop->rate.order(); } - bEmitter->oocull_distance_sqr = temp_oocull; - bEmitter->emit_volume = 0; + t->rate = (t->rate_mode == 2) + ? ((prop->rate.val[1] - prop->rate.val[0]) * xurand()) + prop->rate.val[0] + : prop->rate.val[0]; + t->rate_time = 0.0f; + t->rate_fraction = 0.0f; + t->rate_fraction_cull = 0.0f; + t->oocull_distance_sqr = (pea->emit_flags & 2) ? (1.0f / pea->cull_dist_sqr) : 0.0f; + t->emit_volume = NULL; if ((pea->emit_type == eParEmitterOCircle) || (pea->emit_type == eParEmitterOCircleEdge)) { - vec_length = (pea->e_circle.dir).length2(); - if (vec_length < 0.001f) + F32 len2 = (pea->e_circle.dir).length2(); + + if (len2 < 0.001f) { - pea->e_circle.dir = 0; + (pea->e_circle.dir).assign(0.0f, 1.0f, 0.0f); } else { - pea->e_circle.dir = 1.0f / xsqrt(vec_length); + pea->e_circle.dir *= 1.0f / xsqrt(len2); } } - bEmitter->last_attach_loc += pea->e_circle.dir; + t->last_attach_loc = 1e38f; } void xParEmitterSetup(xParEmitter* t) { - xParEmitterAsset* pea; xEnt* ent; if (t->parSys != NULL) @@ -170,24 +149,28 @@ void xParEmitterSetup(xParEmitter* t) if ((t->tasset->attachToID != 0) && (t->tasset->emit_type == eParEmitterOffsetPoint)) { ent = (xEnt*)zSceneFindObject(t->tasset->attachToID); - iModelTagSetup(&t->tag, ent->model->Data, *(F32*)&t->tasset->e_entbound, - (t->tasset->e_entbound).expand, (t->tasset->e_entbound).deflection); + iModelTagSetup(&t->tag, ent->model->Data, (t->tasset->e_offsetp).offset.x, + (t->tasset->e_offsetp).offset.y, (t->tasset->e_offsetp).offset.z); } - ent = NULL; if (t->tasset->attachToID != 0) { ent = (xEnt*)zSceneFindObject(t->tasset->attachToID); } + else + { + ent = NULL; + } t->attachTo = ent; - if (((t->tasset->emit_type != eParEmitterEntityBound) && - (t->tasset->emit_type != eParEmitterEntityBone)) && - (t->tasset->emit_type == eParEmitterVolume)) + if ((S32)t->tasset->emit_type < eParEmitterEntityBone) { - ent = (xEnt*)zSceneFindObject(t->tasset->attachToID); - t->emit_volume = ent; + switch (t->tasset->emit_type) + { + case eParEmitterVolume: + t->emit_volume = zSceneFindObject((t->tasset->e_volume).emit_volumeID); + break; + } } add_tweaks(*t); - return; } void xParEmitterReset(xParEmitter* t) @@ -196,155 +179,147 @@ void xParEmitterReset(xParEmitter* t) t->emit_flags = t->tasset->emit_flags; } -S32 xParEmitterEventCB(xBase* to, xBase* from, U32 toEvent, F32* toParam, xBase* toParamWidget) +S32 xParEmitterEventCB(xBase* from, xBase* to, U32 toEvent, const F32* toParam, + xBase* toParamWidget) { - xParEmitterCustomSettings sp8; + xParEmitter* t = (xParEmitter*)to; + xParEmitterCustomSettings fake_settings; switch ((S32)toEvent) { case eEventReset: - xParEmitterReset((xParEmitter*)from); + xParEmitterReset(t); break; case eEventOn: - *(U8*)(toEvent + 0x30) |= 1; + t->emit_flags |= 1; break; case eEventOff: - if (*(U8*)(toEvent + 0x30) & 1) + if (t->emit_flags & 1) { - *(U8*)(toEvent + 0x30) = *(U8*)(toEvent + 0x30) ^ 1; + t->emit_flags ^= 1; } break; case eEventEmit: - memset(&sp8, 0, 0x16C); - xParEmitterEmitCustom((xParEmitter*)from, 0.033333335f, &sp8); + memset(&fake_settings, 0, sizeof(xParEmitterCustomSettings)); + xParEmitterEmitCustom(t, 0.033333335f, &fake_settings); break; } return 1; } xPar* xParEmitterEmitCustom(xParEmitter* p, F32 dt, xParEmitterCustomSettings* info) - { - U8 emit_type; - U32 custom_flags; - xParEmitterAsset* p_tasset; + xPar* par; + U32 flags = info->custom_flags; + xParEmitterAsset* pe = p->tasset; - custom_flags = info->custom_flags; - p_tasset = p->tasset; - if ((custom_flags & 0x1) != 0) + if (flags & 0x1) { - sSaveEmmiterSettings(p_tasset, p_tasset, 0.0); - sSaveEmmiterPropSettings(p->prop, p->prop, 0.0); + memcpy(&sSaveEmmiterSettings, pe, sizeof(xParEmitterAsset)); + memcpy(&sSaveEmmiterPropSettings, p->prop, sizeof(xParEmitterPropsAsset)); } - if ((custom_flags & 0x100) != 0) + if (flags & 0x100) { - p_tasset->pos = info->pos; + pe->pos = info->pos; } - if ((custom_flags & 0x10) != 0) + if (flags & 0x10) { - p->prop->value[0] = info->value[0]; + p->prop->rate = info->value[0]; } - if ((custom_flags & 0x2) != 0) + if (flags & 0x2) { p->prop->life = info->life; } - if ((custom_flags & 0x2000) != 0) + if (flags & 0x2000) { p->emit_volume = info->emit_volume; } - if ((custom_flags & 0x4) != 0) + if (flags & 0x4) { p->prop->size_birth = info->size_birth; } - if ((custom_flags & 0x8) != 0) + if (flags & 0x8) { p->prop->size_death = info->size_death; } - if ((custom_flags & 0x200) != 0) + if (flags & 0x200) { - p_tasset->vel = info->vel; + pe->vel = info->vel; p->prop->vel = info->vel; } - if ((custom_flags & 0x40) != 0) + if (flags & 0x40) { - p_tasset->vel_angle_variation = info->vel_angle_variation; + pe->vel_angle_variation = info->vel_angle_variation; } - if ((custom_flags & 0x400) != 0) + if (flags & 0x400) { p->prop->color_birth[0] = info->color_birth[0]; p->prop->color_birth[1] = info->color_birth[1]; p->prop->color_birth[2] = info->color_birth[2]; p->prop->color_birth[3] = info->color_birth[3]; } - if ((custom_flags & 0x800) != 0) + if (flags & 0x800) { p->prop->color_death[0] = info->color_death[0]; p->prop->color_death[1] = info->color_death[1]; p->prop->color_death[2] = info->color_death[2]; p->prop->color_death[3] = info->color_death[3]; } - if ((custom_flags & 0x1000) != 0) + if (flags & 0x1000) { - p_tasset = p->tasset; - emit_type = p_tasset->emit_type; - if ((emit_type == eParEmitterSphere) || (emit_type == eParEmitterSphereEdge3) || - (emit_type == eParEmitterSphereEdge2) || (emit_type == eParEmitterSphereEdge1) || - (emit_type == eParEmitterCircle) || (emit_type == eParEmitterCircleEdge) || - (emit_type == eParEmitterOCircle || (emit_type == eParEmitterOCircleEdge))) + switch (p->tasset->emit_type) { - *(F32*)&p_tasset->e_entbound = info->radius; + case eParEmitterCircleEdge: + case eParEmitterCircle: + case eParEmitterOCircleEdge: + case eParEmitterOCircle: + p->tasset->e_circle.radius = info->radius; + break; + case eParEmitterSphereEdge1: + case eParEmitterSphere: + case eParEmitterSphereEdge2: + case eParEmitterSphereEdge3: + p->tasset->e_sphere.radius = info->radius; + break; } } - if ((custom_flags & 0x1) != 0) + + par = xParEmitterEmit(p, dt); + + if (flags & 0x1) { - sSaveEmmiterSettings(p_tasset, p_tasset, 0.0); - sSaveEmmiterPropSettings(p->prop, p->prop, 0.0); + memcpy(pe, &sSaveEmmiterSettings, sizeof(xParEmitterAsset)); + memcpy(p->prop, &sSaveEmmiterPropSettings, sizeof(xParEmitterPropsAsset)); } - return xParEmitterEmit(p, dt, dt); + return par; } -U32 xParEmitterCull(xParEmitter* t, xPar* p) - +static U32 xParEmitterCull(xParEmitter* t, xPar* p) { - U32 c; - xParEmitterAsset* tas; - F32 vec_length; - xVec3* temp_vec; - xVec3* global_vec; - - temp_vec = 0; - global_vec = 0; + xVec3 campos; + xVec3 dist; + F32 dist2; + xParEmitterAsset* tas = t->tasset; - tas = t->tasset; - if ((tas->emit_flags & 2) == 0) + if (tas->emit_flags & 2) { - c = 0; - } - else - { - global_vec = &(xglobals->camera.mat.pos); - xVec3Sub(temp_vec, global_vec, &p->m_pos); - vec_length = xVec3Length2(temp_vec); - t->distance_to_cull_sqr = vec_length; + campos = xglobals->camera.mat.pos; + xVec3Sub(&dist, &campos, &p->m_pos); + dist2 = xVec3Length2(&dist); + t->distance_to_cull_sqr = dist2; if (tas->cull_mode == 3) { - c = ((((tas->cull_dist_sqr) < vec_length) << 2) << 0x1c) >> 0x1e; - } - else - { - c = (((vec_length < (tas->cull_dist_sqr)) << 3) << 0x1c) >> 0x1f; + return dist2 > tas->cull_dist_sqr; } + return dist2 < tas->cull_dist_sqr; } - return c; + return 0; } F32 xParInterpCompute(S32 interp_mode, xParInterp* r, F32 time, S32 time_has_elapsed, F32 lastVal) - { - F32 val; - F32 val_0 = r->val[0]; + F32 val = time; - val = time; switch (interp_mode) { case 0: @@ -354,76 +329,75 @@ F32 xParInterpCompute(S32 interp_mode, xParInterp* r, F32 time, S32 time_has_ela val = r->val[1]; break; case 2: - if (time_has_elapsed != 0) + if (time_has_elapsed) + { + val = ((r->val[1] - r->val[0]) * xurand()) + r->val[0]; + } + else { - val = xurand(); - val = ((r->val[1] - val_0) * xurand() + val_0); + val = lastVal; } break; case 3: - if (0.0 < r->freq) + if (r->freq < 0.00001f) { - val = ((r->val[1] - r->val[0]) * (val / r->freq) + r->val[0]); + val = r->val[0]; } else { - val = r->val[0]; + val = ((r->val[1] - r->val[0]) * (val / r->freq)) + r->val[0]; } break; case 4: - val = isin((1.0 * (val * r->oofreq))); - val = ((r->val[1] - val_0) * (1.0 * val + 1.0) + val_0); + val = ((r->val[1] - r->val[0]) * + ((0.5f * isin(6.2831855f * (val * r->oofreq))) + 0.5f)) + + r->val[0]; break; case 5: - val = icos((1.0 * (val * r->oofreq))); - val = ((r->val[1] - val_0) * (1.0 * val + 1.0) + val_0); + val = ((r->val[1] - r->val[0]) * + ((0.5f * icos(6.2831855f * (val * r->oofreq))) + 0.5f)) + + r->val[0]; break; case 7: - if ((val * r->freq) < 0.0) + if ((val * r->freq) >= 0.5f) { - val = r->val[0]; + val = r->val[1]; } else { - val = r->val[1]; + val = r->val[0]; } + break; } return val; } -xPar* xParEmitterEmitSetTexIdxs(xPar* p, xParSys* ps) +xPar* xParEmitterEmitSetTexIdxs(xPar* p, const xParSys* ps) { - U8 ps_birthMode; - xParCmdTex* ps_cmdTex; + xParCmdTex* tex = ps->group->m_cmdTex; - ps_cmdTex = ps->group->m_cmdTex; - if (ps_cmdTex == NULL) + if (tex == NULL) { return NULL; } - ps_birthMode = ps_cmdTex->birthMode; - if ((S32)ps_birthMode != 1) - { - if ((S32)ps_birthMode < 1) - { - if ((S32)ps_birthMode < 0) - { - } - else - { - p->m_texIdx[0] = 0; - p->m_texIdx[1] = 0; - } - } - else if ((S32)ps_birthMode < 7) - { - } - } - else + + switch (tex->birthMode) { - p->m_texIdx[0] = (xrand() >> 0x11U) % ps_cmdTex->cols; - p->m_texIdx[1] = (xrand() >> 0x11U) % ps_cmdTex->rows; + case 1: + p->m_texIdx[0] = (xrand() >> 0x11) % tex->cols; + p->m_texIdx[1] = (xrand() >> 0x11) % tex->rows; + break; + case 0: + case 2: + case 3: + case 4: + case 5: + case 6: + p->m_texIdx[0] = 0; + p->m_texIdx[1] = 0; + break; } + return p; } @@ -431,352 +405,343 @@ xPar* xParEmitterEmit(xParEmitter* pe, F32 emit_dt, F32 par_dt) { xPar* p; xPar* last_p; - xMat4x3* bone_mat; - xParSys* ps; - xParEmitterPropsAsset* prop; xParEmitterAsset* pea; - xVec3 emitPosition; - xVec3 bone_vel; - xGroup* g; - xEnt* attach_ent; - + xParEmitterPropsAsset* prop; + S32 rate_has_elapsed; + F32 rate; + xParSys* ps; F32 life; F32 size_birth; F32 size_death; - - S32 i; - S32 c; - S32 attachGroupTotal; - S32 rate_has_elapsed; - U32 attachGroupIndex; + xVec3 emitPosition; + xBase* attachObject; S32 count; + S32 attachGroupIndex; + S32 attachGroupTotal; S32 emitAgain; - bool marker; - S32 group_ptr_chk; - U32 temp_maxPar; + xBase* emitObj; + S32 marker; + xGroup* g; + xEnt* attach_ent; + xMat4x3* bone_mat; + xVec3 bone_vel; + xVec3 attach_vel; + S32 i; + S32 c; + F32 fc1; + F32 fc2; if (pe->parSys == NULL) { - p = NULL; + return NULL; } - else - { // TODO: could probably be less nested - p = NULL; - pea = pe->tasset; - prop = pe->prop; - pe->rate_time = pe->rate_time + emit_dt; - size_birth = pe->rate_time; - if (pe->rate_time == 0.0) - { - pe->rate_time = 0.0; - } - while (pe->rate_time > prop->value[0].freq) + + last_p = NULL; + pea = pe->tasset; + prop = pe->prop; + + pe->rate_time += emit_dt; + rate_has_elapsed = pe->rate_time > prop->rate.freq; + if (prop->rate.freq == 0.0f) + { + pe->rate_time = 0.0f; + } + while (pe->rate_time > prop->rate.freq) + { + pe->rate_time -= prop->rate.freq; + } + + rate = + xParInterpCompute(pe->rate_mode, &prop->rate, pe->rate_time, rate_has_elapsed, pe->rate); + pe->rate = rate; + rate *= emit_dt; + pe->rate_fraction += rate; + pe->rate_fraction_cull += rate; + + rate_has_elapsed = std::floorf(pe->rate_fraction); + if (rate_has_elapsed > 0) + { + pe->rate_fraction -= rate_has_elapsed; + } + if (rate_has_elapsed == 0) + { + return NULL; + } + + ps = pe->parSys; + if (ps == NULL) + { + return NULL; + } + if (ps->group == NULL) + { + return NULL; + } + if ((ps->tasset->maxPar != 0) && (ps->group->m_num_of_particles >= ps->tasset->maxPar)) + { + return NULL; + } + if ((ps->tasset->maxPar != 0) && (ps->group->m_num_of_particles >= ps->tasset->maxPar)) + { + return NULL; + } + if ((ps->tasset->maxPar != 0) && + ((ps->group->m_num_of_particles + rate_has_elapsed) >= ps->tasset->maxPar)) + { + rate_has_elapsed = ps->tasset->maxPar - ps->group->m_num_of_particles; + } + + attachObject = (xBase*)pe->attachTo; + count = -1; + attachGroupTotal = -1; + + do + { + emitAgain = 0; + emitObj = NULL; + marker = 0; + + if (attachObject != NULL) { - pe->rate_time = pe->rate_time - prop->value[0].freq; + if (attachObject->baseType == eBaseTypeGroup) + { + g = (xGroup*)attachObject; + if (count == -1) + { + attachGroupTotal = xGroupGetCount(g); + count = 0; + } + if (g->asset->groupFlags & 1) + { + attachGroupIndex = xrand() % attachGroupTotal; + emitObj = xGroupGetItemPtr(g, attachGroupIndex); + emitAgain = 0; + if (emitObj == NULL) + { + emitObj = + (xBase*)xSTFindAsset(xGroupGetItem(g, attachGroupIndex), NULL); + if (emitObj != NULL) + { + marker = 1; + } + } + } + else + { + emitObj = xGroupGetItemPtr(g, count); + if (emitObj == NULL) + { + emitObj = (xBase*)xSTFindAsset(xGroupGetItem(g, count), NULL); + if (emitObj != NULL) + { + marker = 1; + } + } + count++; + emitAgain = count < attachGroupTotal; + } + } + else + { + emitObj = attachObject; + } } - size_birth = xParInterpCompute(pe->rate_mode, prop->value, pe->rate_time, 0, 0.0); - pe->rate = size_birth; - pe->rate_fraction = pe->rate_fraction + ((double)size_birth * emit_dt); - pe->rate_fraction_cull = pe->rate_fraction_cull + (F32)((double)size_birth * emit_dt); - size_birth = floorf(pe->rate_fraction); - rate_has_elapsed = size_birth; - if (rate_has_elapsed > 0) + + attach_ent = (xEnt*)emitObj; + if (emitObj != NULL) { - pe->rate_fraction = pe->rate_fraction - rate_has_elapsed; + if (marker) + { + emitPosition = *(xVec3*)emitObj; + attach_ent = NULL; + } + else + { + switch (emitObj->baseType) + { + case eBaseTypeMovePoint: + emitPosition = *((xMovePoint*)emitObj)->pos; + attach_ent = NULL; + break; + default: + if (!xEntValidType(emitObj->baseType) || (attach_ent->model == NULL)) + { + emitPosition = 0.0f; + attach_ent = NULL; + } + else + { + emitPosition = *xEntGetPos(attach_ent); + } + break; + } + } } - if (rate_has_elapsed == 0) + else { - p = NULL; + emitPosition = pea->pos; } - else + + if (((pe->emit_flags & 0x10) == 0) || (attach_ent == NULL) || + (xEntIsVisible(attach_ent) != 0)) { - ps = pe->parSys; - if (ps == NULL) + bone_mat = NULL; + if ((pea->emit_type == eParEmitterEntityBone) && (attach_ent != NULL)) { - p = NULL; + bone_mat = xParEmitterTransformEntBone(emitPosition, bone_vel, *pea, *attach_ent); + bone_vel *= par_dt; } - else + + if (pe->emit_flags & 8) { - group_ptr_chk = *(S32*)(ps->group); - if (group_ptr_chk == 0) + attach_vel = emitPosition - pe->last_attach_loc; + pe->last_attach_loc = emitPosition; + if (attach_vel.length2() > 25.0f) { - p = NULL; + attach_vel = 0.0f; } - else + } + else + { + attach_vel = 0.0f; + } + + for (i = 0; i < rate_has_elapsed; i++) + { + p = xParGroupAddPar(ps->group); + if (p != NULL) { - temp_maxPar = ps->tasset->maxPar; - if ((temp_maxPar == 0) || (ps->group->m_num_of_particles < (S32)temp_maxPar)) + last_p = p; + + life = xParInterpCompute((prop->life).interp, &prop->life, pe->rate_time, 1, + 0.0f); + size_birth = xParInterpCompute((prop->size_birth).interp, &prop->size_birth, + pe->rate_time, 1, 0.0f); + size_death = xParInterpCompute((prop->size_death).interp, &prop->size_death, + pe->rate_time, 1, 0.0f); + + p->m_lifetime = life; + p->totalLifespan = life; + p->m_size = size_birth; + if (size_death == size_birth) + { + p->m_sizeVel = 0.0f; + } + else { - if ((temp_maxPar == 0) || - (ps->group->m_num_of_particles < (S32)temp_maxPar)) + p->m_sizeVel = (size_death - size_birth) / life; + } + p->m_flag = 0; + p->m_rotdeg[0] = pe->rot[0]; + p->m_rotdeg[1] = pe->rot[1]; + p->m_rotdeg[2] = pe->rot[2]; + + for (c = 0; c < 4; c++) + { + fc1 = xParInterpCompute(prop->color_birth[c].interp, + &prop->color_birth[c], pe->rate_time, 1, 0.0f); + fc2 = xParInterpCompute(prop->color_death[c].interp, + &prop->color_death[c], pe->rate_time, 1, 0.0f); + p->m_cfl[c] = fc1; + p->m_c[c] = (U8)fc1; + p->m_cvel[c] = (fc2 - fc1) / life; + } + + p->m_pos = emitPosition; + xParEmitterEmitSetTexIdxs(p, ps); + + switch (pea->emit_type) + { + case eParEmitterPoint: + xParEmitterEmitPoint(p, pea, par_dt); + break; + case eParEmitterCircleEdge: + xParEmitterEmitCircleEdge(p, pea, par_dt); + break; + case eParEmitterCircle: + xParEmitterEmitCircle(p, pea, par_dt); + break; + case eParEmitterRectEdge: + xParEmitterEmitRectEdge(p, pea, par_dt); + break; + case eParEmitterRect: + xParEmitterEmitRect(p, pea, par_dt); + break; + case eParEmitterLine: + xParEmitterEmitLine(p, pea, par_dt); + break; + case eParEmitterSphereEdge1: + xParEmitterEmitSphereEdge(p, pea, par_dt, eParEmitterSphereEdge1); + break; + case eParEmitterSphereEdge2: + xParEmitterEmitSphereEdge(p, pea, par_dt, eParEmitterSphereEdge2); + break; + case eParEmitterSphereEdge3: + xParEmitterEmitSphereEdge(p, pea, par_dt, eParEmitterSphereEdge3); + break; + case eParEmitterSphere: + xParEmitterEmitSphere(p, pea, par_dt); + break; + case eParEmitterVolume: + { + xBase* obj = (xBase*)pe->emit_volume; + + if (obj != NULL) { - if ((temp_maxPar != 0) && - ((S32)temp_maxPar <= - ps->group->m_num_of_particles + rate_has_elapsed)) + if (obj->baseType == eBaseTypeVolume) { - rate_has_elapsed = temp_maxPar - ps->group->m_num_of_particles; + xParEmitterEmitVolume(p, pea, par_dt, (xVolume*)obj); } - g = (xGroup*)pe->attachTo; - count = 0xFFFFFFFF; - attachGroupTotal = 0xFFFFFFFF; - while (emitAgain) + else { - emitAgain = false; - marker = false; - attach_ent = NULL; - if ((g != (xGroup*)0x0) && (g->baseType == '\x11')) - { - if (count == 0xFFFFFFFF) - { - attachGroupTotal = xGroupGetCount((xGroup*)g); - count = 0; - } - if (g->asset->groupFlags & 1) - { - attachGroupIndex = xrand(); - attach_ent = (xEnt*)xGroupGetItemPtr( - g, (S32)attachGroupIndex % (S32)attachGroupTotal); - if (attach_ent == NULL) - { - attachGroupIndex = xGroupGetItem( - g, (S32)attachGroupIndex % attachGroupTotal); - attach_ent = (xEnt*)xSTFindAsset(attachGroupIndex, 0); - if (attach_ent != NULL) - { - marker = true; - } - } - } - else - { - attach_ent = (xEnt*)xGroupGetItemPtr(g, count); - if (attach_ent == NULL) - { - attachGroupIndex = xGroupGetItem(g, count); - attach_ent = (xEnt*)xSTFindAsset(attachGroupIndex, 0); - if (attach_ent != NULL) - { - marker = true; - } - } - count = count + 1; - emitAgain = count % attachGroupTotal; - } - } - if (attach_ent == NULL) - { - emitPosition = pea->pos; - } - else if ((attach_ent->baseType) == '\r') - { - attach_ent = NULL; - } - else if (marker) - { - emitPosition = pea->pos; - attach_ent = NULL; - } - else - { - if ((xEntValidType((attach_ent->baseType))) && - (attach_ent->model != (xModelInstance*)0x0)) - { - emitPosition += *xEntGetPos(attach_ent); - } - else - { - emitPosition = 0; - attach_ent = NULL; - } - } - if ((((pe->emit_flags & 0x10) == 0) || (attach_ent == NULL)) || - (xEntIsVisible(attach_ent) != 0)) - { - bone_mat = (xMat4x3*)0x0; - if ((pea->emit_type == eParEmitterEntityBone) && - (attach_ent != NULL)) - { - bone_mat = xParEmitterTransformEntBone( - emitPosition, bone_vel, *pea, *attach_ent); - } - if ((pe->emit_flags & 8) == 0) - { - bone_vel -= (bone_vel * par_dt); - } - else - { - bone_vel *= 2.0; - size_birth = emitPosition.length2(); - bone_vel += 1.0; - emitPosition += 1.0; - - if (0 < emit_dt) - { - // May need a vector operation here - } - } - for (i = 0; i < rate_has_elapsed; i++) - { - p = xParGroupAddPar(ps->group); - if (p == (xPar*)0x0) - { - emitAgain = false; - } - else - { - life = - xParInterpCompute((prop->life).interp, &prop->life, - pe->rate_time, 1, 0.0); - size_birth = - xParInterpCompute((prop->size_birth).interp, - &prop->size_birth, pe->rate_time, - 1, 0.0); - size_death = - xParInterpCompute((prop->size_death).interp, - &prop->size_death, pe->rate_time, - 1, 0.0); - p->m_lifetime = life; - p->totalLifespan = life; - p->m_size = size_birth; - if (size_death == size_birth) - { - p->m_sizeVel = 0.0; - } - else - { - p->m_sizeVel = (size_birth - p->m_size) / life; - } - p->m_flag = '\0'; - p->m_rotdeg[0] = pe->rot[0]; - p->m_rotdeg[1] = pe->rot[1]; - p->m_rotdeg[2] = pe->rot[2]; - last_p = p; - for (c = 0; c < 4; c += 1) - { - size_birth = - xParInterpCompute(prop->color_birth[0].interp, - prop->color_birth, - pe->rate_time, 1, 0.0); - size_death = - xParInterpCompute(prop->color_death[0].interp, - prop->color_death, - pe->rate_time, 1, 0.0); - - last_p->m_cfl[0] = size_birth; - - last_p->m_c[c] = (U8)(int)size_birth; - - last_p->m_cvel[0] = - (size_death - size_birth) / life; - last_p = (xPar*)&last_p->m_prev; - } - p->m_pos = emitPosition; - xParEmitterEmitSetTexIdxs(p, ps); - switch (pea->emit_type) - { - case eParEmitterPoint: - xParEmitterEmitPoint(p, pea, par_dt); - break; - case eParEmitterCircleEdge: - xParEmitterEmitCircleEdge(p, pea, par_dt); - break; - case eParEmitterCircle: - xParEmitterEmitCircle(p, pea, par_dt); - break; - case eParEmitterRectEdge: - xParEmitterEmitRectEdge(p, pea, par_dt); - break; - case eParEmitterRect: - xParEmitterEmitRect(p, pea, par_dt); - break; - case eParEmitterLine: - xParEmitterEmitLine(p, pea, par_dt); - break; - case eParEmitterSphereEdge2: - xParEmitterEmitSphereEdge(p, pea, par_dt, - eParEmitterSphereEdge2); - break; - case eParEmitterSphereEdge3: - xParEmitterEmitSphereEdge(p, pea, par_dt, - eParEmitterSphereEdge3); - break; - case eParEmitterSphereEdge1: - xParEmitterEmitSphereEdge(p, pea, par_dt, - eParEmitterSphereEdge1); - break; - case eParEmitterSphere: - xParEmitterEmitSphere(p, pea, par_dt); - break; - - case eParEmitterVolume: - attach_ent = (xEnt*)pe->emit_volume; - if (attach_ent != NULL) - { - if ((attach_ent->baseType) == '\x1d') - { - xParEmitterEmitVolume(p, pea, par_dt, - (xVolume*)attach_ent); - } - else - { - xParEmitterEmitEntity(p, pea, par_dt, - attach_ent); - } - } - break; - - case eParEmitterOffsetPoint: - xParEmitterEmitOffsetPoint(pe, p, pea, attach_ent); - break; - case eParEmitterVCylEdge: - xParEmitterEmitVCylEdge(p, pea, par_dt); - break; - case eParEmitterOCircleEdge: - xParEmitterEmitOCircleEdge(p, pea, par_dt); - break; - case eParEmitterOCircle: - xParEmitterEmitOCircle(p, pea, par_dt); - break; - case eParEmitterEntityBone: - if (bone_mat != 0) - { - p->m_vel += bone_vel; - xParEmitterEmitEntBone(p, pea, par_dt, - *bone_mat); - } - break; - case eParEmitterEntityBound: - if (attach_ent != NULL) - { - xParEmitterEmitEntBound(p, pea, par_dt, - attach_ent); - } - } - p->m_vel += bone_vel; - c = xParEmitterCull(pe, p); - if (c != 0) - { - xParGroupKillPar(ps->group, p); - } - } - } - } + xParEmitterEmitEntity(p, pea, par_dt, (xEnt*)obj); } } - else + break; + } + case eParEmitterOffsetPoint: + xParEmitterEmitOffsetPoint(pe, p, pea, par_dt, (xEnt*)emitObj); + break; + case eParEmitterVCylEdge: + xParEmitterEmitVCylEdge(p, pea, par_dt); + break; + case eParEmitterOCircleEdge: + xParEmitterEmitOCircleEdge(p, pea, par_dt); + break; + case eParEmitterOCircle: + xParEmitterEmitOCircle(p, pea, par_dt); + break; + case eParEmitterEntityBone: + if (bone_mat != NULL) + { + p->m_vel = bone_vel; + xParEmitterEmitEntBone(p, pea, par_dt, *bone_mat); + } + break; + case eParEmitterEntityBound: + if (attach_ent != NULL) { - p = (xPar*)0x0; + xParEmitterEmitEntBound(p, pea, par_dt, attach_ent); } + break; } - else + + p->m_vel += attach_vel; + c = xParEmitterCull(pe, p); + if (c != 0) { - p = (xPar*)0x0; + xParGroupKillPar(ps->group, p); } } + else + { + emitAgain = 0; + } } } - } - return p; + } while (emitAgain); + + return last_p; } void xParEmitterUpdate(xBase* to, xScene*, F32 dt) @@ -806,24 +771,16 @@ void xParInterp::order() } } -void xParEmitterEmit(xParEmitter* pe, F32 dt) +xPar* xParEmitterEmit(xParEmitter* pe, F32 dt) { - xParEmitterEmit(pe, dt, dt); + return xParEmitterEmit(pe, dt, dt); } void xParInterp::operator=(const xParInterp& p) { + *(S32*)&this->val[0] = *(S32*)&p.val[0]; + *(S32*)&this->val[1] = *(S32*)&p.val[1]; this->interp = p.interp; - this->val[0] = p.val[0]; - this->val[1] = p.val[1]; this->freq = p.freq; this->oofreq = p.oofreq; } - -void sSaveEmmiterSettings(xParEmitterAsset* a, xParEmitterAsset* b, F32 c) -{ -} - -void sSaveEmmiterPropSettings(xParEmitterPropsAsset* a, xParEmitterPropsAsset* b, F32 c) -{ -} diff --git a/src/SB/Core/x/xParEmitter.h b/src/SB/Core/x/xParEmitter.h index 50d6b8f7b..a142a1482 100644 --- a/src/SB/Core/x/xParEmitter.h +++ b/src/SB/Core/x/xParEmitter.h @@ -133,16 +133,14 @@ void xParEmitterInit(void* b, void* tasset); void xParEmitterInit(xBase* b, xParEmitterAsset* pea); void xParEmitterSetup(xParEmitter* t); void xParEmitterReset(xParEmitter* t); -S32 xParEmitterEventCB(xBase* to, xBase* from, U32 toEvent, F32* toParam, xBase* toParamWidget); +S32 xParEmitterEventCB(xBase* from, xBase* to, U32 toEvent, const F32* toParam, + xBase* toParamWidget); xPar* xParEmitterEmitCustom(xParEmitter* p, F32 dt, xParEmitterCustomSettings* info); -U32 xParEmitterCull(xParEmitter* t, xPar* p); F32 xParInterpCompute(S32 interp_mode, xParInterp* r, F32 time, S32 time_has_elapsed, F32 lastVal); -xPar* xParEmitterEmitSetTexIdxs(xPar* p, xParSys* ps); +xPar* xParEmitterEmitSetTexIdxs(xPar* p, const xParSys* ps); xPar* xParEmitterEmit(xParEmitter* pe, F32 emit_dt, F32 par_dt); void xParEmitterUpdate(xBase* to, xScene*, F32 dt); void xParEmitterDestroy(); -void xParEmitterEmit(xParEmitter* pe, F32 dt); +xPar* xParEmitterEmit(xParEmitter* pe, F32 dt); -void sSaveEmmiterSettings(xParEmitterAsset* a, xParEmitterAsset* b, F32 c); -void sSaveEmmiterPropSettings(xParEmitterPropsAsset* a, xParEmitterPropsAsset* b, F32 c); #endif diff --git a/src/SB/Core/x/xParEmitterType.cpp b/src/SB/Core/x/xParEmitterType.cpp index 42591032c..d210da585 100644 --- a/src/SB/Core/x/xParEmitterType.cpp +++ b/src/SB/Core/x/xParEmitterType.cpp @@ -4,6 +4,17 @@ #include #include #include +#include +#include + +namespace +{ + void ocircle_emit(xPar& p, xParEmitterAsset& a, F32 dt, F32 radius); + void transform_ent_bone(xVec3& loc, xVec3& vel, const xParEmitterAsset& a, + const xMat4x3& mat); + xVec3 get_random_offset(const xPEEntBone& region, const xMat4x3& mat); + xVec3 get_random_offset(const xBound& b, F32 expand, U32 type); +} // namespace void xParEmitterEmitPoint(xPar* p, xParEmitterAsset* a, F32 dt) { @@ -14,50 +25,58 @@ void xParEmitterEmitPoint(xPar* p, xParEmitterAsset* a, F32 dt) void xParEmitterAngleVariation(xPar* p, xParEmitterAsset* a) { - S32 temp_m; F32 ang_debrisCone; - F32 ang[3]; + ang_debrisCone = a->vel_angle_variation; if (ang_debrisCone != 0.0f) { + xMat3x3 mat_rot = { 0 }; + F32 ang[3] = { 0.0f, 0.0f, 0.0f }; + ang[0] = ang_debrisCone * (xurand() - 0.5f); ang[1] = ang_debrisCone * (xurand() - 0.5f); ang[2] = ang_debrisCone * (xurand() - 0.5f); - xMat3x3Euler((xMat3x3*)&temp_m, ang[0], ang[1], ang[2]); - xMat3x3LMulVec(&p->m_vel, (xMat3x3*)&temp_m, &p->m_vel); + xMat3x3Euler(&mat_rot, ang[0], ang[1], ang[2]); + xMat3x3LMulVec(&p->m_vel, &mat_rot, &p->m_vel); } } void xParEmitterEmitCircleEdge(xPar* p, xParEmitterAsset* a, F32 dt) { - xVec2 vec1; - xVec2 vec2; - S32 temp_a; F32 dt_radius; F32 rot_amount; F32 temp_icos; - F32 dot_ret_z; - F32 temp_isin; F32 dot_ret_x; + F32 temp_isin; + F32 dot_ret_z; - p->m_vel += a->vel; + p->m_vel = a->vel; xVec3SMulBy(&p->m_vel, dt); + rot_amount = 6.2831855f * xurand(); temp_icos = icos(rot_amount); temp_isin = isin(rot_amount); - vec1 = 0; - vec2 = 0; - xVec2Init(&vec1, temp_icos, temp_isin); - xVec2Init(&vec2, -temp_isin, temp_icos); - temp_a = 0; - dot_ret_x = xVec2Dot(&vec1, (xVec2*)&temp_a) * a->e_rect.x_len; - dot_ret_z = xVec2Dot(&vec2, (xVec2*)&temp_a) * a->e_rect.x_len; + + _xMat2x2 rot_mat = { { 1.0f, 0.0f }, { 0.0f, 1.0f } }; + + xVec2Init(&rot_mat.right, temp_icos, temp_isin); + xVec2Init(&rot_mat.up, -temp_isin, temp_icos); + + xVec2 vec2 = { 0.0f, 1.0f }; + + dot_ret_x = xVec2Dot(&rot_mat.right, &vec2); + dot_ret_x *= a->e_circle.radius; + dot_ret_z = xVec2Dot(&rot_mat.up, &vec2); + dot_ret_z *= a->e_circle.radius; + p->m_pos.x += dot_ret_x; p->m_pos.z += dot_ret_z; + xParEmitterAngleVariation(p, a); - if (a->e_rect.z_len != 0.0f) + + if (a->e_circle.deflection != 0.0f) { - dt_radius = a->e_rect.z_len * (a->e_rect.x_len * dt); + dt_radius = a->e_circle.deflection * (a->e_circle.radius * dt); p->m_vel.x += dot_ret_x * dt_radius; p->m_vel.z += dot_ret_z * dt_radius; } @@ -65,11 +84,7 @@ void xParEmitterEmitCircleEdge(xPar* p, xParEmitterAsset* a, F32 dt) void xParEmitterEmitCircle(xPar* p, xParEmitterAsset* a, F32 dt) { - xVec2 vec1; - xVec2 vec2; - F32 temp_calc; - S32 temp_b; - F32 temp_rand; + F32 rr; F32 dt_radius; F32 rot_amount; F32 temp_icos; @@ -77,25 +92,35 @@ void xParEmitterEmitCircle(xPar* p, xParEmitterAsset* a, F32 dt) F32 temp_isin; F32 dot_ret_z; - p->m_vel += a->vel; + p->m_vel = a->vel; xVec3SMulBy(&p->m_vel, dt); + rot_amount = 6.2831855f * xurand(); temp_icos = icos(rot_amount); temp_isin = isin(rot_amount); - xVec2Init(&vec1, temp_icos, temp_isin); - xVec2Init(&vec2, -temp_isin, temp_icos); - temp_b = 0; - temp_calc = 0; - temp_rand = xurand(); - temp_calc = -((temp_rand * temp_rand) - 1.0f) * a->e_rect.x_len; - dot_ret_x = xVec2Dot(&vec1, (xVec2*)&temp_b); - dot_ret_z = xVec2Dot(&vec2, (xVec2*)&temp_b); + + _xMat2x2 rot_mat = { { 1.0f, 0.0f }, { 0.0f, 1.0f } }; + + xVec2Init(&rot_mat.right, temp_icos, temp_isin); + xVec2Init(&rot_mat.up, -temp_isin, temp_icos); + + xVec2 vec2 = { 0.0f, 1.0f }; + + rr = xurand(); + rr = 1.0f - (rr * rr); + vec2.y = rr * a->e_circle.radius; + + dot_ret_x = xVec2Dot(&rot_mat.right, &vec2); + dot_ret_z = xVec2Dot(&rot_mat.up, &vec2); + p->m_pos.x += dot_ret_x; p->m_pos.z += dot_ret_z; + xParEmitterAngleVariation(p, a); - if (a->e_rect.z_len != 0.0f) + + if (a->e_circle.deflection != 0.0f) { - dt_radius = a->e_rect.z_len * (a->e_rect.x_len * dt); + dt_radius = a->e_circle.deflection * (a->e_circle.radius * dt); p->m_vel.x += dot_ret_x * dt_radius; p->m_vel.z += dot_ret_z * dt_radius; } @@ -117,178 +142,174 @@ void xParEmitterEmitRect(xPar* p, xParEmitterAsset* a, F32 dt) void xParEmitterEmitRectEdge(xPar* p, xParEmitterAsset* a, F32 dt) { - F32 x_length; - F32 z_length; + F32 rand; - p->m_vel += a->vel; + p->m_vel = a->vel; xVec3SMulBy(&p->m_vel, dt); - x_length = a->e_rect.x_len; - if ((2.0f * (xurand() * x_length)) > x_length) + + rand = xurand(); + if ((2.0f * (rand * a->e_rect.x_len)) > a->e_rect.x_len) { - p->m_pos.x += x_length; + p->m_pos.x += a->e_rect.x_len; } else { - p->m_pos.x -= x_length; + p->m_pos.x -= a->e_rect.x_len; } - z_length = a->e_rect.z_len; - if ((2.0f * (xurand() * z_length)) >= z_length) + + rand = xurand(); + if ((2.0f * (rand * a->e_rect.z_len)) >= a->e_rect.z_len) { - p->m_pos.z += z_length; + p->m_pos.z += a->e_rect.z_len; } else { - p->m_pos.z -= z_length; + p->m_pos.z -= a->e_rect.z_len; } + xParEmitterAngleVariation(p, a); } void xParEmitterEmitLine(xPar* p, xParEmitterAsset* a, F32 dt) { xVec3 vec; - F32 temp_1; - F32 temp_2; - F32 temp_3; - xVec3 dir; - F32 temp_random; F32 len; F32 rand_len; F32 yaw; F32 pitch; F32 rr; - p->m_vel += a->vel; + p->m_vel = a->vel; xVec3SMulBy(&p->m_vel, dt); - xVec3Sub(&vec, &a->e_line.pos2, (xVec3*)&a->e_line.pos2.x); + + xVec3Sub(&vec, &a->e_line.pos2, &a->e_line.pos1); len = xVec3Normalize(&vec, &vec); rand_len = len * xurand(); - p->m_pos.x = (1.0 * rand_len) + a->e_line.pos2.x; - p->m_pos.y = (1.0 * rand_len) + a->e_line.pos2.y; - p->m_pos.z = (1.0 * rand_len) + a->e_line.pos2.z; + + p->m_pos.x = (vec.x * rand_len) + a->e_line.pos1.x; + p->m_pos.y = (vec.y * rand_len) + a->e_line.pos1.y; + p->m_pos.z = (vec.z * rand_len) + a->e_line.pos1.z; + if (a->e_line.radius > 0.0f) { yaw = 6.2831855f * xurand(); pitch = 6.2831855f * xurand(); + + F32 sin_yaw = isin(yaw); rr = icos(yaw); - temp_1 = -isin(yaw); - temp_2 = rr * isin(pitch); - temp_3 = rr * icos(pitch); - temp_random = xurand(); - dir *= (a->e_line.radius * -((temp_random * (temp_random * temp_random)) - 1.0f)); - dir += (temp_1 + temp_2 + temp_3); - p->m_pos += dir; + F32 sin_pitch = isin(pitch); + F32 cos_pitch = icos(pitch); + + xVec3 dir = { 0.0f, 0.0f, 0.0f }; + + dir.x = -sin_yaw; + dir.y = rr * sin_pitch; + dir.z = rr * cos_pitch; + + F32 temp_random = xurand(); + + temp_random = 1.0f - (temp_random * (temp_random * temp_random)); + p->m_pos += dir * (a->e_line.radius * temp_random); } + xParEmitterAngleVariation(p, a); } void xParEmitterEmitSphere(xPar* p, xParEmitterAsset* a, F32 dt) { - F32 temp_1; - F32 temp_2; - F32 temp_3; - xVec3 temp_vec; - xVec3 dir; - F32 pitch; F32 yaw; - F32 temp_icos_1; - F32 temp_sum; + F32 pitch; + F32 rr; + + p->m_vel = a->vel * dt; - temp_vec *= dt; - p->m_vel += temp_vec; yaw = 6.2831855f * xurand(); pitch = 6.2831855f * xurand(); - temp_icos_1 = icos(yaw); - temp_1 = -isin(yaw); - temp_2 = temp_icos_1 * isin(pitch); - temp_3 = temp_icos_1 * icos(pitch); - dir *= (a->e_sphere.radius * xurand()); - temp_sum = temp_1 + temp_2 + temp_3; - dir += temp_sum; - p->m_pos += dir; + + F32 sin_yaw = isin(yaw); + rr = icos(yaw); + F32 sin_pitch = isin(pitch); + F32 cos_pitch = icos(pitch); + + xVec3 dir = { 0.0f, 0.0f, 0.0f }; + + dir.x = -sin_yaw; + dir.y = rr * sin_pitch; + dir.z = rr * cos_pitch; + + p->m_pos += dir * (a->e_sphere.radius * xurand()); xParEmitterAngleVariation(p, a); } void xParEmitterEmitSphereEdge(xPar* p, xParEmitterAsset* a, F32 dt, S32 subtype) { - S32 temp_1; - S32 temp_2; - S32 temp_3; - S32 temp_4; + xVec3 dirvec = { 0.0f, 0.0f, 1.0f }; + xVec3 offset = { 0.0f, 0.0f, 0.0f }; + xMat3x3 mat_rot = { 0 }; F32 random_angle_72; F32 random_angle_71; F32 random_angle_10; F32 random_angle_11; - temp_1 = 0; - temp_2 = 0; - temp_3 = 0; - temp_4 = 0; - - p->m_vel += a->vel; + p->m_vel = a->vel; xVec3SMulBy(&p->m_vel, dt); + switch (subtype) { - case 7: + case eParEmitterSphereEdge1: random_angle_71 = 6.2831855f * xurand(); random_angle_72 = 6.2831855f * xurand(); - xMat3x3Euler((xMat3x3*)&temp_3, 6.2831855f * xurand(), random_angle_71, random_angle_72); + xMat3x3Euler(&mat_rot, 6.2831855f * xurand(), random_angle_72, random_angle_71); break; - case 10: + case eParEmitterSphereEdge2: random_angle_10 = (3.1415927f * xurand()) + 3.1415927f; - xMat3x3Euler((xMat3x3*)&temp_3, 6.2831855f * xurand(), random_angle_10, 0.0f); + xMat3x3Euler(&mat_rot, 6.2831855f * xurand(), random_angle_10, 0.0f); break; - case 11: + case eParEmitterSphereEdge3: random_angle_11 = 3.1415927f * xurand(); - xMat3x3Euler((xMat3x3*)&temp_3, 6.2831855f * xurand(), random_angle_11, 0.0f); + xMat3x3Euler(&mat_rot, 6.2831855f * xurand(), random_angle_11, 0.0f); break; } - temp_2 += temp_4; - xVec3SMul(&p->m_vel, (xVec3*)&temp_2, xVec3Length(&p->m_vel)); - xVec3SMul((xVec3*)&temp_1, (xVec3*)&temp_2, a->e_sphere.radius); - xVec3AddTo((xVec3*)&p->m_pos, (xVec3*)&temp_1); + + dirvec = mat_rot.at; + xVec3SMul(&p->m_vel, &dirvec, xVec3Length(&p->m_vel)); + xVec3SMul(&offset, &dirvec, a->e_sphere.radius); + xVec3AddTo(&p->m_pos, &offset); xParEmitterAngleVariation(p, a); } void xParEmitterEmitVolume(xPar* p, xParEmitterAsset* a, F32 dt, xVolume* vol) { - xVec3 temp_1; - F32 temp_2; - F32 temp_3; + xVec3 size; xBound* b; - temp_1 = 0; - temp_2 = 0; - temp_3 = 0; - - p->m_vel += a->vel; + p->m_vel = a->vel; xVec3SMulBy(&p->m_vel, dt); + if (vol != NULL) { b = vol->GetBound(); - if ((U8)b->type == 2) + if (b->type == XBOUND_TYPE_BOX) { - xVec3Sub(&temp_1, &b->box.box.upper, &b->box.box.lower); - temp_1 *= xurand(); - temp_2 *= xurand(); - temp_3 *= xurand(); - xVec3Add((xVec3*)&p->m_pos, &temp_1, &b->box.box.lower); + xVec3Sub(&size, &b->box.box.upper, &b->box.box.lower); + size.x *= xurand(); + size.y *= xurand(); + size.z *= xurand(); + xVec3Add(&p->m_pos, &size, &b->box.box.lower); } } + xParEmitterAngleVariation(p, a); } void xParEmitterEmitEntity(xPar* p, xParEmitterAsset* a, F32 dt, xEnt* ent) { - U32 size; - xModelInstance* model; - U32 which; - xVec3 dir; + U32 size = 0; + xModelInstance* model = ent->model; xVec3 loc; - - size = 0; - model = ent->model; + U32 which; while (model != NULL) { @@ -299,45 +320,46 @@ void xParEmitterEmitEntity(xPar* p, xParEmitterAsset* a, F32 dt, xEnt* ent) model = model->Next; } - which = (xrand() >> 0xDU) % size; + which = (xrand() >> 0xD) % size; - while (model != NULL) { - if (!(model->Flags & 0x8000)) + xModelInstance* model = ent->model; + + while (model != NULL) { - size = model->Data->geometry->numVertices; - if (which < size) - { - iModelVertEval(model->Data, which, 1U, model->Mat, NULL, &dir); - } - else + if (!(model->Flags & 0x8000)) { + U32 size = model->Data->geometry->numVertices; + + if (which < size) + { + iModelVertEval(model->Data, which, 1, model->Mat, NULL, &loc); + break; + } + which -= size; - model = model->Next; } - } - else - { + model = model->Next; } } - p->m_pos += dir; - loc *= dt; - p->m_vel += loc; + + p->m_pos = loc; + p->m_vel = a->vel * dt; xParEmitterAngleVariation(p, a); } -void xParEmitterEmitOffsetPoint(xParEmitter* pe, xPar* p, xParEmitterAsset* a, xEnt* ent) +void xParEmitterEmitOffsetPoint(xParEmitter* pe, xPar* p, xParEmitterAsset* a, F32 dt, xEnt* ent) { - xModelInstance* temp_model; - RpAtomic* temp_data; + xModelInstance* model; + RpAtomic* data; if (ent != NULL) { - temp_model = ent->model; - temp_data = temp_model->Data; - if ((U32)temp_data->geometry->morphTarget->verts != 0U) + model = ent->model; + data = model->Data; + if (data->geometry->morphTarget->verts != NULL) { - iModelTagEval(temp_data, &pe->tag, temp_model->Mat, (xVec3*)&p->m_pos); + iModelTagEval(data, &pe->tag, model->Mat, &p->m_pos); } } else @@ -351,48 +373,400 @@ void xParEmitterEmitVCylEdge(xPar* p, xParEmitterAsset* a, F32 dt) { F32 ang; F32 deflect; - xVec2 dir; - - F32 temp_isin; - F32 temp_icos; - - dir = 0; p->m_vel *= dt; + ang = 6.2831855f * xurand(); - temp_isin = isin(ang); - temp_icos = icos(ang); - dir *= a->e_vcyl.radius; - p->m_pos.x += dir.x; + + xVec2 dir = { 0.0f, 0.0f }; + + dir.x = isin(ang); + dir.y = icos(ang); + + xVec2 offset = dir * a->e_vcyl.radius; + + p->m_pos.x += offset.x; p->m_pos.y += a->e_vcyl.height * xurand(); - p->m_pos.z += dir.y; + p->m_pos.z += offset.y; + deflect = a->e_vcyl.deflection * dt; - p->m_vel.x += dir.x * deflect; - p->m_vel.z += dir.y * deflect; + p->m_vel.x += offset.x * deflect; + p->m_vel.z += offset.y * deflect; + xParEmitterAngleVariation(p, a); } void xParEmitterEmitOCircleEdge(xPar* p, xParEmitterAsset* a, F32 dt) { + ocircle_emit(*p, *a, dt, a->e_circle.radius); } +namespace +{ + void ocircle_emit(xPar& p, xParEmitterAsset& a, F32 dt, F32 radius) + { + xMat3x3 rot_mat; + F32 rot_amount; + F32 temp_icos; + F32 temp_isin; + + xMat3x3LookVec(&rot_mat, &a.e_circle.dir); + + rot_amount = 6.2831855f * xurand(); + temp_icos = icos(rot_amount); + temp_isin = isin(rot_amount); + + xVec3 dir = { 0.0f, 0.0f, 0.0f }; + + dir.x = temp_icos; + dir.y = temp_isin; + dir *= radius; + xMat3x3RMulVec(&dir, &rot_mat, &dir); + + p.m_pos += dir; + p.m_vel = a.e_circle.dir * a.vel.y; + + xParEmitterAngleVariation(&p, &a); + + if (a.e_circle.deflection != 0.0f) + { + p.m_vel += dir * (radius * a.e_circle.deflection); + } + + p.m_vel *= dt; + } +} // namespace + void xParEmitterEmitOCircle(xPar* p, xParEmitterAsset* a, F32 dt) { + F32 rr = xurand(); + F32 radius = 1.0f - (rr * rr); + + radius *= a->e_circle.radius; + ocircle_emit(*p, *a, dt, radius); } -xMat4x3* xParEmitterTransformEntBone(xVec3& loc, xVec3& vel, xParEmitterAsset& a, xEnt& ent) +xMat4x3* xParEmitterTransformEntBone(xVec3& loc, xVec3& vel, const xParEmitterAsset& a, + const xEnt& ent) { - return 0; + static xMat4x3 buffer_mat; + + xMat4x3* mat; + xMat4x3* bone_mat = (xMat4x3*)ent.model->Mat; + U8 bone = a.e_entbone.bone; + + if (bone == 0) + { + mat = bone_mat; + } + else + { + xMat4x3Mul(&buffer_mat, bone_mat + bone, bone_mat); + mat = &buffer_mat; + } + + transform_ent_bone(loc, vel, a, *mat); + + return mat; } -void xParEmitterTransformEntBone(xVec3& loc, xVec3& vel, xParEmitterAsset& a, xMat4x3& mat) +namespace +{ + void transform_ent_bone(xVec3& loc, xVec3& vel, const xParEmitterAsset& a, const xMat4x3& mat) + { + if (a.e_entbone.flags & 0x1) + { + xMat3x3RMulVec(&vel, &mat, &a.vel); + } + else + { + vel = a.vel; + } + + if (a.e_entbone.flags & 0x2) + { + if (a.e_entbone.flags & 0x4) + { + xVec3 offset = { 0.0f, 0.0f, 0.0f }; + + offset.x = a.e_entbone.offset.x; + offset.z = a.e_entbone.offset.z; + xMat4x3Toworld(&loc, &mat, &offset); + loc.y = a.e_entbone.offset.y; + } + else + { + xMat4x3Toworld(&loc, &mat, &a.e_entbone.offset); + } + } + else + { + loc = mat.pos + a.e_entbone.offset; + if (a.e_entbone.flags & 0x4) + { + loc.y = a.e_entbone.offset.y; + } + } + + if (a.e_entbone.flags & 0x4) + { + loc.y = a.e_entbone.offset.y; + } + } +} // namespace + +void xParEmitterTransformEntBone(xVec3& loc, xVec3& vel, const xParEmitterAsset& a, + const xMat4x3& mat) { + transform_ent_bone(loc, vel, a, mat); } -void xParEmitterEmitEntBone(xPar* p, xParEmitterAsset* a, F32 dt, xMat4x3& mat) +void xParEmitterEmitEntBone(xPar* p, xParEmitterAsset* a, F32 dt, const xMat4x3& mat) { + const xPEEntBone& b = a->e_entbone; + + xVec3 offset = get_random_offset(b, mat); + + p->m_pos += offset; + + if (b.deflection != 0.0f) + { + p->m_vel += (offset * b.deflection) * dt; + } + + xParEmitterAngleVariation(p, a); } -void xParEmitterEmitEntBound(xPar* p, xParEmitterAsset* a, F32 dt, xEnt* ent) +namespace { + xVec3 get_random_offset(const xPEEntBone& region, const xMat4x3& mat) + { + xVec3 offset; + + switch (region.type) + { + case 0: + { + offset = 0.0f; + break; + } + case 1: + { + F32 ang = 6.2831855f * xurand(); + F32 z = (2.0f * xurand()) - 1.0f; + F32 s = xsqrt(1.0f - (z * z)); + F32 t = xurand(); + F32 radius = 1.0f - (t * (t * t)); + + radius *= region.radius; + F32 rs = radius * s; + + offset.assign(rs * icos(ang), rs * isin(ang), radius * z); + break; + } + case 2: + { + F32 ang = 6.2831855f * xurand(); + F32 radius = region.radius * xsqrt(xurand()); + + offset.assign(radius * isin(ang), 0.0f, radius * icos(ang)); + break; + } + case 3: + { + F32 ang = 6.2831855f * xurand(); + F32 radius = region.radius * xsqrt(xurand()); + + offset = (mat.up * (radius * isin(ang))) + (mat.at * (radius * icos(ang))); + break; + } + case 4: + { + F32 ang = 6.2831855f * xurand(); + F32 radius = region.radius * xsqrt(xurand()); + + offset = (mat.right * (radius * isin(ang))) + (mat.at * (radius * icos(ang))); + break; + } + case 5: + { + F32 ang = 6.2831855f * xurand(); + F32 radius = region.radius * xsqrt(xurand()); + + offset = (mat.right * (radius * isin(ang))) + (mat.up * (radius * icos(ang))); + break; + } + case 6: + { + F32 ang = 6.2831855f * xurand(); + F32 z = (2.0f * xurand()) - 1.0f; + F32 rs = region.radius * xsqrt(1.0f - (z * z)); + + offset.assign(rs * icos(ang), rs * isin(ang), z * region.radius); + break; + } + case 7: + { + F32 ang = 6.2831855f * xurand(); + + offset.assign(region.radius * isin(ang), 0.0f, region.radius * icos(ang)); + break; + } + case 8: + { + F32 ang = 6.2831855f * xurand(); + F32 radius = region.radius; + + offset = (mat.up * (radius * isin(ang))) + (mat.at * (radius * icos(ang))); + break; + } + case 9: + { + F32 ang = 6.2831855f * xurand(); + F32 radius = region.radius; + + offset = (mat.right * (radius * isin(ang))) + (mat.at * (radius * icos(ang))); + break; + } + case 10: + { + F32 ang = 6.2831855f * xurand(); + F32 radius = region.radius; + + offset = (mat.right * (radius * isin(ang))) + (mat.up * (radius * icos(ang))); + break; + } + } + + return offset; + } +} // namespace + +void xParEmitterEmitEntBound(xPar* p, xParEmitterAsset* a, F32 dt, const xEnt* ent) +{ + const xPEEntBound& region = a->e_entbound; + const xMat4x3& mat = *(xMat4x3*)ent->model->Mat; + + if (region.flags & 0x1) + { + xMat3x3RMulVec(&p->m_vel, &mat, &a->vel); + } + else + { + p->m_vel = a->vel; + } + + xVec3 offset = get_random_offset(ent->bound, region.expand, region.type); + + p->m_pos = mat.pos + offset; + + if (region.deflection != 0.0f) + { + p->m_vel += offset * region.deflection; + } + + p->m_vel *= dt; + + xParEmitterAngleVariation(p, a); } + +namespace +{ + xVec3 get_random_offset(const xBound& b, F32 expand, U32 type) + { + xVec3 offset; + + switch (b.type | (type << 3)) + { + case XBOUND_TYPE_SPHERE: + { + F32 ang = 6.2831855f * xurand(); + F32 z = (2.0f * xurand()) - 1.0f; + F32 s = xsqrt(1.0f - (z * z)); + F32 t = xurand(); + F32 radius = 1.0f - (t * (t * t)); + + radius *= (b.sph.r + expand); + F32 rs = radius * s; + + offset.assign(rs * icos(ang), rs * isin(ang), radius * z); + break; + } + case XBOUND_TYPE_BOX: + { + offset = (b.box.box.upper - b.box.center) + expand; + offset.x *= (2.0f * xurand()) - 1.0f; + offset.y *= (2.0f * xurand()) - 1.0f; + offset.z *= (2.0f * xurand()) - 1.0f; + break; + } + case XBOUND_TYPE_OBB: + { + offset = b.box.box.upper + expand; + offset.x *= (2.0f * xurand()) - 1.0f; + offset.y *= (2.0f * xurand()) - 1.0f; + offset.z *= (2.0f * xurand()) - 1.0f; + xMat3x3RMulVec(&offset, b.mat, &offset); + break; + } + case (1 << 3) | XBOUND_TYPE_SPHERE: + { + F32 ang = 6.2831855f * xurand(); + F32 z = (2.0f * xurand()) - 1.0f; + F32 rs = (b.sph.r + expand) * xsqrt(1.0f - (z * z)); + + offset.assign(rs * icos(ang), rs * isin(ang), z * (b.sph.r + expand)); + break; + } + case (1 << 3) | XBOUND_TYPE_BOX: + { + xVec3 dir; + U32 r = xrand() >> 0xD; + U32 axis = r % 3; + F32 sign = (r & 0x4) ? 1.0f : -1.0f; + + if (axis == 0) + { + dir.assign(sign, (2.0f * xurand()) - 1.0f, (2.0f * xurand()) - 1.0f); + } + else if (axis == 1) + { + dir.assign((2.0f * xurand()) - 1.0f, sign, (2.0f * xurand()) - 1.0f); + } + else + { + dir.assign((2.0f * xurand()) - 1.0f, (2.0f * xurand()) - 1.0f, sign); + } + + offset = ((b.box.box.upper - b.box.center) + expand) * dir; + break; + } + case (1 << 3) | XBOUND_TYPE_OBB: + { + xVec3 dir; + U32 r = xrand() >> 0xD; + U32 axis = r % 3; + F32 sign = (r & 0x4) ? 1.0f : -1.0f; + + if (axis == 0) + { + dir.assign(sign, (2.0f * xurand()) - 1.0f, (2.0f * xurand()) - 1.0f); + } + else if (axis == 1) + { + dir.assign((2.0f * xurand()) - 1.0f, sign, (2.0f * xurand()) - 1.0f); + } + else + { + dir.assign((2.0f * xurand()) - 1.0f, (2.0f * xurand()) - 1.0f, sign); + } + + offset = (b.box.box.upper + expand) * dir; + xMat3x3RMulVec(&offset, b.mat, &offset); + break; + } + } + + return offset; + } +} // namespace diff --git a/src/SB/Core/x/xParEmitterType.h b/src/SB/Core/x/xParEmitterType.h index 85d7795f9..226caa382 100644 --- a/src/SB/Core/x/xParEmitterType.h +++ b/src/SB/Core/x/xParEmitterType.h @@ -80,13 +80,15 @@ void xParEmitterEmitSphere(xPar* p, xParEmitterAsset* a, F32 dt); void xParEmitterEmitSphereEdge(xPar* p, xParEmitterAsset* a, F32 dt, S32 subtype); void xParEmitterEmitVolume(xPar* p, xParEmitterAsset* a, F32 dt, xVolume* vol); void xParEmitterEmitEntity(xPar* p, xParEmitterAsset* a, F32 dt, xEnt* ent); -void xParEmitterEmitOffsetPoint(xParEmitter* pe, xPar* p, xParEmitterAsset* a, xEnt* ent); +void xParEmitterEmitOffsetPoint(xParEmitter* pe, xPar* p, xParEmitterAsset* a, F32 dt, xEnt* ent); void xParEmitterEmitVCylEdge(xPar* p, xParEmitterAsset* a, F32 dt); void xParEmitterEmitOCircleEdge(xPar* p, xParEmitterAsset* a, F32 dt); void xParEmitterEmitOCircle(xPar* p, xParEmitterAsset* a, F32 dt); -xMat4x3* xParEmitterTransformEntBone(xVec3& loc, xVec3& vel, xParEmitterAsset& a, xEnt& ent); -void xParEmitterTransformEntBone(xVec3& loc, xVec3& vel, xParEmitterAsset& a, xMat4x3& mat); -void xParEmitterEmitEntBone(xPar* p, xParEmitterAsset* a, F32 dt, xMat4x3& mat); -void xParEmitterEmitEntBound(xPar* p, xParEmitterAsset* a, F32 dt, xEnt* ent); +xMat4x3* xParEmitterTransformEntBone(xVec3& loc, xVec3& vel, const xParEmitterAsset& a, + const xEnt& ent); +void xParEmitterTransformEntBone(xVec3& loc, xVec3& vel, const xParEmitterAsset& a, + const xMat4x3& mat); +void xParEmitterEmitEntBone(xPar* p, xParEmitterAsset* a, F32 dt, const xMat4x3& mat); +void xParEmitterEmitEntBound(xPar* p, xParEmitterAsset* a, F32 dt, const xEnt* ent); #endif diff --git a/src/SB/Core/x/xVec3.h b/src/SB/Core/x/xVec3.h index fbfe67d0d..610842d00 100644 --- a/src/SB/Core/x/xVec3.h +++ b/src/SB/Core/x/xVec3.h @@ -29,6 +29,30 @@ struct xVec3 xVec3 operator-() const; xVec3 operator*(F32) const; xVec3 operator/(F32) const; + + xVec3 operator*(const xVec3& v) const + { + xVec3 product = *this; + product *= v; + return product; + } + + xVec3& operator*=(const xVec3& v) + { + this->x *= v.x; + this->y *= v.y; + this->z *= v.z; + + return *this; + } + + xVec3 operator+(F32 f) const + { + xVec3 sum = *this; + sum += f; + return sum; + } + xVec3& operator+=(const xVec3&); xVec3& operator+=(F32 f) {