CDecal progress

This commit is contained in:
Luke Street 2022-10-16 22:33:08 -04:00
parent 5e367d95ee
commit cd88e8eedd
12 changed files with 345 additions and 33 deletions

View File

@ -42,6 +42,7 @@ public:
uchar GetAlphau8() const { return mA; }
ushort ToRGB5A3() const;
GXColor ToGX(uint);
uint GetColor_u32() const { return mRgba; }
static const CColor& Black();
static const CColor& White();

View File

@ -30,13 +30,83 @@ enum ERglTevStage {
};
enum ERglPrimitive {
kP_Quads = 0x80,
kP_Triangles = 0x90,
kP_TriangleStrip = 0x98,
kP_TriangleFan = 0xA0,
kP_Lines = 0xA8,
kP_LineStrip = 0xB0,
kP_Points = 0xB8,
kP_Quads = GX_QUADS,
kP_Triangles = GX_TRIANGLES,
kP_TriangleStrip = GX_TRIANGLESTRIP,
kP_TriangleFan = GX_TRIANGLEFAN,
kP_Lines = GX_LINES,
kP_LineStrip = GX_LINESTRIP,
kP_Points = GX_POINTS,
};
enum ERglBlendMode {
kBM_None = GX_BM_NONE,
kBM_Blend = GX_BM_BLEND,
kBM_Logic = GX_BM_LOGIC,
kBM_Subtract = GX_BM_SUBTRACT,
kBM_Max = GX_MAX_BLENDMODE,
};
enum ERglBlendFactor {
kBF_Zero = GX_BL_ZERO,
kBF_One = GX_BL_ONE,
kBF_SrcColor = GX_BL_SRCCLR,
kBF_InvSrcColor = GX_BL_INVSRCCLR,
kBF_SrcAlpha = GX_BL_SRCALPHA,
kBF_InvSrcAlpha = GX_BL_INVSRCALPHA,
kBF_DstAlpha = GX_BL_DSTALPHA,
kBF_InvDstAlpha = GX_BL_INVDSTALPHA,
kBF_DstColor = GX_BL_DSTCLR,
kBF_InvDstColor = GX_BL_INVDSTCLR,
};
enum ERglLogicOp {
kLO_Clear = GX_LO_CLEAR,
kLO_And = GX_LO_AND,
kLO_RevAnd = GX_LO_REVAND,
kLO_Copy = GX_LO_COPY,
kLO_InvAnd = GX_LO_INVAND,
kLO_NoOp = GX_LO_NOOP,
kLO_Xor = GX_LO_XOR,
kLO_Or = GX_LO_OR,
kLO_Nor = GX_LO_NOR,
kLO_Equiv = GX_LO_EQUIV,
kLO_Inv = GX_LO_INV,
kLO_RevOr = GX_LO_REVOR,
kLO_InvCopy = GX_LO_INVCOPY,
kLO_InvOr = GX_LO_INVOR,
kLO_NAnd = GX_LO_NAND,
kLO_Set = GX_LO_SET,
};
enum ERglAlphaFunc {
kAF_Never = GX_NEVER,
kAF_Less = GX_LESS,
kAF_Equal = GX_EQUAL,
kAF_LEqual = GX_LEQUAL,
kAF_Greater = GX_GREATER,
kAF_NEqual = GX_NEQUAL,
kAF_GEqual = GX_GEQUAL,
kAF_Always = GX_ALWAYS,
};
enum ERglAlphaOp {
kAO_And = GX_AOP_AND,
kAO_Or = GX_AOP_OR,
kAO_Xor = GX_AOP_XOR,
kAO_XNor = GX_AOP_XNOR,
kAO_Max = GX_MAX_ALPHAOP,
};
enum ERglEnum {
kE_Never = GX_NEVER,
kE_Less = GX_LESS,
kE_Equal = GX_EQUAL,
kE_LEqual = GX_LEQUAL,
kE_Greater = GX_GREATER,
kE_NEqual = GX_NEQUAL,
kE_GEqual = GX_GEQUAL,
kE_Always = GX_ALWAYS,
};
class CTimeProvider;
@ -60,6 +130,23 @@ public:
static void SetExternalTimeProvider(CTimeProvider* provider);
static void DisableAllLights();
static void SetModelMatrix(const CTransform4f& xf);
static void SetAlphaCompare(ERglAlphaFunc comp0, u8 ref0, ERglAlphaOp op, ERglAlphaFunc comp1,
u8 ref1);
static void SetDepthWriteMode(bool test, ERglEnum comp, bool write);
static void SetBlendMode(ERglBlendMode, ERglBlendFactor, ERglBlendFactor, ERglLogicOp);
static CTevCombiners::CTevPass& kEnvPassThru;
static CTevCombiners::CTevPass kEnvModulateConstColor;
static CTevCombiners::CTevPass kEnvConstColor;
static CTevCombiners::CTevPass kEnvModulate;
static CTevCombiners::CTevPass kEnvDecal;
static CTevCombiners::CTevPass kEnvBlend;
static CTevCombiners::CTevPass kEnvReplace;
static CTevCombiners::CTevPass kEnvModulateAlpha;
static CTevCombiners::CTevPass kEnvModulateColor;
static CTevCombiners::CTevPass kEnvModulateColorByalpha;
private:
static CTransform4f mViewMatrix;
static CTransform4f mModelMatrix;

