You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
291 lines
8.8 KiB
C++
291 lines
8.8 KiB
C++
/*
|
|
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
*
|
|
* 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;
|
|
}
|