mirror of
https://github.com/AxioDL/PrimeWorldEditor.git
synced 2025-12-20 10:25:40 +00:00
Initial commit of current work on Prime World Editor
This commit is contained in:
364
Resource/cooker/CMaterialCooker.cpp
Normal file
364
Resource/cooker/CMaterialCooker.cpp
Normal file
@@ -0,0 +1,364 @@
|
||||
#include "CMaterialCooker.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
CMaterialCooker::CMaterialCooker()
|
||||
{
|
||||
mpMat = nullptr;
|
||||
}
|
||||
|
||||
void CMaterialCooker::WriteMatSetPrime(COutputStream& Out)
|
||||
{
|
||||
// Gather texture list from the materials before starting
|
||||
mTextureIDs.clear();
|
||||
u32 NumMats = mpSet->materials.size();
|
||||
|
||||
for (u32 iMat = 0; iMat < NumMats; iMat++)
|
||||
{
|
||||
CMaterial *pMat = mpSet->materials[iMat];
|
||||
|
||||
u32 NumPasses = pMat->PassCount();
|
||||
for (u32 iPass = 0; iPass < NumPasses; iPass++)
|
||||
{
|
||||
CTexture *pTex = pMat->Pass(iPass)->Texture();
|
||||
if (pTex)
|
||||
mTextureIDs.push_back(pTex->ResID().ToLong());
|
||||
}
|
||||
}
|
||||
|
||||
// Sort/remove duplicates
|
||||
std::sort(mTextureIDs.begin(), mTextureIDs.end());
|
||||
mTextureIDs.erase(std::unique(mTextureIDs.begin(), mTextureIDs.end()), mTextureIDs.end());
|
||||
|
||||
// Write texture IDs
|
||||
Out.WriteLong(mTextureIDs.size());
|
||||
|
||||
for (u32 iTex = 0; iTex < mTextureIDs.size(); iTex++)
|
||||
Out.WriteLong(mTextureIDs[iTex]);
|
||||
|
||||
// Write material offset filler
|
||||
Out.WriteLong(NumMats);
|
||||
u32 MatOffsetsStart = Out.Tell();
|
||||
|
||||
for (u32 iMat = 0; iMat < NumMats; iMat++)
|
||||
Out.WriteLong(0);
|
||||
|
||||
// Write materials
|
||||
u32 MatsStart = Out.Tell();
|
||||
std::vector<u32> MatEndOffsets(NumMats);
|
||||
|
||||
for (u32 iMat = 0; iMat < NumMats; iMat++)
|
||||
{
|
||||
mpMat = mpSet->materials[iMat];
|
||||
WriteMaterialPrime(Out);
|
||||
MatEndOffsets[iMat] = Out.Tell() - MatsStart;
|
||||
}
|
||||
|
||||
// Write material offsets
|
||||
u32 MatsEnd = Out.Tell();
|
||||
Out.Seek(MatOffsetsStart, SEEK_SET);
|
||||
|
||||
for (u32 iMat = 0; iMat < NumMats; iMat++)
|
||||
Out.WriteLong(MatEndOffsets[iMat]);
|
||||
|
||||
// Done!
|
||||
Out.Seek(MatsEnd, SEEK_SET);
|
||||
}
|
||||
|
||||
void CMaterialCooker::WriteMatSetCorruption(COutputStream&)
|
||||
{
|
||||
// Not using parameter 1 (COutputStream& - Out)
|
||||
// todo
|
||||
}
|
||||
|
||||
void CMaterialCooker::WriteMaterialPrime(COutputStream& Out)
|
||||
{
|
||||
// Gather data from the passes before we start writing
|
||||
u32 TexFlags = 0;
|
||||
u32 NumKonst = 0;
|
||||
std::vector<u32> TexIndices;
|
||||
|
||||
for (u32 iPass = 0; iPass < mpMat->mPasses.size(); iPass++)
|
||||
{
|
||||
CMaterialPass *pPass = mpMat->Pass(iPass);
|
||||
|
||||
if ((pPass->KColorSel() >= 0xC) || (pPass->KAlphaSel() >= 0x10))
|
||||
{
|
||||
// Determine the highest Konst index being used
|
||||
u32 KColorIndex = pPass->KColorSel() % 4;
|
||||
u32 KAlphaIndex = pPass->KAlphaSel() % 4;
|
||||
|
||||
if (KColorIndex >= NumKonst)
|
||||
NumKonst = KColorIndex + 1;
|
||||
if (KAlphaIndex >= NumKonst)
|
||||
NumKonst = KAlphaIndex + 1;
|
||||
}
|
||||
|
||||
CTexture *pPassTex = pPass->Texture();
|
||||
if (pPassTex != nullptr)
|
||||
{
|
||||
TexFlags |= (1 << iPass);
|
||||
u32 TexID = pPassTex->ResID().ToLong();
|
||||
|
||||
for (u32 iTex = 0; iTex < mTextureIDs.size(); iTex++)
|
||||
{
|
||||
if (mTextureIDs[iTex] == TexID)
|
||||
{
|
||||
TexIndices.push_back(iTex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get group index
|
||||
u32 GroupIndex;
|
||||
u64 MatHash = mpMat->HashParameters();
|
||||
bool NewHash = true;
|
||||
|
||||
for (u32 iHash = 0; iHash < mMaterialHashes.size(); iHash++)
|
||||
{
|
||||
if (mMaterialHashes[iHash] == MatHash)
|
||||
{
|
||||
GroupIndex = iHash;
|
||||
NewHash = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (NewHash)
|
||||
{
|
||||
GroupIndex = mMaterialHashes.size();
|
||||
mMaterialHashes.push_back(MatHash);
|
||||
}
|
||||
|
||||
// Start writing!
|
||||
// Generate flags value
|
||||
bool HasKonst = (NumKonst > 0);
|
||||
u32 Flags;
|
||||
|
||||
if (mVersion <= ePrime)
|
||||
Flags = 0x1003;
|
||||
else
|
||||
Flags = 0x4002;
|
||||
|
||||
Flags |= (HasKonst << 3) | mpMat->Options() | (TexFlags << 16);
|
||||
|
||||
Out.WriteLong(Flags);
|
||||
|
||||
// Texture indices
|
||||
Out.WriteLong(TexIndices.size());
|
||||
for (u32 iTex = 0; iTex < TexIndices.size(); iTex++)
|
||||
Out.WriteLong(TexIndices[iTex]);
|
||||
|
||||
// Vertex description
|
||||
EVertexDescription Desc = mpMat->VtxDesc();
|
||||
|
||||
if (mVersion < eEchoes)
|
||||
Desc = (EVertexDescription) (Desc & 0x00FFFFFF);
|
||||
|
||||
Out.WriteLong(Desc);
|
||||
|
||||
// Echoes unknowns
|
||||
if (mVersion == eEchoes)
|
||||
{
|
||||
Out.WriteLong(mpMat->EchoesUnknownA());
|
||||
Out.WriteLong(mpMat->EchoesUnknownB());
|
||||
}
|
||||
|
||||
// Group index
|
||||
Out.WriteLong(GroupIndex);
|
||||
|
||||
// Konst
|
||||
if (HasKonst)
|
||||
{
|
||||
Out.WriteLong(NumKonst);
|
||||
for (u32 iKonst = 0; iKonst < NumKonst; iKonst++)
|
||||
Out.WriteLong( mpMat->Konst(iKonst).AsLongRGBA() );
|
||||
}
|
||||
|
||||
// Blend Mode
|
||||
// Some modifications are done to convert the GLenum to the corresponding GX enum
|
||||
u16 BlendSrcFac = (u16) mpMat->BlendSrcFac();
|
||||
u16 BlendDstFac = (u16) mpMat->BlendDstFac();
|
||||
if (BlendSrcFac >= 0x300) BlendSrcFac -= 0x2FE;
|
||||
if (BlendDstFac >= 0x300) BlendDstFac -= 0x2FE;
|
||||
Out.WriteShort(BlendDstFac);
|
||||
Out.WriteShort(BlendSrcFac);
|
||||
|
||||
// Color Channels
|
||||
Out.WriteLong(1);
|
||||
Out.WriteLong(0x3000 | mpMat->IsLightingEnabled());
|
||||
|
||||
// TEV
|
||||
u32 NumPasses = mpMat->PassCount();
|
||||
Out.WriteLong(NumPasses);
|
||||
|
||||
for (u32 iPass = 0; iPass < NumPasses; iPass++)
|
||||
{
|
||||
CMaterialPass *pPass = mpMat->Pass(iPass);
|
||||
|
||||
u32 ColorInputFlags = ((pPass->ColorInput(0)) |
|
||||
(pPass->ColorInput(1) << 5) |
|
||||
(pPass->ColorInput(2) << 10) |
|
||||
(pPass->ColorInput(3) << 15));
|
||||
u32 AlphaInputFlags = ((pPass->AlphaInput(0)) |
|
||||
(pPass->AlphaInput(1) << 5) |
|
||||
(pPass->AlphaInput(2) << 10) |
|
||||
(pPass->AlphaInput(3) << 15));
|
||||
|
||||
u32 ColorOpFlags = 0x100 | (pPass->ColorOutput() << 9);
|
||||
u32 AlphaOpFlags = 0x100 | (pPass->AlphaOutput() << 9);
|
||||
|
||||
Out.WriteLong(ColorInputFlags);
|
||||
Out.WriteLong(AlphaInputFlags);
|
||||
Out.WriteLong(ColorOpFlags);
|
||||
Out.WriteLong(AlphaOpFlags);
|
||||
Out.WriteByte(0); // Padding
|
||||
Out.WriteByte(pPass->KAlphaSel());
|
||||
Out.WriteByte(pPass->KColorSel());
|
||||
Out.WriteByte(pPass->RasSel());
|
||||
}
|
||||
|
||||
// TEV Tex/UV input selection
|
||||
u32 CurTexIdx = 0;
|
||||
|
||||
for (u32 iPass = 0; iPass < NumPasses; iPass++)
|
||||
{
|
||||
Out.WriteShort(0); // Padding
|
||||
|
||||
if (mpMat->Pass(iPass)->Texture())
|
||||
{
|
||||
Out.WriteByte((u8) CurTexIdx);
|
||||
Out.WriteByte((u8) CurTexIdx);
|
||||
CurTexIdx++;
|
||||
}
|
||||
|
||||
else
|
||||
Out.WriteShort(0xFFFF);
|
||||
}
|
||||
|
||||
// TexGen
|
||||
u32 NumTexCoords = CurTexIdx; // TexIdx is currently equal to the tex coord count
|
||||
Out.WriteLong(NumTexCoords);
|
||||
u32 CurTexMtx = 0;
|
||||
|
||||
for (u32 iPass = 0; iPass < NumPasses; iPass++)
|
||||
{
|
||||
CMaterialPass *pPass = mpMat->Pass(iPass);
|
||||
if (pPass->Texture() == nullptr) continue;
|
||||
|
||||
u32 AnimType = pPass->AnimMode();
|
||||
u32 CoordSource = pPass->TexCoordSource();
|
||||
|
||||
u32 TexMtxIdx, PostMtxIdx;
|
||||
bool Normalize;
|
||||
|
||||
// No animation - set TexMtx and PostMtx to identity, disable normalization
|
||||
if (AnimType == eNoUVAnim)
|
||||
{
|
||||
TexMtxIdx = 30;
|
||||
PostMtxIdx = 61;
|
||||
Normalize = false;
|
||||
}
|
||||
|
||||
// Animation - set parameters as the animation mode needs them
|
||||
else
|
||||
{
|
||||
TexMtxIdx = CurTexMtx;
|
||||
|
||||
if ((AnimType < 2) || (AnimType > 5))
|
||||
{
|
||||
PostMtxIdx = CurTexMtx;
|
||||
Normalize = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
PostMtxIdx = 61;
|
||||
Normalize = false;
|
||||
}
|
||||
CurTexMtx += 3;
|
||||
}
|
||||
|
||||
u32 TexGenFlags = (CoordSource << 4) | (TexMtxIdx << 9) | (Normalize << 14) | (PostMtxIdx << 15);
|
||||
Out.WriteLong(TexGenFlags);
|
||||
}
|
||||
|
||||
// Animations
|
||||
u32 AnimSizeOffset = Out.Tell();
|
||||
u32 NumAnims = CurTexMtx; // CurTexMtx is currently equal to the anim count
|
||||
Out.WriteLong(0); // Anim size filler
|
||||
u32 AnimsStart = Out.Tell();
|
||||
Out.WriteLong(NumAnims);
|
||||
|
||||
for (u32 iPass = 0; iPass < NumPasses; iPass++)
|
||||
{
|
||||
CMaterialPass *pPass = mpMat->Pass(iPass);
|
||||
u32 AnimMode = pPass->AnimMode();
|
||||
if (AnimMode == eNoUVAnim) continue;
|
||||
|
||||
Out.WriteLong(AnimMode);
|
||||
|
||||
if ((AnimMode > 1) && (AnimMode != 6))
|
||||
{
|
||||
Out.WriteFloat(pPass->AnimParam(0));
|
||||
Out.WriteFloat(pPass->AnimParam(1));
|
||||
|
||||
if ((AnimMode == 2) || (AnimMode == 4) || (AnimMode == 5))
|
||||
{
|
||||
Out.WriteFloat(pPass->AnimParam(2));
|
||||
Out.WriteFloat(pPass->AnimParam(3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 AnimsEnd = Out.Tell();
|
||||
u32 AnimsSize = AnimsEnd - AnimsStart;
|
||||
Out.Seek(AnimSizeOffset, SEEK_SET);
|
||||
Out.WriteLong(AnimsSize);
|
||||
Out.Seek(AnimsEnd, SEEK_SET);
|
||||
|
||||
// Done!
|
||||
}
|
||||
|
||||
void CMaterialCooker::WriteMaterialCorruption(COutputStream&)
|
||||
{
|
||||
// Not using parameter 1 (COutputStream& - Out)
|
||||
// todo
|
||||
}
|
||||
|
||||
// ************ STATIC ************
|
||||
void CMaterialCooker::WriteCookedMatSet(CMaterialSet *pSet, EGame Version, COutputStream &Out)
|
||||
{
|
||||
CMaterialCooker Cooker;
|
||||
Cooker.mpSet = pSet;
|
||||
Cooker.mVersion = Version;
|
||||
|
||||
switch (Version)
|
||||
{
|
||||
case ePrimeKioskDemo:
|
||||
case ePrime:
|
||||
case eEchoesDemo:
|
||||
case eEchoes:
|
||||
Cooker.WriteMatSetPrime(Out);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CMaterialCooker::WriteCookedMaterial(CMaterial *pMat, EGame Version, COutputStream &Out)
|
||||
{
|
||||
CMaterialCooker Cooker;
|
||||
Cooker.mpMat = pMat;
|
||||
Cooker.mVersion = Version;
|
||||
|
||||
switch (Version)
|
||||
{
|
||||
case ePrimeKioskDemo:
|
||||
case ePrime:
|
||||
case eEchoesDemo:
|
||||
case eEchoes:
|
||||
Cooker.WriteMaterialPrime(Out);
|
||||
break;
|
||||
// TODO: Corruption/Uncooked
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user