Added area cooking support for MP2 and MP3. DKCR support has been started but is currently broken.
This commit is contained in:
parent
200918671b
commit
9f2c4d75bf
|
@ -1,71 +1,71 @@
|
|||
#include "CAnimationParameters.h"
|
||||
#include "CAnimSet.h"
|
||||
#include "CResCache.h"
|
||||
#include "CResourceInfo.h"
|
||||
#include <Common/Log.h>
|
||||
#include <iostream>
|
||||
|
||||
CAnimationParameters::CAnimationParameters()
|
||||
{
|
||||
mGame = ePrime;
|
||||
mpCharSet = nullptr;
|
||||
mNodeIndex = 0;
|
||||
mUnknown1 = 0;
|
||||
mUnknown2 = 0;
|
||||
mUnknown3 = 0;
|
||||
mUnknown4 = 0;
|
||||
}
|
||||
|
||||
CAnimationParameters::CAnimationParameters(IInputStream& SCLY, EGame Game)
|
||||
{
|
||||
mGame = Game;
|
||||
mpCharSet = nullptr;
|
||||
mNodeIndex = 0;
|
||||
mUnknown1 = 0;
|
||||
mUnknown2 = 0;
|
||||
mUnknown3 = 0;
|
||||
mUnknown4 = 0;
|
||||
|
||||
if (Game <= eEchoes)
|
||||
{
|
||||
u32 AnimSetID = SCLY.ReadLong();
|
||||
mCharacter = CResourceInfo(SCLY.ReadLong(), "ANCS");
|
||||
mNodeIndex = SCLY.ReadLong();
|
||||
mUnknown1 = SCLY.ReadLong();
|
||||
|
||||
mpCharSet = gResCache.GetResource(AnimSetID, "ANCS");
|
||||
}
|
||||
|
||||
else if (Game <= eCorruption)
|
||||
{
|
||||
u64 CharID = SCLY.ReadLongLong();
|
||||
mCharacter = CResourceInfo(SCLY.ReadLongLong(), "CHAR");
|
||||
mUnknown1 = SCLY.ReadLong();
|
||||
|
||||
mpCharSet = gResCache.GetResource(CharID, "CHAR");
|
||||
}
|
||||
|
||||
else if (Game == eReturns)
|
||||
{
|
||||
SCLY.Seek(-6, SEEK_CUR);
|
||||
u32 Offset = SCLY.Tell();
|
||||
u32 PropID = SCLY.ReadLong();
|
||||
SCLY.Seek(2, SEEK_CUR);
|
||||
u8 Flags = SCLY.ReadByte();
|
||||
|
||||
mUnknown1 = (u32) SCLY.ReadByte();
|
||||
mUnknown1 &= 0xFF;
|
||||
|
||||
if (mUnknown1 == 0x60)
|
||||
// 0x80 - CharacterAnimationSet is empty.
|
||||
if (Flags & 0x80)
|
||||
{
|
||||
u64 charID = SCLY.ReadLongLong();
|
||||
mUnknown2 = SCLY.ReadLong();
|
||||
mUnknown3 = SCLY.ReadLong();
|
||||
mUnknown4 = SCLY.ReadLong();
|
||||
|
||||
mpCharSet = gResCache.GetResource(charID, "CHAR");
|
||||
mUnknown1 = -1;
|
||||
mUnknown2 = 0;
|
||||
mUnknown3 = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
else if (mUnknown1 != 0x80)
|
||||
mCharacter = CResourceInfo(SCLY.ReadLongLong(), "CHAR");
|
||||
|
||||
// 0x20 - Default Anim is present
|
||||
if (Flags & 0x20)
|
||||
mUnknown1 = SCLY.ReadLong();
|
||||
else
|
||||
mUnknown1 = -1;
|
||||
|
||||
// 0x40 - Two-value struct is present
|
||||
if (Flags & 0x40)
|
||||
{
|
||||
Log::FileError(SCLY.GetSourceString(), Offset,
|
||||
"Unexpected AnimationParameters byte: " + TString::HexString(mUnknown1, true, true, 2) + " (property " + TString::HexString(PropID, true, true, 8) + ")");
|
||||
mUnknown2 = SCLY.ReadLong();
|
||||
mUnknown3 = SCLY.ReadLong();
|
||||
}
|
||||
else
|
||||
{
|
||||
mUnknown2 = 0;
|
||||
mUnknown3 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -74,9 +74,9 @@ void CAnimationParameters::Write(IOutputStream& rSCLY)
|
|||
{
|
||||
if (mGame <= eEchoes)
|
||||
{
|
||||
if (mpCharSet)
|
||||
if (mCharacter.IsValid())
|
||||
{
|
||||
rSCLY.WriteLong(AnimSet()->ResID().ToLong());
|
||||
rSCLY.WriteLong(mCharacter.ID().ToLong());
|
||||
rSCLY.WriteLong(mNodeIndex);
|
||||
rSCLY.WriteLong(mUnknown1);
|
||||
}
|
||||
|
@ -87,26 +87,72 @@ void CAnimationParameters::Write(IOutputStream& rSCLY)
|
|||
rSCLY.WriteLong(0xFFFFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
else if (mGame <= eCorruption)
|
||||
{
|
||||
if (mCharacter.IsValid())
|
||||
{
|
||||
rSCLY.WriteLongLong(mCharacter.ID().ToLongLong());
|
||||
rSCLY.WriteLong(mUnknown1);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
rSCLY.WriteLongLong(CUniqueID::skInvalidID64.ToLongLong());
|
||||
rSCLY.WriteLong(0xFFFFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (!mCharacter.IsValid())
|
||||
rSCLY.WriteByte((u8) 0x80);
|
||||
|
||||
else
|
||||
{
|
||||
u8 Flag = 0;
|
||||
if (mUnknown1 != -1) Flag |= 0x20;
|
||||
if (mUnknown2 != 0 || mUnknown3 != 0) Flag |= 0x40;
|
||||
|
||||
rSCLY.WriteByte(Flag);
|
||||
rSCLY.WriteLongLong(mCharacter.ID().ToLongLong());
|
||||
|
||||
if (Flag & 0x20)
|
||||
rSCLY.WriteLong(mUnknown1);
|
||||
|
||||
if (Flag & 0x40)
|
||||
{
|
||||
rSCLY.WriteLong(mUnknown2);
|
||||
rSCLY.WriteLong(mUnknown3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CModel* CAnimationParameters::GetCurrentModel(s32 NodeIndex /*= -1*/)
|
||||
{
|
||||
if (!mpCharSet) return nullptr;
|
||||
if (mpCharSet->Type() != eAnimSet) return nullptr;
|
||||
if (!mCharacter.IsValid()) return nullptr;
|
||||
|
||||
CAnimSet *pSet = (CAnimSet*) mCharacter.Load();
|
||||
if (!pSet) return nullptr;
|
||||
if (pSet->Type() != eAnimSet) return nullptr;
|
||||
if (NodeIndex == -1) NodeIndex = mNodeIndex;
|
||||
|
||||
if (mpCharSet->getNodeCount() <= (u32) NodeIndex) return nullptr;
|
||||
return mpCharSet->getNodeModel(NodeIndex);
|
||||
if (pSet->getNodeCount() <= (u32) NodeIndex) return nullptr;
|
||||
return pSet->getNodeModel(NodeIndex);
|
||||
}
|
||||
|
||||
TString CAnimationParameters::GetCurrentCharacterName(s32 NodeIndex /*= -1*/)
|
||||
{
|
||||
if (!mpCharSet) return "";
|
||||
if (mpCharSet->Type() != eAnimSet) return "";
|
||||
if (!mCharacter.IsValid()) return "";
|
||||
|
||||
CAnimSet *pSet = (CAnimSet*) mCharacter.Load();
|
||||
if (!pSet) return "";
|
||||
if (pSet->Type() != eAnimSet) return "";
|
||||
if (NodeIndex == -1) NodeIndex = mNodeIndex;
|
||||
|
||||
if (mpCharSet->getNodeCount() <= (u32) NodeIndex) return "";
|
||||
return mpCharSet->getNodeName((u32) NodeIndex);
|
||||
if (pSet->getNodeCount() <= (u32) NodeIndex) return "";
|
||||
return pSet->getNodeName((u32) NodeIndex);
|
||||
}
|
||||
|
||||
// ************ GETTERS ************
|
||||
|
@ -117,7 +163,7 @@ EGame CAnimationParameters::Version()
|
|||
|
||||
CAnimSet* CAnimationParameters::AnimSet()
|
||||
{
|
||||
return mpCharSet;
|
||||
return (CAnimSet*) mCharacter.Load();
|
||||
}
|
||||
|
||||
u32 CAnimationParameters::CharacterIndex()
|
||||
|
@ -132,21 +178,20 @@ u32 CAnimationParameters::Unknown(u32 Index)
|
|||
case 0: return mUnknown1;
|
||||
case 1: return mUnknown2;
|
||||
case 2: return mUnknown3;
|
||||
case 3: return mUnknown4;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// ************ SETTERS ************
|
||||
void CAnimationParameters::SetResource(CResource *pRes)
|
||||
void CAnimationParameters::SetResource(CResourceInfo Res)
|
||||
{
|
||||
if (!pRes || (pRes->Type() == eAnimSet) || (pRes->Type() == eCharacter))
|
||||
if (Res.Type() == "ANCS" || Res.Type() == "CHAR")
|
||||
{
|
||||
mpCharSet = pRes;
|
||||
mCharacter = Res;
|
||||
mNodeIndex = 0;
|
||||
}
|
||||
else
|
||||
Log::Error("Resource with invalid type passed to CAnimationParameters: " + pRes->Source());
|
||||
Log::Error("Resource with invalid type passed to CAnimationParameters: " + Res.ToString());
|
||||
}
|
||||
|
||||
void CAnimationParameters::SetNodeIndex(u32 Index)
|
||||
|
@ -161,6 +206,5 @@ void CAnimationParameters::SetUnknown(u32 Index, u32 Value)
|
|||
case 0: mUnknown1 = Value;
|
||||
case 1: mUnknown2 = Value;
|
||||
case 2: mUnknown3 = Value;
|
||||
case 3: mUnknown4 = Value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define CANIMATIONPARAMETERS_H
|
||||
|
||||
#include "CAnimSet.h"
|
||||
#include "CResourceInfo.h"
|
||||
#include "EGame.h"
|
||||
#include "TResPtr.h"
|
||||
#include "Core/Resource/Model/CModel.h"
|
||||
|
@ -9,13 +10,12 @@
|
|||
class CAnimationParameters
|
||||
{
|
||||
EGame mGame;
|
||||
TResPtr<CAnimSet> mpCharSet;
|
||||
CResourceInfo mCharacter;
|
||||
|
||||
u32 mNodeIndex;
|
||||
u32 mUnknown1;
|
||||
u32 mUnknown2;
|
||||
u32 mUnknown3;
|
||||
u32 mUnknown4;
|
||||
|
||||
public:
|
||||
CAnimationParameters();
|
||||
|
@ -32,7 +32,7 @@ public:
|
|||
u32 Unknown(u32 index);
|
||||
|
||||
// Setters
|
||||
void SetResource(CResource *pRes);
|
||||
void SetResource(CResourceInfo Res);
|
||||
void SetNodeIndex(u32 Index);
|
||||
void SetUnknown(u32 Index, u32 Value);
|
||||
|
||||
|
@ -40,12 +40,11 @@ public:
|
|||
inline bool operator==(const CAnimationParameters& rkOther) const
|
||||
{
|
||||
return ( (mGame == rkOther.mGame) &&
|
||||
(mpCharSet == rkOther.mpCharSet) &&
|
||||
(mCharacter == rkOther.mCharacter) &&
|
||||
(mNodeIndex == rkOther.mNodeIndex) &&
|
||||
(mUnknown1 == rkOther.mUnknown1) &&
|
||||
(mUnknown2 == rkOther.mUnknown2) &&
|
||||
(mUnknown3 == rkOther.mUnknown3) &&
|
||||
(mUnknown4 == rkOther.mUnknown4) );
|
||||
(mUnknown3 == rkOther.mUnknown3) );
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ CGameArea::CGameArea() : CResource()
|
|||
mVertexCount = 0;
|
||||
mTriangleCount = 0;
|
||||
mTerrainMerged = false;
|
||||
mOriginalWorldMeshCount = 0;
|
||||
mUsesCompression = false;
|
||||
mMaterialSet = nullptr;
|
||||
mpGeneratorLayer = nullptr;
|
||||
mCollision = nullptr;
|
||||
|
|
|
@ -29,8 +29,18 @@ class CGameArea : public CResource
|
|||
CTransform4f mTransform;
|
||||
CAABox mAABox;
|
||||
|
||||
// Section data buffers; this is used to avoid having to regenerate the entire contents of the file on cook
|
||||
// Data saved from the original file to help on recook
|
||||
std::vector<std::vector<u8>> mSectionDataBuffers;
|
||||
u32 mOriginalWorldMeshCount;
|
||||
bool mUsesCompression;
|
||||
|
||||
struct SSectionNumber
|
||||
{
|
||||
CFourCC SectionID;
|
||||
u32 Index;
|
||||
};
|
||||
std::vector<SSectionNumber> mSectionNumbers;
|
||||
|
||||
// Geometry
|
||||
CMaterialSet *mMaterialSet;
|
||||
std::vector<CModel*> mTerrainModels; // TerrainModels is the original version of each model; this is currently mainly used in the POI map editor
|
||||
|
@ -39,7 +49,6 @@ class CGameArea : public CResource
|
|||
std::vector<CScriptLayer*> mScriptLayers;
|
||||
CScriptLayer *mpGeneratorLayer;
|
||||
std::unordered_map<u32, CScriptObject*> mObjectMap;
|
||||
|
||||
// Collision
|
||||
CCollisionMeshGroup *mCollision;
|
||||
// Lights
|
||||
|
|
|
@ -25,6 +25,7 @@ void CWorld::SetAreaLayerInfo(CGameArea *pArea, u32 AreaIndex)
|
|||
|
||||
for (u32 iLyr = 0; iLyr < pArea->GetScriptLayerCount(); iLyr++)
|
||||
{
|
||||
if (AreaInfo.Layers.size() <= iLyr) break;
|
||||
CScriptLayer *pLayer = pArea->GetScriptLayer(iLyr);
|
||||
SArea::SLayer& LayerInfo = AreaInfo.Layers[iLyr];
|
||||
|
||||
|
|
|
@ -1,80 +1,190 @@
|
|||
#include "CAreaCooker.h"
|
||||
#include "CScriptCooker.h"
|
||||
#include <Common/CompressionUtil.h>
|
||||
#include <Common/Log.h>
|
||||
|
||||
const bool gkForceDisableCompression = false;
|
||||
|
||||
CAreaCooker::CAreaCooker()
|
||||
{
|
||||
}
|
||||
|
||||
void CAreaCooker::DetermineSectionNumbers()
|
||||
void CAreaCooker::DetermineSectionNumbersPrime()
|
||||
{
|
||||
mGeometrySecNum = 0;
|
||||
|
||||
// Determine how many sections are taken up by geometry...
|
||||
u32 GeometrySections = 1; // Starting at 1 to account for materials
|
||||
// Each world mesh has 7-9 sections (depending on game) plus one section per surface.
|
||||
u32 GeometrySections = 0;
|
||||
u32 OriginalMeshCount = mpArea->mOriginalWorldMeshCount;
|
||||
|
||||
// Each world mesh has (7 + surface count) sections
|
||||
// header, verts, normals, colors, float UVs, short UVs, surface offsets + surfaces
|
||||
for (u32 iMesh = 0; iMesh < mpArea->mTerrainModels.size(); iMesh++)
|
||||
switch (mVersion)
|
||||
{
|
||||
CModel *pModel = mpArea->mTerrainModels[iMesh];
|
||||
GeometrySections += (7 + pModel->GetSurfaceCount());
|
||||
case ePrimeDemo:
|
||||
case ePrime:
|
||||
GeometrySections = 1 + (7 * OriginalMeshCount); // Accounting for materials
|
||||
break;
|
||||
case eEchoesDemo:
|
||||
GeometrySections = 2 + (9 * OriginalMeshCount); // Account for materials + AROT
|
||||
break;
|
||||
case eEchoes:
|
||||
GeometrySections = 3 + (9 * OriginalMeshCount); // Acount for materials + AROT + an unknown section
|
||||
break;
|
||||
}
|
||||
|
||||
for (u32 iMesh = 0; iMesh < mpArea->mTerrainModels.size(); iMesh++)
|
||||
GeometrySections += mpArea->mTerrainModels[iMesh]->GetSurfaceCount();
|
||||
|
||||
// Set section numbers
|
||||
mArotSecNum = mGeometrySecNum + GeometrySections;
|
||||
mSclySecNum = mArotSecNum + 1;
|
||||
mCollisionSecNum = mSclySecNum + 1;
|
||||
mUnknownSecNum = mCollisionSecNum + 1;
|
||||
mLightsSecNum = mUnknownSecNum + 1;
|
||||
mVisiSecNum = mLightsSecNum + 1;
|
||||
mPathSecNum = mVisiSecNum + 1;
|
||||
u32 SecNum = GeometrySections;
|
||||
if (mVersion <= ePrime) mAROTSecNum = SecNum++;
|
||||
if (mVersion >= eEchoesDemo) mFFFFSecNum = SecNum++;
|
||||
|
||||
if (mVersion >= eEchoesDemo)
|
||||
{
|
||||
mSCLYSecNum = SecNum;
|
||||
SecNum += (mVersion >= eEchoes ? mpArea->mScriptLayers.size() : 1);
|
||||
mSCGNSecNum = SecNum++;
|
||||
}
|
||||
else
|
||||
mSCLYSecNum = SecNum++;
|
||||
|
||||
mCollisionSecNum = SecNum++;
|
||||
mUnknownSecNum = SecNum++;
|
||||
mLightsSecNum = SecNum++;
|
||||
mVISISecNum = SecNum++;
|
||||
mPATHSecNum = SecNum++;
|
||||
|
||||
if (mVersion >= eEchoesDemo)
|
||||
{
|
||||
mPTLASecNum = SecNum++;
|
||||
mEGMCSecNum = SecNum++;
|
||||
}
|
||||
}
|
||||
|
||||
void CAreaCooker::DetermineSectionNumbersCorruption()
|
||||
{
|
||||
// Because we're copying these from the original file (because not all the numbers
|
||||
// are present in every file), we don't care about any of these except SCLY and SCGN.
|
||||
for (u32 iNum = 0; iNum < mpArea->mSectionNumbers.size(); iNum++)
|
||||
{
|
||||
CGameArea::SSectionNumber& rNum = mpArea->mSectionNumbers[iNum];
|
||||
if (rNum.SectionID == "SOBJ") mSCLYSecNum = rNum.Index;
|
||||
else if (rNum.SectionID == "SGEN") mSCGNSecNum = rNum.Index;
|
||||
}
|
||||
}
|
||||
|
||||
// ************ HEADER ************
|
||||
void CAreaCooker::WritePrimeHeader(IOutputStream& rOut)
|
||||
{
|
||||
rOut.WriteLong(0xDEADBEEF);
|
||||
rOut.WriteLong(GetMREAVersion(mVersion));
|
||||
mpArea->mTransform.Write(rOut);
|
||||
rOut.WriteLong(mpArea->mTerrainModels.size());
|
||||
rOut.WriteLong(mpArea->mOriginalWorldMeshCount);
|
||||
if (mVersion >= eEchoes) rOut.WriteLong(mpArea->mScriptLayers.size());
|
||||
rOut.WriteLong(mpArea->mSectionDataBuffers.size());
|
||||
|
||||
rOut.WriteLong(mGeometrySecNum);
|
||||
rOut.WriteLong(mSclySecNum);
|
||||
rOut.WriteLong(mSCLYSecNum);
|
||||
if (mVersion >= eEchoesDemo) rOut.WriteLong(mSCGNSecNum);
|
||||
rOut.WriteLong(mCollisionSecNum);
|
||||
rOut.WriteLong(mUnknownSecNum);
|
||||
rOut.WriteLong(mLightsSecNum);
|
||||
rOut.WriteLong(mVisiSecNum);
|
||||
rOut.WriteLong(mPathSecNum);
|
||||
rOut.WriteLong(mArotSecNum);
|
||||
rOut.WriteLong(mVISISecNum);
|
||||
rOut.WriteLong(mPATHSecNum);
|
||||
if (mVersion <= ePrime) rOut.WriteLong(mAROTSecNum);
|
||||
|
||||
mSectionSizesOffset = rOut.Tell();
|
||||
for (u32 iSec = 0; iSec < mpArea->mSectionDataBuffers.size(); iSec++)
|
||||
rOut.WriteLong(0);
|
||||
else
|
||||
{
|
||||
rOut.WriteLong(mFFFFSecNum);
|
||||
rOut.WriteLong(mPTLASecNum);
|
||||
rOut.WriteLong(mEGMCSecNum);
|
||||
}
|
||||
|
||||
if (mVersion >= eEchoesDemo)
|
||||
{
|
||||
if (mVersion >= eEchoes) rOut.WriteLong(mCompressedBlocks.size());
|
||||
rOut.WriteToBoundary(32, 0);
|
||||
}
|
||||
|
||||
for (u32 iSec = 0; iSec < mSectionSizes.size(); iSec++)
|
||||
rOut.WriteLong(mSectionSizes[iSec]);
|
||||
rOut.WriteToBoundary(32, 0);
|
||||
|
||||
if (mVersion >= eEchoes)
|
||||
WriteCompressionHeader(rOut);
|
||||
}
|
||||
|
||||
void CAreaCooker::WriteCorruptionHeader(IOutputStream& rOut)
|
||||
{
|
||||
rOut.WriteLong(0xDEADBEEF);
|
||||
rOut.WriteLong(GetMREAVersion(mVersion));
|
||||
mpArea->mTransform.Write(rOut);
|
||||
rOut.WriteLong(mpArea->mOriginalWorldMeshCount);
|
||||
rOut.WriteLong(mpArea->mScriptLayers.size());
|
||||
rOut.WriteLong(mpArea->mSectionDataBuffers.size());
|
||||
rOut.WriteLong(mCompressedBlocks.size());
|
||||
rOut.WriteLong(mpArea->mSectionNumbers.size());
|
||||
rOut.WriteToBoundary(32, 0);
|
||||
|
||||
for (u32 iSec = 0; iSec < mSectionSizes.size(); iSec++)
|
||||
rOut.WriteLong(mSectionSizes[iSec]);
|
||||
|
||||
rOut.WriteToBoundary(32, 0);
|
||||
|
||||
mSectionMgr.SetSectionCount(mpArea->mSectionDataBuffers.size());
|
||||
mSectionMgr.Init(rOut);
|
||||
WriteCompressionHeader(rOut);
|
||||
|
||||
for (u32 iNum = 0; iNum < mpArea->mSectionNumbers.size(); iNum++)
|
||||
{
|
||||
CGameArea::SSectionNumber& rNum = mpArea->mSectionNumbers[iNum];
|
||||
rOut.WriteLong(rNum.SectionID.ToLong());
|
||||
rOut.WriteLong(rNum.Index);
|
||||
}
|
||||
rOut.WriteToBoundary(32, 0);
|
||||
}
|
||||
|
||||
void CAreaCooker::WriteCompressionHeader(IOutputStream& rOut)
|
||||
{
|
||||
for (u32 iCmp = 0; iCmp < mCompressedBlocks.size(); iCmp++)
|
||||
{
|
||||
SCompressedBlock& rBlock = mCompressedBlocks[iCmp];
|
||||
bool IsCompressed = (rBlock.CompressedSize != 0);
|
||||
|
||||
rOut.WriteLong(IsCompressed ? rBlock.DecompressedSize + 0x120 : rBlock.DecompressedSize);
|
||||
rOut.WriteLong(rBlock.DecompressedSize);
|
||||
rOut.WriteLong(rBlock.CompressedSize);
|
||||
rOut.WriteLong(rBlock.NumSections);
|
||||
}
|
||||
|
||||
rOut.WriteToBoundary(32, 0);
|
||||
}
|
||||
|
||||
void CAreaCooker::WriteAreaData(IOutputStream& rOut)
|
||||
{
|
||||
rOut.WriteBytes(mAreaData.Data(), mAreaData.Size());
|
||||
rOut.WriteToBoundary(32, 0);
|
||||
}
|
||||
|
||||
// ************ SCLY ************
|
||||
void CAreaCooker::WritePrimeSCLY(IOutputStream& rOut)
|
||||
{
|
||||
u32 NumLayers = mpArea->mScriptLayers.size();
|
||||
rOut.WriteString("SCLY", 4);
|
||||
rOut.WriteLong(0x1); // Unknown value, but it's always 1
|
||||
mVersion <= ePrime ? rOut.WriteLong(1) : rOut.WriteByte(1);
|
||||
|
||||
u32 NumLayers = mpArea->mScriptLayers.size();
|
||||
rOut.WriteLong(NumLayers);
|
||||
|
||||
u32 LayerSizesStart = rOut.Tell();
|
||||
for (u32 iLyr = 0; iLyr < NumLayers; iLyr++)
|
||||
rOut.WriteLong(0);
|
||||
|
||||
// SCLY
|
||||
std::vector<u32> LayerSizes(NumLayers);
|
||||
|
||||
for (u32 iLyr = 0; iLyr < mpArea->mScriptLayers.size(); iLyr++)
|
||||
for (u32 iLyr = 0; iLyr < NumLayers; iLyr++)
|
||||
{
|
||||
u32 LayerStart = rOut.Tell();
|
||||
CScriptCooker::WriteLayer(mpArea->Version(), mpArea->mScriptLayers[iLyr], rOut);
|
||||
CScriptCooker::WriteLayer(mVersion, mpArea->mScriptLayers[iLyr], rOut);
|
||||
LayerSizes[iLyr] = rOut.Tell() - LayerStart;
|
||||
}
|
||||
|
||||
|
@ -85,7 +195,114 @@ void CAreaCooker::WritePrimeSCLY(IOutputStream& rOut)
|
|||
rOut.WriteLong(LayerSizes[iLyr]);
|
||||
|
||||
rOut.Seek(LayersEnd, SEEK_SET);
|
||||
rOut.WriteToBoundary(32, 0);
|
||||
FinishSection(false);
|
||||
|
||||
// SCGN
|
||||
if (mVersion == eEchoesDemo)
|
||||
{
|
||||
rOut.WriteString("SCGN", 4);
|
||||
rOut.WriteByte(1);
|
||||
CScriptCooker::WriteLayer(mVersion, mpArea->mpGeneratorLayer, rOut);
|
||||
FinishSection(false);
|
||||
}
|
||||
}
|
||||
|
||||
void CAreaCooker::WriteEchoesSCLY(IOutputStream& rOut)
|
||||
{
|
||||
// SCLY
|
||||
for (u32 iLyr = 0; iLyr < mpArea->mScriptLayers.size(); iLyr++)
|
||||
{
|
||||
rOut.WriteString("SCLY", 4);
|
||||
rOut.WriteByte(0x1);
|
||||
rOut.WriteLong(iLyr);
|
||||
CScriptCooker::WriteLayer(mVersion, mpArea->mScriptLayers[iLyr], rOut);
|
||||
FinishSection(true);
|
||||
}
|
||||
|
||||
// SCGN
|
||||
rOut.WriteString("SCGN", 4);
|
||||
rOut.WriteByte(0x1);
|
||||
CScriptCooker::WriteLayer(mVersion, mpArea->mpGeneratorLayer, rOut);
|
||||
FinishSection(true);
|
||||
}
|
||||
|
||||
// ************ SECTION MANAGEMENT ************
|
||||
void CAreaCooker::AddSectionToBlock()
|
||||
{
|
||||
mCompressedData.WriteBytes(mSectionData.Data(), mSectionData.Size());
|
||||
mCompressedData.WriteToBoundary(32, 0);
|
||||
mCurBlock.DecompressedSize += mSectionData.Size();
|
||||
mCurBlock.NumSections++;
|
||||
}
|
||||
|
||||
void CAreaCooker::FinishSection(bool SingleSectionBlock)
|
||||
{
|
||||
// Our section data is now finished in mSection...
|
||||
const u32 kSizeThreshold = 0x20000;
|
||||
mSectionData.WriteToBoundary(32, 0);
|
||||
|
||||
u32 SecSize = mSectionData.Size();
|
||||
mSectionSizes.push_back(SecSize);
|
||||
|
||||
// Only track compressed blocks for MP2+. Write everything to one block for MP1.
|
||||
if (mVersion >= eEchoes)
|
||||
{
|
||||
// Finish the current block if this is a single section block OR if the new section would push the block over the size limit.
|
||||
if (mCurBlock.NumSections > 0 && (mCurBlock.DecompressedSize + SecSize > kSizeThreshold || SingleSectionBlock))
|
||||
FinishBlock();
|
||||
|
||||
AddSectionToBlock();
|
||||
|
||||
// And finally for a single section block, finish the new block.
|
||||
if (SingleSectionBlock)
|
||||
FinishBlock();
|
||||
}
|
||||
|
||||
else AddSectionToBlock();
|
||||
|
||||
mSectionData.Clear();
|
||||
}
|
||||
|
||||
void CAreaCooker::FinishBlock()
|
||||
{
|
||||
if (mCurBlock.NumSections == 0) return;
|
||||
|
||||
std::vector<u8> CompressedBuf(mCompressedData.Size() * 2);
|
||||
bool EnableCompression = (mVersion >= eEchoes) && mpArea->mUsesCompression && !gkForceDisableCompression;
|
||||
bool UseZlib = (mVersion == eReturns);
|
||||
|
||||
u32 CompressedSize = 0;
|
||||
bool WriteCompressedData = false;
|
||||
|
||||
if (EnableCompression)
|
||||
{
|
||||
bool Success = CompressionUtil::CompressSegmentedData((u8*) mCompressedData.Data(), mCompressedData.Size(), CompressedBuf.data(), CompressedSize, UseZlib);
|
||||
u32 PadBytes = (32 - (CompressedSize % 32)) & 0x3F;
|
||||
WriteCompressedData = Success && (CompressedSize + PadBytes < (u32) mCompressedData.Size());
|
||||
}
|
||||
|
||||
if (WriteCompressedData)
|
||||
{
|
||||
u32 PadBytes = 32 - (CompressedSize % 32);
|
||||
PadBytes &= 0x3F;
|
||||
|
||||
for (u32 iPad = 0; iPad < PadBytes; iPad++)
|
||||
mAreaData.WriteByte(0);
|
||||
|
||||
mAreaData.WriteBytes(CompressedBuf.data(), CompressedSize);
|
||||
mCurBlock.CompressedSize = CompressedSize;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
mAreaData.WriteBytes(mCompressedData.Data(), mCompressedData.Size());
|
||||
mAreaData.WriteToBoundary(32, 0);
|
||||
mCurBlock.CompressedSize = 0;
|
||||
}
|
||||
|
||||
mCompressedData.Clear();
|
||||
mCompressedBlocks.push_back(mCurBlock);
|
||||
mCurBlock = SCompressedBlock();
|
||||
}
|
||||
|
||||
// ************ STATIC ************
|
||||
|
@ -95,39 +312,41 @@ void CAreaCooker::WriteCookedArea(CGameArea *pArea, IOutputStream& rOut)
|
|||
Cooker.mpArea = pArea;
|
||||
Cooker.mVersion = pArea->Version();
|
||||
|
||||
if (Cooker.mVersion > ePrime)
|
||||
{
|
||||
Log::Error("Area cooking is not supported for games other than Metroid Prime");
|
||||
return;
|
||||
}
|
||||
|
||||
// Write header
|
||||
Cooker.DetermineSectionNumbers();
|
||||
Cooker.WritePrimeHeader(rOut);
|
||||
if (Cooker.mVersion <= eEchoes)
|
||||
Cooker.DetermineSectionNumbersPrime();
|
||||
else
|
||||
Cooker.DetermineSectionNumbersCorruption();
|
||||
|
||||
// Write pre-SCLY data sections
|
||||
for (u32 iSec = 0; iSec < Cooker.mSclySecNum; iSec++)
|
||||
for (u32 iSec = 0; iSec < Cooker.mSCLYSecNum; iSec++)
|
||||
{
|
||||
rOut.WriteBytes(pArea->mSectionDataBuffers[iSec].data(), pArea->mSectionDataBuffers[iSec].size());
|
||||
Cooker.mSectionMgr.AddSize(rOut);
|
||||
Cooker.mSectionData.WriteBytes(pArea->mSectionDataBuffers[iSec].data(), pArea->mSectionDataBuffers[iSec].size());
|
||||
Cooker.FinishSection(false);
|
||||
}
|
||||
|
||||
// Write SCLY
|
||||
Cooker.WritePrimeSCLY(rOut);
|
||||
Cooker.mSectionMgr.AddSize(rOut);
|
||||
if (Cooker.mVersion <= eEchoesDemo)
|
||||
Cooker.WritePrimeSCLY(Cooker.mSectionData);
|
||||
else
|
||||
Cooker.WriteEchoesSCLY(Cooker.mSectionData);
|
||||
|
||||
// Write post-SCLY data sections
|
||||
for (u32 iSec = Cooker.mSclySecNum + 1; iSec < pArea->mSectionDataBuffers.size(); iSec++)
|
||||
u32 PostSCLY = (Cooker.mVersion <= ePrime ? Cooker.mSCLYSecNum + 1 : Cooker.mSCGNSecNum + 1);
|
||||
for (u32 iSec = PostSCLY; iSec < pArea->mSectionDataBuffers.size(); iSec++)
|
||||
{
|
||||
rOut.WriteBytes(pArea->mSectionDataBuffers[iSec].data(), pArea->mSectionDataBuffers[iSec].size());
|
||||
Cooker.mSectionMgr.AddSize(rOut);
|
||||
Cooker.mSectionData.WriteBytes(pArea->mSectionDataBuffers[iSec].data(), pArea->mSectionDataBuffers[iSec].size());
|
||||
Cooker.FinishSection(false);
|
||||
}
|
||||
|
||||
// Write section sizes
|
||||
u32 AreaEnd = rOut.Tell();
|
||||
rOut.Seek(Cooker.mSectionSizesOffset, SEEK_SET);
|
||||
Cooker.mSectionMgr.WriteSizes(rOut);
|
||||
rOut.Seek(AreaEnd, SEEK_SET);
|
||||
Cooker.FinishBlock();
|
||||
|
||||
// Write to actual file
|
||||
if (Cooker.mVersion <= eEchoes)
|
||||
Cooker.WritePrimeHeader(rOut);
|
||||
else
|
||||
Cooker.WriteCorruptionHeader(rOut);
|
||||
|
||||
Cooker.WriteAreaData(rOut);
|
||||
}
|
||||
|
||||
u32 CAreaCooker::GetMREAVersion(EGame version)
|
||||
|
|
|
@ -11,22 +11,56 @@ class CAreaCooker
|
|||
TResPtr<CGameArea> mpArea;
|
||||
EGame mVersion;
|
||||
|
||||
CSectionMgrOut mSectionMgr;
|
||||
u32 mSectionSizesOffset;
|
||||
std::vector<u32> mSectionSizes;
|
||||
|
||||
u32 mGeometrySecNum;
|
||||
u32 mSclySecNum;
|
||||
u32 mSCLYSecNum;
|
||||
u32 mSCGNSecNum;
|
||||
u32 mCollisionSecNum;
|
||||
u32 mUnknownSecNum;
|
||||
u32 mLightsSecNum;
|
||||
u32 mVisiSecNum;
|
||||
u32 mPathSecNum;
|
||||
u32 mArotSecNum;
|
||||
u32 mVISISecNum;
|
||||
u32 mPATHSecNum;
|
||||
u32 mAROTSecNum;
|
||||
u32 mFFFFSecNum;
|
||||
u32 mPTLASecNum;
|
||||
u32 mEGMCSecNum;
|
||||
|
||||
struct SCompressedBlock
|
||||
{
|
||||
u32 CompressedSize;
|
||||
u32 DecompressedSize;
|
||||
u32 NumSections;
|
||||
|
||||
SCompressedBlock()
|
||||
: CompressedSize(0), DecompressedSize(0), NumSections(0) {}
|
||||
};
|
||||
|
||||
SCompressedBlock mCurBlock;
|
||||
CVectorOutStream mSectionData;
|
||||
CVectorOutStream mCompressedData;
|
||||
CVectorOutStream mAreaData;
|
||||
|
||||
std::vector<SCompressedBlock> mCompressedBlocks;
|
||||
|
||||
CAreaCooker();
|
||||
void DetermineSectionNumbers();
|
||||
void DetermineSectionNumbersPrime();
|
||||
void DetermineSectionNumbersCorruption();
|
||||
|
||||
// Header
|
||||
void WritePrimeHeader(IOutputStream& rOut);
|
||||
void WriteCorruptionHeader(IOutputStream& rOut);
|
||||
void WriteCompressionHeader(IOutputStream& rOut);
|
||||
void WriteAreaData(IOutputStream& rOut);
|
||||
|
||||
// SCLY
|
||||
void WritePrimeSCLY(IOutputStream& rOut);
|
||||
void WriteEchoesSCLY(IOutputStream& rOut);
|
||||
|
||||
// Section Management
|
||||
void AddSectionToBlock();
|
||||
void FinishSection(bool ForceFinishBlock);
|
||||
void FinishBlock();
|
||||
|
||||
public:
|
||||
static void WriteCookedArea(CGameArea *pArea, IOutputStream& rOut);
|
||||
|
|
|
@ -1,7 +1,17 @@
|
|||
#include "CScriptCooker.h"
|
||||
|
||||
void CScriptCooker::WriteProperty(IProperty *pProp)
|
||||
void CScriptCooker::WriteProperty(IProperty *pProp, bool InSingleStruct)
|
||||
{
|
||||
u32 SizeOffset = 0, PropStart = 0;
|
||||
|
||||
if (mVersion >= eEchoesDemo && !InSingleStruct)
|
||||
{
|
||||
mpSCLY->WriteLong(pProp->ID());
|
||||
SizeOffset = mpSCLY->Tell();
|
||||
mpSCLY->WriteShort(0x0);
|
||||
PropStart = mpSCLY->Tell();
|
||||
}
|
||||
|
||||
switch (pProp->Type())
|
||||
{
|
||||
|
||||
|
@ -96,25 +106,81 @@ void CScriptCooker::WriteProperty(IProperty *pProp)
|
|||
{
|
||||
TMayaSplineProperty *pSplineCast = static_cast<TMayaSplineProperty*>(pProp);
|
||||
std::vector<u8> Buffer = pSplineCast->Get();
|
||||
mpSCLY->WriteBytes(Buffer.data(), Buffer.size());
|
||||
if (!Buffer.empty()) mpSCLY->WriteBytes(Buffer.data(), Buffer.size());
|
||||
|
||||
else
|
||||
{
|
||||
if (mVersion < eReturns)
|
||||
{
|
||||
mpSCLY->WriteShort(0);
|
||||
mpSCLY->WriteLong(0);
|
||||
mpSCLY->WriteByte(1);
|
||||
mpSCLY->WriteFloat(0);
|
||||
mpSCLY->WriteFloat(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
mpSCLY->WriteLong(0);
|
||||
mpSCLY->WriteFloat(0);
|
||||
mpSCLY->WriteFloat(1);
|
||||
mpSCLY->WriteShort(0);
|
||||
mpSCLY->WriteByte(1);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case eStructProperty:
|
||||
case eArrayProperty:
|
||||
{
|
||||
CPropertyStruct *pStruct = static_cast<CPropertyStruct*>(pProp);
|
||||
CStructTemplate *pTemp = static_cast<CStructTemplate*>(pStruct->Template());
|
||||
|
||||
if (!pTemp->IsSingleProperty() || pProp->Type() == eArrayProperty)
|
||||
mpSCLY->WriteLong(pStruct->Count());
|
||||
std::vector<IProperty*> PropertiesToWrite;
|
||||
|
||||
for (u32 iProp = 0; iProp < pStruct->Count(); iProp++)
|
||||
WriteProperty(pStruct->PropertyByIndex(iProp));
|
||||
{
|
||||
IProperty *pSubProp = pStruct->PropertyByIndex(iProp);
|
||||
ECookPreference Pref = pSubProp->Template()->CookPreference();
|
||||
if (Pref == eNeverCook) continue;
|
||||
|
||||
if (mVersion < eReturns || pTemp->IsSingleProperty() || Pref == eAlwaysCook || !pSubProp->MatchesDefault())
|
||||
PropertiesToWrite.push_back(pSubProp);
|
||||
}
|
||||
|
||||
if (!pTemp->IsSingleProperty())
|
||||
{
|
||||
if (mVersion <= ePrime)
|
||||
mpSCLY->WriteLong(PropertiesToWrite.size());
|
||||
else
|
||||
mpSCLY->WriteShort((u16) PropertiesToWrite.size());
|
||||
}
|
||||
|
||||
for (u32 iProp = 0; iProp < PropertiesToWrite.size(); iProp++)
|
||||
WriteProperty(PropertiesToWrite[iProp], pTemp->IsSingleProperty());
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case eArrayProperty:
|
||||
{
|
||||
CArrayProperty *pArray = static_cast<CArrayProperty*>(pProp);
|
||||
mpSCLY->WriteLong(pArray->Count());
|
||||
|
||||
for (u32 iProp = 0; iProp < pArray->Count(); iProp++)
|
||||
WriteProperty(pArray->PropertyByIndex(iProp), true);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (SizeOffset != 0)
|
||||
{
|
||||
u32 PropEnd = mpSCLY->Tell();
|
||||
mpSCLY->Seek(SizeOffset, SEEK_SET);
|
||||
mpSCLY->WriteShort((u16) (PropEnd - PropStart));
|
||||
mpSCLY->Seek(PropEnd, SEEK_SET);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,12 +223,61 @@ void CScriptCooker::WriteInstanceMP1(CScriptObject *pInstance)
|
|||
mpSCLY->WriteLong(rkLink.ObjectID);
|
||||
}
|
||||
|
||||
WriteProperty(pInstance->Properties());
|
||||
WriteProperty(pInstance->Properties(), false);
|
||||
u32 InstanceEnd = mpSCLY->Tell();
|
||||
u32 InstanceSize = InstanceEnd - InstanceStart;
|
||||
|
||||
mpSCLY->Seek(SizeOffset, SEEK_SET);
|
||||
mpSCLY->WriteLong(InstanceSize);
|
||||
mpSCLY->WriteLong(InstanceEnd - InstanceStart);
|
||||
mpSCLY->Seek(InstanceEnd, SEEK_SET);
|
||||
}
|
||||
|
||||
void CScriptCooker::WriteLayerMP2(CScriptLayer *pLayer)
|
||||
{
|
||||
u32 LayerStart = mpSCLY->Tell();
|
||||
mpSCLY->WriteByte(0x1);
|
||||
mpSCLY->WriteLong(pLayer->NumInstances());
|
||||
|
||||
for (u32 iInst = 0; iInst < pLayer->NumInstances(); iInst++)
|
||||
{
|
||||
CScriptObject *pInstance = pLayer->InstanceByIndex(iInst);
|
||||
WriteInstanceMP2(pInstance);
|
||||
}
|
||||
|
||||
if (mVersion == eEchoesDemo)
|
||||
{
|
||||
u32 LayerSize = mpSCLY->Tell() - LayerStart;
|
||||
u32 NumPadBytes = 32 - (LayerSize % 32);
|
||||
if (NumPadBytes == 32) NumPadBytes = 0;
|
||||
|
||||
for (u32 iPad = 0; iPad < NumPadBytes; iPad++)
|
||||
mpSCLY->WriteByte(0);
|
||||
}
|
||||
}
|
||||
|
||||
void CScriptCooker::WriteInstanceMP2(CScriptObject *pInstance)
|
||||
{
|
||||
mpSCLY->WriteLong(pInstance->ObjectTypeID());
|
||||
|
||||
u32 SizeOffset = mpSCLY->Tell();
|
||||
mpSCLY->WriteShort(0);
|
||||
u32 InstanceStart = mpSCLY->Tell();
|
||||
|
||||
mpSCLY->WriteLong(pInstance->InstanceID());
|
||||
mpSCLY->WriteShort((u16) pInstance->NumOutLinks());
|
||||
|
||||
for (u32 iLink = 0; iLink < pInstance->NumOutLinks(); iLink++)
|
||||
{
|
||||
const SLink& rkLink = pInstance->OutLink(iLink);
|
||||
mpSCLY->WriteLong(rkLink.State);
|
||||
mpSCLY->WriteLong(rkLink.Message);
|
||||
mpSCLY->WriteLong(rkLink.ObjectID);
|
||||
}
|
||||
|
||||
WriteProperty(pInstance->Properties(), false);
|
||||
u32 InstanceEnd = mpSCLY->Tell();
|
||||
|
||||
mpSCLY->Seek(SizeOffset, SEEK_SET);
|
||||
mpSCLY->WriteShort((u16) (InstanceEnd - InstanceStart));
|
||||
mpSCLY->Seek(InstanceEnd, SEEK_SET);
|
||||
}
|
||||
|
||||
|
@ -172,5 +287,9 @@ void CScriptCooker::WriteLayer(EGame Game, CScriptLayer *pLayer, IOutputStream&
|
|||
CScriptCooker Cooker;
|
||||
Cooker.mpSCLY = &rOut;
|
||||
Cooker.mVersion = Game;
|
||||
Cooker.WriteLayerMP1(pLayer);
|
||||
|
||||
if (Game <= ePrime)
|
||||
Cooker.WriteLayerMP1(pLayer);
|
||||
else
|
||||
Cooker.WriteLayerMP2(pLayer);
|
||||
}
|
||||
|
|
|
@ -12,9 +12,11 @@ class CScriptCooker
|
|||
EGame mVersion;
|
||||
|
||||
CScriptCooker() {}
|
||||
void WriteProperty(IProperty *pProp);
|
||||
void WriteProperty(IProperty *pProp, bool InSingleStruct);
|
||||
void WriteLayerMP1(CScriptLayer *pLayer);
|
||||
void WriteInstanceMP1(CScriptObject *pInstance);
|
||||
void WriteLayerMP2(CScriptLayer *pLayer);
|
||||
void WriteInstanceMP2(CScriptObject *pInstance);
|
||||
|
||||
public:
|
||||
static void WriteLayer(EGame Game, CScriptLayer *pLayer, IOutputStream& rOut);
|
||||
|
|
|
@ -63,6 +63,8 @@ void CAreaLoader::ReadHeaderPrime()
|
|||
mpMREA->SeekToBoundary(32);
|
||||
mpSectionMgr->Init();
|
||||
LoadSectionDataBuffers();
|
||||
|
||||
mpArea->mOriginalWorldMeshCount = mNumMeshes;
|
||||
}
|
||||
|
||||
void CAreaLoader::ReadGeometryPrime()
|
||||
|
@ -116,39 +118,57 @@ void CAreaLoader::ReadGeometryPrime()
|
|||
|
||||
void CAreaLoader::ReadSCLYPrime()
|
||||
{
|
||||
// Prime, Echoes Demo
|
||||
Log::FileWrite(mpMREA->GetSourceString(), "Reading MREA script layers (MP1)");
|
||||
mpSectionMgr->ToSection(mScriptLayerBlockNum);
|
||||
|
||||
CFourCC SCLY(*mpMREA);
|
||||
if (SCLY != "SCLY")
|
||||
{
|
||||
Log::Error(mpMREA->GetSourceString() + " - Invalid SCLY magic: " + SCLY.ToString());
|
||||
Log::FileError(mpMREA->GetSourceString(), mpMREA->Tell() - 4, "Invalid SCLY magic: " + SCLY.ToString());
|
||||
return;
|
||||
}
|
||||
mpMREA->Seek(0x4, SEEK_CUR); // Skipping unknown value which is always 4
|
||||
|
||||
if (mVersion <= ePrime)
|
||||
mpMREA->Seek(0x4, SEEK_CUR);
|
||||
else
|
||||
mpMREA->Seek(0x1, SEEK_CUR);
|
||||
|
||||
// Read layer sizes
|
||||
mNumLayers = mpMREA->ReadLong();
|
||||
mpArea->mScriptLayers.reserve(mNumLayers);
|
||||
|
||||
mpArea->mScriptLayers.resize(mNumLayers);
|
||||
std::vector<u32> LayerSizes(mNumLayers);
|
||||
for (u32 iLayer = 0; iLayer < mNumLayers; iLayer++)
|
||||
LayerSizes[iLayer] = mpMREA->ReadLong();
|
||||
|
||||
for (u32 iLayer = 0; iLayer < mNumLayers; iLayer++)
|
||||
for (u32 iLyr = 0; iLyr < mNumLayers; iLyr++)
|
||||
LayerSizes[iLyr] = mpMREA->ReadLong();
|
||||
|
||||
// SCLY
|
||||
for (u32 iLyr = 0; iLyr < mNumLayers; iLyr++)
|
||||
{
|
||||
u32 Next = mpMREA->Tell() + LayerSizes[iLayer];
|
||||
|
||||
CScriptLayer *pLayer = CScriptLoader::LoadLayer(*mpMREA, mpArea, mVersion);
|
||||
if (pLayer)
|
||||
mpArea->mScriptLayers.push_back(pLayer);
|
||||
|
||||
u32 Next = mpMREA->Tell() + LayerSizes[iLyr];
|
||||
mpArea->mScriptLayers[iLyr] = CScriptLoader::LoadLayer(*mpMREA, mpArea, mVersion);
|
||||
mpMREA->Seek(Next, SEEK_SET);
|
||||
}
|
||||
|
||||
// SCGN
|
||||
if (mVersion == eEchoesDemo)
|
||||
{
|
||||
mpSectionMgr->ToSection(mScriptGeneratorBlockNum);
|
||||
|
||||
CFourCC SCGN(*mpMREA);
|
||||
if (SCGN != "SCGN")
|
||||
Log::FileError(mpMREA->GetSourceString(), mpMREA->Tell() - 4, "Invalid SCGN magic: " + SCGN.ToString());
|
||||
|
||||
else
|
||||
{
|
||||
mpMREA->Seek(0x1, SEEK_CUR);
|
||||
CScriptLayer *pLayer = CScriptLoader::LoadLayer(*mpMREA, mpArea, mVersion);
|
||||
|
||||
if (pLayer)
|
||||
{
|
||||
mpArea->mpGeneratorLayer = pLayer;
|
||||
pLayer->SetName("Generated Objects");
|
||||
pLayer->SetActive(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetUpObjects();
|
||||
}
|
||||
|
||||
|
@ -270,30 +290,49 @@ void CAreaLoader::ReadHeaderEchoes()
|
|||
|
||||
mpSectionMgr->Init();
|
||||
LoadSectionDataBuffers();
|
||||
|
||||
mpArea->mOriginalWorldMeshCount = mNumMeshes;
|
||||
}
|
||||
|
||||
void CAreaLoader::ReadSCLYEchoes()
|
||||
{
|
||||
// MP2, MP3 Proto, MP3, DKCR
|
||||
Log::FileWrite(mpMREA->GetSourceString(), "Reading MREA script layers (MP2/MP3/DKCR)");
|
||||
mpSectionMgr->ToSection(mScriptLayerBlockNum);
|
||||
mpArea->mScriptLayers.resize(mNumLayers);
|
||||
|
||||
// SCLY
|
||||
for (u32 l = 0; l < mNumLayers; l++)
|
||||
for (u32 iLyr = 0; iLyr < mNumLayers; iLyr++)
|
||||
{
|
||||
CScriptLayer *pLayer = CScriptLoader::LoadLayer(*mpMREA, mpArea, mVersion);
|
||||
|
||||
if (pLayer)
|
||||
mpArea->mScriptLayers.push_back(pLayer);
|
||||
CFourCC SCLY(*mpMREA);
|
||||
if (SCLY != "SCLY")
|
||||
{
|
||||
Log::FileError(mpMREA->GetSourceString(), mpMREA->Tell() - 4, "Layer " + TString::FromInt32(iLyr, 0, 10) + " - Invalid SCLY magic: " + SCLY.ToString());
|
||||
mpSectionMgr->ToNextSection();
|
||||
continue;
|
||||
}
|
||||
|
||||
mpMREA->Seek(0x5, SEEK_CUR); // Skipping unknown + layer index
|
||||
mpArea->mScriptLayers[iLyr] = CScriptLoader::LoadLayer(*mpMREA, mpArea, mVersion);
|
||||
mpSectionMgr->ToNextSection();
|
||||
}
|
||||
|
||||
// SCGN
|
||||
mpSectionMgr->ToSection(mScriptGeneratorBlockNum);
|
||||
CScriptLayer *pLayer = CScriptLoader::LoadLayer(*mpMREA, mpArea, mVersion);
|
||||
CFourCC SCGN(*mpMREA);
|
||||
if (SCGN != "SCGN")
|
||||
{
|
||||
Log::FileError(mpMREA->GetSourceString(), mpMREA->Tell() - 4, "Invalid SCGN magic: " + SCGN.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (pLayer)
|
||||
mpArea->mpGeneratorLayer = pLayer;
|
||||
mpMREA->Seek(0x1, SEEK_CUR); // Skipping unknown
|
||||
mpArea->mpGeneratorLayer = CScriptLoader::LoadLayer(*mpMREA, mpArea, mVersion);
|
||||
|
||||
if (mpArea->mpGeneratorLayer)
|
||||
{
|
||||
mpArea->mpGeneratorLayer->SetName("Generated Objects");
|
||||
mpArea->mpGeneratorLayer->SetActive(true);
|
||||
}
|
||||
|
||||
SetUpObjects();
|
||||
}
|
||||
|
@ -334,12 +373,19 @@ void CAreaLoader::ReadHeaderCorruption()
|
|||
else if (Type == "SOBJ") mScriptLayerBlockNum = Num;
|
||||
else if (Type == "SGEN") mScriptGeneratorBlockNum = Num;
|
||||
else if (Type == "WOBJ") mGeometryBlockNum = Num; // note WOBJ can show up multiple times, but is always 0
|
||||
|
||||
CGameArea::SSectionNumber SecNum;
|
||||
SecNum.SectionID = Type;
|
||||
SecNum.Index = Num;
|
||||
mpArea->mSectionNumbers.push_back(SecNum);
|
||||
}
|
||||
|
||||
mpMREA->SeekToBoundary(32);
|
||||
Decompress();
|
||||
mpSectionMgr->Init();
|
||||
LoadSectionDataBuffers();
|
||||
|
||||
mpArea->mOriginalWorldMeshCount = mNumMeshes;
|
||||
}
|
||||
|
||||
void CAreaLoader::ReadGeometryCorruption()
|
||||
|
@ -478,6 +524,8 @@ void CAreaLoader::ReadCompressedBlocks()
|
|||
mClusters[c].CompressedSize = mpMREA->ReadLong();
|
||||
mClusters[c].NumSections = mpMREA->ReadLong();
|
||||
mTotalDecmpSize += mClusters[c].DecompressedSize;
|
||||
|
||||
if (mClusters[c].CompressedSize != 0) mpArea->mUsesCompression = true;
|
||||
}
|
||||
|
||||
mpMREA->SeekToBoundary(32);
|
||||
|
|
|
@ -367,32 +367,7 @@ CScriptObject* CScriptLoader::LoadObjectMP2(IInputStream& SCLY)
|
|||
|
||||
CScriptLayer* CScriptLoader::LoadLayerMP2(IInputStream& SCLY)
|
||||
{
|
||||
bool IsSCGN = false;
|
||||
|
||||
if (mVersion >= eEchoes)
|
||||
{
|
||||
CFourCC SCLY_Magic(SCLY);
|
||||
|
||||
if (SCLY_Magic == "SCLY")
|
||||
{
|
||||
SCLY.Seek(0x6, SEEK_CUR);
|
||||
}
|
||||
else if (SCLY_Magic == "SCGN")
|
||||
{
|
||||
SCLY.Seek(0x2, SEEK_CUR);
|
||||
IsSCGN = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::FileError(SCLY.GetSourceString(), SCLY.Tell() - 4, "Invalid script layer magic: " + TString::HexString((u32) SCLY_Magic.ToLong()));
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SCLY.Seek(0x1, SEEK_CUR);
|
||||
}
|
||||
|
||||
SCLY.Seek(0x1, SEEK_CUR); // Skipping version. todo: verify this?
|
||||
u32 NumObjects = SCLY.ReadLong();
|
||||
|
||||
mpLayer = new CScriptLayer();
|
||||
|
@ -405,11 +380,6 @@ CScriptLayer* CScriptLoader::LoadLayerMP2(IInputStream& SCLY)
|
|||
mpLayer->AddInstance(pObj);
|
||||
}
|
||||
|
||||
if (IsSCGN)
|
||||
{
|
||||
mpLayer->SetName("Generated");
|
||||
mpLayer->SetActive(true);
|
||||
}
|
||||
return mpLayer;
|
||||
}
|
||||
|
||||
|
|
|
@ -160,7 +160,7 @@ public:
|
|||
TMayaSplineProperty(IPropertyTemplate *pTemp, CPropertyStruct *pParent, const std::vector<u8>& v)
|
||||
: TTypedProperty(pTemp, pParent, v) {}
|
||||
|
||||
virtual bool MatchesDefault() { return true; }
|
||||
virtual bool MatchesDefault() { return Get().empty(); }
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -608,7 +608,7 @@ void CPropertyDelegate::SetCharacterEditorData(QWidget *pEditor, const QModelInd
|
|||
|
||||
if (Type == eFileProperty)
|
||||
{
|
||||
static_cast<WResourceSelector*>(pEditor)->SetResource(Params.AnimSet());
|
||||
static_cast<WResourceSelector*>(pEditor)->SetResource(Params.AnimSet());
|
||||
}
|
||||
|
||||
else if (Type == eEnumProperty)
|
||||
|
@ -632,10 +632,10 @@ void CPropertyDelegate::SetCharacterModelData(QWidget *pEditor, const QModelInde
|
|||
|
||||
if (Type == eFileProperty)
|
||||
{
|
||||
Params.SetResource( static_cast<WResourceSelector*>(pEditor)->GetResource() );
|
||||
Params.SetResource( static_cast<WResourceSelector*>(pEditor)->GetResourceInfo() );
|
||||
// Reset all other parameters to 0
|
||||
Params.SetNodeIndex(0);
|
||||
for (u32 iUnk = 0; iUnk < 4; iUnk++)
|
||||
for (u32 iUnk = 0; iUnk < 3; iUnk++)
|
||||
Params.SetUnknown(iUnk, 0);
|
||||
}
|
||||
|
||||
|
@ -677,7 +677,7 @@ EPropertyType CPropertyDelegate::DetermineCharacterPropType(EGame Game, const QM
|
|||
else
|
||||
{
|
||||
if (rkIndex.row() == 0) return eFileProperty;
|
||||
else if (rkIndex.row() <= 3) return eLongProperty;
|
||||
else if (rkIndex.row() <= 2) return eLongProperty;
|
||||
}
|
||||
return eUnknownProperty;
|
||||
}
|
||||
|
|
|
@ -113,7 +113,7 @@ int CPropertyModel::rowCount(const QModelIndex& rkParent) const
|
|||
CAnimationParameters Params = static_cast<TCharacterProperty*>(pProp)->Get();
|
||||
if (Params.Version() <= eEchoes) return 3;
|
||||
if (Params.Version() <= eCorruption) return 2;
|
||||
return 5;
|
||||
return 4;
|
||||
}
|
||||
|
||||
default:
|
||||
|
@ -241,7 +241,8 @@ QVariant CPropertyModel::data(const QModelIndex& rkIndex, int Role) const
|
|||
if (rkIndex.column() == 0)
|
||||
{
|
||||
if (rkIndex.row() == 0) return "Character";
|
||||
else return "Unknown " + QString::number(rkIndex.row());
|
||||
else if (rkIndex.row() == 1) return "Default Anim";
|
||||
else return "Unknown " + QString::number(rkIndex.row() - 1);
|
||||
}
|
||||
|
||||
if (rkIndex.column() == 1 && rkIndex.row() > 0)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "Editor/UICommon.h"
|
||||
#include <Core/Resource/CAnimSet.h>
|
||||
#include <Core/Resource/CResCache.h>
|
||||
#include <Core/Resource/CResourceInfo.h>
|
||||
|
||||
WAnimParamsEditor::WAnimParamsEditor(QWidget *pParent)
|
||||
: QWidget(pParent),
|
||||
|
@ -66,10 +67,10 @@ void WAnimParamsEditor::SetParameters(const CAnimationParameters& params)
|
|||
// ************ PRIVATE SLOTS ************
|
||||
void WAnimParamsEditor::OnResourceChanged(QString path)
|
||||
{
|
||||
CResource *pRes = gResCache.GetResource(path.toStdString());
|
||||
if (pRes && pRes->Type() != eAnimSet) pRes = nullptr;
|
||||
CResourceInfo ResInfo(path.toStdString());
|
||||
if (ResInfo.Type() != "ANCS" && ResInfo.Type() != "CHAR") ResInfo = CResourceInfo();
|
||||
|
||||
mParams.SetResource(pRes);
|
||||
mParams.SetResource(ResInfo);
|
||||
emit ParametersChanged(mParams);
|
||||
}
|
||||
|
||||
|
@ -217,7 +218,7 @@ void WAnimParamsEditor::SetupUI()
|
|||
connect(mpSpinBoxes[0], SIGNAL(valueChanged(int)), this, SLOT(OnUnknownChanged()));
|
||||
|
||||
// Create unknown spin box B/C/D
|
||||
for (u32 iBox = 1; iBox < 4; iBox++)
|
||||
for (u32 iBox = 1; iBox < 3; iBox++)
|
||||
{
|
||||
mpSpinBoxes[iBox] = new WIntegralSpinBox(this);
|
||||
mpSpinBoxes[iBox]->setRange(INT32_MIN, INT32_MAX);
|
||||
|
|
Loading…
Reference in New Issue