Added area cooking support for MP2 and MP3. DKCR support has been started but is currently broken.

This commit is contained in:
parax0 2016-02-22 11:47:47 -07:00
parent 200918671b
commit 9f2c4d75bf
15 changed files with 638 additions and 189 deletions

View File

@ -1,71 +1,71 @@
#include "CAnimationParameters.h" #include "CAnimationParameters.h"
#include "CAnimSet.h" #include "CAnimSet.h"
#include "CResCache.h" #include "CResCache.h"
#include "CResourceInfo.h"
#include <Common/Log.h> #include <Common/Log.h>
#include <iostream> #include <iostream>
CAnimationParameters::CAnimationParameters() CAnimationParameters::CAnimationParameters()
{ {
mGame = ePrime; mGame = ePrime;
mpCharSet = nullptr;
mNodeIndex = 0; mNodeIndex = 0;
mUnknown1 = 0; mUnknown1 = 0;
mUnknown2 = 0; mUnknown2 = 0;
mUnknown3 = 0; mUnknown3 = 0;
mUnknown4 = 0;
} }
CAnimationParameters::CAnimationParameters(IInputStream& SCLY, EGame Game) CAnimationParameters::CAnimationParameters(IInputStream& SCLY, EGame Game)
{ {
mGame = Game; mGame = Game;
mpCharSet = nullptr;
mNodeIndex = 0; mNodeIndex = 0;
mUnknown1 = 0; mUnknown1 = 0;
mUnknown2 = 0; mUnknown2 = 0;
mUnknown3 = 0; mUnknown3 = 0;
mUnknown4 = 0;
if (Game <= eEchoes) if (Game <= eEchoes)
{ {
u32 AnimSetID = SCLY.ReadLong(); mCharacter = CResourceInfo(SCLY.ReadLong(), "ANCS");
mNodeIndex = SCLY.ReadLong(); mNodeIndex = SCLY.ReadLong();
mUnknown1 = SCLY.ReadLong(); mUnknown1 = SCLY.ReadLong();
mpCharSet = gResCache.GetResource(AnimSetID, "ANCS");
} }
else if (Game <= eCorruption) else if (Game <= eCorruption)
{ {
u64 CharID = SCLY.ReadLongLong(); mCharacter = CResourceInfo(SCLY.ReadLongLong(), "CHAR");
mUnknown1 = SCLY.ReadLong(); mUnknown1 = SCLY.ReadLong();
mpCharSet = gResCache.GetResource(CharID, "CHAR");
} }
else if (Game == eReturns) else if (Game == eReturns)
{ {
SCLY.Seek(-6, SEEK_CUR); u8 Flags = SCLY.ReadByte();
u32 Offset = SCLY.Tell();
u32 PropID = SCLY.ReadLong();
SCLY.Seek(2, SEEK_CUR);
mUnknown1 = (u32) SCLY.ReadByte(); // 0x80 - CharacterAnimationSet is empty.
mUnknown1 &= 0xFF; if (Flags & 0x80)
if (mUnknown1 == 0x60)
{ {
u64 charID = SCLY.ReadLongLong(); mUnknown1 = -1;
mUnknown2 = SCLY.ReadLong(); mUnknown2 = 0;
mUnknown3 = SCLY.ReadLong(); mUnknown3 = 0;
mUnknown4 = SCLY.ReadLong(); return;
mpCharSet = gResCache.GetResource(charID, "CHAR");
} }
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, mUnknown2 = SCLY.ReadLong();
"Unexpected AnimationParameters byte: " + TString::HexString(mUnknown1, true, true, 2) + " (property " + TString::HexString(PropID, true, true, 8) + ")"); mUnknown3 = SCLY.ReadLong();
}
else
{
mUnknown2 = 0;
mUnknown3 = 0;
} }
} }
} }
@ -74,9 +74,9 @@ void CAnimationParameters::Write(IOutputStream& rSCLY)
{ {
if (mGame <= eEchoes) if (mGame <= eEchoes)
{ {
if (mpCharSet) if (mCharacter.IsValid())
{ {
rSCLY.WriteLong(AnimSet()->ResID().ToLong()); rSCLY.WriteLong(mCharacter.ID().ToLong());
rSCLY.WriteLong(mNodeIndex); rSCLY.WriteLong(mNodeIndex);
rSCLY.WriteLong(mUnknown1); rSCLY.WriteLong(mUnknown1);
} }
@ -87,26 +87,72 @@ void CAnimationParameters::Write(IOutputStream& rSCLY)
rSCLY.WriteLong(0xFFFFFFFF); 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*/) CModel* CAnimationParameters::GetCurrentModel(s32 NodeIndex /*= -1*/)
{ {
if (!mpCharSet) return nullptr; if (!mCharacter.IsValid()) return nullptr;
if (mpCharSet->Type() != eAnimSet) return nullptr;
CAnimSet *pSet = (CAnimSet*) mCharacter.Load();
if (!pSet) return nullptr;
if (pSet->Type() != eAnimSet) return nullptr;
if (NodeIndex == -1) NodeIndex = mNodeIndex; if (NodeIndex == -1) NodeIndex = mNodeIndex;
if (mpCharSet->getNodeCount() <= (u32) NodeIndex) return nullptr; if (pSet->getNodeCount() <= (u32) NodeIndex) return nullptr;
return mpCharSet->getNodeModel(NodeIndex); return pSet->getNodeModel(NodeIndex);
} }
TString CAnimationParameters::GetCurrentCharacterName(s32 NodeIndex /*= -1*/) TString CAnimationParameters::GetCurrentCharacterName(s32 NodeIndex /*= -1*/)
{ {
if (!mpCharSet) return ""; if (!mCharacter.IsValid()) return "";
if (mpCharSet->Type() != eAnimSet) return "";
CAnimSet *pSet = (CAnimSet*) mCharacter.Load();
if (!pSet) return "";
if (pSet->Type() != eAnimSet) return "";
if (NodeIndex == -1) NodeIndex = mNodeIndex; if (NodeIndex == -1) NodeIndex = mNodeIndex;
if (mpCharSet->getNodeCount() <= (u32) NodeIndex) return ""; if (pSet->getNodeCount() <= (u32) NodeIndex) return "";
return mpCharSet->getNodeName((u32) NodeIndex); return pSet->getNodeName((u32) NodeIndex);
} }
// ************ GETTERS ************ // ************ GETTERS ************
@ -117,7 +163,7 @@ EGame CAnimationParameters::Version()
CAnimSet* CAnimationParameters::AnimSet() CAnimSet* CAnimationParameters::AnimSet()
{ {
return mpCharSet; return (CAnimSet*) mCharacter.Load();
} }
u32 CAnimationParameters::CharacterIndex() u32 CAnimationParameters::CharacterIndex()
@ -132,21 +178,20 @@ u32 CAnimationParameters::Unknown(u32 Index)
case 0: return mUnknown1; case 0: return mUnknown1;
case 1: return mUnknown2; case 1: return mUnknown2;
case 2: return mUnknown3; case 2: return mUnknown3;
case 3: return mUnknown4;
default: return 0; default: return 0;
} }
} }
// ************ SETTERS ************ // ************ 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; mNodeIndex = 0;
} }
else 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) void CAnimationParameters::SetNodeIndex(u32 Index)
@ -161,6 +206,5 @@ void CAnimationParameters::SetUnknown(u32 Index, u32 Value)
case 0: mUnknown1 = Value; case 0: mUnknown1 = Value;
case 1: mUnknown2 = Value; case 1: mUnknown2 = Value;
case 2: mUnknown3 = Value; case 2: mUnknown3 = Value;
case 3: mUnknown4 = Value;
} }
} }

