aurora: GX Stream API, VtxDesc, TevSwap & more

This commit is contained in:
Luke Street 2022-03-19 13:30:25 -04:00
parent ecb4645e89
commit b9b635b311
17 changed files with 1024 additions and 696 deletions

View File

@ -813,9 +813,7 @@ void CCubeRenderer::SetThermal(bool thermal, float level, const zeus::CColor& co
// TODO
}
void CCubeRenderer::SetThermalColdScale(float scale) {
// TODO
}
void CCubeRenderer::SetThermalColdScale(float scale) { x2f8_thermColdScale = zeus::clamp(0.f, scale, 1.f); }
void CCubeRenderer::DoThermalBlendCold() {
// TODO

View File

@ -3,11 +3,12 @@
#include "Graphics/CTexture.hpp"
namespace metaforce::CGX {
SGXState sGXState;
SGXState sGXState{};
std::array<GX::VtxDescList, 11> sVtxDescList{};
void ResetGXStates() noexcept {
sGXState.x48_descList = nullptr;
// GXClearVtxDesc();
sGXState.x48_descList = 0;
GXClearVtxDesc();
sGXState.x0_arrayPtrs.fill(nullptr);
for (GX::TexMapID id = GX::TEXMAP0; id < GX::MAX_TEXMAP; id = static_cast<GX::TexMapID>(id + 1)) {
CTexture::InvalidateTexMap(id);
@ -16,7 +17,9 @@ void ResetGXStates() noexcept {
GXSetTevKColor(id, item);
id = static_cast<GX::TevKColorID>(id + 1);
}
// GXSetTevSwapModeTable
GXSetTevSwapModeTable(GX::TEV_SWAP1, GX::CH_RED, GX::CH_GREEN, GX::CH_BLUE, GX::CH_RED);
GXSetTevSwapModeTable(GX::TEV_SWAP2, GX::CH_RED, GX::CH_GREEN, GX::CH_BLUE, GX::CH_GREEN);
GXSetTevSwapModeTable(GX::TEV_SWAP3, GX::CH_RED, GX::CH_GREEN, GX::CH_BLUE, GX::CH_BLUE);
SetAlphaCompare(GX::ALWAYS, 0, GX::AOP_AND, GX::ALWAYS, 0);
// GXSetCurrentMtx(0);
SetNumIndStages(0);

View File

@ -31,7 +31,7 @@ struct SGXState {
std::array<u16, 2> x34_chanCtrls{0x4000, 0x4000};
std::array<GXColor, 2> x38_chanAmbColors;
std::array<GXColor, 2> x40_chanMatColors;
GX::VtxDescList* x48_descList = nullptr;
u32 x48_descList = 0;
u8 x4c_dirtyChans = 0;
u8 x4d_prevNumChans = 0;
u8 x4e_numChans = 0;
@ -53,6 +53,7 @@ struct SGXState {
GXColor x25c_fogColor;
};
extern SGXState sGXState;
extern std::array<GX::VtxDescList, 11> sVtxDescList;
static inline void update_fog(u32 value) noexcept {
if (sGXState.x53_fogType == GX::FOG_NONE || (sGXState.x56_blendMode & 0xE0) == (value & 0xE0)) {
@ -92,9 +93,11 @@ static inline void Begin(GX::Primitive primitive, GX::VtxFmt fmt, u16 nverts) no
if (sGXState.x4c_dirtyChans != 0) {
FlushState();
}
// TODO GXBegin(type, fmt, nverts);
GXBegin(primitive, fmt, nverts);
}
static inline void End() noexcept { GXEnd(); }
static inline void CallDisplayList(const void* data, u32 nbytes) noexcept {
if (sGXState.x4c_dirtyChans != 0) {
FlushState();
@ -102,10 +105,6 @@ static inline void CallDisplayList(const void* data, u32 nbytes) noexcept {
GXCallDisplayList(data, nbytes);
}
static inline void End() noexcept {
// no-op
}
static inline const GXColor& GetChanAmbColor(EChannelId id) noexcept {
const auto idx = std::underlying_type_t<EChannelId>(id);
return sGXState.x38_chanAmbColors[idx];
@ -394,11 +393,33 @@ static inline void SetTexCoordGen(GX::TexCoordID dstCoord, u32 flags) noexcept {
}
}
void SetVtxDescv(GX::VtxDescList* descList) noexcept;
static inline void SetVtxDescv_Compressed(u32 descList) noexcept {
// TODO convert to GX::VtxDescList
aurora::gfx::model::set_vtx_desc_compressed(descList);
u32 currentDescList = sGXState.x48_descList;
if (descList != currentDescList) {
size_t remain = sVtxDescList.size();
u32 shift = 0;
u32 attrIdx = 0;
do {
sVtxDescList[attrIdx] = {
GX::Attr(GX::VA_POS + attrIdx),
GX::AttrType(descList >> shift & 3),
};
shift += 2;
++attrIdx;
--remain;
} while (remain != 0);
sVtxDescList[attrIdx] = {};
GXSetVtxDescv(sVtxDescList.data());
sGXState.x48_descList = descList;
}
}
static inline void SetVtxDescv(const GX::VtxDescList* descList) noexcept {
u32 flags = 0;
for (; descList->attr != GX::VA_NULL; ++descList) {
flags |= (descList->type & 3) << (descList->attr - GX::VA_POS) * 2;
}
SetVtxDescv_Compressed(flags);
}
static inline void SetZMode(GXBool compareEnable, GX::Compare func, GXBool updateEnable) noexcept {

View File

@ -59,9 +59,16 @@ const std::array<zeus::CMatrix3f, 6> CGraphics::skCubeBasisMats{{
// Stream API
static EStreamFlags sStreamFlags;
static zeus::CColor sQueuedColor;
static zeus::CVector2f sQueuedTexCoord;
static zeus::CVector3f sQueuedNormal;
static GX::Primitive sStreamPrimitive;
static u32 sVerticesCount;
// Originally writes directly to GX FIFO
struct StreamVertex {
zeus::CColor color;
zeus::CVector2f texCoord;
zeus::CVector3f normal;
zeus::CVector3f vertex;
};
static std::vector<StreamVertex> sQueuedVertices;
void CGraphics::DisableAllLights() {
g_LightActive.reset();
@ -518,55 +525,102 @@ void CGraphics::SetTevOp(ERglTevStage stage, const CTevCombiners::CTevPass& pass
}
void CGraphics::StreamBegin(GX::Primitive primitive) {
sStreamFlags = {};
aurora::gfx::stream_begin(primitive);
// Originally ResetVertexDataStream(true);
sQueuedVertices.clear();
sQueuedVertices.emplace_back();
sVerticesCount = 0;
// End
sStreamFlags = EStreamFlagBits::fHasColor;
sStreamPrimitive = primitive;
}
void CGraphics::StreamNormal(const zeus::CVector3f& nrm) {
sQueuedNormal = nrm;
sQueuedVertices.back().normal = nrm;
sStreamFlags |= EStreamFlagBits::fHasNormal;
}
void CGraphics::StreamColor(float r, float g, float b, float a) {
sQueuedColor = zeus::CColor{r, g, b, a};
sStreamFlags |= EStreamFlagBits::fHasColor;
}
void CGraphics::StreamColor(const zeus::CColor& color) {
sQueuedColor = color;
sQueuedVertices.back().color = color;
sStreamFlags |= EStreamFlagBits::fHasColor;
}
void CGraphics::StreamTexcoord(float x, float y) {
sQueuedTexCoord = {x, y};
sStreamFlags |= EStreamFlagBits::fHasTexture;
}
void CGraphics::StreamTexcoord(const zeus::CVector2f& uv) {
sQueuedTexCoord = uv;
sQueuedVertices.back().texCoord = uv;
sStreamFlags |= EStreamFlagBits::fHasTexture;
}
void CGraphics::StreamVertex(float xyz) {
const zeus::CVector3f pos{xyz, xyz, xyz};
aurora::gfx::stream_vertex(sStreamFlags, pos, sQueuedNormal, sQueuedColor, sQueuedTexCoord);
}
void CGraphics::StreamVertex(float x, float y, float z) {
const zeus::CVector3f pos{x, y, z};
aurora::gfx::stream_vertex(sStreamFlags, pos, sQueuedNormal, sQueuedColor, sQueuedTexCoord);
}
void CGraphics::StreamVertex(const zeus::CVector3f& pos) {
aurora::gfx::stream_vertex(sStreamFlags, pos, sQueuedNormal, sQueuedColor, sQueuedTexCoord);
sQueuedVertices.back().vertex = pos;
UpdateVertexDataStream();
}
void CGraphics::StreamEnd() {
SetTevStates(sStreamFlags);
aurora::gfx::stream_end();
if (sVerticesCount != 0) {
FlushStream();
}
sStreamFlags = {};
}
void CGraphics::UpdateVertexDataStream() {
++sVerticesCount;
if (sVerticesCount == 240) {
FlushStream();
ResetVertexDataStream(false);
} else {
sQueuedVertices.emplace_back(sQueuedVertices.back());
}
}
void CGraphics::FlushStream() {
std::array<GX::VtxDescList, 5> vtxDescList{};
size_t idx = 0;
vtxDescList[idx++] = {GX::VA_POS, GX::DIRECT};
if (sStreamFlags & EStreamFlagBits::fHasNormal) {
vtxDescList[idx++] = {GX::VA_NRM, GX::DIRECT};
}
if (sStreamFlags & EStreamFlagBits::fHasColor) {
vtxDescList[idx++] = {GX::VA_CLR0, GX::DIRECT};
}
if (sStreamFlags & EStreamFlagBits::fHasTexture) {
vtxDescList[idx++] = {GX::VA_TEX0, GX::DIRECT};
}
CGX::SetVtxDescv(vtxDescList.data());
SetTevStates(sStreamFlags);
FullRender();
}
void CGraphics::FullRender() {
CGX::Begin(sStreamPrimitive, GX::VTXFMT0, sVerticesCount);
for (size_t i = 0; i < sVerticesCount; ++i) {
const auto& item = sQueuedVertices[i];
GXPosition3f32(item.vertex);
if (sStreamFlags & EStreamFlagBits::fHasNormal) {
GXNormal3f32(item.normal);
}
if (sStreamFlags & EStreamFlagBits::fHasColor) {
GXColor4f32(item.color);
}
if (sStreamFlags & EStreamFlagBits::fHasTexture) {
GXTexCoord2f32(item.texCoord);
}
}
CGX::End();
}
void CGraphics::ResetVertexDataStream(bool end) {
if (end) {
sQueuedVertices.clear();
} else {
const auto lastVertex = sQueuedVertices.back();
sQueuedVertices.clear();
sQueuedVertices.emplace_back(lastVertex);
}
sVerticesCount = 0;
if (!end) {
// TODO something with triangle fans
}
}
void CGraphics::DrawPrimitive(GX::Primitive primitive, const zeus::CVector3f* pos, const zeus::CVector3f& normal,
const zeus::CColor& col, s32 numVerts) {
StreamBegin(primitive);
@ -580,12 +634,12 @@ void CGraphics::DrawPrimitive(GX::Primitive primitive, const zeus::CVector3f* po
void CGraphics::SetTevStates(EStreamFlags flags) noexcept {
if (flags & EStreamFlagBits::fHasTexture) {
CGX::SetNumTexGens(0);
CGX::SetNumTevStages(1);
CGX::SetNumTexGens(1); // sTextureUsed & 3?
CGX::SetTevOrder(GX::TEVSTAGE0, GX::TEXCOORD0, GX::TEXMAP0, GX::COLOR0A0);
CGX::SetTevOrder(GX::TEVSTAGE1, GX::TEXCOORD1, GX::TEXMAP1, GX::COLOR0A0);
} else /* if (flags < 8) ? */ {
CGX::SetNumTexGens(2); // sTextureUsed & 3?
} else {
CGX::SetNumTexGens(0);
CGX::SetNumTevStages(1);
CGX::SetTevOrder(GX::TEVSTAGE0, GX::TEXCOORD_NULL, GX::TEXMAP_NULL, GX::COLOR0A0);
CGX::SetTevOrder(GX::TEVSTAGE1, GX::TEXCOORD_NULL, GX::TEXMAP_NULL, GX::COLOR0A0);
}
@ -599,4 +653,67 @@ void CGraphics::SetTevStates(EStreamFlags flags) noexcept {
hasLights ? GX::DF_CLAMP : GX::DF_NONE, hasLights ? GX::AF_SPOT : GX::AF_NONE);
CGX::FlushState(); // normally would be handled in FullRender TODO
}
void CGraphics::Startup() {
// Setup GXFifo
CGX::ResetGXStates();
InitGraphicsVariables();
// ConfigureFrameBuffer(...);
InitGraphicsDefaults();
// GXInitTexCacheRegion
// GXSetTexRegionCallback
}
void CGraphics::InitGraphicsVariables() {
// g_lightTypes[0..n] = Directional;
g_LightActive = {};
SetDepthWriteMode(false, g_depthFunc, false);
SetCullMode(ERglCullMode::None);
SetAmbientColor(zeus::CColor{0.2f, 1.f});
g_IsGXModelMatrixIdentity = false;
// SetIdentityViewPointMatrix();
// SetIdentityModelMatrix();
// SetViewport(...);
// SetPerspective(...);
SetCopyClear(g_ClearColor, 1.f);
CGX::SetChanMatColor(CGX::EChannelId::Channel0, zeus::skWhite);
// g_RenderState.ResetFlushAll();
}
void CGraphics::InitGraphicsDefaults() {
SetDepthRange(0.f, 1.f);
g_IsGXModelMatrixIdentity = false;
SetModelMatrix(g_GXModelMatrix);
SetViewPointMatrix(g_GXModelView);
SetDepthWriteMode(false, g_depthFunc, false);
SetCullMode(g_cullMode);
SetViewport(g_Viewport.x0_left, g_Viewport.x4_top, g_Viewport.x8_width, g_Viewport.xc_height);
FlushProjection();
CTevCombiners::Init();
DisableAllLights();
SetDefaultVtxAttrFmt();
}
void CGraphics::SetDefaultVtxAttrFmt() {
// Unneeded, all attributes are expected to be full floats
// Left here for reference
// GXSetVtxAttrFmt(GX::VTXFMT0, GX::VA_POS, GX::POS_XYZ, GX::F32, 0);
// GXSetVtxAttrFmt(GX::VTXFMT1, GX::VA_POS, GX::POS_XYZ, GX::F32, 0);
// GXSetVtxAttrFmt(GX::VTXFMT2, GX::VA_POS, GX::POS_XYZ, GX::F32, 0);
// GXSetVtxAttrFmt(GX::VTXFMT0, GX::VA_NRM, GX::NRM_XYZ, GX::F32, 0);
// GXSetVtxAttrFmt(GX::VTXFMT1, GX::VA_NRM, GX::NRM_XYZ, GX::S16, 14);
// GXSetVtxAttrFmt(GX::VTXFMT2, GX::VA_NRM, GX::NRM_XYZ, GX::S16, 14);
// GXSetVtxAttrFmt(GX::VTXFMT0, GX::VA_CLR0, GX::CLR_RGBA, GX::RGBA8, 0);
// GXSetVtxAttrFmt(GX::VTXFMT1, GX::VA_CLR0, GX::CLR_RGBA, GX::RGBA8, 0);
// GXSetVtxAttrFmt(GX::VTXFMT2, GX::VA_CLR0, GX::CLR_RGBA, GX::RGBA8, 0);
// GXSetVtxAttrFmt(GX::VTXFMT0, GX::VA_TEX0, GX::TEX_ST, GX::F32, 0);
// GXSetVtxAttrFmt(GX::VTXFMT1, GX::VA_TEX0, GX::TEX_ST, GX::F32, 0);
// GXSetVtxAttrFmt(GX::VTXFMT2, GX::VA_TEX0, GX::TEX_ST, GX::U16, 15);
// for (GX::Attr attr = GX::VA_TEX1; attr <= GX::VA_TEX7; attr = GX::Attr(attr + 1)) {
// GXSetVtxAttrFmt(GX::VTXFMT0, attr, GX::TEX_ST, GX::F32, 0);
// GXSetVtxAttrFmt(GX::VTXFMT1, attr, GX::TEX_ST, GX::F32, 0);
// GXSetVtxAttrFmt(GX::VTXFMT2, attr, GX::TEX_ST, GX::F32, 0);
// }
}
} // namespace metaforce

View File

@ -205,6 +205,10 @@ public:
static ERglEnum g_depthFunc;
static ERglCullMode g_cullMode;
static void Startup();
static void InitGraphicsVariables();
static void InitGraphicsDefaults();
static void SetDefaultVtxAttrFmt();
static void DisableAllLights();
static void LoadLight(ERglLight light, const CLight& info);
static void EnableLight(ERglLight light);
@ -353,14 +357,18 @@ public:
static void SetTevOp(ERglTevStage stage, const CTevCombiners::CTevPass& pass);
static void StreamBegin(GX::Primitive primitive);
static void StreamNormal(const zeus::CVector3f& nrm);
static void StreamColor(float r, float g, float b, float a);
static void StreamColor(const zeus::CColor& color);
static void StreamTexcoord(float x, float y);
static inline void StreamColor(float r, float g, float b, float a) { StreamColor({r, g, b, a}); }
static void StreamTexcoord(const zeus::CVector2f& uv);
static void StreamVertex(float xyz);
static void StreamVertex(float x, float y, float z);
static inline void StreamTexcoord(float x, float y) { StreamTexcoord({x, y}); }
static void StreamVertex(const zeus::CVector3f& pos);
static inline void StreamVertex(float xyz) { StreamVertex({xyz, xyz, xyz}); }
static inline void StreamVertex(float x, float y, float z) { StreamVertex({x, y, z}); }
static void StreamEnd();
static void UpdateVertexDataStream();
static void ResetVertexDataStream(bool end);
static void FlushStream();
static void FullRender();
static void DrawPrimitive(GX::Primitive primitive, const zeus::CVector3f* pos, const zeus::CVector3f& normal,
const zeus::CColor& col, s32 numVerts);
};

View File

@ -49,8 +49,9 @@ enum AttrType {
};
struct VtxDescList {
Attr attr;
AttrType type;
Attr attr = GX::VA_NULL;
AttrType type = GX::NONE;
operator bool() const { return attr != GX::VA_NULL; }
};
enum VtxFmt {
@ -665,6 +666,32 @@ enum ProjectionType {
ORTHOGRAPHIC,
};
enum CompCnt {
CLR_RGB = 0,
POS_XY = 0,
TEX_S = 0,
NRM_XYZ = 0,
CLR_RGBA = 1,
POS_XYZ = 1,
NRM_NBT = 1,
TEX_ST = 1,
NRM_NBT3 = 2,
};
enum CompType {
RGB565 = 0,
U8 = 0,
RGB8 = 1,
S8 = 1,
U16 = 2,
RGBX8 = 2,
S16 = 3,
RGBA4 = 3,
F32 = 4,
RGBA6 = 4,
RGBA8 = 5,
};
} // namespace GX
using GXColor = zeus::CColor;
@ -700,6 +727,7 @@ void GXSetChanCtrl(GX::ChannelID id, GXBool lightingEnabled, GX::ColorSrc ambSrc
GX::LightMask lightState, GX::DiffuseFn diffFn, GX::AttnFn attnFn) noexcept;
// Originally u8 instead of floats
void GXSetAlphaCompare(GX::Compare comp0, float ref0, GX::AlphaOp op, GX::Compare comp1, float ref1) noexcept;
void GXSetVtxDesc(GX::Attr attr, GX::AttrType type) noexcept;
void GXSetVtxDescv(GX::VtxDescList* list) noexcept;
void GXClearVtxDesc() noexcept;
void GXSetArray(GX::Attr attr, const void* data, u8 stride) noexcept;
@ -715,3 +743,21 @@ void GXLoadNrmMtxImm(const zeus::CTransform& xf, GX::PosNrmMtx id) noexcept;
void GXSetProjection(const zeus::CMatrix4f& mtx, GX::ProjectionType type) noexcept;
void GXSetViewport(float left, float top, float width, float height, float nearZ, float farZ) noexcept;
void GXSetScissor(u32 left, u32 top, u32 width, u32 height) noexcept;
// Unneeded, all attributes are expected to be full floats
// void GXSetVtxAttrFmt(GX::VtxFmt vtxfmt, GX::Attr attr, GX::CompCnt cnt, GX::CompType type, u8 frac) noexcept;
// Streaming
void GXBegin(GX::Primitive primitive, GX::VtxFmt vtxFmt, u16 nVerts) noexcept;
void GXMatrixIndex1u8(u8 idx) noexcept;
void GXPosition3f32(const zeus::CVector3f& pos) noexcept;
static inline void GXPosition3f32(float x, float y, float z) noexcept { GXPosition3f32({x, y, z}); }
void GXNormal3f32(const zeus::CVector3f& nrm) noexcept;
static inline void GXNormal3f32(float x, float y, float z) noexcept { GXNormal3f32({x, y, z}); }
void GXColor4f32(const zeus::CColor& color) noexcept;
static inline void GXColor4f32(float r, float g, float b, float a) noexcept { GXColor4f32({r, g, b, a}); }
void GXTexCoord2f32(const zeus::CVector2f& uv) noexcept;
static inline void GXTexCoord2f32(float u, float v) noexcept { GXTexCoord2f32({u, v}); }
void GXEnd() noexcept;
// End streaming
void GXSetTevSwapModeTable(GX::TevSwapSel id, GX::TevColorChan red, GX::TevColorChan green, GX::TevColorChan blue,
GX::TevColorChan alpha) noexcept;
void GXSetTevSwapMode(GX::TevStageID stage, GX::TevSwapSel rasSel, GX::TevSwapSel texSel) noexcept;

View File

@ -87,8 +87,8 @@ void CDecal::RenderQuad(CQuadDecal& decal, const SQuadDescr& desc) const {
modXf.origin += offset;
CGraphics::SetModelMatrix(modXf);
SParticleUniforms uniformData = {
CGraphics::GetPerspectiveProjectionMatrix(/*true*/) * CGraphics::g_GXModelView.toMatrix4f(), {1.f, 1.f, 1.f, 1.f}};
// SParticleUniforms uniformData = {
// CGraphics::GetPerspectiveProjectionMatrix(/*true*/) * CGraphics::g_GXModelView.toMatrix4f(), {1.f, 1.f, 1.f, 1.f}};
// decal.m_uniformBuf->load(&uniformData, sizeof(SParticleUniforms));
bool redToAlpha = sMoveRedToAlphaBuffer && desc.x18_ADD && desc.x14_TEX;
@ -104,52 +104,52 @@ void CDecal::RenderQuad(CQuadDecal& decal, const SQuadDescr& desc) const {
// else
// CGraphics::SetShaderDataBinding(decal.m_normalDataBind);
g_instTexData.clear();
g_instTexData.reserve(1);
// g_instTexData.clear();
// g_instTexData.reserve(1);
SParticleInstanceTex& inst = g_instTexData.emplace_back();
if (decal.x8_rotation == 0.f) {
inst.pos[0] = zeus::CVector3f(-size, 0.001f, size);
inst.pos[1] = zeus::CVector3f(size, 0.001f, size);
inst.pos[2] = zeus::CVector3f(-size, 0.001f, -size);
inst.pos[3] = zeus::CVector3f(size, 0.001f, -size);
} else {
float ang = zeus::degToRad(decal.x8_rotation);
float sinSize = std::sin(ang) * size;
float cosSize = std::cos(ang) * size;
inst.pos[0] = zeus::CVector3f(sinSize - cosSize, 0.001f, cosSize + sinSize);
inst.pos[1] = zeus::CVector3f(cosSize + sinSize, 0.001f, cosSize - sinSize);
inst.pos[2] = zeus::CVector3f(-(cosSize + sinSize), 0.001f, -(cosSize - sinSize));
inst.pos[3] = zeus::CVector3f(-sinSize + cosSize, 0.001f, -cosSize - sinSize);
}
inst.color = color;
inst.uvs[0] = zeus::CVector2f(uvSet.xMin, uvSet.yMin);
inst.uvs[1] = zeus::CVector2f(uvSet.xMax, uvSet.yMin);
inst.uvs[2] = zeus::CVector2f(uvSet.xMin, uvSet.yMax);
inst.uvs[3] = zeus::CVector2f(uvSet.xMax, uvSet.yMax);
// SParticleInstanceTex& inst = g_instTexData.emplace_back();
// if (decal.x8_rotation == 0.f) {
// inst.pos[0] = zeus::CVector3f(-size, 0.001f, size);
// inst.pos[1] = zeus::CVector3f(size, 0.001f, size);
// inst.pos[2] = zeus::CVector3f(-size, 0.001f, -size);
// inst.pos[3] = zeus::CVector3f(size, 0.001f, -size);
// } else {
// float ang = zeus::degToRad(decal.x8_rotation);
// float sinSize = std::sin(ang) * size;
// float cosSize = std::cos(ang) * size;
// inst.pos[0] = zeus::CVector3f(sinSize - cosSize, 0.001f, cosSize + sinSize);
// inst.pos[1] = zeus::CVector3f(cosSize + sinSize, 0.001f, cosSize - sinSize);
// inst.pos[2] = zeus::CVector3f(-(cosSize + sinSize), 0.001f, -(cosSize - sinSize));
// inst.pos[3] = zeus::CVector3f(-sinSize + cosSize, 0.001f, -cosSize - sinSize);
// }
// inst.color = color;
// inst.uvs[0] = zeus::CVector2f(uvSet.xMin, uvSet.yMin);
// inst.uvs[1] = zeus::CVector2f(uvSet.xMax, uvSet.yMin);
// inst.uvs[2] = zeus::CVector2f(uvSet.xMin, uvSet.yMax);
// inst.uvs[3] = zeus::CVector2f(uvSet.xMax, uvSet.yMax);
// decal.m_instBuf->load(g_instTexData.data(), g_instTexData.size() * sizeof(SParticleInstanceTex));
// CGraphics::DrawInstances(0, 4, g_instTexData.size());
} else {
g_instNoTexData.clear();
g_instNoTexData.reserve(1);
// g_instNoTexData.clear();
// g_instNoTexData.reserve(1);
SParticleInstanceNoTex& inst = g_instNoTexData.emplace_back();
if (decal.x8_rotation == 0.f) {
inst.pos[0] = zeus::CVector3f(-size, 0.001f, size);
inst.pos[1] = zeus::CVector3f(size, 0.001f, size);
inst.pos[2] = zeus::CVector3f(-size, 0.001f, -size);
inst.pos[3] = zeus::CVector3f(size, 0.001f, -size);
} else {
float ang = zeus::degToRad(decal.x8_rotation);
float sinSize = std::sin(ang) * size;
float cosSize = std::cos(ang) * size;
inst.pos[0] = zeus::CVector3f(sinSize - cosSize, 0.001f, cosSize + sinSize);
inst.pos[1] = zeus::CVector3f(cosSize + sinSize, 0.001f, cosSize - sinSize);
inst.pos[2] = zeus::CVector3f(-(cosSize + sinSize), 0.001f, -(cosSize - sinSize));
inst.pos[3] = zeus::CVector3f(-sinSize + cosSize, 0.001f, -cosSize - sinSize);
}
inst.color = color;
// SParticleInstanceNoTex& inst = g_instNoTexData.emplace_back();
// if (decal.x8_rotation == 0.f) {
// inst.pos[0] = zeus::CVector3f(-size, 0.001f, size);
// inst.pos[1] = zeus::CVector3f(size, 0.001f, size);
// inst.pos[2] = zeus::CVector3f(-size, 0.001f, -size);
// inst.pos[3] = zeus::CVector3f(size, 0.001f, -size);
// } else {
// float ang = zeus::degToRad(decal.x8_rotation);
// float sinSize = std::sin(ang) * size;
// float cosSize = std::cos(ang) * size;
// inst.pos[0] = zeus::CVector3f(sinSize - cosSize, 0.001f, cosSize + sinSize);
// inst.pos[1] = zeus::CVector3f(cosSize + sinSize, 0.001f, cosSize - sinSize);
// inst.pos[2] = zeus::CVector3f(-(cosSize + sinSize), 0.001f, -(cosSize - sinSize));
// inst.pos[3] = zeus::CVector3f(-sinSize + cosSize, 0.001f, -cosSize - sinSize);
// }
// inst.color = color;
// decal.m_instBuf->load(g_instNoTexData.data(), g_instNoTexData.size() * sizeof(SParticleInstanceNoTex));
// CGraphics::DrawInstances(0, 4, g_instNoTexData.size());

View File

@ -3,6 +3,7 @@
#include "Runtime/GameGlobalObjects.hpp"
#include "Runtime/Character/CActorLights.hpp"
#include "Runtime/Graphics/CCubeRenderer.hpp"
#include "Runtime/Graphics/CGX.hpp"
#include "Runtime/Graphics/CModel.hpp"
#include "Runtime/Graphics/Shaders/CElementGenShaders.hpp"
#include "Runtime/Particle/CElectricDescription.hpp"
@ -19,11 +20,11 @@ namespace metaforce {
namespace {
logvisor::Module Log("metaforce::CElementGen");
constexpr std::array ShadClsSizes{
sizeof(SParticleInstanceTex),
sizeof(SParticleInstanceIndTex),
sizeof(SParticleInstanceNoTex),
};
// constexpr std::array ShadClsSizes{
// sizeof(SParticleInstanceTex),
// sizeof(SParticleInstanceIndTex),
// sizeof(SParticleInstanceNoTex),
// };
} // Anonymous namespace
u16 CElementGen::g_GlobalSeed = 99;
@ -35,9 +36,9 @@ bool CElementGen::g_ParticleSystemInitialized = false;
bool CElementGen::sMoveRedToAlphaBuffer = false;
CParticle* CElementGen::g_currentParticle = nullptr;
std::vector<SParticleInstanceTex> g_instTexData;
std::vector<SParticleInstanceIndTex> g_instIndTexData;
std::vector<SParticleInstanceNoTex> g_instNoTexData;
// std::vector<SParticleInstanceTex> g_instTexData;
// std::vector<SParticleInstanceIndTex> g_instIndTexData;
// std::vector<SParticleInstanceNoTex> g_instNoTexData;
void CElementGen::Initialize() {
if (g_ParticleSystemInitialized)
@ -210,21 +211,21 @@ CElementGen::CElementGen(TToken<CGenDescription> gen, EModelOrientationType orie
if (x26c_31_LINE) {
CUVElement* texr = desc->x54_x40_TEXR.get();
// TODO
// aurora::gfx::TextureHandle tex;
// if (texr)
// tex = texr->GetValueTexture(0).GetObj()->GetTexture();
// aurora::gfx::TextureHandle tex;
// if (texr)
// tex = texr->GetValueTexture(0).GetObj()->GetTexture();
int maxVerts = x90_MAXP;
// m_lineRenderer.reset(
// new CLineRenderer(CLineRenderer::EPrimitiveMode::Lines, maxVerts * 2, tex, x26c_26_AAPH, x26c_28_zTest));
// m_lineRenderer.reset(
// new CLineRenderer(CLineRenderer::EPrimitiveMode::Lines, maxVerts * 2, tex, x26c_26_AAPH, x26c_28_zTest));
} else {
m_shaderClass = CElementGenShaders::GetShaderClass(*this);
}
_RecreatePipelines();
// CGraphics::CommitResources([&](boo::IGraphicsDataFactory::Context& ctx) {
// CElementGenShaders::BuildShaderDataBinding(ctx, *this);
// return true;
// } BooTrace);
// CGraphics::CommitResources([&](boo::IGraphicsDataFactory::Context& ctx) {
// CElementGenShaders::BuildShaderDataBinding(ctx, *this);
// return true;
// } BooTrace);
}
CElementGen::~CElementGen() {
@ -260,17 +261,17 @@ void CElementGen::_RecreatePipelines() {
size_t maxInsts = x26c_30_MBLR ? 2560 * 2 : 2560; // x26c_30_MBLR ? (x270_MBSP * x90_MAXP) : x90_MAXP;
maxInsts = (maxInsts == 0 ? 256 : maxInsts);
// CGraphics::CommitResources([&](boo::IGraphicsDataFactory::Context& ctx) {
// if (!x26c_31_LINE) {
// m_instBuf = ctx.newDynamicBuffer(boo::BufferUse::Vertex, ShadClsSizes[size_t(m_shaderClass)], maxInsts);
// m_uniformBuf = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(SParticleUniforms), 1);
// }
// if (x28_loadedGenDesc->x45_24_x31_26_PMUS) {
// m_instBufPmus = ctx.newDynamicBuffer(boo::BufferUse::Vertex, ShadClsSizes[size_t(m_shaderClass)], maxInsts);
// m_uniformBufPmus = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(SParticleUniforms), 1);
// }
// return true;
// } BooTrace);
// CGraphics::CommitResources([&](boo::IGraphicsDataFactory::Context& ctx) {
// if (!x26c_31_LINE) {
// m_instBuf = ctx.newDynamicBuffer(boo::BufferUse::Vertex, ShadClsSizes[size_t(m_shaderClass)], maxInsts);
// m_uniformBuf = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(SParticleUniforms), 1);
// }
// if (x28_loadedGenDesc->x45_24_x31_26_PMUS) {
// m_instBufPmus = ctx.newDynamicBuffer(boo::BufferUse::Vertex, ShadClsSizes[size_t(m_shaderClass)], maxInsts);
// m_uniformBufPmus = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(SParticleUniforms), 1);
// }
// return true;
// } BooTrace);
}
bool CElementGen::InternalUpdate(double dt) {
@ -838,12 +839,12 @@ u32 CElementGen::GetSystemCount() const {
void CElementGen::Render(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;
}
// if (!x26c_31_LINE) {
// return;
// }
// if (x28_loadedGenDesc->x45_24_x31_26_PMUS) { // && (!m_instBufPmus || !m_uniformBufPmus)
// return;
// }
SCOPED_GRAPHICS_DEBUG_GROUP(fmt::format(FMT_STRING("CElementGen::Render {}"), *x1c_genDesc.GetObjectTag()).c_str(),
zeus::skYellow);
@ -876,16 +877,19 @@ void CElementGen::Render(const CActorLights* actorLights) {
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;
}
// if (!x26c_31_LINE) { // && (!m_instBuf || !m_uniformBuf)
// return;
// }
// if (x28_loadedGenDesc->x45_24_x31_26_PMUS) { // && (!m_instBufPmus || !m_uniformBufPmus)
// return;
// }
CParticleGlobals::instance()->m_particleAccessParameters = nullptr;
if (x26d_26_modelsUseLights)
if (x26d_26_modelsUseLights) {
CGraphics::SetLightState(x274_backupLightActive);
} else {
CGraphics::SetAmbientColor(zeus::skWhite);
}
CGlobalRandom gr(x27c_randState);
CGenDescription* desc = x1c_genDesc.GetObj();
@ -897,20 +901,24 @@ void CElementGen::RenderModels(const CActorLights* actorLights) {
bool moveRedToAlphaBuffer = false;
if (desc->x45_24_x31_26_PMUS) {
if (sMoveRedToAlphaBuffer && desc->x44_31_x31_25_PMAB && desc->x54_x40_TEXR)
if (sMoveRedToAlphaBuffer && desc->x44_31_x31_25_PMAB && desc->x54_x40_TEXR) {
moveRedToAlphaBuffer = true;
}
if (desc->x44_31_x31_25_PMAB) {
CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, false);
if (moveRedToAlphaBuffer)
if (moveRedToAlphaBuffer) {
CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::One, ERglBlendFactor::One, ERglLogicOp::Clear);
else
} else {
CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::One,
ERglLogicOp::Clear);
CGraphics::SetAlphaCompare(ERglAlphaFunc::Greater, 0, ERglAlphaOp::And, ERglAlphaFunc::Always, 0);
}
} else {
CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, true);
CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::InvSrcAlpha,
ERglLogicOp::Clear);
CGraphics::SetAlphaCompare(ERglAlphaFunc::Greater, 0, ERglAlphaOp::And, ERglAlphaFunc::Always, 0);
}
CGraphics::SetCullMode(ERglCullMode::None);
@ -920,37 +928,60 @@ void CElementGen::RenderModels(const CActorLights* actorLights) {
int partFrame = x74_curFrame - target.x28_startFrame;
cachedTex = texr->GetValueTexture(partFrame).GetObj();
cachedTex->Load(GX::TEXMAP0, EClampMode::Repeat);
/* Shade as TEXC * RASC and TEXA * RASA */
CGraphics::SetTevOp(ERglTevStage::Stage0, CTevCombiners::sTevPass805a5ebc);
if (moveRedToAlphaBuffer) {
/* Color = Prev.rgb * Prev.a */
/* Alpha = Tex.r * Prev.a */
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::SetTevOrder(GX::TEVSTAGE1, GX::TEXCOORD0, GX::TEXMAP0, GX::COLOR_NULL);
GXSetTevSwapMode(GX::TEVSTAGE1, GX::TEV_SWAP0, GX::TEV_SWAP1);
CGX::SetNumTevStages(2);
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());
CGX::SetChanCtrl(CGX::EChannelId::Channel0, {});
CGX::SetNumChans(1);
CGX::SetTexCoordGen(GX::TEXCOORD0, GX::TG_MTX2x4, GX::TG_TEX0, GX::IDENTITY, false, GX::PTIDENTITY);
CGX::SetTevOrder(GX::TEVSTAGE0, GX::TEXCOORD0, GX::TEXMAP0, GX::COLOR0A0);
CGX::SetNumTexGens(1);
} else {
CGraphics::SetTevOp(ERglTevStage::Stage1, CTevCombiners::skPassThru);
}
texConst = texr->HasConstantTexture();
texr->GetValueUV(partFrame, uvs);
} else {
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;
}
// 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}};
// 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()]);
// 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();
@ -1041,54 +1072,44 @@ void CElementGen::RenderModels(const CActorLights* actorLights) {
CGraphics::SetModelMatrix((x10c_globalScaleTransform * partTrans) * x178_localScaleTransform);
if (desc->x45_24_x31_26_PMUS) {
if (!texConst) {
CTexture* tex = texr->GetValueTexture(x74_curFrame - particle.x28_startFrame).GetObj();
if (tex != cachedTex) {
tex->Load(GX::TEXMAP0, EClampMode::Repeat);
cachedTex = tex;
}
}
switch (m_shaderClass) {
case CElementGenShaders::EShaderClass::Tex: {
SParticleInstanceTex& inst = g_instTexData.emplace_back();
inst.pos[0] = CGraphics::g_GXModelView * zeus::CVector3f{0.5f, 0.f, 0.5f};
inst.pos[1] = CGraphics::g_GXModelView * zeus::CVector3f{-0.5f, 0.f, 0.5f};
inst.pos[2] = CGraphics::g_GXModelView * zeus::CVector3f{0.5f, 0.f, -0.5f};
inst.pos[3] = CGraphics::g_GXModelView * zeus::CVector3f{-0.5f, 0.f, -0.5f};
inst.color = col;
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] = CGraphics::g_GXModelView * zeus::CVector3f{0.5f, 0.f, 0.5f};
inst.pos[1] = CGraphics::g_GXModelView * zeus::CVector3f{-0.5f, 0.f, 0.5f};
inst.pos[2] = CGraphics::g_GXModelView * zeus::CVector3f{0.5f, 0.f, -0.5f};
inst.pos[3] = CGraphics::g_GXModelView * zeus::CVector3f{-0.5f, 0.f, -0.5f};
inst.color = col;
break;
}
default:
break;
if (moveRedToAlphaBuffer) {
CGX::Begin(GX::QUADS, GX::VTXFMT0, 4);
GXPosition3f32(0.5f, 0.f, 0.5f);
GXColor4f32(col);
GXTexCoord2f32(uvs.xMax, uvs.yMax);
GXPosition3f32(-0.5f, 0.f, 0.5f);
GXColor4f32(col);
GXTexCoord2f32(uvs.xMin, uvs.yMax);
GXPosition3f32(-0.5f, 0.f, -0.5f);
GXColor4f32(col);
GXTexCoord2f32(uvs.xMin, uvs.yMin);
GXPosition3f32(0.5f, 0.f, -0.5f);
GXColor4f32(col);
GXTexCoord2f32(uvs.xMax, uvs.yMin);
CGX::End();
} else {
CGraphics::StreamBegin(GX::QUADS);
CGraphics::StreamColor(col);
CGraphics::StreamTexcoord(uvs.xMax, uvs.yMax);
CGraphics::StreamVertex(0.5f, 0.f, 0.5f);
CGraphics::StreamTexcoord(uvs.xMin, uvs.yMax);
CGraphics::StreamVertex(-0.5f, 0.f, 0.5f);
CGraphics::StreamTexcoord(uvs.xMin, uvs.yMin);
CGraphics::StreamVertex(-0.5f, 0.f, -0.5f);
CGraphics::StreamTexcoord(uvs.xMax, uvs.yMin);
CGraphics::StreamVertex(0.5f, 0.f, -0.5f);
CGraphics::StreamEnd();
}
} else {
CModel* model = desc->x5c_x48_PMDL.GetObj();
if (actorLights)
actorLights->ActivateLights();
if (g_subtractBlend) {
model->Draw({5, 0, 1, zeus::CColor(1.f, 0.5f)});
model->Draw({5, 0, 1, zeus::CColor{1.f, 0.5f}});
} else if (desc->x44_31_x31_25_PMAB) {
CModelFlags flags{7, 0, 1, col};
// flags.m_extendedShader = EExtendedShader::ForcedAdditiveNoZWrite;
model->Draw(flags);
model->Draw({7, 0, 1, col});
} else if (1.f == col.a()) {
model->Draw({0, 0, 3, zeus::skWhite});
} else {
model->Draw({5, 0, 1, zeus::CColor(1.f, col.a())});
model->Draw({5, 0, 1, zeus::CColor{1.f, col.a()}});
}
}
@ -1096,28 +1117,15 @@ void CElementGen::RenderModels(const CActorLights* actorLights) {
++matrixIt;
}
if (desc->x45_24_x31_26_PMUS) {
switch (m_shaderClass) {
case CElementGenShaders::EShaderClass::Tex:
// m_instBufPmus->load(g_instTexData.data(), g_instTexData.size() * sizeof(SParticleInstanceTex));
// CGraphics::DrawInstances(0, 4, g_instTexData.size());
break;
case CElementGenShaders::EShaderClass::NoTex:
// m_instBufPmus->load(g_instNoTexData.data(), g_instNoTexData.size() * sizeof(SParticleInstanceNoTex));
// CGraphics::DrawInstances(0, 4, g_instNoTexData.size());
break;
default:
break;
}
}
if (x26d_26_modelsUseLights)
if (x26d_26_modelsUseLights) {
CGraphics::DisableAllLights();
}
CGraphics::SetCullMode(ERglCullMode::Front);
if (moveRedToAlphaBuffer) {
/* Restore passthrough */
GXSetTevSwapMode(GX::TEVSTAGE1, GX::TEV_SWAP0, GX::TEV_SWAP0);
}
CGraphics::SetAlphaCompare(ERglAlphaFunc::Always, 0, ERglAlphaOp::And, ERglAlphaFunc::Always, 0);
}
void CElementGen::RenderLines() {
@ -1258,8 +1266,9 @@ void CElementGen::RenderParticles() {
bool constUVs = true;
CTexture* cachedTex = nullptr;
SParticleUniforms uniformData = {
CGraphics::GetPerspectiveProjectionMatrix(/*true*/) * CGraphics::g_GXModelView.toMatrix4f(), {1.f, 1.f, 1.f, 1.f}};
// SParticleUniforms uniformData = {CGraphics::GetPerspectiveProjectionMatrix(/*true*/) *
// CGraphics::g_GXModelView.toMatrix4f(),
// {1.f, 1.f, 1.f, 1.f}};
if (texr) {
CParticle& target = x30_particles[0];
@ -1269,14 +1278,14 @@ void CElementGen::RenderParticles() {
if (x338_moduColor != zeus::skBlack) {
/* Add RASC * PREVC pass for MODU color loaded into channel mat-color */
uniformData.moduColor = x338_moduColor;
// uniformData.moduColor = x338_moduColor;
}
texr->GetValueUV(partFrame, uvs);
constUVs = texr->HasConstantUV();
}
// m_uniformBuf->load(&uniformData, sizeof(SParticleUniforms));
// m_uniformBuf->load(&uniformData, sizeof(SParticleUniforms));
std::vector<CParticleListItem> sortItems;
if (desc->x44_28_x30_28_SORT) {
@ -1301,15 +1310,15 @@ void CElementGen::RenderParticles() {
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()]);
// 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()]);
// 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);
@ -1344,19 +1353,19 @@ void CElementGen::RenderParticles() {
}
#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;
}
// 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) {
for (size_t i = 0; i < x30_particles.size(); ++i) {
@ -1381,67 +1390,67 @@ void CElementGen::RenderParticles() {
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;
}
// 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;
// }
} 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;
}
// 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;
// }
}
}
} else {
@ -1487,65 +1496,65 @@ void CElementGen::RenderParticles() {
texr->GetValueUV(partFrame, uvs);
}
switch (m_shaderClass) {
case CElementGenShaders::EShaderClass::Tex: {
SParticleInstanceTex& inst = g_instTexData.emplace_back();
viewPoint += rightVec * 0.5f;
inst.pos[0] = zeus::CVector4f{viewPoint + 0.5f * foreVec};
inst.pos[1] = zeus::CVector4f{viewPoint - 0.5f * foreVec};
viewPoint -= rightVec;
inst.pos[2] = zeus::CVector4f{viewPoint + 0.5f * foreVec};
inst.pos[3] = zeus::CVector4f{viewPoint - 0.5f * foreVec};
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();
viewPoint += rightVec * 0.5f;
inst.pos[0] = zeus::CVector4f{viewPoint + 0.5f * foreVec};
inst.pos[1] = zeus::CVector4f{viewPoint - 0.5f * foreVec};
viewPoint -= rightVec;
inst.pos[2] = zeus::CVector4f{viewPoint + 0.5f * foreVec};
inst.pos[3] = zeus::CVector4f{viewPoint - 0.5f * foreVec};
inst.color = particle.x34_color;
break;
}
default:
break;
}
// switch (m_shaderClass) {
// case CElementGenShaders::EShaderClass::Tex: {
// SParticleInstanceTex& inst = g_instTexData.emplace_back();
// viewPoint += rightVec * 0.5f;
// inst.pos[0] = zeus::CVector4f{viewPoint + 0.5f * foreVec};
// inst.pos[1] = zeus::CVector4f{viewPoint - 0.5f * foreVec};
// viewPoint -= rightVec;
// inst.pos[2] = zeus::CVector4f{viewPoint + 0.5f * foreVec};
// inst.pos[3] = zeus::CVector4f{viewPoint - 0.5f * foreVec};
// 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();
// viewPoint += rightVec * 0.5f;
// inst.pos[0] = zeus::CVector4f{viewPoint + 0.5f * foreVec};
// inst.pos[1] = zeus::CVector4f{viewPoint - 0.5f * foreVec};
// viewPoint -= rightVec;
// inst.pos[2] = zeus::CVector4f{viewPoint + 0.5f * foreVec};
// inst.pos[3] = zeus::CVector4f{viewPoint - 0.5f * foreVec};
// inst.color = particle.x34_color;
// break;
// }
// default:
// break;
// }
}
}
switch (m_shaderClass) {
case CElementGenShaders::EShaderClass::Tex:
// m_instBuf->load(g_instTexData.data(), g_instTexData.size() * sizeof(SParticleInstanceTex));
// CGraphics::DrawInstances(0, 4, g_instTexData.size());
// m_instBuf->load(g_instTexData.data(), g_instTexData.size() * sizeof(SParticleInstanceTex));
// CGraphics::DrawInstances(0, 4, g_instTexData.size());
break;
case CElementGenShaders::EShaderClass::NoTex:
// m_instBuf->load(g_instNoTexData.data(), g_instNoTexData.size() * sizeof(SParticleInstanceNoTex));
// CGraphics::DrawInstances(0, 4, g_instNoTexData.size());
// m_instBuf->load(g_instNoTexData.data(), g_instNoTexData.size() * sizeof(SParticleInstanceNoTex));
// CGraphics::DrawInstances(0, 4, g_instNoTexData.size());
break;
default:
break;
}
} else {
switch (m_shaderClass) {
case CElementGenShaders::EShaderClass::Tex:
g_instTexData.clear();
g_instTexData.reserve(x30_particles.size() * mbspVal);
break;
case CElementGenShaders::EShaderClass::NoTex:
g_instNoTexData.clear();
g_instNoTexData.reserve(x30_particles.size() * mbspVal);
break;
default:
Log.report(logvisor::Fatal, FMT_STRING("unexpected particle shader class"));
break;
}
// switch (m_shaderClass) {
// case CElementGenShaders::EShaderClass::Tex:
// g_instTexData.clear();
// g_instTexData.reserve(x30_particles.size() * mbspVal);
// break;
// case CElementGenShaders::EShaderClass::NoTex:
// g_instNoTexData.clear();
// g_instNoTexData.reserve(x30_particles.size() * mbspVal);
// break;
// default:
// Log.report(logvisor::Fatal, FMT_STRING("unexpected particle shader class"));
// break;
// }
const float mbspFac = 1.f / float(mbspVal);
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);
@ -1569,32 +1578,32 @@ void CElementGen::RenderParticles() {
vec += mbspVec;
zeus::CVector3f vec2 = systemCameraMatrix * vec;
switch (m_shaderClass) {
case CElementGenShaders::EShaderClass::Tex: {
SParticleInstanceTex& inst = g_instTexData.emplace_back();
inst.pos[0] = zeus::CVector4f{vec2.x() + size, vec2.y(), vec2.z() + size, 1.f};
inst.pos[1] = zeus::CVector4f{vec2.x() - size, vec2.y(), vec2.z() + size, 1.f};
inst.pos[2] = zeus::CVector4f{vec2.x() + size, vec2.y(), vec2.z() - size, 1.f};
inst.pos[3] = zeus::CVector4f{vec2.x() - size, vec2.y(), vec2.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{vec2.x() + size, vec2.y(), vec2.z() + size, 1.f};
inst.pos[1] = zeus::CVector4f{vec2.x() - size, vec2.y(), vec2.z() + size, 1.f};
inst.pos[2] = zeus::CVector4f{vec2.x() + size, vec2.y(), vec2.z() - size, 1.f};
inst.pos[3] = zeus::CVector4f{vec2.x() - size, vec2.y(), vec2.z() - size, 1.f};
inst.color = particle.x34_color;
break;
}
default:
break;
}
// switch (m_shaderClass) {
// case CElementGenShaders::EShaderClass::Tex: {
// SParticleInstanceTex& inst = g_instTexData.emplace_back();
// inst.pos[0] = zeus::CVector4f{vec2.x() + size, vec2.y(), vec2.z() + size, 1.f};
// inst.pos[1] = zeus::CVector4f{vec2.x() - size, vec2.y(), vec2.z() + size, 1.f};
// inst.pos[2] = zeus::CVector4f{vec2.x() + size, vec2.y(), vec2.z() - size, 1.f};
// inst.pos[3] = zeus::CVector4f{vec2.x() - size, vec2.y(), vec2.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{vec2.x() + size, vec2.y(), vec2.z() + size, 1.f};
// inst.pos[1] = zeus::CVector4f{vec2.x() - size, vec2.y(), vec2.z() + size, 1.f};
// inst.pos[2] = zeus::CVector4f{vec2.x() + size, vec2.y(), vec2.z() - size, 1.f};
// inst.pos[3] = zeus::CVector4f{vec2.x() - size, vec2.y(), vec2.z() - size, 1.f};
// inst.color = particle.x34_color;
// break;
// }
// default:
// break;
// }
}
} else {
float theta = zeus::degToRad(particle.x30_lineWidthOrRota);
@ -1605,43 +1614,43 @@ void CElementGen::RenderParticles() {
vec += mbspVec;
zeus::CVector3f vec2 = systemCameraMatrix * vec;
switch (m_shaderClass) {
case CElementGenShaders::EShaderClass::Tex: {
SParticleInstanceTex& inst = g_instTexData.emplace_back();
inst.pos[0] = zeus::CVector4f{vec2.x() + sinT + cosT, vec2.y(), vec2.z() + cosT - sinT, 1.f};
inst.pos[1] = zeus::CVector4f{vec2.x() + sinT - cosT, vec2.y(), vec2.z() + sinT + cosT, 1.f};
inst.pos[2] = zeus::CVector4f{vec2.x() + (cosT - sinT), vec2.y(), vec2.z() + (-cosT - sinT), 1.f};
inst.pos[3] = zeus::CVector4f{vec2.x() - (sinT + cosT), vec2.y(), vec2.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{vec2.x() + sinT + cosT, vec2.y(), vec2.z() + cosT - sinT, 1.f};
inst.pos[1] = zeus::CVector4f{vec2.x() + sinT - cosT, vec2.y(), vec2.z() + sinT + cosT, 1.f};
inst.pos[2] = zeus::CVector4f{vec2.x() + (cosT - sinT), vec2.y(), vec2.z() + (-cosT - sinT), 1.f};
inst.pos[3] = zeus::CVector4f{vec2.x() - (sinT + cosT), vec2.y(), vec2.z() - (cosT - sinT), 1.f};
inst.color = particle.x34_color;
break;
}
default:
break;
}
// switch (m_shaderClass) {
// case CElementGenShaders::EShaderClass::Tex: {
// SParticleInstanceTex& inst = g_instTexData.emplace_back();
// inst.pos[0] = zeus::CVector4f{vec2.x() + sinT + cosT, vec2.y(), vec2.z() + cosT - sinT, 1.f};
// inst.pos[1] = zeus::CVector4f{vec2.x() + sinT - cosT, vec2.y(), vec2.z() + sinT + cosT, 1.f};
// inst.pos[2] = zeus::CVector4f{vec2.x() + (cosT - sinT), vec2.y(), vec2.z() + (-cosT - sinT), 1.f};
// inst.pos[3] = zeus::CVector4f{vec2.x() - (sinT + cosT), vec2.y(), vec2.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{vec2.x() + sinT + cosT, vec2.y(), vec2.z() + cosT - sinT, 1.f};
// inst.pos[1] = zeus::CVector4f{vec2.x() + sinT - cosT, vec2.y(), vec2.z() + sinT + cosT, 1.f};
// inst.pos[2] = zeus::CVector4f{vec2.x() + (cosT - sinT), vec2.y(), vec2.z() + (-cosT - sinT), 1.f};
// inst.pos[3] = zeus::CVector4f{vec2.x() - (sinT + cosT), vec2.y(), vec2.z() - (cosT - sinT), 1.f};
// inst.color = particle.x34_color;
// break;
// }
// default:
// break;
// }
}
}
}
switch (m_shaderClass) {
case CElementGenShaders::EShaderClass::Tex:
// m_instBuf->load(g_instTexData.data(), g_instTexData.size() * sizeof(SParticleInstanceTex));
// CGraphics::DrawInstances(0, 4, g_instTexData.size());
// m_instBuf->load(g_instTexData.data(), g_instTexData.size() * sizeof(SParticleInstanceTex));
// CGraphics::DrawInstances(0, 4, g_instTexData.size());
break;
case CElementGenShaders::EShaderClass::NoTex:
// m_instBuf->load(g_instNoTexData.data(), g_instNoTexData.size() * sizeof(SParticleInstanceNoTex));
// CGraphics::DrawInstances(0, 4, g_instNoTexData.size());
// m_instBuf->load(g_instNoTexData.data(), g_instNoTexData.size() * sizeof(SParticleInstanceNoTex));
// CGraphics::DrawInstances(0, 4, g_instNoTexData.size());
break;
default:
break;
@ -1660,9 +1669,10 @@ void CElementGen::RenderParticlesIndirectTexture() {
x178_localScaleTransform;
CGraphics::SetModelMatrix(systemViewPointMatrix);
SParticleUniforms uniformData = {
CGraphics::GetPerspectiveProjectionMatrix(/*true*/) * CGraphics::g_GXModelView.toMatrix4f(), {1.f, 1.f, 1.f, 1.f}};
// m_uniformBuf->load(&uniformData, sizeof(SParticleUniforms));
// SParticleUniforms uniformData = {CGraphics::GetPerspectiveProjectionMatrix(/*true*/) *
// CGraphics::g_GXModelView.toMatrix4f(),
// {1.f, 1.f, 1.f, 1.f}};
// m_uniformBuf->load(&uniformData, sizeof(SParticleUniforms));
CGraphics::SetAlphaCompare(ERglAlphaFunc::Always, 0, ERglAlphaOp::And, ERglAlphaFunc::Always, 0);
@ -1712,11 +1722,11 @@ void CElementGen::RenderParticlesIndirectTexture() {
});
}
g_instIndTexData.clear();
g_instIndTexData.reserve(x30_particles.size());
// g_instIndTexData.clear();
// g_instIndTexData.reserve(x30_particles.size());
// if (!x30_particles.empty())
// CGraphics::SetShaderDataBinding(m_normalDataBind[g_Renderer->IsThermalVisorHotPass()]);
// if (!x30_particles.empty())
// CGraphics::SetShaderDataBinding(m_normalDataBind[g_Renderer->IsThermalVisorHotPass()]);
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);
@ -1764,35 +1774,35 @@ void CElementGen::RenderParticlesIndirectTexture() {
CGraphics::ResolveSpareTexture(clipRect);
SParticleInstanceIndTex& inst = g_instIndTexData.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.texrTindUVs[0] = zeus::CVector4f{uvs.xMax, uvs.yMax, uvsInd.xMax, uvsInd.yMax};
inst.texrTindUVs[1] = zeus::CVector4f{uvs.xMin, uvs.yMax, uvsInd.xMin, uvsInd.yMax};
inst.texrTindUVs[2] = zeus::CVector4f{uvs.xMax, uvs.yMin, uvsInd.xMax, uvsInd.yMin};
inst.texrTindUVs[3] = zeus::CVector4f{uvs.xMin, uvs.yMin, uvsInd.xMin, uvsInd.yMin};
// switch (CGraphics::g_BooPlatform) {
// case boo::IGraphicsDataFactory::Platform::OpenGL:
// inst.sceneUVs =
// zeus::CVector4f{clipRect.x18_uvXMin, clipRect.x24_uvYMax, clipRect.x1c_uvXMax, clipRect.x20_uvYMin};
// break;
// default:
inst.sceneUVs = zeus::CVector4f{clipRect.x18_uvXMin, 1.f - clipRect.x24_uvYMax, clipRect.x1c_uvXMax,
1.f - clipRect.x20_uvYMin};
// break;
// }
// CGraphics::DrawInstances(0, 4, 1, g_instIndTexData.size() - 1);
// SParticleInstanceIndTex& inst = g_instIndTexData.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.texrTindUVs[0] = zeus::CVector4f{uvs.xMax, uvs.yMax, uvsInd.xMax, uvsInd.yMax};
// inst.texrTindUVs[1] = zeus::CVector4f{uvs.xMin, uvs.yMax, uvsInd.xMin, uvsInd.yMax};
// inst.texrTindUVs[2] = zeus::CVector4f{uvs.xMax, uvs.yMin, uvsInd.xMax, uvsInd.yMin};
// inst.texrTindUVs[3] = zeus::CVector4f{uvs.xMin, uvs.yMin, uvsInd.xMin, uvsInd.yMin};
// switch (CGraphics::g_BooPlatform) {
// case boo::IGraphicsDataFactory::Platform::OpenGL:
// inst.sceneUVs =
// zeus::CVector4f{clipRect.x18_uvXMin, clipRect.x24_uvYMax, clipRect.x1c_uvXMax, clipRect.x20_uvYMin};
// break;
// default:
// inst.sceneUVs =
// zeus::CVector4f{clipRect.x18_uvXMin, 1.f - clipRect.x24_uvYMax, clipRect.x1c_uvXMax, 1.f - clipRect.x20_uvYMin};
// break;
// }
// CGraphics::DrawInstances(0, 4, 1, g_instIndTexData.size() - 1);
}
if (g_instIndTexData.size()) {
// m_instBuf->load(g_instIndTexData.data(), g_instIndTexData.size() * sizeof(SParticleInstanceIndTex));
// TODO! this looks like a bug
// if (g_instIndTexData.size()) {
// m_instBuf->load(g_instIndTexData.data(), g_instIndTexData.size() * sizeof(SParticleInstanceIndTex));
// TODO! this looks like a bug
// CGraphics::SetShaderDataBinding(m_normalDataBind);
// CGraphics::DrawInstances(0, 4, g_instIndTexData.size());
}
// }
}
void CElementGen::SetOrientation(const zeus::CTransform& orientation) {

View File

@ -59,30 +59,30 @@ public:
}
};
struct SParticleInstanceTex {
std::array<zeus::CVector4f, 4> pos;
zeus::CColor color;
std::array<zeus::CVector2f, 4> uvs;
};
extern std::vector<SParticleInstanceTex> g_instTexData;
struct SParticleInstanceIndTex {
std::array<zeus::CVector4f, 4> pos;
zeus::CColor color;
std::array<zeus::CVector4f, 4> texrTindUVs;
zeus::CVector4f sceneUVs;
};
extern std::vector<SParticleInstanceIndTex> g_instIndTexData;
struct SParticleInstanceNoTex {
std::array<zeus::CVector4f, 4> pos;
zeus::CColor color;
};
extern std::vector<SParticleInstanceNoTex> g_instNoTexData;
struct SParticleUniforms {
zeus::CMatrix4f mvp;
zeus::CColor moduColor;
};
//struct SParticleInstanceTex {
// std::array<zeus::CVector4f, 4> pos;
// zeus::CColor color;
// std::array<zeus::CVector2f, 4> uvs;
//};
//extern std::vector<SParticleInstanceTex> g_instTexData;
//
//struct SParticleInstanceIndTex {
// std::array<zeus::CVector4f, 4> pos;
// zeus::CColor color;
// std::array<zeus::CVector4f, 4> texrTindUVs;
// zeus::CVector4f sceneUVs;
//};
//extern std::vector<SParticleInstanceIndTex> g_instIndTexData;
//
//struct SParticleInstanceNoTex {
// std::array<zeus::CVector4f, 4> pos;
// zeus::CColor color;
//};
//extern std::vector<SParticleInstanceNoTex> g_instNoTexData;
//
//struct SParticleUniforms {
// zeus::CMatrix4f mvp;
// zeus::CColor moduColor;
//};
} // namespace metaforce

View File

@ -132,11 +132,6 @@ struct Light {
[[nodiscard]] bool get_dxt_compression_supported() noexcept;
void stream_begin(GX::Primitive primitive) noexcept;
void stream_vertex(metaforce::EStreamFlags flags, const zeus::CVector3f& pos, const zeus::CVector3f& nrm,
const zeus::CColor& color, const zeus::CVector2f& uv) noexcept;
void stream_end() noexcept;
// GX state
void bind_texture(GX::TexMapID id, metaforce::EClampMode clamp, const TextureHandle& tex, float lod) noexcept;
void unbind_texture(GX::TexMapID id) noexcept;

View File

@ -1,6 +1,7 @@
#include "gx.hpp"
#include "../gpu.hpp"
#include "Runtime/Graphics/GX.hpp"
#include "common.hpp"
#include <absl/container/flat_hash_map.h>
@ -187,6 +188,28 @@ void GXSetFog(GX::FogType type, float startZ, float endZ, float nearZ, float far
g_gxState.fog = {type, startZ, endZ, nearZ, farZ, color};
}
void GXSetFogColor(const GXColor& color) noexcept { g_gxState.fog.color = color; }
void GXSetVtxDesc(GX::Attr attr, GX::AttrType type) noexcept { g_gxState.vtxDesc[attr] = type; }
void GXSetVtxDescv(GX::VtxDescList* list) noexcept {
g_gxState.vtxDesc.fill({});
while (*list) {
g_gxState.vtxDesc[list->attr] = list->type;
++list;
}
}
void GXClearVtxDesc() noexcept { g_gxState.vtxDesc.fill({}); }
void GXSetTevSwapModeTable(GX::TevSwapSel id, GX::TevColorChan red, GX::TevColorChan green, GX::TevColorChan blue,
GX::TevColorChan alpha) noexcept {
if (id < GX::TEV_SWAP0 || id >= GX::MAX_TEVSWAP) {
Log.report(logvisor::Fatal, FMT_STRING("invalid tev swap sel {}"), id);
unreachable();
}
g_gxState.tevSwapTable[id] = {red, green, blue, alpha};
}
void GXSetTevSwapMode(GX::TevStageID stageId, GX::TevSwapSel rasSel, GX::TevSwapSel texSel) noexcept {
auto& stage = g_gxState.tevStages[stageId];
stage.tevSwapRas = rasSel;
stage.tevSwapTex = texSel;
}
namespace aurora::gfx {
static logvisor::Module Log("aurora::gfx::gx");
@ -387,6 +410,9 @@ wgpu::RenderPipeline build_pipeline(const PipelineConfig& config, const ShaderIn
ShaderInfo populate_pipeline_config(PipelineConfig& config, GX::Primitive primitive,
const BindGroupRanges& ranges) noexcept {
config.shaderConfig.fogType = g_gxState.fog.type;
config.shaderConfig.vtxAttrs = g_gxState.vtxDesc;
config.shaderConfig.tevSwapTable = g_gxState.tevSwapTable;
for (u8 i = 0; i < g_gxState.numTevStages; ++i) {
config.shaderConfig.tevStages[i] = g_gxState.tevStages[i];
}
@ -397,7 +423,10 @@ ShaderInfo populate_pipeline_config(PipelineConfig& config, GX::Primitive primit
config.shaderConfig.tcgs[i] = g_gxState.tcgs[i];
}
config.shaderConfig.alphaDiscard = g_gxState.alphaDiscard;
config.shaderConfig.fogType = g_gxState.fog.type;
if (std::any_of(config.shaderConfig.vtxAttrs.begin(), config.shaderConfig.vtxAttrs.end(),
[](const auto type) { return type == GX::INDEX8 || type == GX::INDEX16; })) {
config.shaderConfig.hasIndexedAttributes = true;
}
config = {
.shaderConfig = config.shaderConfig,
.primitive = primitive,
@ -601,7 +630,7 @@ GXBindGroups build_bind_groups(const ShaderInfo& info, const ShaderConfig& confi
.uniformBindGroup = bind_group_ref(wgpu::BindGroupDescriptor{
.label = "GX Uniform Bind Group",
.layout = layouts.uniformLayout,
.entryCount = static_cast<uint32_t>(config.denormalizedVertexAttributes ? 1 : uniformEntries.size()),
.entryCount = static_cast<uint32_t>(config.hasIndexedAttributes ? uniformEntries.size() : 1),
.entries = uniformEntries.data(),
}),
.samplerBindGroup = bind_group_ref(wgpu::BindGroupDescriptor{
@ -621,7 +650,7 @@ GXBindGroups build_bind_groups(const ShaderInfo& info, const ShaderConfig& confi
GXBindGroupLayouts build_bind_group_layouts(const ShaderInfo& info, const ShaderConfig& config) noexcept {
GXBindGroupLayouts out;
u32 uniformSizeKey = info.uniformSize + (config.denormalizedVertexAttributes ? 0 : 1);
u32 uniformSizeKey = info.uniformSize + (config.hasIndexedAttributes ? 1 : 0);
const auto uniformIt = sUniformBindGroupLayouts.find(uniformSizeKey);
if (uniformIt != sUniformBindGroupLayouts.end()) {
out.uniformLayout = uniformIt->second;
@ -676,7 +705,7 @@ GXBindGroupLayouts build_bind_group_layouts(const ShaderInfo& info, const Shader
};
const auto uniformLayoutDescriptor = wgpu::BindGroupLayoutDescriptor{
.label = "GX Uniform Bind Group Layout",
.entryCount = static_cast<uint32_t>(config.denormalizedVertexAttributes ? 1 : uniformLayoutEntries.size()),
.entryCount = static_cast<uint32_t>(config.hasIndexedAttributes ? uniformLayoutEntries.size() : 1),
.entries = uniformLayoutEntries.data(),
};
out.uniformLayout = g_device.CreateBindGroupLayout(&uniformLayoutDescriptor);

View File

@ -13,6 +13,8 @@ constexpr u32 MaxKColors = GX::MAX_KCOLOR;
constexpr u32 MaxTexMtx = 10;
constexpr u32 MaxPTTexMtx = 20;
constexpr u32 MaxTexCoord = GX::MAX_TEXCOORD;
constexpr u32 MaxVtxAttr = GX::VA_MAX_ATTR;
constexpr u32 MaxTevSwap = GX::MAX_TEVSWAP;
template <typename Arg, Arg Default>
struct TevPass {
@ -40,6 +42,8 @@ struct TevStage {
GX::TexCoordID texCoordId = GX::TEXCOORD_NULL;
GX::TexMapID texMapId = GX::TEXMAP_NULL;
GX::ChannelID channelId = GX::COLOR_NULL;
GX::TevSwapSel tevSwapRas = GX::TEV_SWAP0;
GX::TevSwapSel tevSwapTex = GX::TEV_SWAP0;
bool operator==(const TevStage&) const = default;
};
struct TextureBind {
@ -86,6 +90,14 @@ struct FogState {
float farZ = 0.f;
zeus::CColor color;
};
struct TevSwap {
GX::TevColorChan red = GX::CH_RED;
GX::TevColorChan green = GX::CH_GREEN;
GX::TevColorChan blue = GX::CH_BLUE;
GX::TevColorChan alpha = GX::CH_ALPHA;
bool operator==(const TevSwap&) const = default;
operator bool() const { return *this != TevSwap{}; }
};
struct GXState {
zeus::CMatrix4f mv;
@ -111,6 +123,13 @@ struct GXState {
std::array<TexMtxVariant, MaxTexMtx> texMtxs;
std::array<Mat4x4<float>, MaxPTTexMtx> ptTexMtxs;
std::array<TcgConfig, MaxTexCoord> tcgs;
std::array<GX::AttrType, MaxVtxAttr> vtxDesc;
std::array<TevSwap, MaxTevSwap> tevSwapTable{
TevSwap{},
TevSwap{GX::CH_RED, GX::CH_RED, GX::CH_RED, GX::CH_ALPHA},
TevSwap{GX::CH_GREEN, GX::CH_GREEN, GX::CH_GREEN, GX::CH_ALPHA},
TevSwap{GX::CH_BLUE, GX::CH_BLUE, GX::CH_BLUE, GX::CH_ALPHA},
};
bool depthCompare = true;
bool depthUpdate = true;
bool alphaUpdate = true;
@ -128,12 +147,13 @@ const TextureBind& get_texture(GX::TexMapID id) noexcept;
struct ShaderConfig {
GX::FogType fogType;
std::array<GX::AttrType, MaxVtxAttr> vtxAttrs;
std::array<TevSwap, MaxTevSwap> tevSwapTable;
std::array<std::optional<TevStage>, MaxTevStages> tevStages;
std::array<ColorChannelConfig, MaxColorChannels> colorChannels;
std::array<TcgConfig, MaxTexCoord> tcgs;
std::optional<float> alphaDiscard;
bool denormalizedVertexAttributes = false;
bool denormalizedHasNrm = false; // TODO this is a hack
bool hasIndexedAttributes = false;
bool operator==(const ShaderConfig&) const = default;
};
struct PipelineConfig {
@ -168,8 +188,6 @@ struct ShaderInfo {
std::bitset<MaxPTTexMtx> usesPTTexMtx;
std::array<GX::TexGenType, MaxTexMtx> texMtxTypes;
u32 uniformSize = 0;
bool usesVtxColor : 1 = false;
bool usesNormal : 1 = false;
bool usesFog : 1 = false;
};
struct BindGroupRanges {
@ -248,6 +266,9 @@ inline void xxh3_update(XXH3_state_t& state, const gfx::gx::TcgConfig& input) {
}
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));
XXH3_64bits_update(&state, &input.tevSwapTable, sizeof(gfx::gx::ShaderConfig::tevSwapTable));
for (const auto& item : input.tevStages) {
if (!item) {
break;
@ -263,9 +284,6 @@ inline void xxh3_update(XXH3_state_t& state, const gfx::gx::ShaderConfig& input)
if (input.alphaDiscard) {
XXH3_64bits_update(&state, &*input.alphaDiscard, sizeof(float));
}
XXH3_64bits_update(&state, &input.denormalizedVertexAttributes,
sizeof(gfx::gx::ShaderConfig::denormalizedVertexAttributes));
XXH3_64bits_update(&state, &input.denormalizedHasNrm, sizeof(gfx::gx::ShaderConfig::denormalizedHasNrm));
XXH3_64bits_update(&state, &input.fogType, sizeof(gfx::gx::ShaderConfig::fogType));
XXH3_64bits_update(&state, &input.hasIndexedAttributes, sizeof(gfx::gx::ShaderConfig::hasIndexedAttributes));
}
} // namespace aurora

View File

@ -15,7 +15,21 @@ absl::flat_hash_map<ShaderRef, std::pair<wgpu::ShaderModule, gx::ShaderInfo>> g_
static absl::flat_hash_map<ShaderRef, gx::ShaderConfig> g_gxCachedShaderConfigs;
#endif
static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const TevStage& stage, ShaderInfo& info) {
static inline std::string_view chan_comp(GX::TevColorChan chan) noexcept {
switch (chan) {
case GX::CH_RED:
return "r";
case GX::CH_GREEN:
return "g";
case GX::CH_BLUE:
return "b";
case GX::CH_ALPHA:
return "a";
}
}
static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const ShaderConfig& config,
const TevStage& stage, ShaderInfo& info) {
switch (arg) {
case GX::CC_CPREV:
return "prev.rgb";
@ -48,7 +62,9 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Tev
unreachable();
}
info.sampledTextures.set(stage.texMapId);
return fmt::format(FMT_STRING("sampled{}.rgb"), stage.texMapId);
const auto swap = config.tevSwapTable[stage.tevSwapTex];
return fmt::format(FMT_STRING("sampled{}.{}{}{}"), stage.texMapId, chan_comp(swap.red), chan_comp(swap.green),
chan_comp(swap.blue));
}
case GX::CC_TEXA: {
if (stage.texMapId == GX::TEXMAP_NULL) {
@ -59,7 +75,8 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Tev
unreachable();
}
info.sampledTextures.set(stage.texMapId);
return fmt::format(FMT_STRING("sampled{}.a"), stage.texMapId);
const auto swap = config.tevSwapTable[stage.tevSwapTex];
return fmt::format(FMT_STRING("sampled{}.{}"), stage.texMapId, chan_comp(swap.alpha));
}
case GX::CC_RASC: {
if (stage.channelId == GX::COLOR_NULL) {
@ -71,7 +88,9 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Tev
}
u32 idx = stage.channelId - GX::COLOR0A0;
info.sampledColorChannels.set(idx);
return fmt::format(FMT_STRING("rast{}.rgb"), idx);
const auto swap = config.tevSwapTable[stage.tevSwapRas];
return fmt::format(FMT_STRING("rast{}.{}{}{}"), idx, chan_comp(swap.red), chan_comp(swap.green),
chan_comp(swap.blue));
}
case GX::CC_RASA: {
if (stage.channelId == GX::COLOR_NULL) {
@ -83,7 +102,8 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Tev
}
u32 idx = stage.channelId - GX::COLOR0A0;
info.sampledColorChannels.set(idx);
return fmt::format(FMT_STRING("rast{}.a"), idx);
const auto swap = config.tevSwapTable[stage.tevSwapRas];
return fmt::format(FMT_STRING("rast{}.{}"), idx, chan_comp(swap.alpha));
}
case GX::CC_ONE:
return "1.0";
@ -180,7 +200,8 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Tev
}
}
static std::string alpha_arg_reg(GX::TevAlphaArg arg, size_t stageIdx, const TevStage& stage, ShaderInfo& info) {
static std::string alpha_arg_reg(GX::TevAlphaArg arg, size_t stageIdx, const ShaderConfig& config,
const TevStage& stage, ShaderInfo& info) {
switch (arg) {
case GX::CA_APREV:
return "prev.a";
@ -202,7 +223,8 @@ static std::string alpha_arg_reg(GX::TevAlphaArg arg, size_t stageIdx, const Tev
unreachable();
}
info.sampledTextures.set(stage.texMapId);
return fmt::format(FMT_STRING("sampled{}.a"), stage.texMapId);
const auto swap = config.tevSwapTable[stage.tevSwapTex];
return fmt::format(FMT_STRING("sampled{}.{}"), stage.texMapId, chan_comp(swap.alpha));
}
case GX::CA_RASA: {
if (stage.channelId == GX::COLOR_NULL) {
@ -214,7 +236,8 @@ static std::string alpha_arg_reg(GX::TevAlphaArg arg, size_t stageIdx, const Tev
}
u32 idx = stage.channelId - GX::COLOR0A0;
info.sampledColorChannels.set(idx);
return fmt::format(FMT_STRING("rast{}.a"), idx);
const auto swap = config.tevSwapTable[stage.tevSwapRas];
return fmt::format(FMT_STRING("rast{}.{}"), idx, chan_comp(swap.alpha));
}
case GX::CA_KONST: {
switch (stage.kaSel) {
@ -337,14 +360,51 @@ static std::string_view tev_scale(GX::TevScale scale) {
}
}
static std::string in_uv(u32 idx) {
if (idx == 0) {
return "v_packed_uvs.data[in_uv_0_4_idx[0]]";
static inline std::string vtx_attr(const ShaderConfig& config, GX::Attr attr) {
const auto type = config.vtxAttrs[attr];
if (type == GX::NONE) {
if (attr == GX::VA_NRM) {
// Default normal
return "vec3<f32>(1.0, 0.0, 0.0)";
}
Log.report(logvisor::Fatal, FMT_STRING("unmapped attr {}"), attr);
unreachable();
}
if (idx < 4) {
return fmt::format(FMT_STRING("v_uvs.data[in_uv_0_4_idx[{}]]"), idx);
if (attr == GX::VA_POS) {
if (type == GX::DIRECT) {
return "in_pos";
}
return "v_verts.data[in_pos_nrm_idx[0]].xyz";
}
return fmt::format(FMT_STRING("v_uvs.data[in_uv_5_7_idx[{}]]"), idx - 4);
if (attr == GX::VA_NRM) {
if (type == GX::DIRECT) {
return "in_nrm";
}
return "v_norms.data[in_pos_nrm_idx[1]].xyz";
}
if (attr == GX::VA_CLR0 || attr == GX::VA_CLR1) {
const auto idx = attr - GX::VA_CLR0;
if (type == GX::DIRECT) {
return fmt::format(FMT_STRING("in_clr{}"), idx);
}
Log.report(logvisor::Fatal, FMT_STRING("indexed color unsupported"));
unreachable();
}
if (attr >= GX::VA_TEX0 && attr <= GX::VA_TEX7) {
const auto idx = attr - GX::VA_TEX0;
if (type == GX::DIRECT) {
return fmt::format(FMT_STRING("in_tex{}_uv"), idx);
}
if (idx == 0) {
return "v_packed_uvs.data[in_uv_0_4_idx[0]]";
}
if (idx < 4) {
return fmt::format(FMT_STRING("v_uvs.data[in_uv_0_4_idx[{}]]"), idx);
}
return fmt::format(FMT_STRING("v_uvs.data[in_uv_5_7_idx[{}]]"), idx - 4);
}
Log.report(logvisor::Fatal, FMT_STRING("unhandled attr {}"), attr);
unreachable();
}
std::pair<wgpu::ShaderModule, ShaderInfo> build_shader(const ShaderConfig& config) noexcept {
@ -409,7 +469,7 @@ std::pair<wgpu::ShaderModule, ShaderInfo> build_shader(const ShaderConfig& confi
}
}
Log.report(logvisor::Info, FMT_STRING(" alphaDiscard: {}"), config.alphaDiscard.value_or(0.f));
Log.report(logvisor::Info, FMT_STRING(" denormalizedVertexAttributes: {}"), config.denormalizedVertexAttributes);
Log.report(logvisor::Info, FMT_STRING(" hasIndexedAttributes: {}"), config.hasIndexedAttributes);
Log.report(logvisor::Info, FMT_STRING(" fogType: {}"), config.fogType);
}
@ -423,23 +483,14 @@ std::pair<wgpu::ShaderModule, ShaderInfo> build_shader(const ShaderConfig& confi
std::string vtxXfrAttrsPre;
std::string vtxXfrAttrs;
size_t locIdx = 0;
if (config.denormalizedVertexAttributes) {
vtxInAttrs += "\n @location(0) in_pos: vec3<f32>";
vtxOutAttrs += "\n @builtin(position) pos: vec4<f32>;";
vtxXfrAttrsPre +=
"\n var obj_pos = vec4<f32>(in_pos, 1.0);"
"\n var mv_pos = ubuf.mv * obj_pos;"
"\n out.pos = ubuf.proj * mv_pos;";
if (config.denormalizedHasNrm) {
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) nrm: vec3<f32>;"), locIdx);
vtxInAttrs += fmt::format(FMT_STRING("\n , @location({}) in_nrm: vec3<f32>"), ++locIdx);
vtxXfrAttrs += fmt::format(FMT_STRING("\n out.nrm = in_nrm;"));
vtxXfrAttrsPre +=
"\n var obj_norm = vec4<f32>(in_nrm, 0.0);"
"\n var mv_norm = ubuf.mv_inv * obj_norm;";
info.usesNormal = true;
}
} else {
size_t vtxOutIdx = 0;
if (config.hasIndexedAttributes) {
// Display list attributes
vtxInAttrs +=
"\n @location(0) in_pos_nrm_idx: vec2<i32>"
"\n , @location(1) in_uv_0_4_idx: vec4<i32>"
"\n , @location(2) in_uv_5_7_idx: vec4<i32>";
locIdx += 3;
uniformBindings += R"""(
struct Vec3Block {
data: array<vec4<f32>>;
@ -456,18 +507,33 @@ var<storage, read> v_uvs: Vec2Block;
@group(0) @binding(4)
var<storage, read> v_packed_uvs: Vec2Block;
)""";
vtxInAttrs +=
"\n @location(0) in_pos_nrm_idx: vec2<i32>"
"\n , @location(1) in_uv_0_4_idx: vec4<i32>"
"\n , @location(2) in_uv_5_7_idx: vec4<i32>";
vtxOutAttrs += "\n @builtin(position) pos: vec4<f32>;";
vtxXfrAttrsPre +=
"\n var obj_pos = vec4<f32>(v_verts.data[in_pos_nrm_idx[0]].xyz, 1.0);"
"\n var obj_norm = vec4<f32>(v_norms.data[in_pos_nrm_idx[1]].xyz, 0.0);"
"\n var mv_pos = ubuf.mv * obj_pos;"
"\n var mv_norm = ubuf.mv_inv * obj_norm;"
"\n out.pos = ubuf.proj * mv_pos;";
}
for (GX::Attr attr{}; attr < MaxVtxAttr; attr = GX::Attr(attr + 1)) {
// Direct attributes
if (config.vtxAttrs[attr] != GX::DIRECT) {
continue;
}
if (locIdx > 0) {
vtxInAttrs += "\n , ";
} else {
vtxInAttrs += "\n ";
}
if (attr == GX::VA_POS) {
vtxInAttrs += fmt::format(FMT_STRING("@location({}) in_pos: vec3<f32>"), locIdx++);
} else if (attr == GX::VA_NRM) {
vtxInAttrs += fmt::format(FMT_STRING("@location({}) in_nrm: vec3<f32>"), locIdx++);
} else if (attr == GX::VA_CLR0 || attr == GX::VA_CLR1) {
vtxInAttrs += fmt::format(FMT_STRING("@location({}) in_clr{}: vec4<f32>"), locIdx++, attr - GX::VA_CLR0);
} else if (attr >= GX::VA_TEX0 && attr <= GX::VA_TEX7) {
vtxInAttrs += fmt::format(FMT_STRING("@location({}) in_tex{}_uv: vec2<f32>"), locIdx++, attr - GX::VA_TEX0);
}
}
vtxXfrAttrsPre += fmt::format(FMT_STRING("\n var obj_pos = vec4<f32>({}, 1.0);"
"\n var obj_norm = vec4<f32>({}, 0.0);"
"\n var mv_pos = ubuf.mv * obj_pos;"
"\n var mv_norm = ubuf.mv_inv * obj_norm;"
"\n out.pos = ubuf.proj * mv_pos;"),
vtx_attr(config, GX::VA_POS), vtx_attr(config, GX::VA_NRM));
std::string fragmentFnPre;
std::string fragmentFn;
@ -478,7 +544,7 @@ var<storage, read> v_packed_uvs: Vec2Block;
{
std::string outReg;
switch (stage->colorOp.outReg) {
case GX::TevRegID::TEVPREV:
case GX::TEVPREV:
outReg = "prev";
break;
case GX::TEVREG0:
@ -496,11 +562,13 @@ var<storage, read> v_packed_uvs: Vec2Block;
default:
Log.report(logvisor::Fatal, FMT_STRING("invalid colorOp outReg {}"), stage->colorOp.outReg);
}
std::string op = fmt::format(
FMT_STRING("({3} {4} ((1.0 - {2}) * {0} + {2} * {1}){5}){6}"),
color_arg_reg(stage->colorPass.a, idx, *stage, info), color_arg_reg(stage->colorPass.b, idx, *stage, info),
color_arg_reg(stage->colorPass.c, idx, *stage, info), color_arg_reg(stage->colorPass.d, idx, *stage, info),
tev_op(stage->colorOp.op), tev_bias(stage->colorOp.bias), tev_scale(stage->colorOp.scale));
std::string op =
fmt::format(FMT_STRING("({3} {4} ((1.0 - {2}) * {0} + {2} * {1}){5}){6}"),
color_arg_reg(stage->colorPass.a, idx, config, *stage, info),
color_arg_reg(stage->colorPass.b, idx, config, *stage, info),
color_arg_reg(stage->colorPass.c, idx, config, *stage, info),
color_arg_reg(stage->colorPass.d, idx, config, *stage, info), tev_op(stage->colorOp.op),
tev_bias(stage->colorOp.bias), tev_scale(stage->colorOp.scale));
if (stage->colorOp.clamp) {
op = fmt::format(FMT_STRING("clamp(vec3<f32>({}), vec3<f32>(0.0), vec3<f32>(1.0))"), op);
}
@ -509,7 +577,7 @@ var<storage, read> v_packed_uvs: Vec2Block;
{
std::string outReg;
switch (stage->alphaOp.outReg) {
case GX::TevRegID::TEVPREV:
case GX::TEVPREV:
outReg = "prev.a";
break;
case GX::TEVREG0:
@ -527,11 +595,13 @@ var<storage, read> v_packed_uvs: Vec2Block;
default:
Log.report(logvisor::Fatal, FMT_STRING("invalid alphaOp outReg {}"), stage->alphaOp.outReg);
}
std::string op = fmt::format(
FMT_STRING("({3} {4} ((1.0 - {2}) * {0} + {2} * {1}){5}){6}"),
alpha_arg_reg(stage->alphaPass.a, idx, *stage, info), alpha_arg_reg(stage->alphaPass.b, idx, *stage, info),
alpha_arg_reg(stage->alphaPass.c, idx, *stage, info), alpha_arg_reg(stage->alphaPass.d, idx, *stage, info),
tev_op(stage->alphaOp.op), tev_bias(stage->alphaOp.bias), tev_scale(stage->alphaOp.scale));
std::string op =
fmt::format(FMT_STRING("({3} {4} ((1.0 - {2}) * {0} + {2} * {1}){5}){6}"),
alpha_arg_reg(stage->alphaPass.a, idx, config, *stage, info),
alpha_arg_reg(stage->alphaPass.b, idx, config, *stage, info),
alpha_arg_reg(stage->alphaPass.c, idx, config, *stage, info),
alpha_arg_reg(stage->alphaPass.d, idx, config, *stage, info), tev_op(stage->alphaOp.op),
tev_bias(stage->alphaOp.bias), tev_scale(stage->alphaOp.scale));
if (stage->alphaOp.clamp) {
op = fmt::format(FMT_STRING("clamp({}, 0.0, 1.0)"), op);
}
@ -557,11 +627,6 @@ var<storage, read> v_packed_uvs: Vec2Block;
uniBufAttrs += fmt::format(FMT_STRING("\n cc{0}_mat: vec4<f32>;"), i);
info.uniformSize += 32;
if (config.denormalizedVertexAttributes && !info.usesVtxColor) {
vtxInAttrs += fmt::format(FMT_STRING("\n , @location({}) in_clr: vec4<f32>"), ++locIdx);
info.usesVtxColor = true;
}
if (config.colorChannels[i].lightingEnabled) {
if (!addedLightStruct) {
uniformPre +=
@ -580,7 +645,7 @@ var<storage, read> v_packed_uvs: Vec2Block;
uniBufAttrs += fmt::format(FMT_STRING("\n lighting_ambient{}: vec4<f32>;"), i);
info.uniformSize += (80 * GX::MaxLights) + 16;
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4<f32>;"), locIdx++, i);
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4<f32>;"), vtxOutIdx++, i);
vtxXfrAttrs += fmt::format(FMT_STRING(R"""(
{{
var lighting = ubuf.lighting_ambient{0} + ubuf.cc{0}_amb;
@ -604,13 +669,9 @@ var<storage, read> v_packed_uvs: Vec2Block;
i, GX::MaxLights);
fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = in.cc{0};"), i);
} else if (config.colorChannels[i].matSrc == GX::SRC_VTX) {
if (config.denormalizedVertexAttributes) {
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4<f32>;"), locIdx - 1, i);
vtxXfrAttrs += fmt::format(FMT_STRING("\n out.cc{} = in_clr;"), i);
fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = in.cc{0};"), i);
} else {
Log.report(logvisor::Fatal, FMT_STRING("SRC_VTX unsupported with normalized vertex attributes"));
}
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4<f32>;"), vtxOutIdx++, i);
vtxXfrAttrs += fmt::format(FMT_STRING("\n out.cc{} = {};"), i, vtx_attr(config, GX::Attr(GX::VA_CLR0 + i)));
fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = in.cc{0};"), i);
} else {
fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = ubuf.cc{0}_mat;"), i);
}
@ -628,23 +689,17 @@ var<storage, read> v_packed_uvs: Vec2Block;
continue;
}
const auto& tcg = config.tcgs[i];
if (config.denormalizedVertexAttributes) {
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) tex{}_uv: vec2<f32>;"), locIdx, i);
vtxInAttrs += fmt::format(FMT_STRING("\n , @location({}) in_tex{}_uv: vec2<f32>"), locIdx + 1, i);
// TODO check tcg src for denorm?
vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{0} = vec4<f32>(in_tex{0}_uv, 0.0, 1.0);"), i);
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) tex{}_uv: vec2<f32>;"), vtxOutIdx++, i);
if (tcg.src >= GX::TG_TEX0 && tcg.src <= GX::TG_TEX7) {
vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{} = vec4<f32>({}, 0.0, 1.0);"), i,
vtx_attr(config, GX::Attr(GX::VA_TEX0 + (tcg.src - GX::TG_TEX0))));
} else if (tcg.src == GX::TG_POS) {
vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{} = vec4<f32>(obj_pos.xyz, 1.0);"), i);
} else if (tcg.src == GX::TG_NRM) {
vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{} = vec4<f32>(obj_norm.xyz, 1.0);"), i);
} else {
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) tex{}_uv: vec2<f32>;"), locIdx, i);
if (tcg.src >= GX::TG_TEX0 && tcg.src <= GX::TG_TEX7) {
vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{} = vec4<f32>({}, 0.0, 1.0);"), i, in_uv(tcg.src - GX::TG_TEX0));
} else if (tcg.src == GX::TG_POS) {
vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{} = vec4<f32>(obj_pos.xyz, 1.0);"), i);
} else if (tcg.src == GX::TG_NRM) {
vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{} = vec4<f32>(obj_norm.xyz, 1.0);"), i);
} else {
Log.report(logvisor::Fatal, FMT_STRING("unhandled tcg src {}"), tcg.src);
unreachable();
}
Log.report(logvisor::Fatal, FMT_STRING("unhandled tcg src {}"), tcg.src);
unreachable();
}
// TODO this all assumes MTX3x4 currently
if (tcg.mtx == GX::IDENTITY) {
@ -663,12 +718,12 @@ var<storage, read> v_packed_uvs: Vec2Block;
} else {
u32 postMtxIdx = (tcg.postMtx - GX::PTTEXMTX0) / 3;
info.usesPTTexMtx.set(postMtxIdx);
vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{0}_proj = ubuf.postmtx{1} * vec4<f32>(tc{0}_tmp.xyz, 1.0);"), i, postMtxIdx);
vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{0}_proj = ubuf.postmtx{1} * vec4<f32>(tc{0}_tmp.xyz, 1.0);"),
i, postMtxIdx);
}
vtxXfrAttrs += fmt::format(FMT_STRING("\n out.tex{0}_uv = tc{0}_proj.xy;"), i);
fragmentFnPre += fmt::format(
FMT_STRING("\n var sampled{0} = textureSampleBias(tex{0}, tex{0}_samp, in.tex{0}_uv, ubuf.tex{0}_lod);"), i);
locIdx++;
}
for (int i = 0; i < info.usesTexMtx.size(); ++i) {
if (!info.usesTexMtx.test(i)) {
@ -698,7 +753,8 @@ var<storage, read> v_packed_uvs: Vec2Block;
if (config.fogType != GX::FOG_NONE) {
info.usesFog = true;
uniformPre += "\n"
uniformPre +=
"\n"
"struct Fog {\n"
" color: vec4<f32>;\n"
" a: f32;\n"
@ -729,7 +785,8 @@ var<storage, read> v_packed_uvs: Vec2Block;
break;
case GX::FOG_PERSP_REVEXP2:
case GX::FOG_ORTHO_REVEXP2:
fragmentFn += "\n fogF = 1.0 - fogF;"
fragmentFn +=
"\n fogF = 1.0 - fogF;"
"\n var fogZ = exp2(-8.0 * fogF * fogF);";
break;
default:
@ -767,7 +824,8 @@ struct Uniform {{
@group(0) @binding(0)
var<uniform> ubuf: Uniform;{uniformBindings}{sampBindings}{texBindings}
struct VertexOutput {{{vtxOutAttrs}
struct VertexOutput {{
@builtin(position) pos: vec4<f32>;{vtxOutAttrs}
}};
@stage(vertex)

View File

@ -5,47 +5,6 @@
#include <absl/container/flat_hash_map.h>
#include <aurora/model.hpp>
#include <magic_enum.hpp>
enum class VtxDescAttr : u8 {
Position = 0,
Normal = 2,
Color0 = 4,
Color1 = 6,
Tex0 = 8,
Tex1 = 10,
Tex2 = 12,
Tex3 = 14,
Tex4 = 16,
Tex5 = 18,
Tex6 = 20,
PnMatIdx = 24,
Tex0MatIdx = 25,
Tex1MatIdx = 26,
Tex2MatIdx = 27,
Tex3MatIdx = 28,
Tex4MatIdx = 29,
Tex5MatIdx = 30,
Tex6MatIdx = 31,
};
enum class VtxDescAttrType : u8 { None = 0, Direct = 1, Index8 = 2, Index16 = 3 };
class VtxDescFlags {
u32 m_flags = 0;
public:
constexpr VtxDescFlags() noexcept = default;
constexpr VtxDescFlags(u32 flags) noexcept : m_flags(flags){};
[[nodiscard]] constexpr VtxDescAttrType GetAttributeType(VtxDescAttr attribute) const noexcept {
return VtxDescAttrType((m_flags >> u32(attribute)) & 0x3);
}
[[nodiscard]] constexpr VtxDescAttrType GetDirectAttributeType(VtxDescAttr attribute) const noexcept {
return VtxDescAttrType((m_flags >> u32(attribute)) & 0x1);
}
constexpr void SetAttributeType(VtxDescAttr attribute, VtxDescAttrType type) noexcept {
m_flags &= ~(u32(0x3) << u32(attribute));
m_flags |= u32(type) << u32(attribute);
}
};
namespace aurora::gfx::model {
static logvisor::Module Log("aurora::gfx::model");
@ -59,53 +18,52 @@ static std::optional<Range> staticNrmRange;
static std::optional<Range> staticPackedTcRange;
static std::optional<Range> staticTcRange;
enum class VertexFormat : u8 {
F32F32,
S16F32,
S16S16,
};
static VtxDescFlags sVtxDescFlags;
void set_vtx_desc_compressed(u32 vtxDesc) noexcept { sVtxDescFlags = vtxDesc; }
static inline std::pair<gx::DlVert, size_t> readVert(const u8* data) noexcept {
gx::DlVert out{};
size_t offset = 0;
const auto read8 = [data, &offset](VtxDescAttrType type) -> s8 {
if (type == VtxDescAttrType::Direct) {
s8 v = static_cast<s8>(data[offset]);
++offset;
return v;
const auto vtxTypes = gx::g_gxState.vtxDesc;
const auto read8 = [/*data, &offset*/](GX::AttrType type) -> s8 {
// if (type == GX::INDEX8) {
// s8 v = static_cast<s8>(data[offset]);
// ++offset;
// return v;
// }
#ifndef NDEBUG
if (type != GX::NONE) {
Log.report(logvisor::Fatal, FMT_STRING("unsupported vtx attr"));
unreachable();
}
#endif
return 0;
};
const auto read16 = [data, &offset](VtxDescAttrType type) -> s16 {
if (type == VtxDescAttrType::Index16) {
const auto read16 = [data, &offset](GX::AttrType type) -> s16 {
if (type == GX::INDEX16) {
s16 v = metaforce::SBig(*reinterpret_cast<const u16*>(data + offset));
offset += 2;
return v;
}
return 0;
};
read8(sVtxDescFlags.GetDirectAttributeType(VtxDescAttr::PnMatIdx));
read8(sVtxDescFlags.GetDirectAttributeType(VtxDescAttr::Tex0MatIdx));
read8(sVtxDescFlags.GetDirectAttributeType(VtxDescAttr::Tex1MatIdx));
read8(sVtxDescFlags.GetDirectAttributeType(VtxDescAttr::Tex2MatIdx));
read8(sVtxDescFlags.GetDirectAttributeType(VtxDescAttr::Tex3MatIdx));
read8(sVtxDescFlags.GetDirectAttributeType(VtxDescAttr::Tex4MatIdx));
read8(sVtxDescFlags.GetDirectAttributeType(VtxDescAttr::Tex5MatIdx));
read8(sVtxDescFlags.GetDirectAttributeType(VtxDescAttr::Tex6MatIdx));
read8(vtxTypes[GX::VA_PNMTXIDX]);
read8(vtxTypes[GX::VA_TEX0MTXIDX]);
read8(vtxTypes[GX::VA_TEX1MTXIDX]);
read8(vtxTypes[GX::VA_TEX2MTXIDX]);
read8(vtxTypes[GX::VA_TEX3MTXIDX]);
read8(vtxTypes[GX::VA_TEX4MTXIDX]);
read8(vtxTypes[GX::VA_TEX5MTXIDX]);
read8(vtxTypes[GX::VA_TEX6MTXIDX]);
out.pos = read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Position));
out.norm = read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Normal));
read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Color0));
read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Color1));
out.uvs[0] = read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Tex0));
out.uvs[1] = read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Tex1));
out.uvs[2] = read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Tex2));
out.uvs[3] = read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Tex3));
out.uvs[4] = read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Tex4));
out.uvs[5] = read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Tex5));
out.uvs[6] = read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Tex6));
out.pos = read16(vtxTypes[GX::VA_POS]);
out.norm = read16(vtxTypes[GX::VA_NRM]);
read16(vtxTypes[GX::VA_CLR0]);
read16(vtxTypes[GX::VA_CLR1]);
out.uvs[0] = read16(vtxTypes[GX::VA_TEX0]);
out.uvs[1] = read16(vtxTypes[GX::VA_TEX1]);
out.uvs[2] = read16(vtxTypes[GX::VA_TEX2]);
out.uvs[3] = read16(vtxTypes[GX::VA_TEX3]);
out.uvs[4] = read16(vtxTypes[GX::VA_TEX4]);
out.uvs[5] = read16(vtxTypes[GX::VA_TEX5]);
out.uvs[6] = read16(vtxTypes[GX::VA_TEX6]);
return {out, offset};
}
@ -130,7 +88,6 @@ void queue_surface(const u8* dlStart, u32 dlSize) noexcept {
while (offset < dlSize - 6) {
const auto header = dlStart[offset];
const auto primitive = static_cast<GX::Primitive>(header & 0xF8);
const auto vtxFmt = static_cast<VertexFormat>(header & 0x3);
const auto vtxCount = metaforce::SBig(*reinterpret_cast<const u16*>(dlStart + offset + 1));
offset += 3;

View File

@ -4,71 +4,138 @@
#include "common.hpp"
#include "gx.hpp"
namespace aurora::gfx {
static logvisor::Module Log("aurora::gfx::stream");
using aurora::gfx::gx::g_gxState;
struct SStreamState {
GX::Primitive primitive;
metaforce::EStreamFlags flags;
uint32_t vertexCount = 0;
ByteBuffer vertexBuffer;
u16 vertexCount = 0;
aurora::ByteBuffer vertexBuffer;
std::vector<u16> indices;
#ifndef NDEBUG
GX::Attr currentAttr{};
#endif
explicit SStreamState(GX::Primitive primitive) noexcept : primitive(primitive) {}
explicit SStreamState(GX::Primitive primitive, u16 numVerts, u16 vertexSize) noexcept : primitive(primitive) {
vertexBuffer.reserve_extra(size_t(numVerts) * vertexSize);
if (numVerts > 3 && (primitive == GX::TRIANGLEFAN || primitive == GX::TRIANGLESTRIP)) {
indices.reserve((u32(numVerts) - 3) * 3 + 3);
} else if (numVerts > 4 && primitive == GX::QUADS) {
indices.reserve(u32(numVerts) / 4 * 6);
} else {
indices.reserve(numVerts);
}
}
};
static std::optional<SStreamState> sStreamState;
void stream_begin(GX::Primitive primitive) noexcept {
void GXBegin(GX::Primitive primitive, GX::VtxFmt vtxFmt, u16 nVerts) noexcept {
#ifndef NDEBUG
if (sStreamState) {
Log.report(logvisor::Fatal, FMT_STRING("Stream began twice!"));
unreachable();
}
sStreamState.emplace(primitive);
#endif
uint16_t vertexSize = 0;
for (GX::Attr attr{}; const auto type : g_gxState.vtxDesc) {
if (type == GX::DIRECT) {
if (attr == GX::VA_POS || attr == GX::VA_NRM) {
vertexSize += 12;
} else if (attr == GX::VA_CLR0 || attr == GX::VA_CLR1) {
vertexSize += 16;
} else if (attr >= GX::VA_TEX0 && attr <= GX::VA_TEX7) {
vertexSize += 8;
} else {
Log.report(logvisor::Fatal, FMT_STRING("don't know how to handle attr {}"), attr);
unreachable();
}
} else if (type != GX::NONE) {
Log.report(logvisor::Fatal, FMT_STRING("invalid vtx type {} for attr {}"), type, attr);
unreachable();
}
attr = GX::Attr(attr + 1);
}
if (vertexSize == 0) {
Log.report(logvisor::Fatal, FMT_STRING("no vtx attributes enabled?"));
unreachable();
}
sStreamState.emplace(primitive, nVerts, vertexSize);
}
void stream_vertex(metaforce::EStreamFlags flags, const zeus::CVector3f& pos, const zeus::CVector3f& nrm,
const zeus::CColor& color, const zeus::CVector2f& uv) noexcept {
static inline void check_attr_order(GX::Attr attr) noexcept {
#ifndef NDEBUG
if (!sStreamState) {
Log.report(logvisor::Fatal, FMT_STRING("Stream not started!"));
unreachable();
}
if (sStreamState->flags) {
if (sStreamState->flags != flags) {
Log.report(logvisor::Fatal, FMT_STRING("Stream changed flags?"));
unreachable();
}
} else {
sStreamState->flags = flags;
if (sStreamState->currentAttr >= attr) {
Log.report(logvisor::Fatal, FMT_STRING("bad attribute order: {}, last {}"), attr, sStreamState->currentAttr);
unreachable();
}
sStreamState->vertexBuffer.append(&pos, 12);
if (flags & metaforce::EStreamFlagBits::fHasNormal) {
sStreamState->vertexBuffer.append(&nrm, 12);
}
if (flags & metaforce::EStreamFlagBits::fHasColor) {
sStreamState->vertexBuffer.append(&color, 16);
}
if (flags & metaforce::EStreamFlagBits::fHasTexture) {
sStreamState->vertexBuffer.append(&uv, 8);
}
sStreamState->vertexCount++;
sStreamState->currentAttr = attr;
#endif
}
void stream_end() noexcept {
const auto vertRange = push_verts(sStreamState->vertexBuffer.data(), sStreamState->vertexBuffer.size());
stream::PipelineConfig config{};
config.shaderConfig.denormalizedVertexAttributes = true;
config.shaderConfig.denormalizedHasNrm = sStreamState->flags.IsSet(metaforce::EStreamFlagBits::fHasNormal);
const auto info = populate_pipeline_config(config, sStreamState->primitive, {});
const auto pipeline = pipeline_ref(config);
push_draw_command(stream::DrawData{
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
auto& state = *sStreamState;
state.vertexBuffer.append(&pos, 12);
if (state.primitive == GX::TRIANGLES || state.vertexCount < 3) {
state.indices.push_back(state.vertexCount);
} 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);
state.indices.push_back(state.vertexCount - 1);
} else {
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.vertexCount;
}
void GXNormal3f32(const zeus::CVector3f& nrm) noexcept {
check_attr_order(GX::VA_NRM);
sStreamState->vertexBuffer.append(&nrm, 12);
}
void GXColor4f32(const zeus::CColor& color) noexcept {
check_attr_order(GX::VA_CLR0);
sStreamState->vertexBuffer.append(&color, 16);
}
void GXTexCoord2f32(const zeus::CVector2f& uv) noexcept {
check_attr_order(GX::VA_TEX0);
sStreamState->vertexBuffer.append(&uv, 8);
}
void GXEnd() noexcept {
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{};
const auto info = populate_pipeline_config(config, GX::TRIANGLES, {});
const auto pipeline = aurora::gfx::pipeline_ref(config);
aurora::gfx::push_draw_command(aurora::gfx::stream::DrawData{
.pipeline = pipeline,
.vertRange = vertRange,
.uniformRange = build_uniform(info),
.vertexCount = sStreamState->vertexCount,
.indexRange = indexRange,
.indexCount = static_cast<uint32_t>(sStreamState->indices.size()),
.bindGroups = info.bindGroups,
});
sStreamState.reset();
}
} // namespace aurora::gfx

View File

@ -22,7 +22,7 @@ wgpu::RenderPipeline create_pipeline(const State& state, [[maybe_unused]] Pipeli
};
uint64_t offset = 12;
uint32_t shaderLocation = 1;
if (info.usesNormal) {
if (config.shaderConfig.vtxAttrs[GX::VA_NRM] == GX::DIRECT) {
attributes[shaderLocation] = wgpu::VertexAttribute{
.format = wgpu::VertexFormat::Float32x3,
.offset = offset,
@ -31,7 +31,7 @@ wgpu::RenderPipeline create_pipeline(const State& state, [[maybe_unused]] Pipeli
offset += 12;
shaderLocation++;
}
if (info.usesVtxColor) {
if (config.shaderConfig.vtxAttrs[GX::VA_CLR0] == GX::DIRECT) {
attributes[shaderLocation] = wgpu::VertexAttribute{
.format = wgpu::VertexFormat::Float32x4,
.offset = offset,
@ -40,9 +40,8 @@ wgpu::RenderPipeline create_pipeline(const State& state, [[maybe_unused]] Pipeli
offset += 16;
shaderLocation++;
}
// TODO only sample 1?
for (int i = 0; i < info.sampledTextures.size(); ++i) {
if (!info.sampledTextures.test(i)) {
for (int i = GX::VA_TEX0; i < GX::VA_TEX7; ++i) {
if (config.shaderConfig.vtxAttrs[i] != GX::DIRECT) {
continue;
}
attributes[shaderLocation] = wgpu::VertexAttribute{
@ -76,6 +75,7 @@ void render(const State& state, const DrawData& data, const wgpu::RenderPassEnco
pass.SetBindGroup(2, find_bind_group(data.bindGroups.textureBindGroup));
}
pass.SetVertexBuffer(0, g_vertexBuffer, data.vertRange.offset, data.vertRange.size);
pass.Draw(data.vertexCount);
pass.SetIndexBuffer(g_indexBuffer, wgpu::IndexFormat::Uint16, data.indexRange.offset, data.indexRange.size);
pass.DrawIndexed(data.indexCount);
}
} // namespace aurora::gfx::stream

View File

@ -8,7 +8,8 @@ struct DrawData {
PipelineRef pipeline;
Range vertRange;
Range uniformRange;
uint32_t vertexCount;
Range indexRange;
uint32_t indexCount;
gx::GXBindGroups bindGroups;
};