git mv Code\Sandbox\Editor Code/Editor
Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
// Description : Manager for export geometry
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_EXPORT_EXPORTMANAGER_H
|
||||
#define CRYINCLUDE_EDITOR_EXPORT_EXPORTMANAGER_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <AzCore/Component/EntityId.h>
|
||||
#include <IExportManager.h>
|
||||
|
||||
class CExportManager;
|
||||
class CTrackViewTrack;
|
||||
class CTrackViewSequence;
|
||||
class CTrackViewAnimNode;
|
||||
class CEntityObject;
|
||||
|
||||
typedef std::vector<IExporter*> TExporters;
|
||||
|
||||
|
||||
namespace Export
|
||||
{
|
||||
class CMesh
|
||||
: public Mesh
|
||||
, public CRefCountBase
|
||||
{
|
||||
public:
|
||||
CMesh();
|
||||
|
||||
virtual int GetFaceCount() const { return m_faces.size(); }
|
||||
virtual const Face* GetFaceBuffer() const { return m_faces.size() ? &m_faces[0] : 0; }
|
||||
|
||||
private:
|
||||
std::vector<Face> m_faces;
|
||||
|
||||
friend CExportManager;
|
||||
};
|
||||
|
||||
|
||||
class CObject
|
||||
: public Object
|
||||
, public CRefCountBase
|
||||
{
|
||||
public:
|
||||
CObject(const char* pName);
|
||||
|
||||
virtual int GetVertexCount() const { return m_vertices.size(); }
|
||||
virtual const Vector3D* GetVertexBuffer() const{ return m_vertices.size() ? &m_vertices[0] : 0; }
|
||||
|
||||
virtual int GetNormalCount() const { return m_normals.size(); }
|
||||
virtual const Vector3D* GetNormalBuffer() const { return m_normals.size() ? &m_normals[0] : 0; }
|
||||
|
||||
virtual int GetTexCoordCount() const { return m_texCoords.size(); }
|
||||
virtual const UV* GetTexCoordBuffer() const { return m_texCoords.size() ? &m_texCoords[0] : 0; }
|
||||
|
||||
virtual int GetMeshCount() const { return m_meshes.size(); }
|
||||
virtual Mesh* GetMesh(int index) const { return m_meshes[index]; }
|
||||
|
||||
virtual size_t MeshHash() const{return m_MeshHash; }
|
||||
|
||||
void SetMaterialName(const char* pName);
|
||||
virtual int GetEntityAnimationDataCount() const {return m_entityAnimData.size(); }
|
||||
virtual const EntityAnimData* GetEntityAnimationData(int index) const {return &m_entityAnimData[index]; }
|
||||
virtual void SetEntityAnimationData(EntityAnimData entityData){ m_entityAnimData.push_back(entityData); };
|
||||
void SetLastPtr(CBaseObject* pObject){m_pLastObject = pObject; };
|
||||
CBaseObject* GetLastObjectPtr(){return m_pLastObject; };
|
||||
|
||||
private:
|
||||
CBaseObject* m_pLastObject;
|
||||
std::vector<Vector3D> m_vertices;
|
||||
std::vector<Vector3D> m_normals;
|
||||
std::vector<UV> m_texCoords;
|
||||
std::vector< _smart_ptr<CMesh> > m_meshes;
|
||||
std::vector<EntityAnimData> m_entityAnimData;
|
||||
|
||||
size_t m_MeshHash;
|
||||
|
||||
friend CExportManager;
|
||||
};
|
||||
|
||||
|
||||
class CData
|
||||
: public IData
|
||||
{
|
||||
public:
|
||||
virtual int GetObjectCount() const { return m_objects.size(); }
|
||||
virtual Object* GetObject(int index) const { return m_objects[index]; }
|
||||
virtual Object* AddObject(const char* objectName);
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
std::vector< _smart_ptr<Export::CObject> > m_objects;
|
||||
|
||||
friend CExportManager;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
typedef std::map<CBaseObject*, int> TObjectMap;
|
||||
|
||||
class CExportManager
|
||||
: public IExportManager
|
||||
{
|
||||
public:
|
||||
|
||||
CExportManager();
|
||||
virtual ~CExportManager();
|
||||
|
||||
//! Register exporter
|
||||
//! return true if succeed, otherwise false
|
||||
virtual bool RegisterExporter(IExporter* pExporter);
|
||||
|
||||
//! Export specified geometry
|
||||
//! return true if succeed, otherwise false
|
||||
bool Export(const char* defaultName, const char* defaultExt = "", const char* defaultPath = "", bool isSelectedObjects = true,
|
||||
bool isSelectedRegionObjects = false, bool isOccluder = false, bool bAnimationExport = false);
|
||||
|
||||
bool AddSelectedEntityObjects();
|
||||
|
||||
//! Add to Export Data geometry from objects inside selected region volume
|
||||
//! return true if succeed, otherwise false
|
||||
bool AddSelectedRegionObjects();
|
||||
|
||||
//! Export to file collected data, using specified exporter throughout the file extension
|
||||
//! return true if succeed, otherwise false
|
||||
bool ExportToFile(const char* filename, bool bClearDataAfterExport = true);
|
||||
|
||||
bool ImportFromFile(const char* filename);
|
||||
const Export::CData& GetData() const {return m_data; };
|
||||
|
||||
//! Exports the stat obj to the obj file specified
|
||||
//! returns true if succeeded, otherwise false
|
||||
virtual bool ExportSingleStatObj(IStatObj* pStatObj, const char* filename);
|
||||
|
||||
void SetBakedKeysSequenceExport(bool bBaked){m_bBakedKeysSequenceExport = bBaked; };
|
||||
|
||||
void SaveNodeKeysTimeToXML();
|
||||
|
||||
private:
|
||||
void AddMesh(Export::CObject* pObj, const IIndexedMesh* pIndMesh, Matrix34A* pTm = 0);
|
||||
bool AddStatObj(Export::CObject* pObj, IStatObj* pStatObj, Matrix34A* pTm = 0);
|
||||
bool AddMeshes(Export::CObject* pObj);
|
||||
bool AddObject(CBaseObject* pBaseObj);
|
||||
void SolveHierarchy();
|
||||
|
||||
void AddEntityAnimationData(AZ::EntityId entityId);
|
||||
void ProcessEntityAnimationTrack(AZ::EntityId entityId, Export::CObject* pObj, AnimParamType entityTrackParamType);
|
||||
void AddEntityAnimationData(const CTrackViewTrack* pTrack, Export::CObject* pObj, AnimParamType entityTrackParamType);
|
||||
|
||||
void AddPosRotScale(Export::CObject* pObj, const CBaseObject* pBaseObj);
|
||||
void AddEntityData(Export::CObject* pObj, Export::AnimParamType dataType, const float fValue, const float fTime);
|
||||
|
||||
bool AddObjectsFromSequence(CTrackViewSequence* pSequence, XmlNodeRef seqNode = 0);
|
||||
bool IsDuplicateObjectBeingAdded(const QString& newObject);
|
||||
void SetFBXExportSettings(bool bLocalCoordsToSelectedObject, bool bExportOnlyPrimaryCamera, const float fps);
|
||||
bool ProcessObjectsForExport();
|
||||
|
||||
bool ShowFBXExportDialog();
|
||||
|
||||
void FillAnimTimeNode(XmlNodeRef writeNode, CTrackViewAnimNode* pObjectNode, CTrackViewSequence* currentSequence);
|
||||
QString CleanXMLText(const QString& text);
|
||||
|
||||
private:
|
||||
|
||||
TExporters m_exporters;
|
||||
Export::CData m_data;
|
||||
bool m_isPrecaching;
|
||||
bool m_isOccluder;
|
||||
float m_fScale;
|
||||
TObjectMap m_objectMap;
|
||||
bool m_bAnimationExport;
|
||||
|
||||
CBaseObject* m_pBaseObj;
|
||||
|
||||
float m_FBXBakedExportFPS;
|
||||
bool m_bExportLocalCoords;
|
||||
bool m_bExportOnlyPrimaryCamera;
|
||||
int m_numberOfExportFrames;
|
||||
CEntityObject* m_pivotEntityObject;
|
||||
bool m_bBakedKeysSequenceExport;
|
||||
|
||||
QString m_animTimeExportPrimarySequenceName;
|
||||
float m_animTimeExportPrimarySequenceCurrentTime;
|
||||
XmlNodeRef m_animTimeNode;
|
||||
|
||||
bool m_animKeyTimeExport;
|
||||
bool m_soundKeyTimeExport;
|
||||
};
|
||||
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_EXPORT_EXPORTMANAGER_H
|
||||
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "OBJExporter.h"
|
||||
|
||||
|
||||
const char* COBJExporter::GetExtension() const
|
||||
{
|
||||
return "obj";
|
||||
}
|
||||
|
||||
|
||||
const char* COBJExporter::GetShortDescription() const
|
||||
{
|
||||
return "Object files";
|
||||
}
|
||||
|
||||
|
||||
bool COBJExporter::ExportToFile(const char* filename, const Export::IData* pExportData)
|
||||
{
|
||||
CLogFile::FormatLine("Exporting OBJ file to '%s'", filename);
|
||||
|
||||
FILE* hFile = nullptr;
|
||||
azfopen(&hFile, filename, "w");
|
||||
if (!hFile)
|
||||
{
|
||||
CLogFile::FormatLine("Error while opening file '%s'!", filename);
|
||||
assert(hFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write header
|
||||
fprintf(hFile, "# Object file exported by Sandbox\n");
|
||||
fprintf(hFile, "# Attention: while import to 3DS Max Unify checkbox for normals must be unchecked.\n");
|
||||
fprintf(hFile, "#\n");
|
||||
|
||||
// Create MTL library filename
|
||||
QString materialFilename = filename;
|
||||
materialFilename = Path::ReplaceExtension(materialFilename, "mtl");
|
||||
materialFilename = Path::GetFile(materialFilename);
|
||||
|
||||
// Write material library import statement
|
||||
fprintf(hFile, "mtllib %s\n", materialFilename.toUtf8().data());
|
||||
fprintf(hFile, "#\n");
|
||||
|
||||
int numObjects = pExportData->GetObjectCount();
|
||||
for (int i = 0; i < numObjects; ++i)
|
||||
{
|
||||
const Export::Object* pObj = pExportData->GetObject(i);
|
||||
|
||||
Vec3 pos(pObj->pos.x, pObj->pos.y, pObj->pos.z);
|
||||
Quat rot(pObj->rot.w, pObj->rot.v.x, pObj->rot.v.y, pObj->rot.v.z);
|
||||
Vec3 scale(pObj->scale.x, pObj->scale.y, pObj->scale.z);
|
||||
|
||||
Matrix34 tm = Matrix33::CreateScale(scale) * Matrix34(rot);
|
||||
tm.SetTranslation(pos);
|
||||
|
||||
int nParent = pObj->nParent;
|
||||
while (nParent >= 0 && nParent < pExportData->GetObjectCount())
|
||||
{
|
||||
const Export::Object* pParentObj = pExportData->GetObject(nParent);
|
||||
assert(NULL != pParentObj);
|
||||
|
||||
Vec3 pos2(pParentObj->pos.x, pParentObj->pos.y, pParentObj->pos.z);
|
||||
Quat rot2(pParentObj->rot.w, pParentObj->rot.v.x, pParentObj->rot.v.y, pParentObj->rot.v.z);
|
||||
Vec3 scale2(pParentObj->scale.x, pParentObj->scale.y, pParentObj->scale.z);
|
||||
|
||||
Matrix34 parentTm = Matrix33::CreateScale(scale2) * Matrix34(rot2);
|
||||
parentTm.SetScale(scale2);
|
||||
parentTm.SetTranslation(pos2);
|
||||
|
||||
tm = tm * parentTm;
|
||||
nParent = pParentObj->nParent;
|
||||
}
|
||||
|
||||
fprintf(hFile, "g %s\n", pObj->name); //For XSI
|
||||
fprintf(hFile, "# object %s\n", pObj->name);
|
||||
fprintf(hFile, "#\n");
|
||||
|
||||
int numVertices = pObj->GetVertexCount();
|
||||
const Export::Vector3D* pVerts = pObj->GetVertexBuffer();
|
||||
|
||||
for (int ii = 0; ii < numVertices; ++ii)
|
||||
{
|
||||
const Export::Vector3D& vertex = pVerts[ii];
|
||||
|
||||
Vec3 vec(vertex.x, vertex.y, vertex.z);
|
||||
vec = tm.TransformPoint(vec);
|
||||
|
||||
fprintf(hFile, "v %s %s %s\n", TrimFloat(vec.x), TrimFloat(vec.y), TrimFloat(vec.z));
|
||||
}
|
||||
fprintf(hFile, "# %i vertices\n\n", numVertices);
|
||||
|
||||
// Write object texture coordinates
|
||||
int numTexCoords = pObj->GetTexCoordCount();
|
||||
const Export::UV* pTexCoord = pObj->GetTexCoordBuffer();
|
||||
for (int ii = 0; ii < numTexCoords; ++ii)
|
||||
{
|
||||
const Export::UV& textCoord = pTexCoord[ii];
|
||||
fprintf(hFile, "vt %s %s 0\n", TrimFloat(textCoord.u), TrimFloat(textCoord.v));
|
||||
}
|
||||
fprintf(hFile, "# %i texture vertices\n\n", numTexCoords);
|
||||
|
||||
// Write object normals
|
||||
int numNormals = pObj->GetNormalCount();
|
||||
const Export::Vector3D* pNormals = pObj->GetNormalBuffer();
|
||||
for (int ii = 0; ii < numNormals; ++ii)
|
||||
{
|
||||
const Export::Vector3D& normal = pNormals[ii];
|
||||
fprintf(hFile, "vn %s %s %s\n", TrimFloat(normal.x), TrimFloat(normal.y), TrimFloat(normal.z));
|
||||
}
|
||||
fprintf(hFile, "# %i vertex normals\n\n", numNormals);
|
||||
|
||||
|
||||
// Write submeshes
|
||||
int numMeshes = pObj->GetMeshCount();
|
||||
for (int j = 0; j < numMeshes; ++j)
|
||||
{
|
||||
const Export::Mesh* pMesh = pObj->GetMesh(j);
|
||||
if (pMesh->material.name[0] != '\0')
|
||||
{
|
||||
fprintf(hFile, "usemtl %s\n", pMesh->material.name);
|
||||
}
|
||||
|
||||
// TODO: if it's a smoth group fix it to bit difference
|
||||
fprintf(hFile, "s %d\n", j);
|
||||
|
||||
// Write all faces, convert the indices to one based indices
|
||||
int numFaces = pMesh->GetFaceCount();
|
||||
const Export::Face* pFaceBuf = pMesh->GetFaceBuffer();
|
||||
for (int ii = 0; ii < numFaces; ++ii)
|
||||
{
|
||||
const Export::Face& face = pFaceBuf[ii];
|
||||
fprintf(hFile, "f %i/%i/%i %i/%i/%i %i/%i/%i\n",
|
||||
face.idx[0] - numVertices, face.idx[0] - numTexCoords, face.idx[0] - numNormals,
|
||||
face.idx[1] - numVertices, face.idx[1] - numTexCoords, face.idx[1] - numNormals,
|
||||
face.idx[2] - numVertices, face.idx[2] - numTexCoords, face.idx[2] - numNormals);
|
||||
}
|
||||
fprintf(hFile, "# %i faces\n\n", numFaces);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(hFile, "g\n");
|
||||
fclose(hFile);
|
||||
|
||||
|
||||
// Export Material
|
||||
materialFilename = Path::ReplaceExtension(filename, "mtl");
|
||||
|
||||
// Open the material file
|
||||
hFile = nullptr;
|
||||
azfopen(&hFile, materialFilename.toUtf8().data(), "w");
|
||||
if (!hFile)
|
||||
{
|
||||
CLogFile::FormatLine("Error while opening file '%s'!", materialFilename.toUtf8().data());
|
||||
assert(hFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write header
|
||||
fprintf(hFile, "# Material file exported by Sandbox\n\n");
|
||||
|
||||
for (int i = 0; i < numObjects; ++i)
|
||||
{
|
||||
const Export::Object* pObj = pExportData->GetObject(i);
|
||||
|
||||
int numMeshes = pObj->GetMeshCount();
|
||||
for (int j = 0; j < numMeshes; j++)
|
||||
{
|
||||
const Export::Mesh* pMesh = pObj->GetMesh(j);
|
||||
if (pMesh->material.name[0] != '\0')
|
||||
{
|
||||
// Write material
|
||||
const Export::Material& mtl = pMesh->material;
|
||||
fprintf(hFile, "newmtl %s\n", mtl.name);
|
||||
fprintf(hFile, "Ka %s %s %s\n", TrimFloat(mtl.diffuse.r), TrimFloat(mtl.diffuse.g), TrimFloat(mtl.diffuse.b));
|
||||
fprintf(hFile, "Kd %s %s %s\n", TrimFloat(mtl.diffuse.r), TrimFloat(mtl.diffuse.g), TrimFloat(mtl.diffuse.b));
|
||||
fprintf(hFile, "Ks %s %s %s\n", TrimFloat(mtl.specular.r), TrimFloat(mtl.specular.g), TrimFloat(mtl.specular.b));
|
||||
fprintf(hFile, "d %s\n", TrimFloat(1.0f - mtl.opacity));
|
||||
fprintf(hFile, "Tr %s\n", TrimFloat(1.0f - mtl.opacity));
|
||||
fprintf(hFile, "Ns %s\n", TrimFloat(mtl.smoothness));
|
||||
if (strlen(mtl.mapDiffuse))
|
||||
{
|
||||
fprintf(hFile, "map_Kd %s\n", MakeRelativePath(filename, mtl.mapDiffuse).toUtf8().constData());
|
||||
}
|
||||
if (strlen(mtl.mapSpecular))
|
||||
{
|
||||
fprintf(hFile, "map_Ns %s\n", MakeRelativePath(filename, mtl.mapSpecular).toUtf8().constData());
|
||||
}
|
||||
if (strlen(mtl.mapOpacity))
|
||||
{
|
||||
fprintf(hFile, "map_d %s\n", MakeRelativePath(filename, mtl.mapOpacity).toUtf8().constData());
|
||||
}
|
||||
if (strlen(mtl.mapNormals))
|
||||
{
|
||||
fprintf(hFile, "bump %s\n", MakeRelativePath(filename, mtl.mapNormals).toUtf8().constData());
|
||||
}
|
||||
if (strlen(mtl.mapDecal))
|
||||
{
|
||||
fprintf(hFile, "decal %s\n", MakeRelativePath(filename, mtl.mapDecal).toUtf8().constData());
|
||||
}
|
||||
if (strlen(mtl.mapDisplacement))
|
||||
{
|
||||
fprintf(hFile, "disp %s\n", MakeRelativePath(filename, mtl.mapDisplacement).toUtf8().constData());
|
||||
}
|
||||
fprintf(hFile, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(hFile);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
QString COBJExporter::MakeRelativePath(const char* pMainFileName, const char* pFileName) const
|
||||
{
|
||||
const char* ch = strrchr(pMainFileName, '\\');
|
||||
if (ch)
|
||||
{
|
||||
if (strlen(pFileName) > ch - pMainFileName && !_strnicmp(pMainFileName, pFileName, ch - pMainFileName))
|
||||
{
|
||||
return QString(pFileName + (ch - pMainFileName) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return QString(pFileName);
|
||||
}
|
||||
|
||||
|
||||
const char* COBJExporter::TrimFloat(float fValue) const
|
||||
{
|
||||
// Convert a float into a string representation and remove all
|
||||
// uneccessary zeroes and the decimal dot if it is not needed
|
||||
const int nMaxAccessInTime = 4;
|
||||
|
||||
static char ppBufs[nMaxAccessInTime][16];
|
||||
static int nCurBuf = 0;
|
||||
|
||||
if (nCurBuf >= nMaxAccessInTime)
|
||||
{
|
||||
nCurBuf = 0;
|
||||
}
|
||||
|
||||
char* pBuf = ppBufs[nCurBuf];
|
||||
size_t bufSize = sizeof(ppBufs[nCurBuf]);
|
||||
++nCurBuf;
|
||||
sprintf_s(pBuf, bufSize, "%f", fValue);
|
||||
|
||||
for (int i = strlen(pBuf) - 1; i > 0; --i)
|
||||
{
|
||||
if (pBuf[i] == '0')
|
||||
{
|
||||
pBuf[i] = 0;
|
||||
}
|
||||
else if (pBuf[i] == '.')
|
||||
{
|
||||
pBuf[i] = 0;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return pBuf;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void COBJExporter::Release()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
// Description : Export geometry OBJ file format
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_EXPORT_OBJEXPORTER_H
|
||||
#define CRYINCLUDE_EDITOR_EXPORT_OBJEXPORTER_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <IExportManager.h>
|
||||
|
||||
|
||||
class COBJExporter
|
||||
: public IExporter
|
||||
{
|
||||
public:
|
||||
virtual const char* GetExtension() const;
|
||||
virtual const char* GetShortDescription() const;
|
||||
virtual bool ExportToFile(const char* filename, const Export::IData* pExportData);
|
||||
virtual bool ImportFromFile([[maybe_unused]] const char* filename, [[maybe_unused]] Export::IData* pData){return false; };
|
||||
virtual void Release();
|
||||
|
||||
private:
|
||||
const char* TrimFloat(float fValue) const;
|
||||
QString MakeRelativePath(const char* pMainFileName, const char* pFileName) const;
|
||||
};
|
||||
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_EXPORT_OBJEXPORTER_H
|
||||
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "OCMExporter.h"
|
||||
|
||||
|
||||
class CFileEndianWriter
|
||||
{
|
||||
std::vector<uint8> m_Data;
|
||||
size_t m_Offset;
|
||||
public:
|
||||
CFileEndianWriter()
|
||||
: m_Offset(0){}
|
||||
void Seek(size_t Offset){m_Offset = Offset; }
|
||||
void Write(const void* pData, size_t Size)
|
||||
{
|
||||
if (m_Offset + Size > m_Data.size())
|
||||
{
|
||||
m_Data.resize(m_Offset + Size);
|
||||
}
|
||||
memcpy(&m_Data[m_Offset], pData, Size);
|
||||
m_Offset += Size;
|
||||
}
|
||||
size_t Pos() const{return m_Offset; }
|
||||
template<size_t Padding>
|
||||
void Align(){m_Offset = (m_Offset + (Padding - 1)) & ~(Padding - 1); }
|
||||
template<class T>
|
||||
void Write(T D){Write(&D, sizeof(T)); }
|
||||
|
||||
|
||||
const std::vector<uint8>& Data() const{return m_Data; }
|
||||
};
|
||||
|
||||
const char* COCMExporter::GetExtension() const
|
||||
{
|
||||
return "ocm";
|
||||
}
|
||||
|
||||
const char* COCMExporter::GetShortDescription() const
|
||||
{
|
||||
return "occlusion culler mesh";
|
||||
}
|
||||
|
||||
Matrix44 MatRotate(f32 a, f32 b, f32 g)
|
||||
{
|
||||
const f32 CosR = cosf(a);
|
||||
const f32 SinR = sinf(a);
|
||||
const f32 CosP = cosf(b);
|
||||
const f32 SinP = sinf(b);
|
||||
const f32 CosY = cosf(g);
|
||||
const f32 SinY = sinf(g);
|
||||
const f32 SRSP = SinR * SinP;
|
||||
const f32 CRSP = CosR * SinP;
|
||||
|
||||
Matrix44 Mat;
|
||||
Mat.m00 = CosP * CosY;
|
||||
Mat.m01 = CosP * SinY;
|
||||
Mat.m02 = -SinP;
|
||||
Mat.m03 = 0.f;
|
||||
Mat.m10 = SRSP * CosY - CosR * SinY;
|
||||
Mat.m11 = SRSP * SinY + CosR * CosY;
|
||||
Mat.m12 = SinR * CosP;
|
||||
Mat.m13 = 0.f;
|
||||
Mat.m20 = CRSP * CosY + SinR * SinY;
|
||||
Mat.m21 = CRSP * SinY - SinR * CosY;
|
||||
Mat.m22 = CosR * CosP;
|
||||
Mat.m23 = 0.f;
|
||||
Mat.m30 = 0.f;
|
||||
Mat.m31 = 0.f;
|
||||
Mat.m32 = 0.f;
|
||||
Mat.m33 = 1.f;
|
||||
return Mat;
|
||||
};
|
||||
|
||||
void COCMExporter::Extends(const Matrix44& rTransform, const Export::Object* pMesh, f32& rMinX, f32& rMaxX, f32& rMinY, f32& rMaxY, f32& rMinZ, f32& rMaxZ) const
|
||||
{
|
||||
rMinX = rMinY = rMinZ = FLT_MAX;
|
||||
rMaxX = rMaxY = rMaxZ = -FLT_MAX;
|
||||
const uint32 TriCount = pMesh->GetVertexCount();
|
||||
const Export::Vector3D* pVerts = pMesh->GetVertexBuffer();
|
||||
for (size_t a = 0; a < TriCount; a++)
|
||||
{
|
||||
const Export::Vector3D& rV = pVerts[a];
|
||||
const Vec3 VO(rV.x, rV.y, rV.z);
|
||||
const Vec3 V = rTransform.TransformPoint(VO);
|
||||
rMinX = std::min(rMinX, V.x);
|
||||
rMinY = std::min(rMinY, V.y);
|
||||
rMinZ = std::min(rMinZ, V.z);
|
||||
rMaxX = std::max(rMaxX, V.x);
|
||||
rMaxY = std::max(rMaxY, V.y);
|
||||
rMaxZ = std::max(rMaxZ, V.z);
|
||||
}
|
||||
}
|
||||
|
||||
Matrix44 COCMExporter::CalcOBB(const Export::Object* pMesh)
|
||||
{
|
||||
Matrix44 OBBMat(IDENTITY);
|
||||
f32 MinX, MaxX, MinY, MaxY, MinZ, MaxZ;
|
||||
Extends(OBBMat, pMesh, MinX, MaxX, MinY, MaxY, MinZ, MaxZ);
|
||||
|
||||
OBBMat.m03 = -(MaxX + MinX) * 0.5f;
|
||||
OBBMat.m13 = -(MaxY + MinY) * 0.5f;
|
||||
OBBMat.m23 = -(MaxZ + MinZ) * 0.5f;
|
||||
|
||||
return OBBMat;
|
||||
}
|
||||
|
||||
size_t COCMExporter::SaveMesh(CFileEndianWriter& rWriter, const Export::Object* pMesh, Matrix44& rOBBMat)
|
||||
{
|
||||
const size_t PosStart = rWriter.Pos();
|
||||
rOBBMat = CalcOBB(pMesh);
|
||||
const Export::Vector3D* pVerts = pMesh->GetVertexBuffer();
|
||||
std::vector<float> Pos;
|
||||
const uint32 SubMeshCount = pMesh->GetMeshCount();
|
||||
for (uint32 b = 0; b < SubMeshCount; b++)
|
||||
{
|
||||
const Export::Mesh* pSubMesh = pMesh->GetMesh(b);
|
||||
const uint32 FaceCount = pSubMesh->GetFaceCount();
|
||||
const Export::Face* pFaces = pSubMesh->GetFaceBuffer();
|
||||
Pos.reserve(Pos.size() + FaceCount * 9);
|
||||
for (size_t a = 0; a < FaceCount; a++)
|
||||
{
|
||||
const Export::Vector3D& rV0 = pVerts[pFaces[a].idx[0]];
|
||||
const Export::Vector3D& rV1 = pVerts[pFaces[a].idx[1]];
|
||||
const Export::Vector3D& rV2 = pVerts[pFaces[a].idx[2]];
|
||||
const Vec3 VO0(rV0.x, rV0.y, rV0.z);
|
||||
const Vec3 VO1(rV1.x, rV1.y, rV1.z);
|
||||
const Vec3 VO2(rV2.x, rV2.y, rV2.z);
|
||||
const Vec3 V0 = rOBBMat.TransformPoint(VO0);
|
||||
const Vec3 V1 = rOBBMat.TransformPoint(VO1);
|
||||
const Vec3 V2 = rOBBMat.TransformPoint(VO2);
|
||||
const Vec3 N = (V2 - V0).cross(V1 - V0);
|
||||
if (fabsf(N.dot(N)) <= FLT_EPSILON)//degenerated?
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Pos.push_back(V0.x);
|
||||
Pos.push_back(V0.y);
|
||||
Pos.push_back(V0.z);
|
||||
Pos.push_back(1.f);
|
||||
Pos.push_back(V1.x);
|
||||
Pos.push_back(V1.y);
|
||||
Pos.push_back(V1.z);
|
||||
Pos.push_back(1.f);
|
||||
Pos.push_back(V2.x);
|
||||
Pos.push_back(V2.y);
|
||||
Pos.push_back(V2.z);
|
||||
Pos.push_back(1.f);
|
||||
}
|
||||
}
|
||||
const uint32 TriCount = static_cast<uint16>(std::min<size_t>(65535, Pos.size() / 4));//vertex count at 4float/vertex
|
||||
rWriter.Write(TriCount);
|
||||
rWriter.Align<16>();
|
||||
rWriter.Write(&Pos[0], 4 * TriCount * sizeof(float));
|
||||
rWriter.Align<4>();
|
||||
const size_t PosEnd = rWriter.Pos();
|
||||
return PosEnd - PosStart;//sizeof(TriCount)+sizeof(Pos[0])*Pos.size();
|
||||
}
|
||||
|
||||
void COCMExporter::SaveInstance(CFileEndianWriter& rWriter, const Export::Object* pInstance, const SOCMeshInfo& rMeshInfo)
|
||||
{
|
||||
Vec3 pos(pInstance->pos.x, pInstance->pos.y, pInstance->pos.z);
|
||||
Quat rot(pInstance->rot.w, pInstance->rot.v.x, pInstance->rot.v.y, pInstance->rot.v.z);
|
||||
Vec3 scale(pInstance->scale.x, pInstance->scale.y, pInstance->scale.z);
|
||||
|
||||
Matrix44 tm = Matrix33::CreateScale(scale) * Matrix34(rot);
|
||||
tm.SetTranslation(pos);
|
||||
|
||||
tm = tm * rMeshInfo.m_OBBMat.GetInverted();
|
||||
|
||||
//const uint32 MeshID = pInstance->MeshToUse()->ID();
|
||||
rWriter.Write(rMeshInfo.m_Offset);
|
||||
for (size_t a = 0; a < 12; a++)//just savin the 3x4 matrix
|
||||
{
|
||||
rWriter.Write(*(reinterpret_cast<float*>(&tm) + a));
|
||||
}
|
||||
}
|
||||
|
||||
bool COCMExporter::ExportToFile(const char* filename, const Export::IData* pExportData)
|
||||
{
|
||||
CLogFile::FormatLine("Exporting OCM file to '%s'", filename);
|
||||
|
||||
FILE* pFile = nullptr;
|
||||
azfopen(&pFile, filename, "wb");
|
||||
if (!pFile)
|
||||
{
|
||||
CLogFile::FormatLine("Error while opening file '%s'!", filename);
|
||||
assert(pFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
CFileEndianWriter Writer;
|
||||
// Write header
|
||||
const uint32 Version = ~(4u << 24);
|
||||
const uint32 MeshCount = pExportData->GetObjectCount();
|
||||
const uint32 InstCount = pExportData->GetObjectCount();
|
||||
uint32 OffsetInstances = 0;
|
||||
Writer.Write(Version);
|
||||
Writer.Write(MeshCount);
|
||||
Writer.Write(InstCount);
|
||||
Writer.Write(OffsetInstances);//keep header end aligned to 16byte
|
||||
|
||||
tdMeshOffset MeshOffsets;
|
||||
MeshOffsets.reserve(MeshCount);
|
||||
size_t Offset = 16;
|
||||
//std::map<void*,size_t> MeshO
|
||||
for (size_t a = 0; a < MeshCount; a++)
|
||||
{
|
||||
SOCMeshInfo MeshInfo;
|
||||
MeshInfo.m_MeshHash = pExportData->GetObject(a)->MeshHash();
|
||||
const tdMeshOffset::iterator it = std::find(MeshOffsets.begin(), MeshOffsets.end(), MeshInfo);
|
||||
if (it != MeshOffsets.end())
|
||||
{
|
||||
MeshInfo = *it;
|
||||
}
|
||||
else
|
||||
{
|
||||
MeshInfo.m_Offset = Offset;
|
||||
Offset += SaveMesh(Writer, pExportData->GetObject(a), MeshInfo.m_OBBMat);
|
||||
}
|
||||
MeshOffsets.push_back(MeshInfo);
|
||||
}
|
||||
OffsetInstances = Offset;
|
||||
for (size_t a = 0; a < InstCount; a++)
|
||||
{
|
||||
SaveInstance(Writer, pExportData->GetObject(a), MeshOffsets[a]);
|
||||
}
|
||||
Writer.Seek(4);
|
||||
Writer.Write(static_cast<uint32>(MeshOffsets.size()));
|
||||
Writer.Seek(12);
|
||||
Writer.Write(OffsetInstances);
|
||||
|
||||
fwrite(&Writer.Data()[0], 1, Writer.Data().size(), pFile);
|
||||
|
||||
fclose(pFile);
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* COCMExporter::TrimFloat(float fValue) const
|
||||
{
|
||||
// Convert a float into a string representation and remove all
|
||||
// unnecessary zeros and the decimal dot if it is not needed
|
||||
const int nMaxAccessInTime = 4;
|
||||
|
||||
static char ppBufs[nMaxAccessInTime][16];
|
||||
static int nCurBuf = 0;
|
||||
|
||||
if (nCurBuf >= nMaxAccessInTime)
|
||||
{
|
||||
nCurBuf = 0;
|
||||
}
|
||||
|
||||
char* pBuf = ppBufs[nCurBuf];
|
||||
size_t bufSize = sizeof(ppBufs[nCurBuf]);
|
||||
++nCurBuf;
|
||||
sprintf_s(pBuf, bufSize, "%f", fValue);
|
||||
|
||||
for (int i = strlen(pBuf) - 1; i > 0; --i)
|
||||
{
|
||||
if (pBuf[i] == '0')
|
||||
{
|
||||
pBuf[i] = 0;
|
||||
}
|
||||
else if (pBuf[i] == '.')
|
||||
{
|
||||
pBuf[i] = 0;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return pBuf;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void COCMExporter::Release()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
// Description : Export geometry OCM file format
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_EXPORT_OCMEXPORTER_H
|
||||
#define CRYINCLUDE_EDITOR_EXPORT_OCMEXPORTER_H
|
||||
#pragma once
|
||||
|
||||
#include <IExportManager.h>
|
||||
|
||||
class CFileEndianWriter;
|
||||
|
||||
struct SOCMeshInfo
|
||||
{
|
||||
Matrix44 m_OBBMat;
|
||||
uint32 m_Offset;
|
||||
size_t m_MeshHash;
|
||||
bool operator==(const SOCMeshInfo& rOther) const{return m_MeshHash == rOther.m_MeshHash; }
|
||||
};
|
||||
typedef std::vector<SOCMeshInfo> tdMeshOffset;
|
||||
|
||||
class COCMExporter
|
||||
: public IExporter
|
||||
{
|
||||
public:
|
||||
virtual const char* GetExtension() const;
|
||||
virtual const char* GetShortDescription() const;
|
||||
virtual bool ExportToFile(const char* filename, const Export::IData* pExportData);
|
||||
virtual bool ImportFromFile([[maybe_unused]] const char* filename, [[maybe_unused]] Export::IData* pData){return false; };
|
||||
virtual void Release();
|
||||
|
||||
private:
|
||||
const char* TrimFloat(float fValue) const;
|
||||
void SaveInstance(CFileEndianWriter& rWriter, const Export::Object* pInstance, const SOCMeshInfo& rMeshInfo);
|
||||
size_t SaveMesh(CFileEndianWriter& rWriter, const Export::Object* pMesh, Matrix44& rOBBMat);
|
||||
|
||||
void Extends(const Matrix44& rTransform, const Export::Object* pMesh, f32& rMinX, f32& rMaxX, f32& rMinY, f32& rMaxY, f32& rMinZ, f32& rMaxZ) const;
|
||||
Matrix44 CalcOBB(const Export::Object* pMesh);
|
||||
};
|
||||
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_EXPORT_OCMEXPORTER_H
|
||||
Reference in New Issue
Block a user