View File

@ -2,6 +2,7 @@
#define CANIMATIONPARAMETERS_H #define CANIMATIONPARAMETERS_H
#include "CAnimSet.h" #include "CAnimSet.h"
#include "CResourceInfo.h"
#include "EGame.h" #include "EGame.h"
#include "TResPtr.h" #include "TResPtr.h"
#include "Core/Resource/Model/CModel.h" #include "Core/Resource/Model/CModel.h"
@ -9,13 +10,12 @@
class CAnimationParameters class CAnimationParameters
{ {
EGame mGame; EGame mGame;
TResPtr<CAnimSet> mpCharSet; CResourceInfo mCharacter;
u32 mNodeIndex; u32 mNodeIndex;
u32 mUnknown1; u32 mUnknown1;
u32 mUnknown2; u32 mUnknown2;
u32 mUnknown3; u32 mUnknown3;
u32 mUnknown4;
public: public:
CAnimationParameters(); CAnimationParameters();
@ -32,7 +32,7 @@ public:
u32 Unknown(u32 index); u32 Unknown(u32 index);
// Setters // Setters
void SetResource(CResource *pRes); void SetResource(CResourceInfo Res);
void SetNodeIndex(u32 Index); void SetNodeIndex(u32 Index);
void SetUnknown(u32 Index, u32 Value); void SetUnknown(u32 Index, u32 Value);
@ -40,12 +40,11 @@ public:
inline bool operator==(const CAnimationParameters& rkOther) const inline bool operator==(const CAnimationParameters& rkOther) const
{ {
return ( (mGame == rkOther.mGame) && return ( (mGame == rkOther.mGame) &&
(mpCharSet == rkOther.mpCharSet) && (mCharacter == rkOther.mCharacter) &&
(mNodeIndex == rkOther.mNodeIndex) && (mNodeIndex == rkOther.mNodeIndex) &&
(mUnknown1 == rkOther.mUnknown1) && (mUnknown1 == rkOther.mUnknown1) &&
(mUnknown2 == rkOther.mUnknown2) && (mUnknown2 == rkOther.mUnknown2) &&
(mUnknown3 == rkOther.mUnknown3) && (mUnknown3 == rkOther.mUnknown3) );
(mUnknown4 == rkOther.mUnknown4) );
} }
}; };

