Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
@@ -0,0 +1,79 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_ADJUSTROTLOG_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_ADJUSTROTLOG_H
#pragma once
inline double DLength (const Vec3& v)
{
return sqrt (double(v.x) * double(v.x) + double(v.y) * double(v.y) + double(v.z) * double(v.z));
}
//////////////////////////////////////////////////////////////////////////
// Given the rotations in logarithmic space, adjusts the target rotation so
// that it's the same in rotational group, but the closest to the reference
// in the QLog space.
inline void AdjustRotLog (Vec3& vTgt, const Vec3& vRef)
{
double dLenTgt = DLength(vTgt);
const double dPi = 3.1415926535897932384626433832795;
if (dLenTgt < 1e-4)
{
// the target is very small rotation, so the algorithm is to find
// ANY vector of length n*PI closest to the vRef point
double dLenRef = DLength(vRef);
if (dLenRef > dPi / 2) // Otherwise the vRef vector is small enough not to make any adjustments
{
double f = (dPi * floor(dLenRef / dPi + 0.5) / dLenRef);
vTgt.x = float(vRef.x * f);
vTgt.y = float(vRef.y * f);
vTgt.z = float(vRef.z * f);
}
}
else
{
// the target is big enough rotation to pick the rotation axis out
// find the projection of the reference to the target axis
// then find the target (projection) mod PI
// there are basically three possibilities: the new target is in the same PI interval
// as the reference projection, in the next or in the previous. Find the closest.
double dProjRef = (vRef * vTgt) / dLenTgt;
double dModTgt = fmod (dLenTgt, dPi);
if (dModTgt < 0)
{
dModTgt += dPi;
}
assert (dModTgt >= 0 && dModTgt < dPi);
double dBaseTgt = dPi * floor (dProjRef / dPi + 0.5);
double dNewTgtR = dBaseTgt + dModTgt;
double dNewTgtL = dBaseTgt + dModTgt - dPi;
double dNewTgt = (fabs(dNewTgtR - dProjRef) < fabs(dNewTgtL - dProjRef))
? dNewTgtR : dNewTgtL;
assert (fabs(dNewTgt + dPi - dProjRef) > fabs(dNewTgt - dProjRef));
assert (fabs(dNewTgt - dPi - dProjRef) > fabs(dNewTgt - dProjRef));
double f = (dNewTgt / dLenTgt);
vTgt.x = float(vTgt.x * f);
vTgt.y = float(vTgt.y * f);
vTgt.z = float(vTgt.z * f);
}
}
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_ADJUSTROTLOG_H
@@ -0,0 +1,174 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "ResourceCompilerPC_precompiled.h"
#include "../CryEngine/Cry3DEngine/CGF/ChunkFile.h"
#include "StaticObjectCompiler.h"
#include "CGF/CGFSaver.h"
#include "MathHelpers.h"
#include "StringHelpers.h"
#include "AssetWriter.h"
#include <SceneAPI/SceneCore/DataTypes/Groups/IAnimationGroup.h>
const bool AssetWriter::s_swapEndian;
bool AssetWriter::WriteCGF(CContentCGF* content)
{
if (!content)
{
return false;
}
CChunkFile chunkFile;
CSaverCGF cgfSaver(chunkFile);
#if defined(AZ_PLATFORM_WINDOWS)
// _EM_INVALID is used to avoid Floating Point Exception inside CryPhysics
MathHelpers::AutoFloatingPointExceptions autoFpe(~(_EM_INEXACT | _EM_UNDERFLOW | _EM_INVALID));
#endif
CStaticObjectCompiler compiler(false);
CContentCGF* const pCompiledCGF = compiler.MakeCompiledCGF(content);
if (!pCompiledCGF)
{
return false;
}
const bool bNeedEndianSwap = false;
const bool bUseQtangents = false;
const bool bStorePositionsAsF16 = false;
const bool bStoreIndicesAsU16 = false;
cgfSaver.SaveContent(pCompiledCGF, bNeedEndianSwap, bStorePositionsAsF16, bUseQtangents, bStoreIndicesAsU16);
chunkFile.Write(content->GetFilename());
return true;
}
//
// Implemented by referencing to ColladaCompiler::CompileToCHR
//
bool AssetWriter::WriteCHR(CContentCGF* content, [[maybe_unused]] IConvertContext* convertContext)
{
if (!content)
{
return false;
}
CChunkFile chunkFile;
CSaverCGF cgfSaver(chunkFile);
cgfSaver.SetContent(content);
cgfSaver.SaveExportFlags(s_swapEndian);
if (!PrepareSkeletonDataChunks(&cgfSaver))
{
return false;
}
return true;
}
bool AssetWriter::WriteSKIN(CContentCGF* content, [[maybe_unused]] IConvertContext* convertContext, bool exportMorphTargets)
{
if (!content)
{
return false;
}
CChunkFile chunkFile;
CSaverCGF cgfSaver(chunkFile);
cgfSaver.SetContent(content);
cgfSaver.SaveExportFlags(s_swapEndian);
cgfSaver.SaveMaterials(s_swapEndian);
cgfSaver.SaveUncompiledNodes();
if (exportMorphTargets)
{
cgfSaver.SaveUncompiledMorphTargets();
}
if (!PrepareSkeletonDataChunks(&cgfSaver))
{
return false;
}
return true;
}
bool AssetWriter::PrepareSkeletonDataChunks(CSaverCGF* cgfSaver)
{
const CSkinningInfo* skinningInfo = cgfSaver->GetContent()->GetSkinningInfo();
if (skinningInfo->m_arrBonesDesc.empty())
{
return false;
}
if (skinningInfo->m_arrBonesDesc.size() != skinningInfo->m_arrBoneEntities.size())
{
RCLogError("Bone description number and bone entity data number don't match.\n");
return false;
}
// Save bone entity data to chunk
DynArray<BONE_ENTITY> tempBoneEntities = skinningInfo->m_arrBoneEntities;
for (int i = 0; i < tempBoneEntities.size(); ++i)
{
tempBoneEntities[i].phys.nPhysGeom = -1;
StringHelpers::SafeCopyPadZeros(tempBoneEntities[i].prop, sizeof(tempBoneEntities[i].prop), skinningInfo->m_arrBoneEntities[i].prop);
}
const int numBones = skinningInfo->m_arrBonesDesc.size();
cgfSaver->SaveBones(s_swapEndian, &tempBoneEntities[0], numBones, numBones*sizeof(BONE_ENTITY));
// Save bone names
std::vector<char> boneNames;
static const int maxBoneNameLength = 32;
boneNames.reserve(maxBoneNameLength * numBones);
std::vector<SBoneInitPosMatrix> boneMatices(numBones);
for (int boneId = 0; boneId < numBones; ++boneId)
{
const char* boneName = skinningInfo->m_arrBonesDesc[boneId].m_arrBoneName;
size_t len = strlen(boneName);
boneNames.insert(boneNames.end(), boneName, boneName + len);
boneNames.push_back('\0');
for (int x = 0; x < 4; ++x)
{
// Reference to ColladaCompiler::CompileToCHR
// CryTek requires the bone matrix is converted from meter unit to centimeter unit
// We have intentionally convert bone transform matrix to meter unit in FbxSceneSystem::ConvertBoneUnit
// For example, a valid bone matrix would look like
// 100 0 0 | 50
// 0 100 0 | 0
// 0 0 100 | 0
// In which 50 means 50 centimeters
Matrix34 m = Matrix34::CreateScale(Vec3(100.0f, 100.0f, 100.0f)) * skinningInfo->m_arrBonesDesc[boneId].m_DefaultB2W;
Vec3 column = m.GetColumn(x);
for (int y = 0; y < 3; ++y)
{
boneMatices[boneId][x][y] = column[y];
}
}
}
boneNames.push_back('\0');
cgfSaver->SaveBoneNames(s_swapEndian, &boneNames[0], numBones, boneNames.size());
cgfSaver->SaveBoneInitialMatrices(s_swapEndian, &boneMatices[0], numBones, sizeof(SBoneInitPosMatrix)*numBones);
return true;
}
@@ -0,0 +1,36 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_CGF_ASSETWRITER_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_CGF_ASSETWRITER_H
#pragma once
#include "CGFContent.h"
class CSaverCGF;
class AssetWriter
: public IAssetWriter
{
public:
bool WriteCGF(CContentCGF* content) override;
bool WriteCHR(CContentCGF* content, IConvertContext* convertContext) override;
bool WriteSKIN(CContentCGF* content, IConvertContext* convertContext, bool exportMorphTargets = false) override;
protected:
bool PrepareSkeletonDataChunks(CSaverCGF* cgfSaver);
static const bool s_swapEndian = false;
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_CGF_ASSETWRITER_H
@@ -0,0 +1,153 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "ResourceCompilerPC_precompiled.h"
#include "CGFNodeMerger.h"
#include "CGFContent.h"
#include "StringHelpers.h"
//////////////////////////////////////////////////////////////////////////
bool CGFNodeMerger::SetupMeshSubsets(CContentCGF* pCGF, CMesh& mesh, CMaterialCGF* pMaterialCGF, string& errorMessage)
{
const DynArray<int>& usedMaterialIds = pCGF->GetUsedMaterialIDs();
unsigned int i;
if (mesh.m_subsets.empty())
{
//////////////////////////////////////////////////////////////////////////
// Setup mesh subsets.
//////////////////////////////////////////////////////////////////////////
mesh.m_subsets.clear();
for (i = 0; i < usedMaterialIds.size(); i++)
{
SMeshSubset meshSubset;
int nMatID = usedMaterialIds[i];
meshSubset.nMatID = nMatID;
meshSubset.nPhysicalizeType = PHYS_GEOM_TYPE_NONE;
mesh.m_subsets.push_back(meshSubset);
}
}
//////////////////////////////////////////////////////////////////////////
// Setup physicalization type from materials (and autofix matId if needed)
//////////////////////////////////////////////////////////////////////////
if (pMaterialCGF)
{
for (i = 0; i < mesh.m_subsets.size(); i++)
{
SMeshSubset& meshSubset = mesh.m_subsets[i];
if (pMaterialCGF->subMaterials.size() > 0)
{
int id = meshSubset.nMatID;
if (id >= (int)pMaterialCGF->subMaterials.size())
{
// Let's use 3dsMax's approach of handling material ids out of range
id %= (int)pMaterialCGF->subMaterials.size();
}
if (id >= 0 && pMaterialCGF->subMaterials[id] != NULL)
{
meshSubset.nMatID = id;
meshSubset.nPhysicalizeType = pMaterialCGF->subMaterials[id]->nPhysicalizeType;
}
else
{
errorMessage = StringHelpers::Format(
"%s: Submaterial %d is not available for subset %d (%d subsets) in %s",
__FUNCTION__, meshSubset.nMatID, i, (int)mesh.m_subsets.size(), pCGF->GetFilename());
return false;
}
}
else
{
meshSubset.nPhysicalizeType = pMaterialCGF->nPhysicalizeType;
}
}
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool CGFNodeMerger::MergeNodes(CContentCGF* pCGF, std::vector<CNodeCGF*> nodes, string& errorMessage, CMesh* pMergedMesh)
{
assert(pMergedMesh);
AABB meshBBox;
meshBBox.Reset();
for (size_t i = 0; i < nodes.size(); i++)
{
CNodeCGF* pNode = nodes[i];
assert(pNode->pMesh == 0 || pNode->pMesh->m_pPositionsF16 == 0);
int nOldVerts = pMergedMesh->GetVertexCount();
if (pMergedMesh->GetVertexCount() == 0)
{
pMergedMesh->Copy(*pNode->pMesh);
}
else
{
const char* const errText = pMergedMesh->Append(*pNode->pMesh);
if (errText)
{
errorMessage = errText;
return false;
}
// Keep color stream in sync size with vertex/normals stream.
if (pMergedMesh->m_streamSize[CMesh::COLORS][0] > 0 && pMergedMesh->m_streamSize[CMesh::COLORS][0] < pMergedMesh->GetVertexCount())
{
int nOldCount = pMergedMesh->m_streamSize[CMesh::COLORS][0];
pMergedMesh->ReallocStream(CMesh::COLORS, 0, pMergedMesh->GetVertexCount());
memset(pMergedMesh->m_pColor0 + nOldCount, 255, (pMergedMesh->GetVertexCount() - nOldCount) * sizeof(SMeshColor));
}
if (pMergedMesh->m_streamSize[CMesh::COLORS][1] > 0 && pMergedMesh->m_streamSize[CMesh::COLORS][1] < pMergedMesh->GetVertexCount())
{
int nOldCount = pMergedMesh->m_streamSize[CMesh::COLORS][1];
pMergedMesh->ReallocStream(CMesh::COLORS, 1, pMergedMesh->GetVertexCount());
memset(pMergedMesh->m_pColor1 + nOldCount, 255, (pMergedMesh->GetVertexCount() - nOldCount) * sizeof(SMeshColor));
}
}
AABB bbox = pNode->pMesh->m_bbox;
if (!pNode->bIdentityMatrix)
{
bbox.SetTransformedAABB(pNode->worldTM, bbox);
}
meshBBox.Add(bbox.min);
meshBBox.Add(bbox.max);
pMergedMesh->m_bbox = meshBBox;
if (!pNode->bIdentityMatrix)
{
// Transform merged mesh into the world space.
// Only transform newly added vertices.
for (int j = nOldVerts; j < pMergedMesh->GetVertexCount(); j++)
{
pMergedMesh->m_pPositions[j] = pNode->worldTM.TransformPoint(pMergedMesh->m_pPositions[j]);
pMergedMesh->m_pNorms[j].RotateSafelyBy(pNode->worldTM);
}
}
}
bool setupMeshSuccessful = true;
if (pCGF != NULL)
{
if (!SetupMeshSubsets(pCGF, *pMergedMesh, pCGF->GetCommonMaterial(), errorMessage))
{
return false;
}
}
pMergedMesh->RecomputeTexMappingDensity();
return setupMeshSuccessful;
}
@@ -0,0 +1,30 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_CGF_CGFNODEMERGER_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_CGF_CGFNODEMERGER_H
#pragma once
class CContentCGF;
class CMesh;
struct CMaterialCGF;
struct CNodeCGF;
namespace CGFNodeMerger
{
bool SetupMeshSubsets(CContentCGF* pCGF, CMesh& mesh, CMaterialCGF* pMaterialCGF, string& errorMessage);
bool MergeNodes(CContentCGF* pCGF, std::vector<CNodeCGF*> nodes, string& errorMessage, CMesh* pOutMesh);
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_CGF_CGFNODEMERGER_H
@@ -0,0 +1,40 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_CGF_CHUNKDATA_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_CGF_CHUNKDATA_H
#pragma once
struct CChunkData
{
char* data;
int size;
CChunkData() { data = 0; size = 0; }
~CChunkData() { free(data); }
template <class T>
void Add(const T& object)
{
AddData(&object, sizeof(object));
}
void AddData(const void* pSrcData, int nSrcDataSize)
{
data = (char*)realloc(data, size + nSrcDataSize);
memcpy(data + size, pSrcData, nSrcDataSize);
size += nSrcDataSize;
}
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_CGF_CHUNKDATA_H
@@ -0,0 +1,286 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "ResourceCompilerPC_precompiled.h"
#include "DataWriter.h"
#include "CryEndian.h"
DataWriter::DataWriter()
{
m_outputBuffer = NULL;
Reset();
}
DataWriter::~DataWriter()
{
this->Reset();
}
void DataWriter::Reset()
{
if (m_outputBuffer)
{
free(m_outputBuffer);
}
m_currentBufferSize = 0;
m_outputBuffer = NULL;
m_writtenBytes = 0;
m_labelMap.clear();
m_offsetLocations.clear();
m_bClosed = false;
m_bSwapEndian = false;
}
void DataWriter::SetSwapEndian(bool bEnable)
{
m_bSwapEndian = bEnable;
}
void* DataWriter::GetDataAndTakeOwnership()
{
if (m_bClosed && m_outputBuffer)
{
void* returnData = m_outputBuffer;
m_outputBuffer = NULL;
Reset();
return returnData;
}
return NULL;
}
uint32 DataWriter::GetDataSize() const
{
return (m_bClosed && m_outputBuffer) ? m_writtenBytes : 0;
}
void DataWriter::BeginWriting()
{
ExpandBuffer(1);
AddLabel("fileStart");
}
void DataWriter::WriteUInt8(const uint8 v)
{
ExpandBuffer(sizeof(v));
uint8* out = (uint8*)(((uint8*)m_outputBuffer) + m_writtenBytes);
*out = v;
SwapEndian(*out, m_bSwapEndian);
m_writtenBytes += sizeof(v);
}
void DataWriter::WriteInt8(const int8 v)
{
ExpandBuffer(sizeof(v));
int8* out = (int8*)(((uint8*)m_outputBuffer) + m_writtenBytes);
*out = v;
SwapEndian(*out, m_bSwapEndian);
m_writtenBytes += sizeof(v);
}
void DataWriter::WriteUInt16(const uint16 v)
{
ExpandBuffer(sizeof(v));
uint16* out = (uint16*)(((uint8*)m_outputBuffer) + m_writtenBytes);
*out = v;
SwapEndian(*out, m_bSwapEndian);
m_writtenBytes += sizeof(v);
}
void DataWriter::WriteInt16(const int16 v)
{
ExpandBuffer(sizeof(v));
int16* out = (int16*)(((uint8*)m_outputBuffer) + m_writtenBytes);
*out = v;
SwapEndian(*out, m_bSwapEndian);
m_writtenBytes += sizeof(v);
}
void DataWriter::WriteUInt32(const uint32 v)
{
ExpandBuffer(sizeof(v));
uint32* out = (uint32*)(((uint8*)m_outputBuffer) + m_writtenBytes);
*out = v;
SwapEndian(*out, m_bSwapEndian);
m_writtenBytes += sizeof(v);
}
void DataWriter::WriteInt32(const int32 v)
{
ExpandBuffer(sizeof(v));
int32* out = (int32*)(((uint8*)m_outputBuffer) + m_writtenBytes);
*out = v;
SwapEndian(*out, m_bSwapEndian);
m_writtenBytes += sizeof(v);
}
void DataWriter::WriteFloat(const float v)
{
ExpandBuffer(sizeof(v));
float* out = (float*)(((uint8*)m_outputBuffer) + m_writtenBytes);
*out = v;
SwapEndian(*out, m_bSwapEndian);
m_writtenBytes += sizeof(v);
}
void DataWriter::WriteData(const void* v, const uint32 size)
{
ExpandBuffer(size);
void* out = (void*)(((uint8*)m_outputBuffer) + m_writtenBytes);
memcpy(out, v, size);
m_writtenBytes += size;
}
void DataWriter::WriteAlign(const uint32 alignBytes)
{
const uint32 a = m_writtenBytes % alignBytes;
if (a != 0)
{
m_writtenBytes += (alignBytes - a);
}
ExpandBuffer();
}
void DataWriter::AddLabel(const string& label)
{
const std::map<string, uint32>::iterator f = m_labelMap.find(label);
if (f == m_labelMap.end())
{
m_labelMap.insert(std::make_pair(label, m_writtenBytes));
}
}
void DataWriter::WriteOffsetInt32(const string& label)
{
this->WriteOffsetInt32("", label);
}
void DataWriter::WriteOffsetInt32(const string& fromLabel, const string& label)
{
SOffsetLocation loc;
loc.b16Bit = false;
loc.offset = m_writtenBytes;
loc.labelName = label;
loc.fromLabelName = fromLabel;
m_offsetLocations.push_back(loc);
WriteInt32(0); // Make space to write the offset into later
}
void DataWriter::WriteOffsetInt16(const string& label)
{
this->WriteOffsetInt16("", label);
}
void DataWriter::WriteOffsetInt16(const string& fromLabel, const string& label)
{
SOffsetLocation loc;
loc.b16Bit = true;
loc.offset = m_writtenBytes;
loc.labelName = label;
loc.fromLabelName = fromLabel;
m_offsetLocations.push_back(loc);
WriteInt16(0); // Make space to write the offset into later
}
bool DataWriter::EndWriting()
{
m_missingLabels.clear();
for (int iOffset = 0; iOffset < m_offsetLocations.size(); iOffset++)
{
const SOffsetLocation* loc = &m_offsetLocations[iOffset];
const std::map<string, uint32>::iterator itLabel = m_labelMap.find(loc->labelName);
if (itLabel != m_labelMap.end())
{
const uint32 labelLoc = (*itLabel).second;
uint32 fromLoc = 0;
if (loc->fromLabelName.length() > 0)
{
const std::map<string, uint32>::iterator itFromLabel = m_labelMap.find(loc->fromLabelName);
if (itFromLabel != m_labelMap.end())
{
fromLoc = (*itFromLabel).second;
}
else
{
m_missingLabels.push_back(loc->fromLabelName);
}
}
if (loc->b16Bit)
{
const int16 offset = (int16)(labelLoc - fromLoc);
int16* out = (int16*)(((uint8*)m_outputBuffer) + loc->offset);
*out = offset;
SwapEndian(*out, m_bSwapEndian);
}
else
{
const int32 offset = labelLoc - fromLoc;
int32* out = (int32*)(((uint8*)m_outputBuffer) + loc->offset);
*out = offset;
SwapEndian(*out, m_bSwapEndian);
}
}
else
{
m_missingLabels.push_back(loc->labelName);
}
}
m_bClosed = true;
return m_missingLabels.empty();
}
uint32 DataWriter::CalculateSize(const string& fromLabel, const string& toLabel)
{
const std::map<string, uint32>::iterator itFromLabel = m_labelMap.find(fromLabel);
const std::map<string, uint32>::iterator itToLabel = m_labelMap.find(toLabel);
uint32 size = 0;
if (itFromLabel != m_labelMap.end() && itToLabel != m_labelMap.end())
{
const uint32 fromLoc = (*itFromLabel).second;
const uint32 toLoc = (*itToLabel).second;
if (fromLoc < toLoc)
{
size = toLoc - fromLoc;
}
else
{
size = 0;
}
}
return size;
}
#define BUFFERINCREASESIZE (1024 * 1024)
void DataWriter::ExpandBuffer(const uint32 addBytes)
{
if (m_writtenBytes + addBytes > m_currentBufferSize)
{
const uint32 newBufferSize = m_currentBufferSize + BUFFERINCREASESIZE;
if (m_outputBuffer)
{
m_outputBuffer = realloc(m_outputBuffer, newBufferSize);
}
else
{
m_outputBuffer = malloc(newBufferSize);
}
m_currentBufferSize = newBufferSize;
}
}
@@ -0,0 +1,79 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_CGF_DATAWRITER_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_CGF_DATAWRITER_H
#pragma once
class DataWriter
{
public:
DataWriter();
virtual ~DataWriter();
void Reset();
void SetSwapEndian(bool bEnable);
uint32 GetDataSize() const;
void* GetDataAndTakeOwnership();
void BeginWriting();
void WriteUInt8(const uint8 v);
void WriteInt8(const int8 v);
void WriteUInt16(const uint16 v);
void WriteInt16(const int16 v);
void WriteUInt32(const uint32 v);
void WriteInt32(const int32 v);
void WriteFloat(const float v);
void WriteData(const void* v, const uint32 size);
void WriteAlign(const uint32 alignBytes);
void AddLabel(const string& label);
void WriteOffsetInt32(const string& label);
void WriteOffsetInt32(const string& fromLabel, const string& label);
void WriteOffsetInt16(const string& label);
void WriteOffsetInt16(const string& fromLabel, const string& label);
bool EndWriting();
uint32 CalculateSize(const string& fromLabel, const string& toLabel);
private:
void ExpandBuffer(const uint32 addBytes = 0);
uint32 m_currentBufferSize;
void* m_outputBuffer;
uint32 m_writtenBytes;
bool m_bClosed;
bool m_bSwapEndian;
std::map<string, uint32> m_labelMap;
struct SOffsetLocation
{
bool b16Bit;
uint32 offset;
string labelName;
string fromLabelName;
};
std::vector< SOffsetLocation > m_offsetLocations;
std::vector<string> m_missingLabels;
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_CGF_DATAWRITER_H
@@ -0,0 +1,98 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
if(NOT PAL_TRAIT_BUILD_HOST_TOOLS)
return()
endif()
ly_add_target(
NAME ResourceCompilerPC.Static STATIC
NAMESPACE Legacy
FILES_CMAKE
resourcecompilerpc_files.cmake
PLATFORM_INCLUDE_FILES
Platform/Common/${PAL_TRAIT_COMPILER_ID}/resourcecompilerpc_${PAL_TRAIT_COMPILER_ID_LOWERCASE}.cmake
INCLUDE_DIRECTORIES
PUBLIC
.
PCH
COMPILE_DEFINITIONS
PRIVATE
RESOURCE_COMPILER
BUILD_DEPENDENCIES
PRIVATE
3rdParty::mikkelsen
Legacy::EditorCommon.Headers
Legacy::Cry3DEngine.Static
Legacy::Cry3DEngine.MeshCompiler.Static
Legacy::Cry3DEngine.CGF.RC.Static
Legacy::CryCommon.EngineSettings.RC.Static
Legacy::CryCommonTools
AZ::SceneData
AZ::AzToolsFramework
AZ::AssetBuilderSDK
PUBLIC
Legacy::CryCommon
Legacy::ResourceCompiler.Static
AZ::AzCore
${additional_dependencies}
RUNTIME_DEPENDENCIES
Legacy::CryXML
)
ly_add_target(
NAME ResourceCompilerPC MODULE
NAMESPACE Legacy
OUTPUT_SUBDIRECTORY rc_plugins
FILES_CMAKE
resourcecompilerpc_shared_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
.
BUILD_DEPENDENCIES
PRIVATE
Legacy::ResourceCompilerPC.Static
Legacy::Cry3DEngine.Static
Legacy::CryCommonTools
AZ::AzToolsFramework
)
ly_add_dependencies(RC Legacy::ResourceCompilerPC)
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
ly_add_target(
NAME ResourceCompilerPC.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
NAMESPACE Legacy
FILES_CMAKE
resourcecompilerpc_test_files.cmake
PLATFORM_INCLUDE_FILES
Platform/Common/${PAL_TRAIT_COMPILER_ID}/resourcecompilerpc_${PAL_TRAIT_COMPILER_ID_LOWERCASE}.cmake
COMPILE_DEFINITIONS
PRIVATE
RESOURCE_COMPILER
CGF_PHYSX_COMPILER
INCLUDE_DIRECTORIES
PRIVATE
Source
Tests
.
BUILD_DEPENDENCIES
PRIVATE
AZ::AzTest
Legacy::ResourceCompilerPC.Static
AZ::AssetBuilderSDK
Legacy::CryCommonTools
Legacy::Cry3DEngine.Static
)
ly_add_googletest(
NAME Legacy::ResourceCompilerPC.Tests
)
endif()
@@ -0,0 +1,255 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "ResourceCompilerPC_precompiled.h"
#include "ConvertContext.h"
#include "ChunkCompiler.h"
#include "../Cry3DEngine/CGF/ChunkFileReaders.h"
#include "../Cry3DEngine/CGF/ChunkFileWriters.h"
#include "CryHeaders.h"
#include "IChunkFile.h"
#include "IConfig.h"
#include "IResCompiler.h"
#include "IResourceCompilerHelper.h"
#include "StringHelpers.h"
#include "UpToDateFileHelpers.h"
static bool writeChunkFile(
ChunkFile::MemorylessChunkFileWriter::EChunkFileFormat eFormat,
const char* dstFilename,
ChunkFile::IReader* pReader,
const char* srcFilename,
const std::vector<IChunkFile::ChunkDesc>& chunks)
{
ChunkFile::OsFileWriter writer;
if (!writer.Create(dstFilename))
{
RCLogError("Failed to create '%s'", dstFilename);
return false;
}
ChunkFile::MemorylessChunkFileWriter wr(eFormat, &writer);
wr.SetAlignment(4);
while (wr.StartPass())
{
for (uint32 i = 0; i < chunks.size(); ++i)
{
wr.StartChunk((chunks[i].bSwapEndian ? eEndianness_NonNative : eEndianness_Native), chunks[i].chunkType, chunks[i].chunkVersion, chunks[i].chunkId);
uint32 srcSize = chunks[i].size;
if (srcSize <= 0)
{
continue;
}
if (!pReader->SetPos(chunks[i].fileOffset) != 0)
{
RCLogError("Failed to read (seek) file %s.", srcFilename);
return false;
}
while (srcSize > 0)
{
char bf[4 * 1024];
const uint32 sz = Util::getMin((uint32)sizeof(bf), srcSize);
srcSize -= sz;
if (!pReader->Read(bf, sz))
{
RCLogError("Failed to read %u byte(s) from file %s.", (uint)sz, srcFilename);
return false;
}
wr.AddChunkData(bf, sz);
}
}
}
if (!wr.HasWrittenSuccessfully())
{
RCLogError("Failed to write %s.", dstFilename);
return false;
}
return true;
}
static bool convertChunkFile(const uint32 version, const char* srcFilename, const char* dstFilename)
{
if (srcFilename == 0 || srcFilename[0] == 0 || dstFilename == 0 || dstFilename[0] == 0)
{
RCLogError("Empty name of a chunk file. Contact RC programmer.");
return false;
}
ChunkFile::CryFileReader f;
if (!f.Open(srcFilename))
{
RCLogError("File to open file %s for reading", srcFilename);
return false;
}
std::vector<IChunkFile::ChunkDesc> chunks;
string s;
s = ChunkFile::GetChunkTableEntries_0x746(&f, chunks);
if (!s.empty())
{
s = ChunkFile::GetChunkTableEntries_0x744_0x745(&f, chunks);
if (s.empty())
{
s = ChunkFile::StripChunkHeaders_0x744_0x745(&f, chunks);
}
}
if (!s.empty())
{
RCLogError("%s", s.c_str());
return false;
}
const ChunkFile::MemorylessChunkFileWriter::EChunkFileFormat eFormat =
(version == 0x745)
? ChunkFile::MemorylessChunkFileWriter::eChunkFileFormat_0x745
: ChunkFile::MemorylessChunkFileWriter::eChunkFileFormat_0x746;
const bool bOk = writeChunkFile(eFormat, dstFilename, &f, srcFilename, chunks);
return bOk;
}
//////////////////////////////////////////////////////////////////////////
CChunkCompiler::CChunkCompiler()
{
m_refCount = 1;
}
CChunkCompiler::~CChunkCompiler()
{
}
//////////////////////////////////////////////////////////////////////////
// ICompiler + IConvertor methods.
//////////////////////////////////////////////////////////////////////////
void CChunkCompiler::Release()
{
if (--m_refCount <= 0)
{
delete this;
}
}
//////////////////////////////////////////////////////////////////////////
// ICompiler methods.
//////////////////////////////////////////////////////////////////////////
string CChunkCompiler::GetOutputFileNameOnly() const
{
const string sourceFileFinal = m_CC.m_config->GetAsString("overwritefilename", m_CC.m_sourceFileNameOnly.c_str(), m_CC.m_sourceFileNameOnly.c_str());
return sourceFileFinal;
}
string CChunkCompiler::GetOutputPath() const
{
return PathHelpers::Join(m_CC.GetOutputFolder(), GetOutputFileNameOnly());
}
bool CChunkCompiler::Process()
{
const string sourceFile = m_CC.GetSourcePath();
const string outputFile = GetOutputPath();
if (!m_CC.m_bForceRecompiling && UpToDateFileHelpers::FileExistsAndUpToDate(GetOutputPath(), m_CC.GetSourcePath()))
{
// The file is up-to-date
m_CC.m_pRC->AddInputOutputFilePair(m_CC.GetSourcePath(), GetOutputPath());
return true;
}
if (m_CC.m_config->GetAsBool("SkipMissing", false, true))
{
// Skip missing source files.
const DWORD dwFileSpecAttr = GetFileAttributes(sourceFile.c_str());
if (dwFileSpecAttr == INVALID_FILE_ATTRIBUTES)
{
// Skip missing file instead of reporting it as an error.
return true;
}
}
bool bOk = false;
#if !defined(AZ_PLATFORM_LINUX) && !defined(AZ_PLATFORM_APPLE) // Exception handling not enabled on linux/mac builds
try
#endif // !defined(AZ_PLATFORM_LINUX)
{
const uint32 version =
StringHelpers::EndsWith(m_CC.m_config->GetAsString("targetversion", "0x746", "0x746"), "745")
? 0x745
: 0x746;
bOk = convertChunkFile(version, sourceFile.c_str(), outputFile.c_str());
}
#if !defined(AZ_PLATFORM_LINUX) && !defined(AZ_PLATFORM_APPLE)// Exception handling not enabled on linux builds
catch (char*)
{
RCLogError("Unexpected failure in processing %s - contact an RC programmer.", sourceFile.c_str());
return false;
}
#endif // !defined(AZ_PLATFORM_LINUX) && !defined(AZ_PLATFORM_APPLE)
if (bOk)
{
if (!UpToDateFileHelpers::SetMatchingFileTime(GetOutputPath(), m_CC.GetSourcePath()))
{
return false;
}
m_CC.m_pRC->AddInputOutputFilePair(m_CC.GetSourcePath(), GetOutputPath());
}
return bOk;
}
//////////////////////////////////////////////////////////////////////////
// IConvertor methods.
//////////////////////////////////////////////////////////////////////////
ICompiler* CChunkCompiler::CreateCompiler()
{
// Only ever return one compiler, since we don't support multithreading. Since
// the compiler is just this object, we can tell whether we have already returned
// a compiler by checking the ref count.
if (m_refCount >= 2)
{
return 0;
}
// Until we support multithreading for this convertor, the compiler and the
// convertor may as well just be the same object.
++m_refCount;
return this;
}
const char* CChunkCompiler::GetExt(int index) const
{
return (index == 0) ? "chunk" : 0;
}
@@ -0,0 +1,65 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_CHUNKCOMPILER_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_CHUNKCOMPILER_H
#pragma once
#include "IConvertor.h"
struct ConvertContext;
class CChunkCompiler
: public ICompiler
, public IConvertor
{
public:
class Error
{
public:
Error(int nCode);
Error(const char* szFormat, ...);
const char* c_str() const
{
return m_strReason.c_str();
}
protected:
string m_strReason;
};
CChunkCompiler();
~CChunkCompiler();
// ICompiler + IConvertor methods.
virtual void Release();
// ICompiler methods.
virtual void BeginProcessing([[maybe_unused]] const IConfig* config) { }
virtual void EndProcessing() { }
virtual IConvertContext* GetConvertContext() { return &m_CC; }
virtual bool Process();
// IConvertor methods.
virtual ICompiler* CreateCompiler();
virtual const char* GetExt(int index) const;
private:
string GetOutputFileNameOnly() const;
string GetOutputPath() const;
ConvertContext m_CC;
int m_refCount;
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_CHUNKCOMPILER_H
@@ -0,0 +1,218 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "ResourceCompilerPC_precompiled.h"
#include "ConvertContext.h"
#include "IConfig.h"
#include "FileUtil.h"
#include "UpToDateFileHelpers.h"
#include "LuaCompiler.h"
extern "C"
{
#include <Lua/lua.h>
#include <Lua/lauxlib.h>
#include <Lua/ldo.h>
#include <Lua/lfunc.h>
#include <Lua/lmem.h>
#include <Lua/lobject.h>
#include <Lua/lopcodes.h>
#include <Lua/lstring.h>
#include <Lua/lundump.h>
}
extern "C"
{
float script_frand0_1()
{
return rand() / static_cast<float>(RAND_MAX);
}
void script_randseed(uint seed)
{
srand(seed);
}
}
// Shamelessly stolen from luac.c and modified a bit to support rc usage
#define toproto(L, i) (clvalue(L->top + (i))->l.p)
static const Proto* combine(lua_State* L)
{
return toproto(L, -1);
}
static int writer(lua_State* L, const void* p, size_t size, void* u)
{
UNUSED(L);
return (fwrite(p, size, 1, (FILE*)u) != 1) && (size != 0);
}
static int pmain(lua_State* L)
{
LuaCompiler* pCompiler = reinterpret_cast<LuaCompiler*>(lua_touserdata(L, 1));
const Proto* f;
const char* filename = pCompiler->GetInFilename();
if (luaL_loadfile(L, filename) != 0)
{
RCLogError(lua_tostring(L, -1));
return 1;
}
f = combine(L);
if (pCompiler->IsDumping())
{
const char* outputFilename = pCompiler->GetOutFilename();
FILE* D = nullptr;
azfopen(&D, outputFilename, "wb");
if (D == NULL)
{
RCLogError("Cannot open %s", outputFilename);
return 1;
}
lua_lock(L);
luaU_dump(L, f, writer, D, (int)pCompiler->IsStripping());
lua_unlock(L);
if (ferror(D))
{
RCLogError("Cannot write to %s", outputFilename);
return 1;
}
if (fclose(D))
{
RCLogError("Cannot close %s", outputFilename);
return 1;
}
}
return 0;
}
//////////////////////////////////////////////////////////////////////////
LuaCompiler::LuaCompiler()
: m_bIsDumping(true)
, m_bIsStripping(true)
, m_bIsBigEndian(false)
{
m_refCount = 1;
}
//////////////////////////////////////////////////////////////////////////
LuaCompiler::~LuaCompiler()
{
}
////////////////////////////////////////////////////////////
string LuaCompiler::GetOutputFileNameOnly() const
{
return PathHelpers::RemoveExtension(m_CC.m_sourceFileNameOnly) + ".lua";
}
////////////////////////////////////////////////////////////
string LuaCompiler::GetOutputPath() const
{
return PathHelpers::Join(m_CC.GetOutputFolder(), GetOutputFileNameOnly());
}
//////////////////////////////////////////////////////////////////////////
void LuaCompiler::Release()
{
if (--m_refCount <= 0)
{
delete this;
}
}
//////////////////////////////////////////////////////////////////////////
ICompiler* LuaCompiler::CreateCompiler()
{
// Only ever return one compiler, since we don't support multithreading. Since
// the compiler is just this object, we can tell whether we have already returned
// a compiler by checking the ref count.
if (m_refCount >= 2)
{
return 0;
}
// Until we support multithreading for this convertor, the compiler and the
// convertor may as well just be the same object.
++m_refCount;
return this;
}
//////////////////////////////////////////////////////////////////////////
bool LuaCompiler::Process()
{
string sourceFile = m_CC.GetSourcePath();
string outputFile = GetOutputPath();
std::replace(sourceFile.begin(), sourceFile.end(), '/', '\\');
std::replace(outputFile.begin(), outputFile.end(), '/', '\\');
if (!m_CC.m_bForceRecompiling && UpToDateFileHelpers::FileExistsAndUpToDate(GetOutputPath(), m_CC.GetSourcePath()))
{
// The file is up-to-date
m_CC.m_pRC->AddInputOutputFilePair(m_CC.GetSourcePath(), GetOutputPath());
return true;
}
bool ok = false;
const bool isPlatformBigEndian = m_CC.m_pRC->GetPlatformInfo(m_CC.m_platform)->bBigEndian;
m_bIsDumping = true;
m_bIsStripping = true;
m_bIsBigEndian = isPlatformBigEndian;
m_sInFilename = sourceFile;
m_sOutFilename = outputFile;
lua_State* L = luaL_newstate();
if (L)
{
lua_pushcfunction(L, pmain);
lua_pushlightuserdata(L, this);
if (lua_pcall(L, 1, 0, 0) == 0)
{
ok = true;
}
else
{
RCLogError(lua_tostring(L, -1));
}
lua_close(L);
}
else
{
RCLogError("Not enough memory for lua state");
}
if (ok)
{
if (!UpToDateFileHelpers::SetMatchingFileTime(GetOutputPath(), m_CC.GetSourcePath()))
{
return false;
}
m_CC.m_pRC->AddInputOutputFilePair(m_CC.GetSourcePath(), GetOutputPath());
}
return ok;
}
@@ -0,0 +1,67 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_LUACOMPILER_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_LUACOMPILER_H
#pragma once
#include "IConvertor.h"
struct ConvertContext;
class LuaCompiler
: public IConvertor
, public ICompiler
{
public:
LuaCompiler();
~LuaCompiler();
// IConvertor methods.
virtual ICompiler* CreateCompiler();
virtual const char* GetExt(int index) const { return (index == 0) ? "lua" : 0; }
// ICompiler methods.
virtual void BeginProcessing([[maybe_unused]] const IConfig* config) { }
virtual void EndProcessing() { }
virtual IConvertContext* GetConvertContext() { return &m_CC; }
virtual bool Process();
// ICompiler + IConvertor methods.
void Release();
public:
bool IsDumping() const { return m_bIsDumping; }
bool IsStripping() const { return m_bIsStripping; }
bool IsBigEndian() const { return m_bIsBigEndian; }
const char* GetInFilename() const { return m_sInFilename.c_str(); }
const char* GetOutFilename() const { return m_sOutFilename.c_str(); }
private:
string GetOutputFileNameOnly() const;
string GetOutputPath() const;
private:
int m_refCount;
private:
bool m_bIsDumping; /* dump bytecodes? */
bool m_bIsStripping; /* strip debug information? */
bool m_bIsBigEndian;
string m_sInFilename;
string m_sOutFilename;
ConvertContext m_CC;
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_LUACOMPILER_H
@@ -0,0 +1,19 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_PHYSWORLD_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_PHYSWORLD_H
#pragma once
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_PHYSWORLD_H
@@ -0,0 +1,12 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(LY_COMPILE_OPTIONS PRIVATE -fexceptions)
@@ -0,0 +1,12 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(LY_COMPILE_OPTIONS PRIVATE /EHsc)
@@ -0,0 +1,12 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
@@ -0,0 +1,11 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
@@ -0,0 +1,10 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
@@ -0,0 +1,501 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "ResourceCompilerPC_precompiled.h"
#include "RenderMeshBuilder.h"
#include "StlUtils.h"
#include "NvTriStrip/NvTriStrip.h"
// constructs everything for the render mesh out of the given mesh
void CRenderMeshBuilder::build (const CryChunkedFile::MeshDesc* pMeshDesc)
{
clear();
m_pMeshDesc = pMeshDesc;
// build the tangent bases
MeshProxy Proxy;
Proxy.init(pMeshDesc);
m_TangBaseBuilder.CalculateTangentSpace (Proxy);
buildExtToIntMaps();
// create the m_arrMtlFaces: the faces are sorted and perhaps
// degraded faces are deleted
buildMtlFaces();
// create the indices and the array m_arrMaterials
buildIndexBuffer();
// optimize the final vertex buffer spacial locality
remapIndicesForVBCache();
//selfValidate();
}
// increases all indices of materials by the given offset
void CRenderMeshBuilder::addMaterialOffset (unsigned nOffset)
{
for (MaterialGroupArray::iterator it = m_arrPrimGroups.begin(); it != m_arrPrimGroups.end(); ++it)
{
it->nMaterial += nOffset;
}
}
// cleans up the object
void CRenderMeshBuilder::clear()
{
m_arrIndices.clear();
m_arrPrimGroups.clear();
m_arrExtTangMap.clear();
m_arrExtUVMap.clear();
m_arrExtTangents.clear();
m_arrMtlFaces.clear();
m_arrExtFaces.clear();
m_mapVUVP.clear();
m_arrExtToTBBMap.clear();
m_pMeshDesc = NULL;
}
// returns the number of vertices in the resulting vertex buffer
unsigned CRenderMeshBuilder::numVertices() const
{
// the number of external tangent bases determine this, because the
// tangent base calculation algorithm completely splits all the necessary
// vertices, so that the vertex buffer can be formed
return m_arrExtTangents.size();
}
// prepares the m_arrExtTangents, m_arrExtToTBBMap, m_arrExtTangMap and m_arrExtUVMap
void CRenderMeshBuilder::prepareExtToIntMapping ()
{
unsigned numTBBTangents = m_TangBaseBuilder.GetBaseCount();
unsigned numTBBTangents_Reserve = numTBBTangents * 9 / 7;
// prepare ext->TBB and the table of actual tangents
m_arrExtToTBBMap.reserve (numTBBTangents_Reserve);
//m_arrExtToTBBMap.resize (numTBBTangents);
m_arrExtTangents.reserve (numTBBTangents_Reserve);
//m_arrExtTangents.resize (numTBBTangents);
//for (i = 0; i < numTBBTangents; ++i)
//{
// m_arrExtToTBBMap[i] = i;
// TangData& rBase = m_arrExtTangents[i];
// m_TangBaseBuilder.GetBase(i, &rBase.tangent.x, &rBase.binormal.x, &rBase.tnormal.x);
//}
// create the indexation map new->old
m_arrExtTangMap.reserve(numTBBTangents_Reserve);
//m_arrExtTangMap.resize (numTBBTangents,-1);
if (m_pMeshDesc->numTexFaces())
{
m_arrExtUVMap.reserve(numTBBTangents_Reserve);
//m_arrExtUVMap.resize (numTBBTangents, -1);
}
m_arrExtFaces.reserve (m_pMeshDesc->numFaces());
}
// adds an entry to all required maps - m_arrExtTangents, m_arrExtToTBBMap, m_arrExtTangMap and m_arrExtUVMap
bool CRenderMeshBuilder::addExtToIntMapEntry (DWORD FaceExt[3], const CryFace& FaceInt, const CryTexFace& TexFaceInt)
{
unsigned numTBBTangents = m_TangBaseBuilder.GetBaseCount();
assert (m_arrExtTangMap.size() == m_arrExtUVMap.size() || m_arrExtUVMap.empty());
assert (m_arrExtTangMap.size() == m_arrExtTangents.size());
CryFace NewExtFace = FaceInt;
if (FaceExt[0] == FaceExt[1] || FaceExt[1] == FaceExt[2] || FaceExt[2] == FaceExt[0])
{
return false;
}
for (unsigned i = 0; i < 3; ++i)
{
VertexUVPair VUVPair((ushort)FaceInt[i], (ushort)TexFaceInt[i], (ushort)FaceExt[i]);
VertexUVPairMap::iterator itVUVPair = m_mapVUVP.find (VUVPair);
unsigned nExtEntry;
if (itVUVPair == m_mapVUVP.end())
{
// no such pair, add a new one.
nExtEntry = m_arrExtTangents.size();
TangData rBase;
m_TangBaseBuilder.GetBase (FaceExt[i], &rBase.tangent.x, &rBase.binormal.x, &rBase.tnormal.x);
AdjustBase(rBase);
m_arrExtTangents.push_back (rBase);
m_arrExtTangMap.push_back(FaceInt[i]);
m_arrExtToTBBMap.push_back((ushort)FaceExt[i]);
if (m_pMeshDesc->numTexFaces())
{
m_arrExtUVMap.push_back(TexFaceInt[i]);
}
m_mapVUVP.insert (VertexUVPairMap::value_type(VUVPair, nExtEntry));
}
else
{
// there's already such a pair, use it
nExtEntry = itVUVPair->second;
}
NewExtFace[i] = nExtEntry;
}
assert(!NewExtFace.isDegenerate());
m_arrExtFaces.push_back(NewExtFace);
return true;
}
// creates the mapping from the external to internal indices
void CRenderMeshBuilder::buildExtToIntMaps()
{
unsigned i, numTBBTangents = m_TangBaseBuilder.GetBaseCount();
prepareExtToIntMapping();
unsigned numDegenerate = 0;
CryTexFace TexFaceInt (0, 0, 0);
DWORD FaceExt[3];
for (i = 0; i < m_pMeshDesc->numFaces(); ++i)
{
// internal indexation face
const CryFace& FaceInt = m_pMeshDesc->pFaces[i];
// external indexation face
m_TangBaseBuilder.GetTriangleBaseIndices(i, FaceExt);
if (m_pMeshDesc->numTexFaces())
{
TexFaceInt = m_pMeshDesc->pTexFaces[i];
}
if (!addExtToIntMapEntry (FaceExt, FaceInt, TexFaceInt))
{
++numDegenerate;
continue; // degenerate face
}
#ifdef _DEBUG
CryFace& NewExtFace = m_arrExtFaces.back();
for (int j = 0; j < 3; ++j)
{
assert (m_arrExtUVMap[NewExtFace[j]] == TexFaceInt[j]);
assert (m_arrExtTangMap[NewExtFace[j]] == FaceInt[j]);
}
#endif
}
if (numDegenerate)
{
LogWarning("%u degenerate faces (skipped)", numDegenerate);
}
}
// calculate the number of elements == nEl
// create the indices and the array m_arrMaterials
// Create the m_arrMtlFaces
// degraded faces are deleted
void CRenderMeshBuilder::buildMtlFaces()
{
unsigned nFace, numExtFaces = m_arrExtFaces.size();
// pass 1: calculate each material's number of faces, and the number of materials
// SKIPPED NOW
const unsigned nMaxMatID = 0x400;
// pass 2: create the face groups and reserve space for the faces
m_arrMtlFaces.reserve (nMaxMatID / 4);
unsigned numSkippedFaces = 0;
// pass 3: create the faces in the face groups
for (nFace = 0; nFace < numExtFaces; ++nFace)
{
// external indexation face
const CryFace& rExtFace = m_arrExtFaces[nFace];
int nMatID = rExtFace.MatID;
// material id of the face to count
if (nMatID < 0 || nMatID > nMaxMatID)
{
++numSkippedFaces;
continue;
}
assert (!rExtFace.isDegenerate());
if (m_arrMtlFaces.size() <= (unsigned)nMatID)
{
m_arrMtlFaces.resize (nMatID + 1);
}
m_arrMtlFaces[nMatID].push_back (Face(rExtFace));
}
if (numSkippedFaces)
{
LogWarning ("%d faces skipped: no material or material id is out of range", numSkippedFaces);
}
}
//////////////////////////////////////////////////////////////////////////
// create the indices and the array m_arrMaterials out of m_arrMtlFaces
void CRenderMeshBuilder::buildIndexBuffer()
{
m_arrIndices.reserve (m_pMeshDesc->numFaces() * 3);
SetListsOnly (true);
for (unsigned nMaterial = 0; nMaterial < m_arrMtlFaces.size(); ++nMaterial)
{
const FaceArray& arrFaces = m_arrMtlFaces[nMaterial];
if (arrFaces.empty())
{
continue;
}
PrimitiveGroup* pGroup = NULL;
unsigned short numGroups = 0;
GenerateStrips((unsigned short*)&arrFaces[0], arrFaces.size() * 3, &pGroup, &numGroups);
for (unsigned nGroup = 0; nGroup < numGroups; ++nGroup)
{
appendNvidiaStrip (pGroup[nGroup], nMaterial);
}
delete[numGroups] pGroup;
}
}
//////////////////////////////////////////////////////////////////////////
// remaps (transposes, permutates) the indices to improve spatial locality of the vertex buffer
void CRenderMeshBuilder::remapIndicesForVBCache()
{
// this is the old->new indexation
std::vector<unsigned> arrVCache;
arrVCache.resize (m_arrExtTangents.size(), -1);
unsigned nNextVertex = 0;
for (unsigned i = 0; i < m_arrIndices.size(); ++i)
{
ushort nVertex = m_arrIndices[i];
if (arrVCache[nVertex] == -1)
{
// we've met this vertex for the first time
arrVCache[nVertex] = nNextVertex++;
}
}
remapExtIndices(&arrVCache[0], nNextVertex);
}
// permutate the contents of the array with a permutation old->new
template <class T>
void Permutate (std::vector<T>& arrOld, unsigned* pPermutation, unsigned newSize)
{
assert (newSize <= arrOld.size());
std::vector<T> arrNew;
arrNew.resize (newSize);
for (unsigned nEntry = 0; nEntry < arrOld.size(); ++nEntry)
{
if (pPermutation[nEntry] < arrNew.size())
{
arrNew[pPermutation[nEntry]] = arrOld[nEntry];
}
else
{
assert (pPermutation[nEntry] == -1);
}
}
arrOld.swap(arrNew);
}
// remaps external indices according to the given permutation old->new
void CRenderMeshBuilder::remapExtIndices (unsigned* pPermutation, unsigned numNewVertices)
{
unsigned numVertices = this->numVertices();
// remap the indices
for (unsigned nIndex = 0; nIndex < m_arrIndices.size(); ++nIndex)
{
assert (m_arrIndices[nIndex] < numVertices);
m_arrIndices[nIndex] = pPermutation[m_arrIndices[nIndex]];
assert (m_arrIndices[nIndex] < numNewVertices);
}
for (unsigned nFace = 0; nFace < m_arrExtFaces.size(); ++nFace)
{
m_arrExtFaces[nFace].v0 = pPermutation[m_arrExtFaces[nFace].v0];
m_arrExtFaces[nFace].v1 = pPermutation[m_arrExtFaces[nFace].v1];
m_arrExtFaces[nFace].v2 = pPermutation[m_arrExtFaces[nFace].v2];
}
// remap the ExtToInt mappings
assert (m_arrExtTangMap.size() == numVertices);
Permutate(m_arrExtTangMap, pPermutation, numNewVertices);
if (m_pMeshDesc->numTexFaces())
{
assert (m_arrExtUVMap.size() == numVertices);
Permutate(m_arrExtUVMap, pPermutation, numNewVertices);
}
assert (m_arrExtTangents.size() == numVertices);
// remap the tangent bases
Permutate(m_arrExtTangents, pPermutation, numNewVertices);
assert (m_arrExtTangents.size() == numNewVertices);
}
//////////////////////////////////////////////////////////////////////////
// add the primitive group(s) and indices (m_arrPrimGroups and m_arrIndices)
// from the given primitives generated by Nvidia Stripifier
void CRenderMeshBuilder::appendNvidiaStrip (const struct PrimitiveGroup& rGroup, unsigned nMaterial)
{
int j;
// in case we'll add this material group, collect info in it
MaterialGroup MatGroup;
MatGroup.nMaterial = nMaterial;
MatGroup.nIndexBase = m_arrIndices.size();
MatGroup.numIndices = 0;
for (int nIndex = 0; nIndex < (int)rGroup.numIndices - 2; )
{
int v[3];
unsigned short* src = rGroup.indices + nIndex;
switch (rGroup.type)
{
case PT_LIST:
v[0] = src[0];
v[1] = src[1];
v[2] = src[2];
nIndex += 3;
break;
case PT_STRIP:
if (nIndex & 1)
{
v[0] = src[1];
v[1] = src[0];
v[2] = src[2];
}
else
{
v[0] = src[0];
v[1] = src[1];
v[2] = src[2];
}
nIndex += 1;
break;
case PT_FAN:
v[0] = rGroup.indices[0];
v[1] = src[1];
v[2] = src[2];
break;
}
if (v[0] == v[1] || v[1] == v[2] || v[2] == v[0])
{
continue;
}
MatGroup.numIndices += 3;
for (j = 0; j < 3; ++j)
{
m_arrIndices.push_back(v[j]);
}
}
if (MatGroup.numIndices)
{
// there were some triangles - add a new group or append those triangles to the previous group
if (!m_arrPrimGroups.empty() && m_arrPrimGroups.back().nMaterial == nMaterial)
{
m_arrPrimGroups.back().numIndices += MatGroup.numIndices;
}
else
{
m_arrPrimGroups.push_back(MatGroup);
}
}
}
void CRenderMeshBuilder::selfValidate()
{
assert (m_arrExtFaces.size() <= m_pMeshDesc->numFaces());
unsigned numFaces = m_arrExtFaces.size();
for (unsigned nFace = 0; nFace < numFaces; ++nFace)
{
CryFace ExtFace = m_arrExtFaces[nFace];
CryFace IntFace = m_pMeshDesc->pFaces[nFace];
CryTexFace TexFace = m_pMeshDesc->pTexFaces[nFace];
for (int i = 0; i < 3; ++i)
{
// this is only applicable to a normal manifold mesh
assert (m_arrExtUVMap[ExtFace[i]] == TexFace[i]);
assert (m_arrExtTangMap[ExtFace[i]] == IntFace[i]);
}
}
}
// adjusts the base - converts from Martin's algorithm's requirements to the engine requirements
void CRenderMeshBuilder::AdjustBase(TangData& rBase)
{
/*
float fBinormal = rBase.binormal * rBase.tnormal;
float fTangent = rBase.tangent * rBase.tnormal;
assert (fabs(fBinormal) < 1e-2 && fabs(fTangent) < 1e-2);
/* // normalize the normal
float fEpsilon = 0.0005f;
float fSqrt1_2 = 0.70710678118654752440084436210485f; // square root of 1/2
float fNormalLen = rBase.tnormal.GetLength();
if (fNormalLen < fEpsilon)
rBase.tnormal /= fNormalLen;
rBase.tnormal /= fNormalLen;
// make the bisect that
Vec3 vBisect = rBase.binormal+rBase.tangent;
vBisect -= (vBisect * rBase.tnormal) * rBase.tnormal; // make it orthogonal to the normal
float fBisectLen = vBisect.GetLength();
if (fBisectLen < fEpsilon)
return;
vBisect /= fBisectLen;
Vec3 vBase = vBisect ^ rBase.tnormal;
if (rBase.binormal * vBase > rBase.tangent * vBase)
{
assert (rBase.binormal * vBase > 0 && rBase.tangent * vBase < 0);
rBase.binormal = (vBisect + vBase) * fSqrt1_2;
rBase.tangent = (vBisect - vBase) * fSqrt1_2;
}
else
{
assert (rBase.binormal * vBase < 0 && rBase.tangent * vBase > 0);
rBase.binormal = (vBisect - vBase) * fSqrt1_2;
rBase.tangent = (vBisect + vBase) * fSqrt1_2;
}
*/
//std::swap(rBase.binormal, rBase.tangent);
rBase.binormal = -rBase.binormal;
}
void CRenderMeshBuilder::MeshProxy::GetPos(const DWORD indwPos, float outfPos[3]) const
{
const Vec3 ptPos = m_pMeshDesc->pVertices[indwPos].p;
// unrotate the object
for (int i = 0; i < 3; ++i)
{
outfPos[i] = m_tm(0, i) * ptPos.x + m_tm(1, i) * ptPos.y + m_tm(2, i) * ptPos.z;
}
}
@@ -0,0 +1,257 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// This is the class that makes a renderable (stripified) vertex/index buffers
// and tangent bases out of a CGF mesh
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_RENDERMESHBUILDER_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_RENDERMESHBUILDER_H
#pragma once
#include "CryChunkedFile.h"
#include "TangentSpaceCalculation.h"
#include "CryCompiledFile.h"
// Calculates tangent spaces
// Builds index buffer (stripifies), material group array, ext-to-int map.
class CRenderMeshBuilder
{
public:
// constructs everything for the render mesh out of the given mesh
void build (const CryChunkedFile::MeshDesc* pMeshDesc);
// increases all indices of materials by the given offset
void addMaterialOffset (unsigned nOffset);
// cleans up the object
void clear();
// this error class is thrown from the constructor when the object can't be constructed
class Error
{
public:
Error(const char* szDesc)
: m_szDesc(szDesc){}
const char* c_str() const{return m_szDesc; }
protected:
const char* m_szDesc;
};
// returns the number of vertices in the resulting vertex buffer
unsigned numVertices() const;
// face/vertex index type
typedef unsigned short ushort;
// this is the index buffer (external indexation)
std::vector<ushort> m_arrIndices;
// this array represents the groups of indices in the index buffer:
// each group has its own material id and number of elements (indices, i.e. number of faces * 3 in case of strip stripification)
typedef CCFMaterialGroup MaterialGroup;
typedef std::vector<MaterialGroup> MaterialGroupArray;
MaterialGroupArray m_arrPrimGroups;
// this is the mapping from new indices to original
std::vector<ushort> m_arrExtTangMap;
// this is the mapping from new indices to original UV indices
// in the original CGF, texture and geometric mesh (faces/tex faces) are
// different (tex face indices are not necessarily the same as face indices),
// this is why the ExtToInt map doesn't coincide with this ExtUVMap
std::vector<ushort> m_arrExtUVMap;
// these are the tangent bases (external indexation)
std::vector<TangData> m_arrExtTangents;
#pragma pack(push,2)
// this is a group of faces, as they will be inside a group (material)
struct Face
{
ushort v[3];
Face(){}
Face(ushort v0, ushort v1, ushort v2)
{
v[0] = v0;
v[1] = v1;
v[2] = v2;
}
Face (const CryFace& rFace)
{
v[0] = rFace.v0;
v[1] = rFace.v1;
v[2] = rFace.v2;
}
Face (DWORD src[3])
{
v[0] = (ushort)src[0];
v[1] = (ushort)src[1];
v[2] = (ushort)src[2];
}
bool isDegenerate() const
{
return v[0] == v[1] || v[1] == v[2] || v[2] == v[0];
}
};
#pragma pack(pop)
// WARNING: this array must be binary-compatible with the array of unsigned shorts
// passed to Nvidia Stripifier. external indexation
typedef std::vector<Face> FaceArray;
// this is the array of faces for each material
std::vector<FaceArray> m_arrMtlFaces;
// this is the actual array of faces, but in the final external indexation
std::vector<CryFace> m_arrExtFaces;
protected:
// adjusts the base - converts from Martin's algorithm's requirements to the engine requirements
static void AdjustBase(TangData& rBase);
// creates the mapping from the external to internal indices
void buildExtToIntMaps();
// create m_arrMtlFaces; the degenerated faces are not included
void buildMtlFaces();
// create the indices and the array m_arrMaterials out of m_arrMtlFaces
void buildIndexBuffer();
// remaps (transposes, permutates) the indices to improve spatial locality of the vertex buffer
void remapIndicesForVBCache();
// remaps external indices according to the given permutation old->new
void remapExtIndices (unsigned* pPermutation, unsigned numNewTargets);
// prepares the m_arrExtTangents, m_arrExtToTBBMap, m_arrExtTangMap and m_arrExtUVMap
void prepareExtToIntMapping();
// adds an entry to all required maps - m_arrExtTangents, m_arrExtToTBBMap, m_arrExtTangMap and m_arrExtUVMap
bool addExtToIntMapEntry (DWORD FaceExt[3], const CryFace&FaceInt, const CryTexFace &TexFaceInt);
protected:
// add the primitive group(s) and indices (m_arrPrimGroups and m_arrIndices)
// from the given primitives generated by Nvidia Stripifier
void appendNvidiaStrip (const struct PrimitiveGroup& Group, unsigned nMaterial);
void selfValidate();
protected:
const CryChunkedFile::MeshDesc* m_pMeshDesc;
struct VertexUVPair
{
VertexUVPair(){}
VertexUVPair(ushort _nVertex, ushort _nTexVertex, ushort _nExtTangent)
: nVertex(_nVertex)
, nTexVertex (_nTexVertex)
, nExtTangent(_nExtTangent){}
bool operator < (const VertexUVPair& right) const
{
return
nVertex < right.nVertex ? true:
nVertex > right.nVertex ? false :
nTexVertex < right.nTexVertex? true:
nTexVertex > right.nTexVertex ? false :
nExtTangent < right.nExtTangent;
}
ushort nVertex; // vertex in internal indexation
ushort nTexVertex; // texture vertex (UV) in internal indexation
ushort nExtTangent; // vertex in TBB indexation, or tangent in the array of tangents generated by TBB
};
// this is the map from the vertex-uv pair to the index of the
// temporary vertex mapping in this->arrVertMap;
typedef std::map <VertexUVPair, ushort> VertexUVPairMap;
//////////////////////////////////////////////////////////////////////////
// a proxy structure that gets passed to the tangent space calculation algorithm
struct MeshProxy
{
public:
MeshProxy ()
{
m_pMeshDesc = NULL;
}
// creates temporary mapping for splitting the vertices
// with different UVs
void init (const CryChunkedFile::MeshDesc* pMeshDesc)
{
m_pMeshDesc = pMeshDesc;
Matrix34 tm;
const float* pMat = &m_pMeshDesc->pNode->pDesc->tm[0][0];
tm.SetFromVectors(
Vec3(pMat[ 0], pMat[ 1], pMat[ 2]),
Vec3(pMat[ 4], pMat[ 5], pMat[ 6]),
Vec3(pMat[ 8], pMat[ 9], pMat[10]),
Vec3(pMat[12], pMat[13], pMat[14]));
m_tm = tm;
}
DWORD GetTriangleCount(void) const
{
return m_pMeshDesc->numFaces();
}
void GetTriangleIndices(const DWORD indwTriNo, DWORD outdwPos[3], DWORD outdwNorm[3], DWORD outdwUV[3]) const
{
const CryFace& rFace = m_pMeshDesc->pFaces[indwTriNo];
outdwNorm[0] = outdwPos[0] = rFace.v0;
outdwNorm[1] = outdwPos[1] = rFace.v1;
outdwNorm[2] = outdwPos[2] = rFace.v2;
if (m_pMeshDesc->numTexFaces())
{
const CryTexFace& rTexFace = m_pMeshDesc->pTexFaces[indwTriNo];
outdwUV[0] = rTexFace.t0;
outdwUV[1] = rTexFace.t1;
outdwUV[2] = rTexFace.t2;
}
else
{
outdwUV[0] = outdwUV[1] = outdwUV[2] = 0;
}
}
void GetPos(const DWORD indwPos, float outfPos[3]) const;
void GetUV (const DWORD indwPos, float outfUV[2]) const
{
const CryUV& uv = m_pMeshDesc->pUVs[indwPos];
outfUV[0] = uv.u;
outfUV[1] = uv.v;
}
std::vector<VertexUVPair> arrVertMap;
protected:
const CryChunkedFile::MeshDesc* m_pMeshDesc;
Matrix34 m_tm;
};
CTangentSpaceCalculation<MeshProxy> m_TangBaseBuilder;
// this mapping gives the ext->tang ext mapping, i.e.
// maps from the final external indexation (that's found in
// m_arrExtTangMap, m_arrExtUVMap, m_arrExtTangents)
// to the tangent base indexation in m_TangBaseBuilder
// (GetBaseCount, GetTriangleBaseIndices, GetBase)
std::vector<ushort> m_arrExtToTBBMap;
// this is used during construction of the external maps to quickly find
// corresponding vertex-uv pairs and avoid collisions
// the vertex-uv indices are in internal indexations of vertices and UVs
VertexUVPairMap m_mapVUVP;
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_RENDERMESHBUILDER_H
@@ -0,0 +1,138 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "ResourceCompilerPC_precompiled.h"
#include "CryAssert_impl.h"
#include "StatCGFCompiler.h"
#include "ChunkCompiler.h"
#include "LuaCompiler.h"
#include "CGF/AssetWriter.h"
#include "../../CryXML/ICryXML.h"
#include <AzCore/Module/Environment.h>
#include <AzCore/Utils/Utils.h>
#include <CryLibrary.h>
#include <ResourceCompiler/ResourceCompiler.h>
#if defined(AZ_PLATFORM_WINDOWS)
#define WIN32_LEAN_AND_MEAN
#include <windows.h> // HANDLE
#endif
#include "ResourceCompilerPC.h"
static HMODULE g_hInst;
static AssetWriter g_AssetWriter;
#if defined(AZ_PLATFORM_WINDOWS) && !defined(AZ_MONOLITHIC_BUILD)
BOOL APIENTRY DllMain(
HANDLE hModule,
DWORD ul_reason_for_call,
[[maybe_unused]] LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
g_hInst = (HMODULE)hModule;
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
#endif
extern "C" DLL_EXPORT void __stdcall RegisterConvertors(IResourceCompiler* const pRC)
{
PREVENT_MODULE_AND_ENVIRONMENT_SYMBOL_STRIPPING
SetRCLog(pRC->GetIRCLog());
pRC->RegisterConvertor("StatCGFCompiler", new CStatCGFCompiler());
pRC->RegisterConvertor("ChunkCompiler", new CChunkCompiler());
pRC->RegisterConvertor("LuaCompiler", new LuaCompiler());
pRC->SetAssetWriter(&g_AssetWriter);
ICryXML* const pCryXML = LoadICryXML();
if (pCryXML == 0)
{
RCLogError("Loading xml library failed - not registering collada converter.");
}
pRC->RegisterKey("createmtl", "[DAE] 0=don't create .mtl files (default), 1=create .mtl files");
pRC->RegisterKey("file", "animation file for processing");
pRC->RegisterKey("dest", "destination folder for the results\n"
"OBSOLETE. Use 'targetroot' pointing to folder with .cba file instead.");
pRC->RegisterKey("report", "report mode");
pRC->RegisterKey("dcc", "the name of the dcc that called the rc.");
pRC->RegisterKey("dccv", "the version of the dcc that called the rc.");
pRC->RegisterKey("SkipDba", "skip build dba");
pRC->RegisterKey("animConfigFolder", "Path to a folder that contains SkeletonList.xml and DBATable.json");
pRC->RegisterKey("cbaUpdate", "Check for CBA-update only. Do not recompile CAF-s when CBA is up to date");
pRC->RegisterKey("checkloco",
"should be used with report mode.\n"
"Compare locomotion_locator motion with recalculated root motion");
pRC->RegisterKey("debugcompression", "[I_CAF] show per-bone compression values during CAF-compression");
pRC->RegisterKey("ignorepresets", "[I_CAF] do not apply compression presets");
pRC->RegisterKey("animSettingsFile", "File to use instead of the default animation settings file");
pRC->RegisterKey("cafAlignTracks", "[I_CAF] Apply padding to animation tracks to make the CAF suitable for in-place streaming");
pRC->RegisterKey("dbaStreamPrepare", "[DBA] Prepare DBAs so they can be streamed in-place");
pRC->RegisterKey("qtangents", "0=use vectors to represent tangent space(default), 1=use quaternions");
pRC->RegisterKey("vertexPositionFormat",
"[CGF] Format of mesh vertex positions:\n"
"f32 = 32-bit floating point (default)\n"
"f16 = 16-bit floating point\n"
"exporter = format specified in exporter\n");
pRC->RegisterKey("vertexIndexFormat",
"[CGF] Format of mesh vertex indices:\n"
"u32 = 32-bit unsigned integer (default)\n"
"u16 = 16-bit unsigned integer\n");
pRC->RegisterKey("debugdump", "[CGF] dump contents of source .cgf file instead of compiling it");
pRC->RegisterKey("debugvalidate", "[CGF, CHR] validate source file instead of compiling it");
pRC->RegisterKey("targetversion", "[chunk] Convert chunk file to the specified version\n"
"0x745 = chunk data contain chunk headers\n"
"0x746 = chunk data has no chunk headers (default)\n");
pRC->RegisterKey("StripMesh", "[CGF/CHR] Strip mesh chunks from output files\n"
"0 = No stripping\n"
"1 = Only strip mesh\n"
"3 = [CHR] Treat input as a skin file, stripping all unnecessary chunks (including mesh)\n"
"4 = [CHR] Treat input as a skel file, stripping all unnecessary chunks (including mesh)");
pRC->RegisterKey("StripNonMesh", "[CGF/CHR] Strip non mesh chunks from the output files");
pRC->RegisterKey("CompactVertexStreams",
"[CGF] Optimise vertex streams for streaming, by removing those that are unneeded for streaming,\n"
"and packing those streams that are left into the format used internally by the engine.");
// Confetti: Nicholas Baldwin
// add option for outputting triangle strip mesh primitives for processors that prefer them.
pRC->RegisterKey("OptimizedPrimitiveType", "[CGF/CHR] Choose the preferred optimized mesh primitive type\n"
"0 = Forsyth Indexed Triangle Lists Algorithm (default)\n"
"1 = PowerVR Indexed Triangle Strips Lists Algorithm");
pRC->RegisterKey("ComputeSubsetTexelDensity", "[CGF] Compute per-subset texel density");
pRC->RegisterKey("SplitLODs", "[CGF] Auto split LODs into the separate files");
pRC->RegisterKey("maxWeightsPerVertex", "[CHR] Maximum number of weights per vertex (default is 4)");
pRC->RegisterKey("DegenerateFacesAreErrors", "If the meshcompiler finds a degenerate face, it is a suboptimal mesh. Should the we treat this as a warning or error.");
}
@@ -0,0 +1,21 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_RESOURCECOMPILERPC_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_RESOURCECOMPILERPC_H
#pragma once
#include "IRCLog.h"
#include "IResCompiler.h"
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_RESOURCECOMPILERPC_H
@@ -0,0 +1,14 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "ResourceCompilerPC_precompiled.h"
@@ -0,0 +1,62 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// StdAfx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
#pragma once
#include <assert.h>
#define CRY_ASSERT(condition) assert(condition)
#define CRY_ASSERT_TRACE(condition, message) assert(condition)
#define CRY_ASSERT_MESSAGE(condition, message) assert(condition)
// Define this to prevent including CryAssert (there is no proper hook for turning this off, like the above).
#define CRYINCLUDE_CRYCOMMON_CRYASSERT_H
#include <platform.h>
typedef string tstring;
#include <float.h>
#include <memory>
#include <set>
#include <map>
#include <vector>
#include <algorithm>
#include <stdio.h>
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some string constructors will be explicit
#include "IXml.h"
#include <Cry_Math.h>
#include <Cry_Geo.h>
#include <CryHeaders.h>
#include <primitives.h>
#include <smartptr.h>
#include <physinterface.h>
#include <CrySizer.h>
#include "ResourceCompilerPC.h"
#include "CryFile.h"
#include <VertexFormats.h>
#include "IRCLog.h"
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,113 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_STATCGFCOMPILER_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_STATCGFCOMPILER_H
#pragma once
#include "Cry_Color.h"
#include <IConvertor.h>
#include <AzCore/Asset/AssetCommon.h>
#include "../../CryEngine/Cry3DEngine/MeshCompiler/MeshCompiler.h"
#include <AzToolsFramework/Application/ToolsApplication.h>
struct ConvertContext;
class CContentCGF;
class CChunkFile;
class CPhysicsInterface;
struct CMaterialCGF;
namespace AssetBuilderSDK
{
struct ProcessJobResponse;
}
class CGFToolApplication : public AzToolsFramework::ToolsApplication
{
public:
CGFToolApplication() = default;
AZ::ComponentTypeList GetRequiredSystemComponents() const override;
void SetSettingsRegistrySpecializations(AZ::SettingsRegistryInterface::Specializations& specializations) override;
};
class CStatCGFCompiler
: public IConvertor
, public ICompiler
{
public:
class Error
{
public:
Error (int nCode);
Error (const char* szFormat, ...);
const char* c_str() const { return m_strReason.c_str(); }
protected:
string m_strReason;
};
CStatCGFCompiler();
~CStatCGFCompiler();
// IConvertor methods.
virtual ICompiler* CreateCompiler();
virtual const char* GetExt(int index) const
{
switch (index)
{
case 0:
return "cga";
case 1:
return "cgf";
case 2:
return "i_cgf";
default:
return 0;
}
}
// ICompiler methods.
virtual void BeginProcessing([[maybe_unused]] const IConfig* config) { }
virtual void EndProcessing() { }
virtual IConvertContext* GetConvertContext() { return &m_CC; }
virtual bool Process();
// ICompiler + IConvertor methods.
virtual void Release();
// Helper function to dump detailed debug information for a CGF
static bool DebugDumpCGF(const char* sourceFileName, const char* outputFilePath);
// Do the entire compilation process for the CGF source asset, populating the ProcessJobResponse
bool CompileCGF(AssetBuilderSDK::ProcessJobResponse& response, AZStd::string assetRoot = "", AZStd::string gameFolder = "");
// Write the JobProduct response file
bool WriteResponse(const char* folder, AssetBuilderSDK::ProcessJobResponse& response, bool success = true) const;
private:
string GetOutputFileNameOnly() const;
string GetOutputPath() const;
AZStd::string GetDependencyAbsolutePath(const AZStd::string& fileName) const;
void DeleteOldChunks(CContentCGF* pCGF, CChunkFile& chunkFile);
bool IsLodFile(const string& filename) const;
private:
ConvertContext m_CC;
int m_refCount;
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_STATCGFCOMPILER_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,83 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_STATICOBJECTCOMPILER_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_STATICOBJECTCOMPILER_H
#pragma once
#include "ConvertContext.h"
class CContentCGF;
struct CMaterialCGF;
class CMesh;
class CPhysicsInterface;
//START: Add Skinned Geometry (.CGF) export type (for touch bending vegetation)
struct CSkinningInfo;
struct SFoliageInfoCGF;
struct SSpineRC;
//END: Add Skinned Geometry (.CGF) export type (for touch bending vegetation)
struct CNodeCGF;
class CStaticObjectCompiler
{
public:
CStaticObjectCompiler(bool bConsole, int logVerbosityLevel = 0);
~CStaticObjectCompiler();
void SetSplitLods(bool bSplit);
// Confetti: Nicholas Baldwin
void SetOptimizeStripify(bool bStripify);
void SetUseMikkTB(bool bUseMikkTB);
CContentCGF* MakeCompiledCGF(CContentCGF* pCGF, bool const forceRecompile = false);
static int GetSubMeshCount(const CContentCGF* pCGFLod0);
static int GetJointCount(const CContentCGF* pCGF);
private:
bool ProcessCompiledCGF(CContentCGF* pCGF);
void AnalyzeSharedMeshes(CContentCGF* pCGF);
bool CompileMeshes(CContentCGF* pCGF);
bool SplitLODs(CContentCGF* pCGF);
CContentCGF* MakeLOD(int nLodNum, const CContentCGF* pCGF);
bool Physicalize(CContentCGF* pCompiledCGF, CContentCGF* pSrcCGF);
void CompileDeformablePhysData(CContentCGF* pCGF);
void PrepareSkinData(CNodeCGF* pNode, const Matrix34& mtxSkelToMesh, CNodeCGF* pNodeSkel, float r, bool bSwapEndian);
bool ValidateBoundingBoxes(CContentCGF* pCGF);
void ValidateBreakableJoints(const CContentCGF* pCGF);
bool MakeMergedCGF(CContentCGF* pCompiledCGF, CContentCGF* pCGF);
private:
bool m_bSplitLODs;
bool m_bOwnLod0;
bool m_bConsole;
int m_logVerbosityLevel;
bool m_bUseMikkTB;
// Confetti: Nicholas Baldwin
bool m_bOptimizePVRStripify;
public:
enum
{
MAX_LOD_COUNT = 6
};
CContentCGF* m_pLODs[MAX_LOD_COUNT];
};
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_STATICOBJECTCOMPILER_H
@@ -0,0 +1,23 @@
<Material MtlFlags="524544" vertModifType="0">
<SubMaterials>
<Material Name="Block_01" MtlFlags="524416" Shader="Illum" GenMask="80000001" StringGenMask="%ALLOW_SILHOUETTE_POM%SUBSURFACE_SCATTERING" SurfaceType="mat_wood" MatTemplate="" Diffuse="0.016807377,0.12743771,0.016807377" Specular="0,0,0" Emissive="0,0,0" Opacity="1" Shininess="10" CloakAmount="0" vertModifType="0" LayerAct="1">
<Textures>
<Texture Map="Diffuse" File="textures/gettingstartedtextures/white.tif"/>
</Textures>
<PublicParams SSSIndex="0" IndirectColor="0.25,0.25,0.25"/>
</Material>
<Material Name="Block_02" MtlFlags="524416" Shader="Illum" GenMask="80000001" StringGenMask="%ALLOW_SILHOUETTE_POM%SUBSURFACE_SCATTERING" SurfaceType="mat_wood" MatTemplate="" Diffuse="0.12743771,0.016807377,0.016807377" Specular="0,0,0" Emissive="0,0,0" Opacity="1" Shininess="10" CloakAmount="0" vertModifType="0" LayerAct="1">
<Textures>
<Texture Map="Diffuse" File="textures/gettingstartedtextures/white.tif"/>
</Textures>
<PublicParams SSSIndex="0" IndirectColor="0.25,0.25,0.25"/>
</Material>
<Material Name="Block_03" MtlFlags="524416" Shader="Illum" GenMask="80000001" StringGenMask="%ALLOW_SILHOUETTE_POM%SUBSURFACE_SCATTERING" SurfaceType="mat_wood" MatTemplate="" Diffuse="0.016807377,0.016807377,0.12743771" Specular="0,0,0" Emissive="0,0,0" Opacity="1" Shininess="10" CloakAmount="0" vertModifType="0" LayerAct="1">
<Textures>
<Texture Map="Diffuse" File="textures/gettingstartedtextures/white.tif"/>
</Textures>
<PublicParams SSSIndex="0" IndirectColor="0.25,0.25,0.25"/>
</Material>
</SubMaterials>
<PublicParams SSSIndex="0" IndirectColor="0.25,0.25,0.25"/>
</Material>
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c02e949b50a340cb7507c14ce7b01933ed471f03d8d11f3d191f0063c85fca2e
size 33820
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7acc775dee00c5ae3be27578ca8722935b6afbaaa53348667291ad57c3f76b62
size 2948
@@ -0,0 +1,12 @@
<Material MtlFlags="557312" DccMaterialHash="0" vertModifType="0">
<SubMaterials>
<Material Name="Grass_Atlas" MtlFlags="524416" DccMaterialHash="0" Shader="Vegetation" GenMask="2400201000" StringGenMask="%DETAIL_BENDING%GRASS%TEMP_VEGETATION%VERTCOLORS" SurfaceType="mat_default" Diffuse="1,1,1,1" Specular="0,0,0,1" Opacity="1" Shininess="10" AlphaTest="0.46000001" vertModifType="0" LayerAct="1">
<Textures>
<Texture Map="Diffuse" File="objects/natural/vegetation/grass_atlas_diff.dds">
<TexMod TexMod_RotateType="0" TexMod_TexGenType="0" TexMod_bTexGenProjected="0"/>
</Texture>
</Textures>
<PublicParams bendDetailLeafAmplitude="0.2" bendDetailFrequency="1" bendDetailBranchAmplitude="-0.5" BlendTerrainCol="0" NormalViewDependency="0.5" TransmittanceColor="1,1,0.60000002" BackDiffuseMultiplier="1" BlendTerrainColDist="0.5" IndirectColor="0.25,0.25,0.25"/>
</Material>
</SubMaterials>
</Material>
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3ba56813f5d8e5c73e7d245154e130ed8fbb43dd4891fac0b9977f9383db62dd
size 2440
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:35452caba31ce0de0c53bd811e5c35e826e9b4b7c058458199ae83b0553ed8e9
size 28088
@@ -0,0 +1,13 @@
<Material MtlFlags="524544" vertModifType="0">
<SubMaterials>
<Material Name="primitives_default_001_mat" MtlFlags="524416" Shader="Illum" GenMask="80000001" StringGenMask="%ALLOW_SILHOUETTE_POM%SUBSURFACE_SCATTERING" SurfaceType="" Diffuse="1,1,1" Specular="0.5,0.5,0.5" Emissive="0,0,0" Opacity="1" Shininess="10" vertModifType="0" LayerAct="1">
<Textures>
<Texture Map="Diffuse" File="primitives_001_diff.tif"/>
</Textures>
<PublicParams SSSIndex="0" IndirectColor="0.25,0.25,0.25"/>
</Material>
<Material Name="primitives_proxy_001_mat" MtlFlags="525440" Shader="Nodraw" GenMask="0" StringGenMask="" SurfaceType="mat_nodraw" Diffuse="1,0,0" Specular="0.5,0.5,0.5" Emissive="0,0,0" Opacity="1" Shininess="10" vertModifType="0" LayerAct="1">
<Textures />
</Material>
</SubMaterials>
</Material>
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a44a5b1b222256a1904ea8da54cfb70db6cc1944b42a15a3ab0a78443e7a4252
size 812376
@@ -0,0 +1,304 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "ResourceCompilerPC_precompiled.h"
#include <AzTest/AzTest.h>
#include <AzTest/Utils.h>
#include <AzCore/IO/Path/Path.h>
#include <AzFramework/IO/LocalFileIO.h>
#include <AssetBuilderSDK/AssetBuilderSDK.h>
#include <AzCore/Component/ComponentApplication.h>
#include <AzCore/UserSettings/UserSettingsComponent.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzToolsFramework/Application/ToolsApplication.h>
#include "../CryEngine/Cry3DEngine/CGF/CGFLoader.h"
#include "StatCGFCompiler.h"
#include "MultiplatformConfig.h"
#include <QTemporaryDir>
AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV);
AZStd::string GetTestAssetRootPath()
{
char resolvedDir[AZ_MAX_PATH_LEN];
AZ::IO::FileIOBase::GetInstance()->ResolvePath(
"@engroot@/Code/Tools/RC/ResourceCompilerPC/Tests/TestAssets/SamplesProject/",
resolvedDir, sizeof(resolvedDir));
return AZStd::string(resolvedDir);
}
// This is a dummy ResourceCompiler object overload.
// The CGF compiler is heavily dependent upon a ResourceCompiler object existing, so this overload
// just does the minimum amount of work to allow the CGF compiler to query it for default values and
// specific values needed for our test cases.
class ResourceCompilerForTesting
: public IResourceCompiler
, public IConfigKeyRegistry
{
public:
ResourceCompilerForTesting()
{
platformInfo.SetName(0, "pc");
platformInfo.bBigEndian = false;
}
virtual ~ResourceCompilerForTesting() {}
//IConfigKeyRegistry
virtual void VerifyKeyRegistration([[maybe_unused]] const char* szKey) const {}
virtual bool HasKeyRegistered([[maybe_unused]] const char* szKey) const { return false; }
//IResourceCompiler
virtual void RegisterConvertor([[maybe_unused]] const char* name, [[maybe_unused]] IConvertor* conv) {}
virtual IPakSystem* GetPakSystem() { return nullptr; }
virtual const ICfgFile* GetIniFile() const { return nullptr; }
virtual int GetPlatformCount() const { return 1; }
virtual const PlatformInfo* GetPlatformInfo([[maybe_unused]] int index) const { return &platformInfo; }
virtual int FindPlatform([[maybe_unused]] const char* name) const { return 0; }
virtual void AddInputOutputFilePair([[maybe_unused]] const char* inputFilename, [[maybe_unused]] const char* outputFilename) {}
virtual void MarkOutputFileForRemoval([[maybe_unused]] const char* sOutputFilename) {}
virtual void AddExitObserver([[maybe_unused]] IExitObserver* p) {}
virtual void RemoveExitObserver([[maybe_unused]] IExitObserver* p) {}
virtual IRCLog* GetIRCLog() { return nullptr; }
virtual int GetVerbosityLevel() const { return 0; }
virtual const SFileVersion& GetFileVersion() const { return fileVersionInfo; }
virtual const void GetGenericInfo([[maybe_unused]] char* buffer, [[maybe_unused]] size_t bufferSize, [[maybe_unused]] const char* rowSeparator) const {}
virtual void RegisterKey([[maybe_unused]] const char* key, [[maybe_unused]] const char* helptxt) {}
virtual const char* GetExePath() const { return nullptr; }
virtual const char* GetTmpPath() const { return nullptr; }
virtual const char* GetInitialCurrentDir() const { return nullptr; }
virtual XmlNodeRef LoadXml([[maybe_unused]] const char* filename) { XmlNodeRef tmp; return tmp; }
virtual XmlNodeRef CreateXml([[maybe_unused]] const char* tag) { XmlNodeRef tmp; return tmp; }
virtual bool CompileSingleFileBySingleProcess([[maybe_unused]] const char* filename) { return true; }
virtual void SetAssetWriter([[maybe_unused]] IAssetWriter* pAssetWriter) {}
virtual IAssetWriter* GetAssetWriter() const { return nullptr; }
virtual const char* GetAppRoot() const { return nullptr; }
SFileVersion fileVersionInfo;
PlatformInfo platformInfo;
MultiplatformConfig localMultiConfig;
};
class CGFBuilderTest
: public ::testing::Test
{
protected:
AZStd::string GetTemporaryDirectory()
{
QString tempPath = m_temporaryDirectory.path();
return AZStd::string(tempPath.toUtf8().constData());
}
void SetUp() override
{
AZ::AllocatorInstance<AZ::SystemAllocator>::Create();
AZ::AllocatorInstance<AZ::LegacyAllocator>::Create();
AZ::AllocatorInstance<CryStringAllocator>::Create();
m_app.reset(aznew AzToolsFramework::ToolsApplication());
AZ::ComponentApplication::Descriptor desc;
desc.m_useExistingAllocator = true;
m_app->Start(desc);
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
// in the unit tests.
AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
AssetBuilderSDK::InitializeSerializationContext();
const AZStd::string engroot = AZ::Test::GetEngineRootPath();
AZ::IO::FileIOBase::GetInstance()->SetAlias("@engroot@", engroot.c_str());
AZ::IO::Path assetRoot(engroot);
assetRoot /= "Cache";
AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", assetRoot.c_str());
m_rc = new ResourceCompilerForTesting();
m_compiler = new CStatCGFCompiler();
m_rc->localMultiConfig.init(1, 0, m_rc);
m_rc->localMultiConfig.setActivePlatform(0);
}
void TearDown() override
{
delete m_compiler;
delete m_rc;
m_compiler = nullptr;
m_rc = nullptr;
m_app->Stop();
m_app = nullptr;
AZ::AllocatorInstance<CryStringAllocator>::Destroy();
AZ::AllocatorInstance<AZ::LegacyAllocator>::Destroy();
AZ::AllocatorInstance<AZ::SystemAllocator>::Destroy();
}
void LoadCompileAndValidateCGF(const AZStd::string& cgfName, const AZStd::string& cgfPath, const AZStd::string& outputPath, AssetBuilderSDK::ProcessJobResponse& response);
AZStd::unique_ptr<AzToolsFramework::ToolsApplication> m_app;
QTemporaryDir m_temporaryDirectory;
CStatCGFCompiler* m_compiler = nullptr;
ResourceCompilerForTesting* m_rc = nullptr;
};
void CGFBuilderTest::LoadCompileAndValidateCGF(const AZStd::string& cgfName, const AZStd::string& cgfPath, const AZStd::string& outputPath, AssetBuilderSDK::ProcessJobResponse& response)
{
// Pass in a custom asset root to the CGF compiler because our test assets are not going through AP
AZStd::string assetRoot(GetTestAssetRootPath());
// Our test assets came from SamplesProject, so emulate that being our game project
AZStd::string gameFolder = "SamplesProject";
IConvertContext* const pCC = m_compiler->GetConvertContext();
pCC->SetMultiplatformConfig(&m_rc->localMultiConfig);
pCC->SetRC(m_rc);
pCC->SetForceRecompiling(true);
pCC->SetConvertorExtension(".cgf");
pCC->SetSourceFileNameOnly(cgfName.c_str());
pCC->SetSourceFolder(cgfPath.c_str());
pCC->SetOutputFolder(outputPath.c_str());
bool compileSuccess = m_compiler->CompileCGF(response, assetRoot, gameFolder);
EXPECT_TRUE(compileSuccess);
bool responseSuccess = m_compiler->WriteResponse(outputPath.c_str(), response, compileSuccess);
EXPECT_TRUE(responseSuccess);
}
// In this case, we load a basic CGF where the material path is just the name of the material file,
// so it is assumed that material is in the same folder as the CGF
TEST_F(CGFBuilderTest, CGF_MaterialInSameFolder)
{
AZStd::string cgfName = "cube_material_same_folder.cgf";
AZStd::string cgfPath(PathHelpers::Join(GetTestAssetRootPath().c_str(),"Objects/Primitives/"));
AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::Bus::Events::NormalizePathKeepCase, cgfPath);
AZStd::string outputPath = GetTemporaryDirectory();
AZStd::string expectedMaterialPath;
AzFramework::StringFunc::AssetDatabasePath::Join(cgfPath.c_str(), "primitives_001_mg.mtl", expectedMaterialPath);
AssetBuilderSDK::ProcessJobResponse response;
LoadCompileAndValidateCGF(cgfName, cgfPath, outputPath, response);
ASSERT_EQ(response.m_outputProducts.size(), 1);
AZStd::string productPath = response.m_outputProducts[0].m_productFileName;
EXPECT_TRUE(productPath == "cube_material_same_folder.cgf"); // Path would be relative to the AP temp directory, so just the file name itself
ASSERT_EQ(response.m_outputProducts[0].m_pathDependencies.size(), 1);
AssetBuilderSDK::ProductPathDependency& dependency = *response.m_outputProducts[0].m_pathDependencies.begin();
AZStd::string materialPath = dependency.m_dependencyPath;
EXPECT_TRUE(materialPath == expectedMaterialPath);
EXPECT_EQ(dependency.m_dependencyType, AssetBuilderSDK::ProductPathDependencyType::SourceFile);
}
// In this case, we load a basic CGF where the material path is absolute from the dev/ folder,
// for example "samplesproject/materials/test.mtl".
TEST_F(CGFBuilderTest, CGF_MaterialInDifferentFolder)
{
AZStd::string cgfName = "gs_block.cgf";
AZStd::string cgfPath(PathHelpers::Join(GetTestAssetRootPath().c_str(), "Objects/GettingStartedAssets/"));
AZStd::string outputPath = GetTemporaryDirectory();
AssetBuilderSDK::ProcessJobResponse response;
LoadCompileAndValidateCGF(cgfName, cgfPath, outputPath, response);
ASSERT_EQ(response.m_outputProducts.size(), 1);
AZStd::string productPath = response.m_outputProducts[0].m_productFileName;
EXPECT_TRUE(productPath == "gs_block.cgf"); // Path would be relative to the AP temp directory, so just the file name itself
ASSERT_EQ(response.m_outputProducts[0].m_pathDependencies.size(), 1);
AssetBuilderSDK::ProductPathDependency& dependency = *response.m_outputProducts[0].m_pathDependencies.begin();
AZStd::string materialPath = dependency.m_dependencyPath;
EXPECT_TRUE(materialPath == "materials/gettingstartedmaterials/gs_block.mtl");
EXPECT_EQ(dependency.m_dependencyType, AssetBuilderSDK::ProductPathDependencyType::ProductFile);
}
// A simple CGF with 2 lods, outputting to just 1 compiled CGF file
TEST_F(CGFBuilderTest, CGF_WithLOD_NoSplit)
{
AZStd::string cgfName = "CGF_LOD_Test.cgf";
AZStd::string cgfPath(PathHelpers::Join(GetTestAssetRootPath().c_str(), "Objects/"));
AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::Bus::Events::NormalizePathKeepCase, cgfPath);
AZStd::string outputPath = GetTemporaryDirectory();
AZStd::string expectedMaterialPath;
AzFramework::StringFunc::AssetDatabasePath::Join(cgfPath.c_str(), "Grass_Atlas_matGroup.mtl", expectedMaterialPath);
m_rc->localMultiConfig.setKeyValue(eCP_PriorityLowest, "SplitLODs", "false");
AssetBuilderSDK::ProcessJobResponse response;
LoadCompileAndValidateCGF(cgfName, cgfPath, outputPath, response);
ASSERT_EQ(response.m_outputProducts.size(), 1);
AZStd::string productPath = response.m_outputProducts[0].m_productFileName;
EXPECT_TRUE(productPath == "CGF_LOD_Test.cgf"); // Path would be relative to the AP temp directory, so just the file name itself
ASSERT_EQ(response.m_outputProducts[0].m_pathDependencies.size(), 1);
AssetBuilderSDK::ProductPathDependency& dependency = *response.m_outputProducts[0].m_pathDependencies.begin();
AZStd::string materialPath = dependency.m_dependencyPath;
EXPECT_TRUE(materialPath == expectedMaterialPath);
}
// A simple CGF with 2 lods, outputting to a unique CGF per lod
TEST_F(CGFBuilderTest, CGF_WithLOD_Split)
{
AZStd::string cgfName = "CGF_LOD_Test.cgf";
AZStd::string cgfPath(PathHelpers::Join(GetTestAssetRootPath().c_str(), "Objects/"));
AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::Bus::Events::NormalizePathKeepCase, cgfPath);
AZStd::string outputPath = GetTemporaryDirectory();
m_rc->localMultiConfig.setKeyValue(eCP_PriorityLowest, "SplitLODs", "true");
AssetBuilderSDK::ProcessJobResponse response;
LoadCompileAndValidateCGF(cgfName, cgfPath, outputPath, response);
ASSERT_EQ(response.m_outputProducts.size(), 3);
AZStd::string productPath = response.m_outputProducts[0].m_productFileName;
EXPECT_TRUE(productPath == "CGF_LOD_Test.cgf");
productPath = response.m_outputProducts[1].m_productFileName;
EXPECT_TRUE(productPath == "CGF_LOD_Test_lod1.cgf");
productPath = response.m_outputProducts[2].m_productFileName;
EXPECT_TRUE(productPath == "CGF_LOD_Test_lod2.cgf");
EXPECT_TRUE(response.m_outputProducts[0].m_pathDependencies.size() == 3);
AZStd::vector<AZStd::string> expectedDependencyPaths = {
"Grass_Atlas_matGroup.mtl",
"CGF_LOD_Test_lod1.cgf",
"CGF_LOD_Test_lod2.cgf"
};
for (AZStd::string& expectedDependency : expectedDependencyPaths)
{
const char* fileName = expectedDependency.c_str();
AzFramework::StringFunc::AssetDatabasePath::Join(cgfPath.c_str(), fileName, expectedDependency);
}
for (const AssetBuilderSDK::ProductPathDependency& dependency : response.m_outputProducts[0].m_pathDependencies)
{
ASSERT_TRUE(AZStd::find(expectedDependencyPaths.begin(), expectedDependencyPaths.end(), dependency.m_dependencyPath) != expectedDependencyPaths.end());
}
}
+35
View File
@@ -0,0 +1,35 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_TICKS_H
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_TICKS_H
#pragma once
#define TICKS_PER_SECOND (30) //the maximum keyframe value is 4800Hz per second
#define SECONDS_PER_TICK (1.0f / 30.0f) //the maximum keyframe value is 4800Hz per second
#define TICKS_PER_FRAME (1) //if we have 30 keyframes per second, then one tick is 1
#define TICKS_CONVERT (160)
//#define TICKS_PER_SECOND (120) //the maximum keyframe value is 4800Hz per second
//#define SECONDS_PER_TICK (1.0f/120.0f) //the maximum keyframe value is 4800Hz per second
//#define TICKS_PER_FRAME (4) //if we have 30 keyframes per second, then one tick is 4
//#define TICKS_CONVERT (40)
//#define TICKS_PER_SECOND (4800) //the maximum keyframe value is 4800Hz per second
//#define SECONDS_PER_TICK (1.0f/4800.0f) //the time for 1 tick
//#define TICKS_PER_FRAME (160) //if we have 30 keyframes per second, then one tick is 160
//#define TICKS_CONVERT (1)
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILERPC_TICKS_H
@@ -0,0 +1,36 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
CGF/CGFNodeMerger.cpp
CGF/DataWriter.cpp
CGF/AssetWriter.cpp
CGF/CGFNodeMerger.h
CGF/ChunkData.h
CGF/DataWriter.h
CGF/AssetWriter.h
ChunkCompiler.cpp
ChunkCompiler.h
LuaCompiler.cpp
LuaCompiler.h
ResourceCompilerPC_precompiled.h
ResourceCompilerPC_precompiled.cpp
StatCGFCompiler.cpp
StaticObjectCompiler.cpp
StatCGFCompiler.h
StaticObjectCompiler.h
PhysWorld.h
)
set(SKIP_UNITY_BUILD_INCLUSION_FILES
StatCGFCompiler.h
StatCGFCompiler.cpp
)
@@ -0,0 +1,15 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
ResourceCompilerPC.cpp
ResourceCompilerPC.h
)
@@ -0,0 +1,16 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
Tests/test_Main.cpp
ResourceCompilerPC.cpp
StatCGFCompiler.cpp
)