/* * 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 "StdAfx.h" #include "OCMExporter.h" class CFileEndianWriter { std::vector 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 void Align(){m_Offset = (m_Offset + (Padding - 1)) & ~(Padding - 1); } template void Write(T D){Write(&D, sizeof(T)); } const std::vector& 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 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(std::min(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(&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 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(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; }