View File

@ -7,6 +7,8 @@ CGameArea::CGameArea() : CResource()
mVertexCount = 0; mVertexCount = 0;
mTriangleCount = 0; mTriangleCount = 0;
mTerrainMerged = false; mTerrainMerged = false;
mOriginalWorldMeshCount = 0;
mUsesCompression = false;
mMaterialSet = nullptr; mMaterialSet = nullptr;
mpGeneratorLayer = nullptr; mpGeneratorLayer = nullptr;
mCollision = nullptr; mCollision = nullptr;

View File

@ -29,8 +29,18 @@ class CGameArea : public CResource
CTransform4f mTransform; CTransform4f mTransform;
CAABox mAABox; 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; std::vector<std::vector<u8>> mSectionDataBuffers;
u32 mOriginalWorldMeshCount;
bool mUsesCompression;
struct SSectionNumber
{
CFourCC SectionID;
u32 Index;
};
std::vector<SSectionNumber> mSectionNumbers;
// Geometry // Geometry
CMaterialSet *mMaterialSet; CMaterialSet *mMaterialSet;
std::vector<CModel*> mTerrainModels; // TerrainModels is the original version of each model; this is currently mainly used in the POI map editor 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; std::vector<CScriptLayer*> mScriptLayers;
CScriptLayer *mpGeneratorLayer; CScriptLayer *mpGeneratorLayer;
std::unordered_map<u32, CScriptObject*> mObjectMap; std::unordered_map<u32, CScriptObject*> mObjectMap;
// Collision // Collision
CCollisionMeshGroup *mCollision; CCollisionMeshGroup *mCollision;
// Lights // Lights

View File