View File

@ -10,9 +10,9 @@ class CInputStream;
class CTexture {
public:
enum EClampMode {
Clamp,
Repeat,
Mirror,
kCM_Clamp,
kCM_Repeat,
kCM_Mirror,
};
enum EAutoMipmap {
kAM_Zero,

View File

@ -43,6 +43,7 @@ CHECK_SIZEOF(CRelAngle, 0x4)
// __mi__FRC9CRelAngleRC9CRelAngle
// __pl__FRC9CRelAngleRC9CRelAngle
// __dv__FRC9CRelAnglef
// sine__FRC9CRelAngle
static inline float sine(const CRelAngle& angle) { return sin(angle.AsRadians()); }
static inline float cosine(const CRelAngle& angle) { return cos(angle.AsRadians()); }
#endif // _CRELANGLE

View File

@ -9,6 +9,7 @@
#include "rstl/optional_object.hpp"
#include "rstl/single_ptr.hpp"
class CModel;
class CElectricDescription;
class CSwooshDescription;
class CSpawnSystemKeyframeData;

View File

@ -53,6 +53,10 @@ public:
struct SUVElementSet {
float xMin, yMin, xMax, yMax;
SUVElementSet() : xMin(0.f), yMin(1.f), xMax(0.f), yMax(1.f) {}
SUVElementSet(float xMin, float yMin, float xMax, float yMax)
: xMin(xMin), yMin(yMin), xMax(xMax), yMax(yMax) {}
};
class CUVElement : public IElement {

View File

@ -55,6 +55,7 @@ public:
operator const TToken< T >&() const { return x0_token; }
T* operator*() const { return x8_item; }
T* operator->() const { return x8_item; }
bool IsLoaded() const { return x0_token.IsLoaded(); }
private:

View File

@ -3,6 +3,7 @@
#include "Kyoto/CRandom16.hpp"
#include "Kyoto/Math/CTransform4f.hpp"
#include "Kyoto/Particles/CParticleGlobals.hpp"
#include "Kyoto/TToken.hpp"
#include "Weapons/CDecalDescription.hpp"
@ -11,7 +12,7 @@
class CDecalDescription;
class CDecal {
static CRandom16 sDecalRandom;
static bool sMoveRedToAlpha;
static bool sMoveRedToAlphaBuffer;
public:
class CQuadDecal {
@ -29,7 +30,7 @@ public:
inline float GetRotation() const { return x8_rotation; }
inline void SetRotation(float rotation) { x8_rotation = rotation; }
private:
// private:
bool x0_24_invalid : 1;
int x4_lifetime;
float x8_rotation;
@ -43,6 +44,8 @@ public:
void Render() const;
void Update(float dt);
bool IsDone() const { return x5c_flags == 7; }
private:
TLockedToken< CDecalDescription > x0_description;
CTransform4f xc_transform;
@ -52,5 +55,44 @@ private:
int x58_frameIdx;
int x5c_flags;
CVector3f x60_rotation;
void InitQuad(CQuadDecal& quad, const CDecalDescription::SQuadDescr& desc, int flag) {
if (!desc.x14_TEX.null()) {
if (!desc.x0_LFT.null()) {
desc.x0_LFT->GetValue(0, quad.x4_lifetime);
} else {
quad.x4_lifetime = 0x7FFFFF;
}
if (!desc.x8_ROT.null()) {
desc.x8_ROT->GetValue(0, quad.x8_rotation);
quad.x0_24_invalid &= desc.x8_ROT->IsConstant();
}
if (!desc.x4_SZE.null()) {
quad.x0_24_invalid &= desc.x4_SZE->IsConstant();
if (quad.x0_24_invalid) {
float size = 1.f;
desc.x4_SZE->GetValue(0, size);
quad.x0_24_invalid = size <= 1.f;
}
}
if (!desc.xc_OFF.null()) {
quad.x0_24_invalid &= desc.xc_OFF->IsFastConstant();
}
} else {
quad.x0_24_invalid = false;
x5c_flags |= flag;
}
}
void ProcessQuad(CQuadDecal& quad, const CDecalDescription::SQuadDescr& desc, int flag) const {
if (!desc.x14_TEX.null() && (x5c_flags & flag) == 0) {
CParticleGlobals::SetParticleLifetime(quad.x4_lifetime);
CParticleGlobals::UpdateParticleLifetimeTweenValues(x58_frameIdx);
RenderQuad(quad, desc);
}
}
};
#endif // _CDECAL

View File

@ -1,11 +1,31 @@
#ifndef _CDECALDESCRIPTION
#define _CDECALDESCRIPTION
#include "Kyoto/Particles/CGenDescription.hpp"
class CDecalDescription {
public:
struct SQuadDescr {};
struct SQuadDescr {
rstl::single_ptr< CIntElement > x0_LFT;
rstl::single_ptr< CRealElement > x4_SZE;
rstl::single_ptr< CRealElement > x8_ROT;
rstl::single_ptr< CVectorElement > xc_OFF;
rstl::single_ptr< CColorElement > x10_CLR;
rstl::single_ptr< CUVElement > x14_TEX;
bool x18_ADD;
};
private:
// private:
SQuadDescr x0_quad1;
SQuadDescr x1c_quad2;
CGenDescription::TParticleModel x38_DMDL;
rstl::single_ptr< CIntElement > x48_DLFT;
rstl::single_ptr< CVectorElement > x4c_DMOP;
rstl::single_ptr< CVectorElement > x50_DMRT;
rstl::single_ptr< CVectorElement > x54_DMSC;
rstl::single_ptr< CColorElement > x58_DMCL;
bool x5c_24_DMAB : 1;
bool x5c_25_DMOO : 1;
};
#endif // _CDECALDESCRIPTION

View File

@ -104,6 +104,10 @@ static inline void GXNormal3f32(const f32 x, const f32 y, const f32 z) {
GXWGFifo.f32 = z;
}
static inline void GXColor1u32(const u32 v) {
GXWGFifo.u32 = v;
}
static inline void GXColor4u8(const u8 r, const u8 g, const u8 b, const u8 a) {
GXWGFifo.u8 = r;
GXWGFifo.u8 = g;

View File

@ -8,21 +8,20 @@
#include "rstl/math.hpp"
CRipple::CRipple(TUniqueId id, const CVector3f& center, float intensity)
: x0_id(id)
, x4_time(0.f)
, x8_center(center)
, x14_timeFalloff(2.f)
, x18_distFalloff(12.f)
, x1c_frequency(3.f)
, x20_amplitude(0.25f)
, x24_lookupAmplitude(0.00098039221f)
, x28_ooTimeFalloff(0.f)
, x2c_ooDistFalloff(0.f)
, x30_ooPhase(0.f)
, x34_phase(0.f)
, x38_lookupPhase(0.f)
, x3c_(sub_8012f098())
{
: x0_id(id)
, x4_time(0.f)
, x8_center(center)
, x14_timeFalloff(2.f)
, x18_distFalloff(12.f)
, x1c_frequency(3.f)
, x20_amplitude(0.25f)
, x24_lookupAmplitude(0.00098039221f)
, x28_ooTimeFalloff(0.f)
, x2c_ooDistFalloff(0.f)
, x30_ooPhase(0.f)
, x34_phase(0.f)
, x38_lookupPhase(0.f)
, x3c_(sub_8012f098()) {
if (0.f < intensity && intensity < 1.f) {
static CRandom16 sRippleRandom(0xABBA);

View File

@ -1,9 +1,12 @@
#include "Weapons/CDecal.hpp"
#include "Kyoto/Graphics/CGX.hpp"
#include "Kyoto/Graphics/CGraphics.hpp"
#include "Kyoto/Graphics/CTexture.hpp"
#include "Kyoto/Math/CRelAngle.hpp"
#include "Kyoto/Particles/CParticleGlobals.hpp"
CRandom16 CDecal::sDecalRandom(99);
bool CDecal::sMoveRedToAlpha = false;
bool CDecal::sMoveRedToAlphaBuffer = false;
void CDecal::SetGlobalSeed(ushort seed) { sDecalRandom.SetSeed(seed); }
@ -15,18 +18,167 @@ CDecal::CDecal(const TToken< CDecalDescription >& desc, const CTransform4f& xf)
, x5c_flags(0)
, x60_rotation(CVector3f::Zero()) {
CGlobalRandom gr(sDecalRandom);
InitQuad(x3c_quad1, x0_description->x0_quad1, 1);
InitQuad(x48_quad2, x0_description->x1c_quad2, 2);
if (x0_description->x38_DMDL) {
if (!x0_description->x48_DLFT.null()) {
x0_description->x48_DLFT->GetValue(0, x54_modelLifetime);
} else {
x54_modelLifetime = 0x7FFFFF;
}
if (!x0_description->x50_DMRT.null()) {
x0_description->x50_DMRT->GetValue(0, x60_rotation);
}
} else {
x5c_flags |= 4;
}
}
void CDecal::RenderQuad(CQuadDecal& decal, const CDecalDescription::SQuadDescr& desc) const {
CColor color = CColor::White();
float size = 1.f;
CVector3f offset = CVector3f::Zero();
if (CColorElement* clr = desc.x10_CLR.get()) {
clr->GetValue(x58_frameIdx, color);
}
if (CRealElement* sze = desc.x4_SZE.get()) {
sze->GetValue(x58_frameIdx, size);
size *= 0.5f;
}
if (CRealElement* rot = desc.x8_ROT.get()) {
rot->GetValue(x58_frameIdx, decal.x8_rotation);
}
if (CVectorElement* off = desc.xc_OFF.get()) {
off->GetValue(x58_frameIdx, offset);
offset.SetY(0.f);
}
CTransform4f modXf = xc_transform;
modXf.SetTranslation(modXf.GetTranslation() + offset);
CGraphics::SetModelMatrix(modXf);
CGraphics::SetAlphaCompare(kAF_Always, 0, kAO_And, kAF_Always, 0);
bool redToAlpha = CDecal::sMoveRedToAlphaBuffer && desc.x18_ADD && !desc.x14_TEX.null();
if (desc.x18_ADD) {
CGraphics::SetDepthWriteMode(true, kE_LEqual, false);
if (redToAlpha) {
CGraphics::SetBlendMode(kBM_Blend, kBF_One, kBF_One, kLO_Clear);
} else {
CGraphics::SetBlendMode(kBM_Blend, kBF_SrcAlpha, kBF_One, kLO_Clear);
}
} else {
CGraphics::SetDepthWriteMode(true, kE_LEqual, false);
CGraphics::SetBlendMode(kBM_Blend, kBF_SrcAlpha, kBF_InvSrcAlpha, kLO_Clear);
}
SUVElementSet uvSet;
if (!desc.x14_TEX.null()) {
TLockedToken< CTexture > tex = desc.x14_TEX->GetValueTexture(x58_frameIdx);
tex->Load(GX_TEXMAP0, CTexture::kCM_Repeat);
CGraphics::SetTevOp(kTS_Stage0, CGraphics::kEnvModulate);
desc.x14_TEX->GetValueUV(x58_frameIdx, uvSet);
if (redToAlpha) {
CGX::SetNumTevStages(2);
CGX::SetTevColorIn(GX_TEVSTAGE1, GX_CC_ZERO, GX_CC_CPREV, GX_CC_APREV, GX_CC_ZERO);
CGX::SetTevAlphaIn(GX_TEVSTAGE1, GX_CA_ZERO, GX_CA_TEXA, GX_CA_APREV, GX_CA_ZERO);
CGX::SetStandardTevColorAlphaOp(GX_TEVSTAGE1);
CGX::SetAlphaCompare(GX_GREATER, 0, GX_AOP_OR, GX_NEVER, 0);
GXSetTevSwapMode(GX_TEVSTAGE1, GX_TEV_SWAP0, GX_TEV_SWAP1);
} else {
CGraphics::SetTevOp(kTS_Stage1, CGraphics::kEnvPassThru);
}
} else {
CGraphics::SetTevOp(kTS_Stage0, CGraphics::kEnvPassThru);
CGraphics::SetTevOp(kTS_Stage1, CGraphics::kEnvPassThru);
}
CGX::SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
CGX::SetTevOrder(GX_TEVSTAGE1, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL);
CGX::SetNumTexGens(1);
CGX::SetNumChans(1);
CGX::SetNumIndStages(0);
CGX::SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY, false, GX_PTIDENTITY);
CGX::SetChanCtrl(CGX::Channel0, false, GX_SRC_REG, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_NONE,
GX_AF_NONE);
static const GXVtxDescList vtxDesc[4] = {
{GX_VA_POS, GX_DIRECT},
{GX_VA_CLR0, GX_DIRECT},
{GX_VA_TEX0, GX_DIRECT},
{GX_VA_NULL, GX_NONE},
};
CGX::SetVtxDescv(vtxDesc);
CGX::Begin(GX_TRIANGLESTRIP, GX_VTXFMT0, 4);
float y = 0.001f;
if (decal.x8_rotation == 0.f) {
// Vertex 0
GXPosition3f32(-size, y, size);
GXColor1u32(color.GetColor_u32());
GXTexCoord2f32(uvSet.xMin, uvSet.yMin);
// Vertex 1
GXPosition3f32(size, y, size);
GXColor1u32(color.GetColor_u32());
GXTexCoord2f32(uvSet.xMax, uvSet.yMin);
// Vertex 2
GXPosition3f32(-size, y, -size);
GXColor1u32(color.GetColor_u32());
GXTexCoord2f32(uvSet.xMin, uvSet.yMax);
// Vertex 3
GXPosition3f32(size, y, -size);
GXColor1u32(color.GetColor_u32());
GXTexCoord2f32(uvSet.xMax, uvSet.yMax);
} else {
CRelAngle ang = CRelAngle::FromDegrees(decal.x8_rotation);
float sinSize = sine(ang) * size;
float cosSize = cosine(ang) * size;
// Vertex 0
GXPosition3f32(sinSize - cosSize, y, cosSize + sinSize);
GXColor1u32(color.GetColor_u32());
GXTexCoord2f32(uvSet.xMin, uvSet.yMin);
// Vertex 1
GXPosition3f32(cosSize + sinSize, y, cosSize - sinSize);
GXColor1u32(color.GetColor_u32());
GXTexCoord2f32(uvSet.xMax, uvSet.yMin);
// Vertex 2
GXPosition3f32(-(cosSize + sinSize), y, -(cosSize - sinSize));
GXColor1u32(color.GetColor_u32());
GXTexCoord2f32(uvSet.xMin, uvSet.yMax);
// Vertex 3
GXPosition3f32(-sinSize + cosSize, y, -cosSize - sinSize);
GXColor1u32(color.GetColor_u32());
GXTexCoord2f32(uvSet.xMax, uvSet.yMax);
}
CGX::End();
if (redToAlpha) {
GXSetTevSwapMode(GX_TEVSTAGE1, GX_TEV_SWAP0, GX_TEV_SWAP0);
CGX::SetAlphaCompare(GX_ALWAYS, 0, GX_AOP_OR, GX_ALWAYS, 0);
}
}
void CDecal::RenderQuad(CQuadDecal& quad, const CDecalDescription::SQuadDescr& quadDesc) const {}
void CDecal::RenderMdl() const {}
void CDecal::Render() const {
CGlobalRandom gr(sDecalRandom);
if (x5c_flags == 7) {
if (IsDone()) {
return;
}
CGraphics::DisableAllLights();
CParticleGlobals::SetEmitterTime(x58_frameIdx);
ProcessQuad(const_cast< CQuadDecal& >(x3c_quad1), x0_description->x0_quad1, 1);
ProcessQuad(const_cast< CQuadDecal& >(x48_quad2), x0_description->x1c_quad2, 2);
if (x0_description->x38_DMDL && (x5c_flags & 4) == 0) {
CParticleGlobals::SetParticleLifetime(x54_modelLifetime);
CParticleGlobals::UpdateParticleLifetimeTweenValues(x58_frameIdx);
RenderMdl();
}
}
void CDecal::Update(float dt) {
if (x58_frameIdx >= x3c_quad1.GetLifetime()) {
x5c_flags |= 1;