Begin transitioning CElementGen RenderParticles & many fixes

This commit is contained in:
Luke Street 2022-03-20 16:24:02 -04:00
parent a42769627c
commit fcfa9f0d64
28 changed files with 448 additions and 280 deletions

View File

@ -365,14 +365,14 @@ u32 CCubeMaterial::HandleAnimatedUV(const u32* uvAnim, GX::TexMtx texMtx, GX::PT
const float* params = reinterpret_cast<const float*>(uvAnim + 1);
switch (type) {
case 0: {
auto xf = CGraphics::g_GXModelViewInvXpose;
auto xf = CGraphics::g_ViewMatrix.inverse().multiplyIgnoreTranslation(CGraphics::g_GXModelMatrix);
xf.origin.zeroOut();
GXLoadTexMtxImm(&xf, texMtx, GX::MTX3x4);
GXLoadTexMtxImm(&MvPostXf, pttTexMtx, GX::MTX3x4);
return 1;
}
case 1: {
auto xf = CGraphics::g_GXModelViewInvXpose;
xf.origin = CGraphics::g_ViewMatrix.inverse() * CGraphics::g_GXModelMatrix.origin;
auto xf = CGraphics::g_ViewMatrix.inverse() * CGraphics::g_GXModelMatrix;
GXLoadTexMtxImm(&xf, texMtx, GX::MTX3x4);
GXLoadTexMtxImm(&MvPostXf, pttTexMtx, GX::MTX3x4);
return 1;

View File

@ -902,7 +902,7 @@ void CCubeRenderer::SetupCGraphicsState() {
void CCubeRenderer::SetupRendererStates(bool depthWrite) {
CGraphics::DisableAllLights();
CGraphics::SetModelMatrix({});
CGraphics::SetAmbientColor(zeus::skBlack);
CGraphics::SetAmbientColor(zeus::skClear);
CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, depthWrite);
CCubeMaterial::ResetCachedMaterials();
GXSetTevColor(GX::TEVREG1, x2fc_tevReg1Color);

View File

@ -25,6 +25,14 @@ const CTevPass skPassThru{
{GX::TevColorArg::CC_ZERO, GX::TevColorArg::CC_ZERO, GX::TevColorArg::CC_ZERO, GX::TevColorArg::CC_RASC},
{GX::TevAlphaArg::CA_ZERO, GX::TevAlphaArg::CA_ZERO, GX::TevAlphaArg::CA_ZERO, GX::TevAlphaArg::CA_RASA},
};
const CTevPass sTevPass804bfcc0{
{GX::TevColorArg::CC_C0, GX::TevColorArg::CC_TEXC, GX::TevColorArg::CC_RASC, GX::TevColorArg::CC_ZERO},
{GX::TevAlphaArg::CA_ZERO, GX::TevAlphaArg::CA_ZERO, GX::TevAlphaArg::CA_ZERO, GX::TevAlphaArg::CA_RASA},
};
const CTevPass sTevPass804bfe68{
{GX::TevColorArg::CC_ZERO, GX::TevColorArg::CC_CPREV, GX::TevColorArg::CC_RASC, GX::TevColorArg::CC_ZERO},
{GX::TevAlphaArg::CA_ZERO, GX::TevAlphaArg::CA_APREV, GX::TevAlphaArg::CA_RASA, GX::TevAlphaArg::CA_ZERO},
};
const CTevPass sTevPass805a5698{
{GX::TevColorArg::CC_ZERO, GX::TevColorArg::CC_RASC, GX::TevColorArg::CC_C0, GX::TevColorArg::CC_ZERO},
{GX::TevAlphaArg::CA_ZERO, GX::TevAlphaArg::CA_RASA, GX::TevAlphaArg::CA_A0, GX::TevAlphaArg::CA_ZERO},
@ -49,10 +57,6 @@ const CTevPass sTevPass805a5fa0{
{GX::TevColorArg::CC_ZERO, GX::TevColorArg::CC_ZERO, GX::TevColorArg::CC_ZERO, GX::TevColorArg::CC_TEXC},
{GX::TevAlphaArg::CA_ZERO, GX::TevAlphaArg::CA_ZERO, GX::TevAlphaArg::CA_ZERO, GX::TevAlphaArg::CA_TEXA},
};
const CTevPass sTevPass804bfcc0{
{GX::TevColorArg::CC_C0, GX::TevColorArg::CC_TEXC, GX::TevColorArg::CC_RASC, GX::TevColorArg::CC_ZERO},
{GX::TevAlphaArg::CA_ZERO, GX::TevAlphaArg::CA_ZERO, GX::TevAlphaArg::CA_ZERO, GX::TevAlphaArg::CA_RASA},
};
const CTevPass sTevPass805a5fec{
{GX::TevColorArg::CC_ZERO, GX::TevColorArg::CC_ZERO, GX::TevColorArg::CC_ZERO, GX::TevColorArg::CC_RASC},
{GX::TevAlphaArg::CA_ZERO, GX::TevAlphaArg::CA_TEXA, GX::TevAlphaArg::CA_RASA, GX::TevAlphaArg::CA_ZERO},

View File

@ -102,13 +102,14 @@ public:
};
extern const CTevPass skPassThru;
extern const CTevPass sTevPass804bfcc0;
extern const CTevPass sTevPass804bfe68;
extern const CTevPass sTevPass805a5698;
extern const CTevPass sTevPass805a5e70;
extern const CTevPass sTevPass805a5ebc;
extern const CTevPass sTevPass805a5f08;
extern const CTevPass sTevPass805a5f54;
extern const CTevPass sTevPass805a5fa0;
extern const CTevPass sTevPass804bfcc0;
extern const CTevPass sTevPass805a5fec;
extern const CTevPass sTevPass805a6038;
extern const CTevPass sTevPass805a6084;

View File

@ -145,7 +145,7 @@ void CBloodFlower::LaunchPollenProjectile(const zeus::CTransform& xf, CStateMana
void CBloodFlower::Render(CStateManager& mgr) {
CPatterned::Render(mgr);
x574_podEffect->Render(GetActorLights());
x574_podEffect->Render();
}
EWeaponCollisionResponseTypes CBloodFlower::GetCollisionResponseType(const zeus::CVector3f&, const zeus::CVector3f&,

View File

@ -125,8 +125,10 @@ void CBurrower::AddToRenderer(const zeus::CFrustum& frustum, CStateManager& mgr)
}
void CBurrower::Render(CStateManager& mgr) {
if (GetActorLights() != nullptr && x674_jumpParticle) {
x674_jumpParticle->Render(GetActorLights());
auto* lights = GetActorLights();
if (lights != nullptr && x674_jumpParticle) {
lights->ActivateLights();
x674_jumpParticle->Render();
}
CPatterned::Render(mgr);
}

View File

@ -154,7 +154,7 @@ void CPuddleSpore::Render(CStateManager& mgr) {
CPatterned::Render(mgr);
if (x56c_ > 0.01f) {
for (const auto& elemGen : x5dc_elemGens)
elemGen->Render(GetActorLights());
elemGen->Render();
}
}

View File

@ -837,15 +837,7 @@ u32 CElementGen::GetSystemCount() const {
return ret + (x25c_activeParticleCount != 0);
}
void CElementGen::Render(const CActorLights* actorLights) {
// Check to make sure our buffers are ready to render
// if (!x26c_31_LINE) {
// return;
// }
// if (x28_loadedGenDesc->x45_24_x31_26_PMUS) { // && (!m_instBufPmus || !m_uniformBufPmus)
// return;
// }
void CElementGen::Render() {
SCOPED_GRAPHICS_DEBUG_GROUP(fmt::format(FMT_STRING("CElementGen::Render {}"), *x1c_genDesc.GetObjectTag()).c_str(),
zeus::skYellow);
@ -855,35 +847,27 @@ void CElementGen::Render(const CActorLights* actorLights) {
CGraphics::DisableAllLights();
for (std::unique_ptr<CParticleGen>& child : x290_activePartChildren)
child->Render(actorLights);
child->Render();
CParticleGlobals::SParticleSystem* prevSystem = CParticleGlobals::instance()->m_currentParticleSystem;
CParticleGlobals::SParticleSystem thisSystem{FOURCC('PART'), this};
CParticleGlobals::instance()->m_currentParticleSystem = &thisSystem;
if (x30_particles.size()) {
SParticleModel& pmdl = desc->x5c_x48_PMDL;
if (pmdl || desc->x45_24_x31_26_PMUS)
RenderModels(actorLights);
if (x26c_31_LINE)
if (!x30_particles.empty()) {
if (desc->x5c_x48_PMDL || desc->x45_24_x31_26_PMUS) {
RenderModels();
}
if (x26c_31_LINE) {
RenderLines();
else
} else {
RenderParticles();
}
}
CParticleGlobals::instance()->m_currentParticleSystem = prevSystem;
}
void CElementGen::RenderModels(const CActorLights* actorLights) {
// Check to make sure our buffers are ready to render
// if (!x26c_31_LINE) { // && (!m_instBuf || !m_uniformBuf)
// return;
// }
// if (x28_loadedGenDesc->x45_24_x31_26_PMUS) { // && (!m_instBufPmus || !m_uniformBufPmus)
// return;
// }
void CElementGen::RenderModels() {
CParticleGlobals::instance()->m_particleAccessParameters = nullptr;
if (x26d_26_modelsUseLights) {
CGraphics::SetLightState(x274_backupLightActive);
@ -959,29 +943,6 @@ void CElementGen::RenderModels(const CActorLights* actorLights) {
CGraphics::SetTevOp(ERglTevStage::Stage0, CTevCombiners::skPassThru);
CGraphics::SetTevOp(ERglTevStage::Stage1, CTevCombiners::skPassThru);
}
// switch (m_shaderClass) {
// case CElementGenShaders::EShaderClass::Tex:
// g_instTexData.clear();
// g_instTexData.reserve(x30_particles.size());
// break;
// case CElementGenShaders::EShaderClass::NoTex:
// g_instNoTexData.clear();
// g_instNoTexData.reserve(x30_particles.size());
// break;
// default:
// Log.report(logvisor::Fatal, FMT_STRING("unexpected particle shader class"));
// break;
// }
// SParticleUniforms uniformData = {CGraphics::GetPerspectiveProjectionMatrix(/*true*/), {1.f, 1.f, 1.f, 1.f}};
// m_uniformBufPmus->load(&uniformData, sizeof(SParticleUniforms));
//
// if (moveRedToAlphaBuffer)
// CGraphics::SetShaderDataBinding(m_redToAlphaDataBindPmus[g_Renderer->IsThermalVisorHotPass()]);
// else
// CGraphics::SetShaderDataBinding(m_normalDataBindPmus[g_Renderer->IsThermalVisorHotPass()]);
}
zeus::CTransform orient = zeus::CTransform();
@ -1122,6 +1083,7 @@ void CElementGen::RenderModels(const CActorLights* actorLights) {
}
CGraphics::SetCullMode(ERglCullMode::Front);
CTevCombiners::ResetStates();
if (moveRedToAlphaBuffer) {
GXSetTevSwapMode(GX::TEVSTAGE1, GX::TEV_SWAP0, GX::TEV_SWAP0);
}
@ -1231,9 +1193,7 @@ void CElementGen::RenderParticles() {
CGenDescription* desc = x1c_genDesc.GetObj();
CGlobalRandom gr(x27c_randState);
CUVElement* texr = desc->x54_x40_TEXR.get();
CUVElement* tind = desc->x58_x44_TIND.get();
if (texr && tind) {
if (IsIndirectTextured()) {
RenderParticlesIndirectTexture();
return;
}
@ -1249,6 +1209,8 @@ void CElementGen::RenderParticles() {
}
}
bool hasModuColor = x338_moduColor != zeus::skBlack; // TODO skClear?
CGraphics::SetCullMode(ERglCullMode::None);
zeus::CTransform systemModelMatrix(CGraphics::g_ViewMatrix);
systemModelMatrix.origin.zeroOut();
zeus::CTransform systemCameraMatrix = systemModelMatrix.inverse() * x22c_globalOrientation;
@ -1260,32 +1222,116 @@ void CElementGen::RenderParticles() {
else
CGraphics::SetModelMatrix(systemModelMatrix);
CGraphics::SetAlphaCompare(ERglAlphaFunc::Always, 0, ERglAlphaOp::And, ERglAlphaFunc::Always, 0);
CGraphics::SetAlphaCompare(ERglAlphaFunc::Greater, 0, ERglAlphaOp::And, ERglAlphaFunc::Always, 0);
SUVElementSet uvs = {0.f, 0.f, 1.f, 1.f};
bool constUVs = true;
CTexture* cachedTex = nullptr;
// SParticleUniforms uniformData = {CGraphics::GetPerspectiveProjectionMatrix(/*true*/) *
// CGraphics::g_GXModelView.toMatrix4f(),
// {1.f, 1.f, 1.f, 1.f}};
auto* rota = x28_loadedGenDesc->x50_x3c_ROTA.get();
bool noRota = rota == nullptr;
if (rota != nullptr && rota->IsConstant()) {
float value = 1.f;
rota->GetValue(0, value);
if (value == 0.f) {
value = 1.f;
rota->GetValue(1, value);
if (value == 0.f) {
noRota = true;
}
}
}
if (texr) {
auto* texr = x28_loadedGenDesc->x54_x40_TEXR.get();
if (texr != nullptr) {
CParticle& target = x30_particles[0];
int partFrame = x74_curFrame - target.x28_startFrame;
cachedTex = texr->GetValueTexture(partFrame).GetObj();
cachedTex->Load(GX::TEXMAP0, EClampMode::Repeat);
if (x338_moduColor != zeus::skBlack) {
CGraphics::SetTevOp(ERglTevStage::Stage0, CTevCombiners::sTevPass805a5ebc);
if (hasModuColor) {
/* Add RASC * PREVC pass for MODU color loaded into channel mat-color */
// uniformData.moduColor = x338_moduColor;
CGraphics::SetTevOp(ERglTevStage::Stage1, CTevCombiners::sTevPass804bfe68);
} else {
CGraphics::SetTevOp(ERglTevStage::Stage1, CTevCombiners::skPassThru);
}
texr->GetValueUV(partFrame, uvs);
constUVs = texr->HasConstantUV();
} else {
CGraphics::SetTevOp(ERglTevStage::Stage0, CTevCombiners::skPassThru);
CGraphics::SetTevOp(ERglTevStage::Stage1, CTevCombiners::skPassThru);
}
// m_uniformBuf->load(&uniformData, sizeof(SParticleUniforms));
constexpr std::array vtxDescList{
GX::VtxDescList{GX::VA_POS, GX::DIRECT},
GX::VtxDescList{GX::VA_CLR0, GX::DIRECT},
GX::VtxDescList{GX::VA_TEX0, GX::DIRECT},
GX::VtxDescList{},
};
CGX::SetVtxDescv(vtxDescList.data());
GX::TevStageID nextStage;
if (hasModuColor) {
CGX::SetNumChans(2);
nextStage = GX::TEVSTAGE2;
CGX::SetTevOrder(GX::TEVSTAGE1, GX::TEXCOORD_NULL, GX::TEXMAP_NULL, GX::COLOR1A1);
CGX::SetChanAmbColor(CGX::EChannelId::Channel1, zeus::skBlack);
CGX::SetChanMatColor(CGX::EChannelId::Channel1, x338_moduColor);
CGX::SetChanCtrl(CGX::EChannelId::Channel1, {});
} else {
CGX::SetNumChans(1);
nextStage = GX::TEVSTAGE1;
}
bool moveRedToAlphaBuffer = sMoveRedToAlphaBuffer;
if (g_subtractBlend) {
CGraphics::SetDepthWriteMode(x26c_28_zTest, ERglEnum::LEqual, false);
CGX::SetBlendMode(GX::BM_SUBTRACT, GX::BL_ONE, GX::BL_ZERO, GX::LO_CLEAR);
if (moveRedToAlphaBuffer) {
CGX::SetTevColorIn(nextStage, GX::CC_ZERO, GX::CC_CPREV, GX::CC_APREV, GX::CC_ZERO);
CGX::SetTevAlphaIn(nextStage, GX::CA_ZERO, GX::CA_TEXA, GX::CA_APREV, GX::CA_ZERO);
CGX::SetStandardTevColorAlphaOp(nextStage);
CGX::SetTevOrder(nextStage, GX::TEXCOORD0, GX::TEXMAP0, GX::COLOR_NULL);
GXSetTevSwapMode(nextStage, GX::TEV_SWAP0, GX::TEV_SWAP1);
nextStage = GX::TevStageID(nextStage + 1);
}
} else if (moveRedToAlphaBuffer) {
CGraphics::SetDepthWriteMode(x26c_28_zTest, ERglEnum::LEqual, false);
CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::One, ERglBlendFactor::One, ERglLogicOp::Clear);
CGX::SetTevColorIn(nextStage, GX::CC_ZERO, GX::CC_CPREV, GX::CC_APREV, GX::CC_ZERO);
CGX::SetTevAlphaIn(nextStage, GX::CA_ZERO, GX::CA_TEXA, GX::CA_APREV, GX::CA_ZERO);
CGX::SetStandardTevColorAlphaOp(nextStage);
CGX::SetTevOrder(nextStage, GX::TEXCOORD0, GX::TEXMAP0, GX::COLOR_NULL);
GXSetTevSwapMode(nextStage, GX::TEV_SWAP0, GX::TEV_SWAP1);
nextStage = GX::TevStageID(nextStage + 1);
} else if (x26c_26_AAPH) {
CGraphics::SetDepthWriteMode(x26c_28_zTest, ERglEnum::LEqual, false);
CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::One, ERglLogicOp::Clear);
} else {
CGraphics::SetDepthWriteMode(x26c_28_zTest, ERglEnum::LEqual, x26c_27_ZBUF);
CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::InvSrcAlpha,
ERglLogicOp::Clear);
}
CGX::SetNumTevStages(nextStage);
CGX::SetNumTexGens(1);
CGX::SetTevOrder(GX::TEVSTAGE0, GX::TEXCOORD0, GX::TEXMAP0, GX::COLOR0A0);
CGX::SetChanCtrl(CGX::EChannelId::Channel0, false, GX::SRC_REG, GX::SRC_VTX, {}, GX::DF_NONE, GX::AF_NONE);
CGX::SetTexCoordGen(GX::TEXCOORD0, GX::TG_MTX2x4, GX::TG_TEX0, GX::IDENTITY, false, GX::PTIDENTITY);
// GXSetVtxAttrFmt(GX::VTXFMT6, GX::VA_POS, GX::POS_XYZ, GX::F32, 0);
// GXSetVtxAttrFmt(GX::VTXFMT6, GX::VA_CLR0, GX::CLR_RGBA, GX::RGBA8, 0);
// if (constUVs) {
// GXSetVtxAttrFmt(GX::VTXFMT6, GX::VA_TEX0, GX::TEX_ST, GX::RGBA8, 1);
// } else {
// GXSetVtxAttrFmt(GX::VTXFMT6, GX::VA_TEX0, GX::TEX_ST, GX::F32, 0);
// }
int mbspVal = std::max(1, x270_MBSP);
if (x26c_30_MBLR) {
CGX::Begin(GX::QUADS, GX::VTXFMT6, mbspVal * x30_particles.size() * 4);
} else {
CGX::Begin(GX::QUADS, GX::VTXFMT6, mbspVal * 4);
}
std::vector<CParticleListItem> sortItems;
if (desc->x44_28_x30_28_SORT) {
@ -1304,70 +1350,21 @@ void CElementGen::RenderParticles() {
});
}
bool moveRedToAlphaBuffer = false;
if (sMoveRedToAlphaBuffer && x26c_26_AAPH)
moveRedToAlphaBuffer = true;
if (g_subtractBlend) {
// FIXME should there be NoTex specializations for RedToAlpha?
// if (moveRedToAlphaBuffer && desc->x54_x40_TEXR)
// CGraphics::SetShaderDataBinding(m_redToAlphaSubDataBind[g_Renderer->IsThermalVisorHotPass()]);
// else
// CGraphics::SetShaderDataBinding(m_normalSubDataBind[g_Renderer->IsThermalVisorHotPass()]);
} else {
// if (moveRedToAlphaBuffer && desc->x54_x40_TEXR)
// CGraphics::SetShaderDataBinding(m_redToAlphaDataBind[g_Renderer->IsThermalVisorHotPass()]);
// else
// CGraphics::SetShaderDataBinding(m_normalDataBind[g_Renderer->IsThermalVisorHotPass()]);
}
int mbspVal = std::max(1, x270_MBSP);
CParticleGlobals::instance()->SetEmitterTime(x74_curFrame);
if (!x26c_30_MBLR) {
#if 0
if (!desc->x44_28_x30_28_SORT && constUVs && !x26c_29_ORNT)
{
if (!desc->x50_x3c_ROTA)
{
if (!zeus::close_enough(x80_timeDeltaScale, 1.f))
{
RenderBasicParticlesNoRotNoTS(systemCameraMatrix);
}
else
{
RenderBasicParticlesNoRotTS(systemCameraMatrix);
}
}
else
{
if (!zeus::close_enough(x80_timeDeltaScale, 1.f))
{
RenderBasicParticlesRotNoTS(systemCameraMatrix);
}
else
{
RenderBasicParticlesRotTS(systemCameraMatrix);
}
}
if (!desc->x44_28_x30_28_SORT && constUVs && !x26c_29_ORNT) {
if (noRota) {
if (zeus::close_enough(x80_timeDeltaScale, 1.f)) {
RenderBasicParticlesNoRotNoTS(systemCameraMatrix);
} else {
RenderBasicParticlesNoRotTS(systemCameraMatrix);
}
#endif
// switch (m_shaderClass) {
// case CElementGenShaders::EShaderClass::Tex:
// g_instTexData.clear();
// g_instTexData.reserve(x30_particles.size());
// break;
// case CElementGenShaders::EShaderClass::NoTex:
// g_instNoTexData.clear();
// g_instNoTexData.reserve(x30_particles.size());
// break;
// default:
// Log.report(logvisor::Fatal, FMT_STRING("unexpected particle shader class"));
// break;
// }
if (!x26c_29_ORNT) {
} else if (zeus::close_enough(x80_timeDeltaScale, 1.f)) {
RenderBasicParticlesRotNoTS(systemCameraMatrix);
} else {
RenderBasicParticlesRotTS(systemCameraMatrix);
}
} else if (!x26c_29_ORNT) {
for (size_t i = 0; i < x30_particles.size(); ++i) {
const int partIdx = desc->x44_28_x30_28_SORT ? sortItems[i].x0_partIdx : int(i);
CParticle& particle = x30_particles[partIdx];
@ -1382,75 +1379,42 @@ void CElementGen::RenderParticles() {
((particle.x4_pos - particle.x10_prevPos) * x80_timeDeltaScale + particle.x10_prevPos);
}
const float size = 0.5f * particle.x2c_lineLengthOrSize;
if (!constUVs) {
CParticleGlobals::instance()->SetParticleLifetime(particle.x0_endFrame - particle.x28_startFrame);
CParticleGlobals::instance()->UpdateParticleLifetimeTweenValues(partFrame);
texr->GetValueUV(partFrame, uvs);
}
const float size = 0.5f * particle.x2c_lineLengthOrSize;
if (0.f == particle.x30_lineWidthOrRota) {
// switch (m_shaderClass) {
// case CElementGenShaders::EShaderClass::Tex: {
// SParticleInstanceTex& inst = g_instTexData.emplace_back();
// inst.pos[0] = zeus::CVector4f{viewPoint.x() + size, viewPoint.y(), viewPoint.z() + size, 1.f};
// inst.pos[1] = zeus::CVector4f{viewPoint.x() - size, viewPoint.y(), viewPoint.z() + size, 1.f};
// inst.pos[2] = zeus::CVector4f{viewPoint.x() + size, viewPoint.y(), viewPoint.z() - size, 1.f};
// inst.pos[3] = zeus::CVector4f{viewPoint.x() - size, viewPoint.y(), viewPoint.z() - size, 1.f};
// inst.color = particle.x34_color;
// inst.uvs[0] = {uvs.xMax, uvs.yMax};
// inst.uvs[1] = {uvs.xMin, uvs.yMax};
// inst.uvs[2] = {uvs.xMax, uvs.yMin};
// inst.uvs[3] = {uvs.xMin, uvs.yMin};
// break;
// }
// case CElementGenShaders::EShaderClass::NoTex: {
// SParticleInstanceNoTex& inst = g_instNoTexData.emplace_back();
// inst.pos[0] = zeus::CVector4f{viewPoint.x() + size, viewPoint.y(), viewPoint.z() + size, 1.f};
// inst.pos[1] = zeus::CVector4f{viewPoint.x() - size, viewPoint.y(), viewPoint.z() + size, 1.f};
// inst.pos[2] = zeus::CVector4f{viewPoint.x() + size, viewPoint.y(), viewPoint.z() - size, 1.f};
// inst.pos[3] = zeus::CVector4f{viewPoint.x() - size, viewPoint.y(), viewPoint.z() - size, 1.f};
// inst.color = particle.x34_color;
// break;
// }
// default:
// break;
// }
if (noRota) {
GXPosition3f32(viewPoint.x() + size, viewPoint.y(), viewPoint.z() + size);
GXColor4f32(particle.x34_color);
GXTexCoord2f32(uvs.xMax, uvs.yMax);
GXPosition3f32(viewPoint.x() - size, viewPoint.y(), viewPoint.z() + size);
GXColor4f32(particle.x34_color);
GXTexCoord2f32(uvs.xMin, uvs.yMax);
GXPosition3f32(viewPoint.x() - size, viewPoint.y(), viewPoint.z() - size);
GXColor4f32(particle.x34_color);
GXTexCoord2f32(uvs.xMin, uvs.yMin);
GXPosition3f32(viewPoint.x() + size, viewPoint.y(), viewPoint.z() - size);
GXColor4f32(particle.x34_color);
GXTexCoord2f32(uvs.xMax, uvs.yMin);
} else {
float theta = zeus::degToRad(particle.x30_lineWidthOrRota);
float sinT = std::sin(theta) * size;
float cosT = std::cos(theta) * size;
// switch (m_shaderClass) {
// case CElementGenShaders::EShaderClass::Tex: {
// SParticleInstanceTex& inst = g_instTexData.emplace_back();
// inst.pos[0] = zeus::CVector4f{viewPoint.x() + sinT + cosT, viewPoint.y(), viewPoint.z() + cosT - sinT, 1.f};
// inst.pos[1] = zeus::CVector4f{viewPoint.x() + sinT - cosT, viewPoint.y(), viewPoint.z() + sinT + cosT, 1.f};
// inst.pos[2] =
// zeus::CVector4f{viewPoint.x() + (cosT - sinT), viewPoint.y(), viewPoint.z() + (-cosT - sinT), 1.f};
// inst.pos[3] =
// zeus::CVector4f{viewPoint.x() - (sinT + cosT), viewPoint.y(), viewPoint.z() - (cosT - sinT), 1.f};
// inst.color = particle.x34_color;
// inst.uvs[0] = {uvs.xMax, uvs.yMax};
// inst.uvs[1] = {uvs.xMin, uvs.yMax};
// inst.uvs[2] = {uvs.xMax, uvs.yMin};
// inst.uvs[3] = {uvs.xMin, uvs.yMin};
// break;
// }
// case CElementGenShaders::EShaderClass::NoTex: {
// SParticleInstanceNoTex& inst = g_instNoTexData.emplace_back();
// inst.pos[0] = zeus::CVector4f{viewPoint.x() + sinT + cosT, viewPoint.y(), viewPoint.z() + cosT - sinT, 1.f};
// inst.pos[1] = zeus::CVector4f{viewPoint.x() + sinT - cosT, viewPoint.y(), viewPoint.z() + sinT + cosT, 1.f};
// inst.pos[2] =
// zeus::CVector4f{viewPoint.x() + (cosT - sinT), viewPoint.y(), viewPoint.z() + (-cosT - sinT), 1.f};
// inst.pos[3] =
// zeus::CVector4f{viewPoint.x() - (sinT + cosT), viewPoint.y(), viewPoint.z() - (cosT - sinT), 1.f};
// inst.color = particle.x34_color;
// break;
// }
// default:
// break;
// }
const float theta = zeus::degToRad(particle.x30_lineWidthOrRota);
const float sinT = std::sin(theta) * size;
const float cosT = std::cos(theta) * size;
GXPosition3f32(viewPoint.x() + (sinT + cosT), viewPoint.y(), viewPoint.z() + (cosT - sinT));
GXColor4f32(particle.x34_color);
GXTexCoord2f32(uvs.xMax, uvs.yMax);
GXPosition3f32(viewPoint.x() + (sinT - cosT), viewPoint.y(), viewPoint.z() + (sinT + cosT));
GXColor4f32(particle.x34_color);
GXTexCoord2f32(uvs.xMin, uvs.yMax);
GXPosition3f32(viewPoint.x() - (sinT + cosT), viewPoint.y(), viewPoint.z() - (cosT - sinT));
GXColor4f32(particle.x34_color);
GXTexCoord2f32(uvs.xMin, uvs.yMin);
GXPosition3f32(viewPoint.x() + (-sinT + cosT), viewPoint.y(), viewPoint.z() + (-cosT - sinT));
GXColor4f32(particle.x34_color);
GXTexCoord2f32(uvs.xMax, uvs.yMin);
}
}
} else {
@ -1656,6 +1620,8 @@ void CElementGen::RenderParticles() {
break;
}
}
CGraphics::SetCullMode(ERglCullMode::Front);
CGraphics::SetAlphaCompare(ERglAlphaFunc::Always, 0, ERglAlphaOp::And, ERglAlphaFunc::Always, 0);
}
void CElementGen::RenderParticlesIndirectTexture() {
@ -1965,4 +1931,85 @@ void CElementGen::Reset() {
void CElementGen::SetMoveRedToAlphaBuffer(bool move) { sMoveRedToAlphaBuffer = move; }
void CElementGen::RenderBasicParticlesNoRotNoTS(const zeus::CTransform& xf) noexcept {
for (const auto& particle : x30_particles) {
const auto pos = xf * particle.x4_pos;
const auto size = 0.5f * particle.x2c_lineLengthOrSize;
GXPosition3f32(pos.x() + size, pos.y(), pos.z() + size);
GXColor4f32(particle.x34_color);
GXTexCoord2f32(1.f, 1.f);
GXPosition3f32(pos.x() - size, pos.y(), pos.z() + size);
GXColor4f32(particle.x34_color);
GXTexCoord2f32(0.f, 1.f);
GXPosition3f32(pos.x() - size, pos.y(), pos.z() - size);
GXColor4f32(particle.x34_color);
GXTexCoord2f32(0.f, 0.f);
GXPosition3f32(pos.x() + size, pos.y(), pos.z() - size);
GXColor4f32(particle.x34_color);
GXTexCoord2f32(1.f, 0.f);
}
}
void CElementGen::RenderBasicParticlesNoRotTS(const zeus::CTransform& xf) noexcept {
for (const auto& particle : x30_particles) {
const auto pos = xf * (x80_timeDeltaScale * (particle.x4_pos - particle.x10_prevPos) + particle.x10_prevPos);
const auto size = 0.5f * particle.x2c_lineLengthOrSize;
GXPosition3f32(pos.x() + size, pos.y(), pos.z() + size);
GXColor4f32(particle.x34_color);
GXTexCoord2f32(1.f, 1.f);
GXPosition3f32(pos.x() - size, pos.y(), pos.z() + size);
GXColor4f32(particle.x34_color);
GXTexCoord2f32(0.f, 1.f);
GXPosition3f32(pos.x() - size, pos.y(), pos.z() - size);
GXColor4f32(particle.x34_color);
GXTexCoord2f32(0.f, 0.f);
GXPosition3f32(pos.x() + size, pos.y(), pos.z() - size);
GXColor4f32(particle.x34_color);
GXTexCoord2f32(1.f, 0.f);
}
}
void CElementGen::RenderBasicParticlesRotNoTS(const zeus::CTransform& xf) noexcept {
for (const auto& particle : x30_particles) {
const auto pos = xf * particle.x4_pos;
const auto size = 0.5f * particle.x2c_lineLengthOrSize;
const float theta = zeus::degToRad(particle.x30_lineWidthOrRota);
const float sinT = std::sin(theta) * size;
const float cosT = std::cos(theta) * size;
GXPosition3f32(pos.x() + (sinT + cosT), pos.y(), pos.z() + (cosT - sinT));
GXColor4f32(particle.x34_color);
GXTexCoord2f32(1.f, 1.f);
GXPosition3f32(pos.x() + (sinT - cosT), pos.y(), pos.z() + (sinT + cosT));
GXColor4f32(particle.x34_color);
GXTexCoord2f32(0.f, 1.f);
GXPosition3f32(pos.x() - (sinT + cosT), pos.y(), pos.z() - (cosT - sinT));
GXColor4f32(particle.x34_color);
GXTexCoord2f32(0.f, 0.f);
GXPosition3f32(pos.x() + (-sinT + cosT), pos.y(), pos.z() + (-cosT - sinT));
GXColor4f32(particle.x34_color);
GXTexCoord2f32(1.f, 0.f);
}
}
void CElementGen::RenderBasicParticlesRotTS(const zeus::CTransform& xf) noexcept {
for (const auto& particle : x30_particles) {
const auto pos = xf * (x80_timeDeltaScale * (particle.x4_pos - particle.x10_prevPos) + particle.x10_prevPos);
const auto size = 0.5f * particle.x2c_lineLengthOrSize;
const float theta = zeus::degToRad(particle.x30_lineWidthOrRota);
const float sinT = std::sin(theta) * size;
const float cosT = std::cos(theta) * size;
GXPosition3f32(pos.x() + (sinT + cosT), pos.y(), pos.z() + (cosT - sinT));
GXColor4f32(particle.x34_color);
GXTexCoord2f32(1.f, 1.f);
GXPosition3f32(pos.x() + (sinT - cosT), pos.y(), pos.z() + (sinT + cosT));
GXColor4f32(particle.x34_color);
GXTexCoord2f32(0.f, 1.f);
GXPosition3f32(pos.x() - (sinT + cosT), pos.y(), pos.z() - (cosT - sinT));
GXColor4f32(particle.x34_color);
GXTexCoord2f32(0.f, 0.f);
GXPosition3f32(pos.x() + (-sinT + cosT), pos.y(), pos.z() + (-cosT - sinT));
GXColor4f32(particle.x34_color);
GXTexCoord2f32(1.f, 0.f);
}
}
} // namespace metaforce

View File

@ -184,13 +184,13 @@ public:
void SetExternalVar(int index, float var) { x9c_externalVars[index] = var; }
bool InternalUpdate(double dt);
void RenderModels(const CActorLights* actLights);
void RenderModels();
void RenderLines();
void RenderParticles();
void RenderParticlesIndirectTexture();
bool Update(double t) override;
void Render(const CActorLights* actorLights = nullptr) override;
void Render() override;
void SetOrientation(const zeus::CTransform& orientation) override;
void SetTranslation(const zeus::CVector3f& translation) override;
void SetGlobalOrientation(const zeus::CTransform& orientation) override;
@ -228,6 +228,12 @@ public:
std::vector<CParticle> const& GetParticles() const { return x30_particles; }
std::vector<CParticle>& GetParticles() { return x30_particles; }
private:
void RenderBasicParticlesNoRotNoTS(const zeus::CTransform& xf) noexcept;
void RenderBasicParticlesNoRotTS(const zeus::CTransform& xf) noexcept;
void RenderBasicParticlesRotNoTS(const zeus::CTransform& xf) noexcept;
void RenderBasicParticlesRotTS(const zeus::CTransform& xf) noexcept;
};
ENABLE_BITWISE_ENUM(CElementGen::EOptionalSystemFlags)

View File

@ -78,30 +78,51 @@ SElectricGeneratorDesc CParticleDataFactory::GetElectricGeneratorDesc(CInputStre
return resPool->GetObj({FOURCC('ELSC'), id});
}
static std::unique_ptr<CTexture> CreateTexture(u32 value) {
auto tex = std::make_unique<CTexture>(ETexelFormat::RGBA8, 4, 4, 1, "CUVElement Fallback Texture"sv);
auto* data = reinterpret_cast<u32*>(tex->Lock());
for (int i = 0; i < 4 * 4; ++i) {
data[i] = value;
}
tex->UnLock();
return tex;
}
std::unique_ptr<CUVElement> CParticleDataFactory::GetTextureElement(CInputStream& in, CSimplePool* resPool) {
FourCC clsId = GetClassID(in);
switch (clsId.toUint32()) {
case SBIG('CNST'): {
FourCC subId = GetClassID(in);
if (subId == SBIG('NONE'))
return nullptr;
CAssetId id = in.Get<CAssetId>();
TToken<CTexture> txtr = resPool->GetObj({FOURCC('TXTR'), id});
CAssetId id;
const auto subId = GetClassID(in);
if (subId != SBIG('NONE')) {
id = in.Get<CAssetId>();
}
TToken<CTexture> txtr;
if (id.IsValid()) {
txtr = resPool->GetObj({FOURCC('TXTR'), id});
} else {
txtr = CreateTexture(0xFFFFFFFF);
}
return std::make_unique<CUVEConstant>(std::move(txtr));
}
case SBIG('ATEX'): {
const FourCC subId = GetClassID(in);
if (subId == SBIG('NONE')) {
return nullptr;
CAssetId id;
const auto subId = GetClassID(in);
if (subId != SBIG('NONE')) {
id = in.Get<CAssetId>();
}
const CAssetId id = in.Get<CAssetId>();
auto a = GetIntElement(in);
auto b = GetIntElement(in);
auto c = GetIntElement(in);
auto d = GetIntElement(in);
auto e = GetIntElement(in);
const bool f = GetBool(in);
TToken<CTexture> txtr = resPool->GetObj({FOURCC('TXTR'), id});
TToken<CTexture> txtr;
if (id.IsValid()) {
txtr = resPool->GetObj({FOURCC('TXTR'), id});
} else {
txtr = CreateTexture(0xFFFFFFFF);
}
return std::make_unique<CUVEAnimTexture>(std::move(txtr), std::move(std::move(a)), std::move(b), std::move(c),
std::move(d), std::move(e), f);
}

View File

@ -607,7 +607,7 @@ bool CParticleElectric::Update(double dt) {
return ret;
}
void CParticleElectric::Render(const CActorLights* lights) {
void CParticleElectric::Render() {
SCOPED_GRAPHICS_DEBUG_GROUP(
fmt::format(FMT_STRING("CParticleElectric::Render {}"), *x1c_elecDesc.GetObjectTag()).c_str(), zeus::skYellow);
@ -625,13 +625,13 @@ void CParticleElectric::Render(const CActorLights* lights) {
if (x450_25_haveGPSM) {
for (int i = 0; i < x154_SCNT; ++i) {
x400_gpsmGenerators[i]->Render(lights);
x400_gpsmGenerators[i]->Render();
}
}
if (x450_26_haveEPSM) {
for (int i = 0; i < x154_SCNT; ++i) {
x410_epsmGenerators[i]->Render(lights);
x410_epsmGenerators[i]->Render();
}
}
}

View File

@ -112,7 +112,7 @@ public:
explicit CParticleElectric(const TToken<CElectricDescription>& desc);
bool Update(double) override;
void Render(const CActorLights* lights = nullptr) override;
void Render() override;
void SetOrientation(const zeus::CTransform& orientation) override;
void SetTranslation(const zeus::CVector3f& translation) override;
void SetGlobalOrientation(const zeus::CTransform& orientation) override;

View File

@ -34,7 +34,7 @@ public:
virtual ~CParticleGen() = default;
virtual bool Update(double) = 0;
virtual void Render(const CActorLights* = nullptr) = 0;
virtual void Render() = 0;
virtual void SetOrientation(const zeus::CTransform&) = 0;
virtual void SetTranslation(const zeus::CVector3f&) = 0;
virtual void SetGlobalOrientation(const zeus::CTransform&) = 0;

View File

@ -928,7 +928,7 @@ void CParticleSwoosh::Render2SidedNoSplineNoGaps() {
// CGraphics::DrawArray(drawStart, m_cachedVerts.size() - drawStart);
}
void CParticleSwoosh::Render(const CActorLights*) {
void CParticleSwoosh::Render() {
if (x1b4_LENG < 2 || x1ac_particleCount <= 1) {
return;
}

View File

@ -136,7 +136,7 @@ public:
CSwooshDescription* GetDesc() { return x1c_desc.GetObj(); }
bool Update(double) override;
void Render(const CActorLights* = nullptr) override;
void Render() override;
void SetOrientation(const zeus::CTransform&) override;
void SetTranslation(const zeus::CVector3f&) override;
void SetGlobalOrientation(const zeus::CTransform&) override;

View File

@ -241,9 +241,9 @@ void CWaveBuster::RenderParticles() {
}
x38c_busterSparksGen->SetParticleEmission(false);
x384_busterSwoosh1Gen->Render(GetActorLights());
x388_busterSwoosh2Gen->Render(GetActorLights());
x38c_busterSparksGen->Render(GetActorLights());
x384_busterSwoosh1Gen->Render();
x388_busterSwoosh2Gen->Render();
x38c_busterSparksGen->Render();
}
void CWaveBuster::RenderBeam() {

View File

@ -525,8 +525,8 @@ float CActor::GetPitch() const { return zeus::CQuaternion(x34_transform.buildMat
float CActor::GetYaw() const { return zeus::CQuaternion(x34_transform.buildMatrix3f()).yaw(); }
void CActor::EnsureRendered(const CStateManager& mgr) {
const zeus::CAABox aabb = GetSortingBounds(mgr);
EnsureRendered(mgr, aabb.closestPointAlongVector(CGraphics::g_ViewMatrix.basis[1]), aabb);
const auto bounds = GetSortingBounds(mgr);
EnsureRendered(mgr, bounds.closestPointAlongVector(CGraphics::g_ViewMatrix.frontVector()), bounds);
}
void CActor::EnsureRendered(const CStateManager& stateMgr, const zeus::CVector3f& pos, const zeus::CAABox& aabb) {

View File

@ -249,18 +249,16 @@ void CScriptEffect::AddToRenderer(const zeus::CFrustum& frustum, CStateManager&
}
void CScriptEffect::Render(CStateManager& mgr) {
/* The following code is kept for reference, this is now performed in CElementGen
if (x138_actorLights)
x138_actorLights->ActivateLights();
*/
if (x138_actorLights) {
x138_actorLights->ActivateLights();
}
if (x104_particleSystem && x104_particleSystem->GetParticleCountAll() > 0) {
g_NumParticlesRendered += x104_particleSystem->GetParticleCountAll();
x104_particleSystem->Render(x138_actorLights.get());
x104_particleSystem->Render();
}
if (xf4_electric && xf4_electric->GetParticleCount() > 0) {
g_NumParticlesRendered += xf4_electric->GetParticleCount();
xf4_electric->Render(x138_actorLights.get());
xf4_electric->Render();
}
}
@ -348,14 +346,12 @@ void CScriptEffect::CalculateRenderBounds() {
}
if (particleBounds || electricBounds) {
zeus::CAABox renderBounds = zeus::CAABox();
zeus::CAABox renderBounds;
if (particleBounds) {
renderBounds.accumulateBounds(particleBounds->min);
renderBounds.accumulateBounds(particleBounds->max);
renderBounds.accumulateBounds(*particleBounds);
}
if (electricBounds) {
renderBounds.accumulateBounds(electricBounds->min);
renderBounds.accumulateBounds(electricBounds->max);
renderBounds.accumulateBounds(*electricBounds);
}
x9c_renderBounds = renderBounds;
x111_26_canRender = true;

View File

@ -510,30 +510,30 @@ void CScriptGunTurret::Render(CStateManager& mgr) {
case ETurretState::DeactiveFromReady:
case ETurretState::Deactivating:
case ETurretState::DeactivatingFromReady:
x470_deactivateLight->Render(x90_actorLights.get());
x470_deactivateLight->Render();
break;
case ETurretState::Inactive:
x468_idleLight->Render(x90_actorLights.get());
x468_idleLight->Render();
break;
case ETurretState::PanningA:
case ETurretState::PanningB:
x490_panningEffect->Render(x90_actorLights.get());
x490_panningEffect->Render();
break;
case ETurretState::Ready:
case ETurretState::Targeting:
case ETurretState::Firing:
case ETurretState::ExitTargeting:
case ETurretState::Frenzy:
x478_targettingLight->Render(x90_actorLights.get());
x478_targettingLight->Render();
if (x520_state == ETurretState::Firing) {
x488_chargingEffect->Render(x90_actorLights.get());
x488_chargingEffect->Render();
}
break;
default:
break;
}
} else {
x480_frozenEffect->Render(x90_actorLights.get());
x480_frozenEffect->Render();
}
} else if (x258_type == ETurretComponent::Base) {
if (x4a4_extensionModel && x4f8_extensionT > 0.f) {

View File

@ -191,6 +191,7 @@ inline void xxh3_update(XXH3_state_t& state, const wgpu::SamplerDescriptor& inpu
namespace aurora::gfx {
using NewPipelineCallback = std::function<wgpu::RenderPipeline()>;
std::mutex g_pipelineMutex;
static bool g_hasPipelineThread = false;
static std::thread g_pipelineThread;
static std::atomic_bool g_pipelineThreadEnd;
static std::condition_variable g_pipelineCv;
@ -225,9 +226,14 @@ static PipelineRef find_pipeline(PipelineCreateCommand command, NewPipelineCallb
std::scoped_lock guard{g_pipelineMutex};
found = g_pipelines.contains(hash);
if (!found) {
const auto ref =
std::find_if(g_queuedPipelines.begin(), g_queuedPipelines.end(), [=](auto v) { return v.first == hash; });
if (ref != g_queuedPipelines.end()) {
if (g_hasPipelineThread) {
const auto ref =
std::find_if(g_queuedPipelines.begin(), g_queuedPipelines.end(), [=](auto v) { return v.first == hash; });
if (ref != g_queuedPipelines.end()) {
found = true;
}
} else {
g_pipelines.try_emplace(hash, cb());
found = true;
}
}
@ -387,7 +393,11 @@ static void pipeline_worker() {
}
void initialize() {
g_pipelineThread = std::thread(pipeline_worker);
// No async pipelines for OpenGL (ES)
if (gpu::g_backendType != wgpu::BackendType::OpenGL && gpu::g_backendType != wgpu::BackendType::OpenGLES) {
g_pipelineThread = std::thread(pipeline_worker);
g_hasPipelineThread = true;
}
const auto createBuffer = [](wgpu::Buffer& out, wgpu::BufferUsage usage, uint64_t size, const char* label) {
const wgpu::BufferDescriptor descriptor{
@ -419,9 +429,11 @@ void initialize() {
}
void shutdown() {
g_pipelineThreadEnd = true;
g_pipelineCv.notify_all();
g_pipelineThread.join();
if (g_hasPipelineThread) {
g_pipelineThreadEnd = true;
g_pipelineCv.notify_all();
g_pipelineThread.join();
}
gx::shutdown();

View File

@ -282,37 +282,93 @@ static inline wgpu::CompareFunction to_compare_function(GX::Compare func) {
}
static inline wgpu::BlendState to_blend_state(GX::BlendMode mode, GX::BlendFactor srcFac, GX::BlendFactor dstFac,
std::optional<float> dstAlpha) {
GX::LogicOp op, std::optional<float> dstAlpha) {
wgpu::BlendComponent colorBlendComponent;
switch (mode) {
case GX::BM_NONE:
colorBlendComponent = {
.operation = wgpu::BlendOperation::Add,
.srcFactor = wgpu::BlendFactor::Src,
.dstFactor = wgpu::BlendFactor::Zero,
};
break;
case GX::BM_BLEND:
colorBlendComponent = {
.operation = wgpu::BlendOperation::Add,
.srcFactor = to_blend_factor(srcFac),
.dstFactor = to_blend_factor(dstFac),
.operation = wgpu::BlendOperation::Add,
.srcFactor = to_blend_factor(srcFac),
.dstFactor = to_blend_factor(dstFac),
};
break;
case GX::BM_SUBTRACT:
colorBlendComponent = {
.operation = wgpu::BlendOperation::Subtract,
.operation = wgpu::BlendOperation::ReverseSubtract,
.srcFactor = wgpu::BlendFactor::Src,
.dstFactor = wgpu::BlendFactor::Dst,
};
break;
case GX::BM_LOGIC:
switch (op) {
case GX::LO_CLEAR:
colorBlendComponent = {
.operation = wgpu::BlendOperation::Add,
.srcFactor = wgpu::BlendFactor::Zero,
.dstFactor = wgpu::BlendFactor::Zero,
};
break;
case GX::LO_COPY:
colorBlendComponent = {
.operation = wgpu::BlendOperation::Add,
.srcFactor = wgpu::BlendFactor::Src,
.dstFactor = wgpu::BlendFactor::Zero,
};
break;
case GX::LO_NOOP:
colorBlendComponent = {
.operation = wgpu::BlendOperation::Add,
.srcFactor = wgpu::BlendFactor::Zero,
.dstFactor = wgpu::BlendFactor::Dst,
};
break;
case GX::LO_INV:
colorBlendComponent = {
.operation = wgpu::BlendOperation::Add,
.srcFactor = wgpu::BlendFactor::Zero,
.dstFactor = wgpu::BlendFactor::OneMinusDst,
};
break;
case GX::LO_INVCOPY:
colorBlendComponent = {
.operation = wgpu::BlendOperation::Add,
.srcFactor = wgpu::BlendFactor::OneMinusSrc,
.dstFactor = wgpu::BlendFactor::Zero,
};
break;
case GX::LO_SET:
colorBlendComponent = {
.operation = wgpu::BlendOperation::Add,
.srcFactor = wgpu::BlendFactor::One,
.dstFactor = wgpu::BlendFactor::Zero,
};
break;
default:
Log.report(logvisor::Fatal, FMT_STRING("unsupported logic op {}"), op);
unreachable();
}
break;
default:
Log.report(logvisor::Fatal, FMT_STRING("How to {}?"), mode);
Log.report(logvisor::Fatal, FMT_STRING("unsupported blend mode {}"), mode);
unreachable();
}
wgpu::BlendComponent alphaBlendComponent{
.operation = wgpu::BlendOperation::Add,
.srcFactor = wgpu::BlendFactor::Zero,
.dstFactor = wgpu::BlendFactor::One,
.operation = wgpu::BlendOperation::Add,
.srcFactor = wgpu::BlendFactor::SrcAlpha,
.dstFactor = wgpu::BlendFactor::Zero,
};
if (dstAlpha) {
alphaBlendComponent = wgpu::BlendComponent{
.operation = wgpu::BlendOperation::Add,
.srcFactor = wgpu::BlendFactor::Zero,
.dstFactor = wgpu::BlendFactor::Constant,
.srcFactor = wgpu::BlendFactor::Constant,
.dstFactor = wgpu::BlendFactor::Zero,
};
}
return {
@ -372,7 +428,8 @@ wgpu::RenderPipeline build_pipeline(const PipelineConfig& config, const ShaderIn
.depthWriteEnabled = config.depthUpdate,
.depthCompare = to_compare_function(config.depthFunc),
};
const auto blendState = to_blend_state(config.blendMode, config.blendFacSrc, config.blendFacDst, config.dstAlpha);
const auto blendState =
to_blend_state(config.blendMode, config.blendFacSrc, config.blendFacDst, config.blendOp, config.dstAlpha);
const std::array colorTargets{wgpu::ColorTargetState{
.format = g_graphicsConfig.colorFormat,
.blend = &blendState,

View File

@ -67,8 +67,8 @@ struct ColorChannelConfig {
};
// For uniform generation
struct ColorChannelState {
zeus::CColor matColor = zeus::skClear;
zeus::CColor ambColor = zeus::skClear;
zeus::CColor matColor;
zeus::CColor ambColor;
GX::LightMask lightState;
};
using LightVariant = std::variant<std::monostate, Light, zeus::CColor>;
@ -98,7 +98,6 @@ struct TevSwap {
bool operator==(const TevSwap&) const = default;
operator bool() const { return *this != TevSwap{}; }
};
struct AlphaCompare {
GX::Compare comp0 = GX::ALWAYS;
float ref0 = 0.f;
@ -108,6 +107,7 @@ struct AlphaCompare {
bool operator==(const AlphaCompare& other) const = default;
operator bool() const { return *this != AlphaCompare{}; }
};
struct GXState {
zeus::CMatrix4f mv;
zeus::CMatrix4f mvInv;
@ -274,6 +274,14 @@ inline void xxh3_update(XXH3_state_t& state, const gfx::gx::TcgConfig& input) {
XXH3_64bits_update(&state, &input.normalize, sizeof(gfx::gx::TcgConfig::normalize));
}
template <>
inline void xxh3_update(XXH3_state_t& state, const gfx::gx::AlphaCompare& input) {
XXH3_64bits_update(&state, &input.comp0, sizeof(gfx::gx::AlphaCompare::comp0));
XXH3_64bits_update(&state, &input.ref0, sizeof(gfx::gx::AlphaCompare::ref0));
XXH3_64bits_update(&state, &input.op, sizeof(gfx::gx::AlphaCompare::op));
XXH3_64bits_update(&state, &input.comp1, sizeof(gfx::gx::AlphaCompare::comp1));
XXH3_64bits_update(&state, &input.ref1, sizeof(gfx::gx::AlphaCompare::ref1));
}
template <>
inline void xxh3_update(XXH3_state_t& state, const gfx::gx::ShaderConfig& input) {
XXH3_64bits_update(&state, &input.fogType, sizeof(gfx::gx::ShaderConfig::fogType));
XXH3_64bits_update(&state, &input.vtxAttrs, sizeof(gfx::gx::ShaderConfig::vtxAttrs));
@ -291,7 +299,7 @@ inline void xxh3_update(XXH3_state_t& state, const gfx::gx::ShaderConfig& input)
xxh3_update(state, item);
}
if (input.alphaCompare) {
XXH3_64bits_update(&state, &input.alphaCompare, sizeof(gfx::gx::AlphaCompare));
xxh3_update(state, input.alphaCompare);
}
XXH3_64bits_update(&state, &input.hasIndexedAttributes, sizeof(gfx::gx::ShaderConfig::hasIndexedAttributes));
}

View File

@ -179,6 +179,7 @@ void queue_surface(const u8* dlStart, u32 dlSize) noexcept {
.uniformRange = build_uniform(info),
.indexCount = numIndices,
.bindGroups = info.bindGroups,
.dstAlpha = gx::g_gxState.dstAlpha,
});
}
@ -213,6 +214,10 @@ void render(const State& state, const DrawData& data, const wgpu::RenderPassEnco
}
pass.SetVertexBuffer(0, g_vertexBuffer, data.vertRange.offset, data.vertRange.size);
pass.SetIndexBuffer(g_indexBuffer, wgpu::IndexFormat::Uint32, data.idxRange.offset, data.idxRange.size);
if (data.dstAlpha) {
const wgpu::Color color{0.f, 0.f, 0.f, *data.dstAlpha};
pass.SetBlendConstant(&color);
}
pass.DrawIndexed(data.indexCount);
}
} // namespace aurora::gfx::model

View File

@ -12,6 +12,7 @@ struct DrawData {
Range uniformRange;
uint32_t indexCount;
gx::GXBindGroups bindGroups;
std::optional<float> dstAlpha;
};
struct PipelineConfig : gx::PipelineConfig {};

View File

@ -14,7 +14,7 @@ struct SStreamState {
aurora::ByteBuffer vertexBuffer;
std::vector<u16> indices;
#ifndef NDEBUG
GX::Attr currentAttr{};
GX::Attr nextAttr;
#endif
explicit SStreamState(GX::Primitive primitive, u16 numVerts, u16 vertexSize) noexcept : primitive(primitive) {
@ -26,6 +26,10 @@ struct SStreamState {
} else {
indices.reserve(numVerts);
}
#ifndef NDEBUG
nextAttr =
GX::Attr(std::find(g_gxState.vtxDesc.begin(), g_gxState.vtxDesc.end(), GX::DIRECT) - g_gxState.vtxDesc.begin());
#endif
}
};
static std::optional<SStreamState> sStreamState;
@ -68,29 +72,26 @@ static inline void check_attr_order(GX::Attr attr) noexcept {
Log.report(logvisor::Fatal, FMT_STRING("Stream not started!"));
unreachable();
}
if (sStreamState->currentAttr >= attr) {
Log.report(logvisor::Fatal, FMT_STRING("bad attribute order: {}, last {}"), attr, sStreamState->currentAttr);
if (sStreamState->nextAttr != attr) {
Log.report(logvisor::Fatal, FMT_STRING("bad attribute order: {}, expected {}"), attr, sStreamState->nextAttr);
unreachable();
}
sStreamState->currentAttr = attr;
auto nextAttr = std::find(g_gxState.vtxDesc.begin() + attr + 1, g_gxState.vtxDesc.end(), GX::DIRECT);
if (nextAttr == g_gxState.vtxDesc.end()) {
nextAttr = std::find(g_gxState.vtxDesc.begin(), g_gxState.vtxDesc.end(), GX::DIRECT);
}
sStreamState->nextAttr = GX::Attr(nextAttr - g_gxState.vtxDesc.begin());
#endif
}
void GXPosition3f32(const zeus::CVector3f& pos) noexcept {
#ifndef NDEBUG
if (!sStreamState) {
Log.report(logvisor::Fatal, FMT_STRING("Stream not started!"));
unreachable();
}
sStreamState->currentAttr = GX::VA_POS;
#endif
check_attr_order(GX::VA_POS);
auto& state = *sStreamState;
state.vertexBuffer.append(&pos, 12);
if (state.primitive == GX::TRIANGLES || state.vertexCount < 3) {
state.indices.push_back(state.vertexCount);
// pass
} else if (state.primitive == GX::TRIANGLEFAN) {
state.indices.push_back(0);
state.indices.push_back(state.vertexCount - 1);
state.indices.push_back(state.vertexCount);
} else if (state.primitive == GX::TRIANGLESTRIP) {
if ((state.vertexCount & 1) == 0) {
state.indices.push_back(state.vertexCount - 2);
@ -99,16 +100,13 @@ void GXPosition3f32(const zeus::CVector3f& pos) noexcept {
state.indices.push_back(state.vertexCount - 1);
state.indices.push_back(state.vertexCount - 2);
}
state.indices.push_back(state.vertexCount);
} else if (state.primitive == GX::QUADS) {
if ((state.vertexCount & 3) == 3) {
state.indices.push_back(state.vertexCount - 1);
state.indices.push_back(state.vertexCount);
state.indices.push_back(state.vertexCount - 3);
} else {
state.indices.push_back(state.vertexCount);
state.indices.push_back(state.vertexCount - 1);
}
}
state.indices.push_back(state.vertexCount);
++state.vertexCount;
}
void GXNormal3f32(const zeus::CVector3f& nrm) noexcept {
@ -124,6 +122,10 @@ void GXTexCoord2f32(const zeus::CVector2f& uv) noexcept {
sStreamState->vertexBuffer.append(&uv, 8);
}
void GXEnd() noexcept {
if (sStreamState->vertexCount == 0) {
sStreamState.reset();
return;
}
const auto vertRange = aurora::gfx::push_verts(sStreamState->vertexBuffer.data(), sStreamState->vertexBuffer.size());
const auto indexRange = aurora::gfx::push_indices(aurora::ArrayRef{sStreamState->indices});
aurora::gfx::stream::PipelineConfig config{};
@ -136,6 +138,7 @@ void GXEnd() noexcept {
.indexRange = indexRange,
.indexCount = static_cast<uint32_t>(sStreamState->indices.size()),
.bindGroups = info.bindGroups,
.dstAlpha = g_gxState.dstAlpha,
});
sStreamState.reset();
}

View File

@ -76,6 +76,10 @@ void render(const State& state, const DrawData& data, const wgpu::RenderPassEnco
}
pass.SetVertexBuffer(0, g_vertexBuffer, data.vertRange.offset, data.vertRange.size);
pass.SetIndexBuffer(g_indexBuffer, wgpu::IndexFormat::Uint16, data.indexRange.offset, data.indexRange.size);
if (data.dstAlpha) {
const wgpu::Color color{0.f, 0.f, 0.f, *data.dstAlpha};
pass.SetBlendConstant(&color);
}
pass.DrawIndexed(data.indexCount);
}
} // namespace aurora::gfx::stream

View File

@ -11,6 +11,7 @@ struct DrawData {
Range indexRange;
uint32_t indexCount;
gx::GXBindGroups bindGroups;
std::optional<float> dstAlpha;
};
struct PipelineConfig : public gx::PipelineConfig {};

2
extern/zeus vendored

@ -1 +1 @@
Subproject commit 11606d3676f4bd60e70e1bbd045f55352257dbb6
Subproject commit f3e649716af215157b1d64a0f25de8e1d7f185fa