@ -25,6 +25,7 @@ void CWorld::SetAreaLayerInfo(CGameArea *pArea, u32 AreaIndex)
for (u32 iLyr = 0; iLyr < pArea->GetScriptLayerCount(); iLyr++) for (u32 iLyr = 0; iLyr < pArea->GetScriptLayerCount(); iLyr++)
{ {
if (AreaInfo.Layers.size() <= iLyr) break;
CScriptLayer *pLayer = pArea->GetScriptLayer(iLyr); CScriptLayer *pLayer = pArea->GetScriptLayer(iLyr);
SArea::SLayer& LayerInfo = AreaInfo.Layers[iLyr]; SArea::SLayer& LayerInfo = AreaInfo.Layers[iLyr];

View File

@ -1,80 +1,190 @@
#include "CAreaCooker.h" #include "CAreaCooker.h"
#include "CScriptCooker.h" #include "CScriptCooker.h"
#include <Common/CompressionUtil.h>
#include <Common/Log.h> #include <Common/Log.h>
const bool gkForceDisableCompression = false;
CAreaCooker::CAreaCooker() CAreaCooker::CAreaCooker()
{ {
} }
void CAreaCooker::DetermineSectionNumbers() void CAreaCooker::DetermineSectionNumbersPrime()
{ {
mGeometrySecNum = 0; mGeometrySecNum = 0;
// Determine how many sections are taken up by geometry... // 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 switch (mVersion)
// header, verts, normals, colors, float UVs, short UVs, surface offsets + surfaces
for (u32 iMesh = 0; iMesh < mpArea->mTerrainModels.size(); iMesh++)
{ {
CModel *pModel = mpArea->mTerrainModels[iMesh]; case ePrimeDemo:
GeometrySections += (7 + pModel->GetSurfaceCount()); 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 // Set section numbers
mArotSecNum = mGeometrySecNum + GeometrySections; u32 SecNum = GeometrySections;
mSclySecNum = mArotSecNum + 1; if (mVersion <= ePrime) mAROTSecNum = SecNum++;
mCollisionSecNum = mSclySecNum + 1; if (mVersion >= eEchoesDemo) mFFFFSecNum = SecNum++;
mUnknownSecNum = mCollisionSecNum + 1;
mLightsSecNum = mUnknownSecNum + 1; if (mVersion >= eEchoesDemo)
mVisiSecNum = mLightsSecNum + 1; {
mPathSecNum = mVisiSecNum + 1; 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) void CAreaCooker::WritePrimeHeader(IOutputStream& rOut)
{ {
rOut.WriteLong(0xDEADBEEF); rOut.WriteLong(0xDEADBEEF);
rOut.WriteLong(GetMREAVersion(mVersion)); rOut.WriteLong(GetMREAVersion(mVersion));
mpArea->mTransform.Write(rOut); 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(mpArea->mSectionDataBuffers.size());
rOut.WriteLong(mGeometrySecNum); rOut.WriteLong(mGeometrySecNum);
rOut.WriteLong(mSclySecNum); rOut.WriteLong(mSCLYSecNum);
if (mVersion >= eEchoesDemo) rOut.WriteLong(mSCGNSecNum);
rOut.WriteLong(mCollisionSecNum); rOut.WriteLong(mCollisionSecNum);
rOut.WriteLong(mUnknownSecNum); rOut.WriteLong(mUnknownSecNum);
rOut.WriteLong(mLightsSecNum); rOut.WriteLong(mLightsSecNum);
rOut.WriteLong(mVisiSecNum); rOut.WriteLong(mVISISecNum);
rOut.WriteLong(mPathSecNum); rOut.WriteLong(mPATHSecNum);
rOut.WriteLong(mArotSecNum); if (mVersion <= ePrime) rOut.WriteLong(mAROTSecNum);
mSectionSizesOffset = rOut.Tell(); else
for (u32 iSec = 0; iSec < mpArea->mSectionDataBuffers.size(); iSec++) {
rOut.WriteLong(0); 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); rOut.WriteToBoundary(32, 0);
mSectionMgr.SetSectionCount(mpArea->mSectionDataBuffers.size()); WriteCompressionHeader(rOut);
mSectionMgr.Init(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) void CAreaCooker::WritePrimeSCLY(IOutputStream& rOut)
{ {
u32 NumLayers = mpArea->mScriptLayers.size();
rOut.WriteString("SCLY", 4); 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); rOut.WriteLong(NumLayers);
u32 LayerSizesStart = rOut.Tell(); u32 LayerSizesStart = rOut.Tell();
for (u32 iLyr = 0; iLyr < NumLayers; iLyr++) for (u32 iLyr = 0; iLyr < NumLayers; iLyr++)
rOut.WriteLong(0); rOut.WriteLong(0);
// SCLY
std::vector<u32> LayerSizes(NumLayers); 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(); u32 LayerStart = rOut.Tell();
CScriptCooker::WriteLayer(mpArea->Version(), mpArea->mScriptLayers[iLyr], rOut); CScriptCooker::WriteLayer(mVersion, mpArea->mScriptLayers[iLyr], rOut);
LayerSizes[iLyr] = rOut.Tell() - LayerStart; LayerSizes[iLyr] = rOut.Tell() - LayerStart;
} }
@ -85,7 +195,114 @@ void CAreaCooker::WritePrimeSCLY(IOutputStream& rOut)
rOut.WriteLong(LayerSizes[iLyr]); rOut.WriteLong(LayerSizes[iLyr]);
rOut.Seek(LayersEnd, SEEK_SET); 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 ************ // ************ STATIC ************
@ -95,39 +312,41 @@ void CAreaCooker::WriteCookedArea(CGameArea *pArea, IOutputStream& rOut)
Cooker.mpArea = pArea; Cooker.mpArea = pArea;
Cooker.mVersion = pArea->Version(); Cooker.mVersion = pArea->Version();
if (Cooker.mVersion > ePrime) if (Cooker.mVersion <= eEchoes)
{ Cooker.DetermineSectionNumbersPrime();
Log::Error("Area cooking is not supported for games other than Metroid Prime"); else
return; Cooker.DetermineSectionNumbersCorruption();
}
// Write header
Cooker.DetermineSectionNumbers();
Cooker.WritePrimeHeader(rOut);
// Write pre-SCLY data sections // 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.mSectionData.WriteBytes(pArea->mSectionDataBuffers[iSec].data(), pArea->mSectionDataBuffers[iSec].size());
Cooker.mSectionMgr.AddSize(rOut); Cooker.FinishSection(false);
} }
// Write SCLY // Write SCLY
Cooker.WritePrimeSCLY(rOut); if (Cooker.mVersion <= eEchoesDemo)
Cooker.mSectionMgr.AddSize(rOut); Cooker.WritePrimeSCLY(Cooker.mSectionData);
else
Cooker.WriteEchoesSCLY(Cooker.mSectionData);
// Write post-SCLY data sections // 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.mSectionData.WriteBytes(pArea->mSectionDataBuffers[iSec].data(), pArea->mSectionDataBuffers[iSec].size());
Cooker.mSectionMgr.AddSize(rOut); Cooker.FinishSection(false);
} }
// Write section sizes Cooker.FinishBlock();
u32 AreaEnd = rOut.Tell();
rOut.Seek(Cooker.mSectionSizesOffset, SEEK_SET); // Write to actual file
Cooker.mSectionMgr.WriteSizes(rOut); if (Cooker.mVersion <= eEchoes)
rOut.Seek(AreaEnd, SEEK_SET); Cooker.WritePrimeHeader(rOut);
else
Cooker.WriteCorruptionHeader(rOut);
Cooker.WriteAreaData(rOut);
} }
u32 CAreaCooker::GetMREAVersion(EGame version) u32 CAreaCooker::GetMREAVersion(EGame version)

View File

@ -11,22 +11,56 @@ class CAreaCooker
TResPtr<CGameArea> mpArea; TResPtr<CGameArea> mpArea;
EGame mVersion; EGame mVersion;
CSectionMgrOut mSectionMgr; std::vector<u32> mSectionSizes;
u32 mSectionSizesOffset;
u32 mGeometrySecNum; u32 mGeometrySecNum;
u32 mSclySecNum; u32 mSCLYSecNum;
u32 mSCGNSecNum;
u32 mCollisionSecNum; u32 mCollisionSecNum;
u32 mUnknownSecNum; u32 mUnknownSecNum;
u32 mLightsSecNum; u32 mLightsSecNum;
u32 mVisiSecNum; u32 mVISISecNum;
u32 mPathSecNum; u32 mPATHSecNum;
u32 mArotSecNum; 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(); CAreaCooker();
void DetermineSectionNumbers(); void DetermineSectionNumbersPrime();
void DetermineSectionNumbersCorruption();
// Header
void WritePrimeHeader(IOutputStream& rOut); void WritePrimeHeader(IOutputStream& rOut);
void WriteCorruptionHeader(IOutputStream& rOut);
void WriteCompressionHeader(IOutputStream& rOut);
void WriteAreaData(IOutputStream& rOut);
// SCLY
void WritePrimeSCLY(IOutputStream& rOut); void WritePrimeSCLY(IOutputStream& rOut);
void WriteEchoesSCLY(IOutputStream& rOut);
// Section Management
void AddSectionToBlock();
void FinishSection(bool ForceFinishBlock);
void FinishBlock();
public: public:
static void WriteCookedArea(CGameArea *pArea, IOutputStream& rOut); static void WriteCookedArea(CGameArea *pArea, IOutputStream& rOut);

View File

@ -1,7 +1,17 @@
#include "CScriptCooker.h" #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()) switch (pProp->Type())
{ {
@ -96,25 +106,81 @@ void CScriptCooker::WriteProperty(IProperty *pProp)
{ {
TMayaSplineProperty *pSplineCast = static_cast<TMayaSplineProperty*>(pProp); TMayaSplineProperty *pSplineCast = static_cast<TMayaSplineProperty*>(pProp);
std::vector<u8> Buffer = pSplineCast->Get(); 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; break;
} }
case eStructProperty: case eStructProperty:
case eArrayProperty:
{ {
CPropertyStruct *pStruct = static_cast<CPropertyStruct*>(pProp); CPropertyStruct *pStruct = static_cast<CPropertyStruct*>(pProp);
CStructTemplate *pTemp = static_cast<CStructTemplate*>(pStruct->Template()); CStructTemplate *pTemp = static_cast<CStructTemplate*>(pStruct->Template());
if (!pTemp->IsSingleProperty() || pProp->Type() == eArrayProperty) std::vector<IProperty*> PropertiesToWrite;
mpSCLY->WriteLong(pStruct->Count());
for (u32 iProp = 0; iProp < pStruct->Count(); iProp++) 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; 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); mpSCLY->WriteLong(rkLink.ObjectID);
} }
WriteProperty(pInstance->Properties()); WriteProperty(pInstance->Properties(), false);
u32 InstanceEnd = mpSCLY->Tell(); u32 InstanceEnd = mpSCLY->Tell();
u32 InstanceSize = InstanceEnd - InstanceStart;
mpSCLY->Seek(SizeOffset, SEEK_SET); 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); mpSCLY->Seek(InstanceEnd, SEEK_SET);
} }
@ -172,5 +287,9 @@ void CScriptCooker::WriteLayer(EGame Game, CScriptLayer *pLayer, IOutputStream&
CScriptCooker Cooker; CScriptCooker Cooker;
Cooker.mpSCLY = &rOut; Cooker.mpSCLY = &rOut;
Cooker.mVersion = Game; Cooker.mVersion = Game;
if (Game <= ePrime)
Cooker.WriteLayerMP1(pLayer); Cooker.WriteLayerMP1(pLayer);
else
Cooker.WriteLayerMP2(pLayer);
} }

View File

@ -12,9 +12,11 @@ class CScriptCooker
EGame mVersion; EGame mVersion;
CScriptCooker() {} CScriptCooker() {}
void WriteProperty(IProperty *pProp); void WriteProperty(IProperty *pProp, bool InSingleStruct);
void WriteLayerMP1(CScriptLayer *pLayer); void WriteLayerMP1(CScriptLayer *pLayer);
void WriteInstanceMP1(CScriptObject *pInstance); void WriteInstanceMP1(CScriptObject *pInstance);
void WriteLayerMP2(CScriptLayer *pLayer);
void WriteInstanceMP2(CScriptObject *pInstance);
public: public:
static void WriteLayer(EGame Game, CScriptLayer *pLayer, IOutputStream& rOut); static void WriteLayer(EGame Game, CScriptLayer *pLayer, IOutputStream& rOut);

View File

@ -63,6 +63,8 @@ void CAreaLoader::ReadHeaderPrime()
mpMREA->SeekToBoundary(32); mpMREA->SeekToBoundary(32);
mpSectionMgr->Init(); mpSectionMgr->Init();
LoadSectionDataBuffers(); LoadSectionDataBuffers();
mpArea->mOriginalWorldMeshCount = mNumMeshes;
} }
void CAreaLoader::ReadGeometryPrime() void CAreaLoader::ReadGeometryPrime()
@ -116,39 +118,57 @@ void CAreaLoader::ReadGeometryPrime()
void CAreaLoader::ReadSCLYPrime() void CAreaLoader::ReadSCLYPrime()
{ {
// Prime, Echoes Demo
Log::FileWrite(mpMREA->GetSourceString(), "Reading MREA script layers (MP1)"); Log::FileWrite(mpMREA->GetSourceString(), "Reading MREA script layers (MP1)");
mpSectionMgr->ToSection(mScriptLayerBlockNum); mpSectionMgr->ToSection(mScriptLayerBlockNum);
CFourCC SCLY(*mpMREA); CFourCC SCLY(*mpMREA);
if (SCLY != "SCLY") 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; return;
} }
mpMREA->Seek(0x4, SEEK_CUR); // Skipping unknown value which is always 4
if (mVersion <= ePrime) // Read layer sizes
mpMREA->Seek(0x4, SEEK_CUR);
else
mpMREA->Seek(0x1, SEEK_CUR);
mNumLayers = mpMREA->ReadLong(); mNumLayers = mpMREA->ReadLong();
mpArea->mScriptLayers.reserve(mNumLayers); mpArea->mScriptLayers.resize(mNumLayers);
std::vector<u32> LayerSizes(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]; u32 Next = mpMREA->Tell() + LayerSizes[iLyr];
mpArea->mScriptLayers[iLyr] = CScriptLoader::LoadLayer(*mpMREA, mpArea, mVersion);
CScriptLayer *pLayer = CScriptLoader::LoadLayer(*mpMREA, mpArea, mVersion);
if (pLayer)
mpArea->mScriptLayers.push_back(pLayer);
mpMREA->Seek(Next, SEEK_SET); 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(); SetUpObjects();
} }
@ -270,30 +290,49 @@ void CAreaLoader::ReadHeaderEchoes()
mpSectionMgr->Init(); mpSectionMgr->Init();
LoadSectionDataBuffers(); LoadSectionDataBuffers();
mpArea->mOriginalWorldMeshCount = mNumMeshes;
} }
void CAreaLoader::ReadSCLYEchoes() void CAreaLoader::ReadSCLYEchoes()
{ {
// MP2, MP3 Proto, MP3, DKCR
Log::FileWrite(mpMREA->GetSourceString(), "Reading MREA script layers (MP2/MP3/DKCR)"); Log::FileWrite(mpMREA->GetSourceString(), "Reading MREA script layers (MP2/MP3/DKCR)");
mpSectionMgr->ToSection(mScriptLayerBlockNum); mpSectionMgr->ToSection(mScriptLayerBlockNum);
mpArea->mScriptLayers.resize(mNumLayers);
// SCLY // SCLY
for (u32 l = 0; l < mNumLayers; l++) for (u32 iLyr = 0; iLyr < mNumLayers; iLyr++)
{ {
CScriptLayer *pLayer = CScriptLoader::LoadLayer(*mpMREA, mpArea, mVersion); CFourCC SCLY(*mpMREA);
if (SCLY != "SCLY")
if (pLayer) {
mpArea->mScriptLayers.push_back(pLayer); 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(); mpSectionMgr->ToNextSection();
} }
// SCGN // SCGN
mpSectionMgr->ToSection(mScriptGeneratorBlockNum); CFourCC SCGN(*mpMREA);
CScriptLayer *pLayer = CScriptLoader::LoadLayer(*mpMREA, mpArea, mVersion); if (SCGN != "SCGN")
{
Log::FileError(mpMREA->GetSourceString(), mpMREA->Tell() - 4, "Invalid SCGN magic: " + SCGN.ToString());
return;
}
if (pLayer) mpMREA->Seek(0x1, SEEK_CUR); // Skipping unknown
mpArea->mpGeneratorLayer = pLayer; mpArea->mpGeneratorLayer = CScriptLoader::LoadLayer(*mpMREA, mpArea, mVersion);
if (mpArea->mpGeneratorLayer)
{
mpArea->mpGeneratorLayer->SetName("Generated Objects");
mpArea->mpGeneratorLayer->SetActive(true);
}
SetUpObjects(); SetUpObjects();
} }
@ -334,12 +373,19 @@ void CAreaLoader::ReadHeaderCorruption()
else if (Type == "SOBJ") mScriptLayerBlockNum = Num; else if (Type == "SOBJ") mScriptLayerBlockNum = Num;
else if (Type == "SGEN") mScriptGeneratorBlockNum = Num; else if (Type == "SGEN") mScriptGeneratorBlockNum = Num;
else if (Type == "WOBJ") mGeometryBlockNum = Num; // note WOBJ can show up multiple times, but is always 0 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); mpMREA->SeekToBoundary(32);
Decompress(); Decompress();
mpSectionMgr->Init(); mpSectionMgr->Init();
LoadSectionDataBuffers(); LoadSectionDataBuffers();
mpArea->mOriginalWorldMeshCount = mNumMeshes;
} }
void CAreaLoader::ReadGeometryCorruption() void CAreaLoader::ReadGeometryCorruption()
@ -478,6 +524,8 @@ void CAreaLoader::ReadCompressedBlocks()
mClusters[c].CompressedSize = mpMREA->ReadLong(); mClusters[c].CompressedSize = mpMREA->ReadLong();
mClusters[c].NumSections = mpMREA->ReadLong(); mClusters[c].NumSections = mpMREA->ReadLong();
mTotalDecmpSize += mClusters[c].DecompressedSize; mTotalDecmpSize += mClusters[c].DecompressedSize;
if (mClusters[c].CompressedSize != 0) mpArea->mUsesCompression = true;
} }
mpMREA->SeekToBoundary(32); mpMREA->SeekToBoundary(32);

View File

@ -367,32 +367,7 @@ CScriptObject* CScriptLoader::LoadObjectMP2(IInputStream& SCLY)
CScriptLayer* CScriptLoader::LoadLayerMP2(IInputStream& SCLY) CScriptLayer* CScriptLoader::LoadLayerMP2(IInputStream& SCLY)
{ {
bool IsSCGN = false; SCLY.Seek(0x1, SEEK_CUR); // Skipping version. todo: verify this?
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);
}
u32 NumObjects = SCLY.ReadLong(); u32 NumObjects = SCLY.ReadLong();
mpLayer = new CScriptLayer(); mpLayer = new CScriptLayer();
@ -405,11 +380,6 @@ CScriptLayer* CScriptLoader::LoadLayerMP2(IInputStream& SCLY)
mpLayer->AddInstance(pObj); mpLayer->AddInstance(pObj);
} }
if (IsSCGN)
{
mpLayer->SetName("Generated");
mpLayer->SetActive(true);
}
return mpLayer; return mpLayer;
} }

View File

@ -160,7 +160,7 @@ public:
TMayaSplineProperty(IPropertyTemplate *pTemp, CPropertyStruct *pParent, const std::vector<u8>& v) TMayaSplineProperty(IPropertyTemplate *pTemp, CPropertyStruct *pParent, const std::vector<u8>& v)
: TTypedProperty(pTemp, pParent, v) {} : TTypedProperty(pTemp, pParent, v) {}
virtual bool MatchesDefault() { return true; } virtual bool MatchesDefault() { return Get().empty(); }
}; };
/* /*

View File

@ -632,10 +632,10 @@ void CPropertyDelegate::SetCharacterModelData(QWidget *pEditor, const QModelInde
if (Type == eFileProperty) if (Type == eFileProperty)
{ {
Params.SetResource( static_cast<WResourceSelector*>(pEditor)->GetResource() ); Params.SetResource( static_cast<WResourceSelector*>(pEditor)->GetResourceInfo() );
// Reset all other parameters to 0 // Reset all other parameters to 0
Params.SetNodeIndex(0); Params.SetNodeIndex(0);
for (u32 iUnk = 0; iUnk < 4; iUnk++) for (u32 iUnk = 0; iUnk < 3; iUnk++)
Params.SetUnknown(iUnk, 0); Params.SetUnknown(iUnk, 0);
} }
@ -677,7 +677,7 @@ EPropertyType CPropertyDelegate::DetermineCharacterPropType(EGame Game, const QM
else else
{ {
if (rkIndex.row() == 0) return eFileProperty; if (rkIndex.row() == 0) return eFileProperty;
else if (rkIndex.row() <= 3) return eLongProperty; else if (rkIndex.row() <= 2) return eLongProperty;
} }
return eUnknownProperty; return eUnknownProperty;
} }

View File

@ -113,7 +113,7 @@ int CPropertyModel::rowCount(const QModelIndex& rkParent) const
CAnimationParameters Params = static_cast<TCharacterProperty*>(pProp)->Get(); CAnimationParameters Params = static_cast<TCharacterProperty*>(pProp)->Get();
if (Params.Version() <= eEchoes) return 3; if (Params.Version() <= eEchoes) return 3;
if (Params.Version() <= eCorruption) return 2; if (Params.Version() <= eCorruption) return 2;
return 5; return 4;
} }
default: default:
@ -241,7 +241,8 @@ QVariant CPropertyModel::data(const QModelIndex& rkIndex, int Role) const
if (rkIndex.column() == 0) if (rkIndex.column() == 0)
{ {
if (rkIndex.row() == 0) return "Character"; 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) if (rkIndex.column() == 1 && rkIndex.row() > 0)

View File

@ -2,6 +2,7 @@
#include "Editor/UICommon.h" #include "Editor/UICommon.h"
#include <Core/Resource/CAnimSet.h> #include <Core/Resource/CAnimSet.h>
#include <Core/Resource/CResCache.h> #include <Core/Resource/CResCache.h>
#include <Core/Resource/CResourceInfo.h>
WAnimParamsEditor::WAnimParamsEditor(QWidget *pParent) WAnimParamsEditor::WAnimParamsEditor(QWidget *pParent)
: QWidget(pParent), : QWidget(pParent),
@ -66,10 +67,10 @@ void WAnimParamsEditor::SetParameters(const CAnimationParameters& params)
// ************ PRIVATE SLOTS ************ // ************ PRIVATE SLOTS ************
void WAnimParamsEditor::OnResourceChanged(QString path) void WAnimParamsEditor::OnResourceChanged(QString path)
{ {
CResource *pRes = gResCache.GetResource(path.toStdString()); CResourceInfo ResInfo(path.toStdString());
if (pRes && pRes->Type() != eAnimSet) pRes = nullptr; if (ResInfo.Type() != "ANCS" && ResInfo.Type() != "CHAR") ResInfo = CResourceInfo();
mParams.SetResource(pRes); mParams.SetResource(ResInfo);
emit ParametersChanged(mParams); emit ParametersChanged(mParams);
} }
@ -217,7 +218,7 @@ void WAnimParamsEditor::SetupUI()
connect(mpSpinBoxes[0], SIGNAL(valueChanged(int)), this, SLOT(OnUnknownChanged())); connect(mpSpinBoxes[0], SIGNAL(valueChanged(int)), this, SLOT(OnUnknownChanged()));
// Create unknown spin box B/C/D // 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] = new WIntegralSpinBox(this);
mpSpinBoxes[iBox]->setRange(INT32_MIN, INT32_MAX); mpSpinBoxes[iBox]->setRange(INT32_MIN, INT32_MAX);