aboutsummaryrefslogtreecommitdiff
path: root/sdk/extensions/import/source/NvBlastExtApexImportTool.cpp
diff options
context:
space:
mode:
authorBryan Galdrikian <[email protected]>2018-05-31 11:36:08 -0700
committerBryan Galdrikian <[email protected]>2018-05-31 11:36:08 -0700
commit7115f60b91b5717d90f643fd692010905c7004db (patch)
treeeffd68c6978751c517d54c2f2bb5bb6e7dc93e18 /sdk/extensions/import/source/NvBlastExtApexImportTool.cpp
parentUpdating BlastTool zip (diff)
downloadblast-1.1.3_rc1.tar.xz
blast-1.1.3_rc1.zip
Blast 1.1.3. See docs/release_notes.txt.v1.1.3_rc1
Diffstat (limited to 'sdk/extensions/import/source/NvBlastExtApexImportTool.cpp')
-rwxr-xr-x[-rw-r--r--]sdk/extensions/import/source/NvBlastExtApexImportTool.cpp1888
1 files changed, 944 insertions, 944 deletions
diff --git a/sdk/extensions/import/source/NvBlastExtApexImportTool.cpp b/sdk/extensions/import/source/NvBlastExtApexImportTool.cpp
index ad3acaf..fad9ade 100644..100755
--- a/sdk/extensions/import/source/NvBlastExtApexImportTool.cpp
+++ b/sdk/extensions/import/source/NvBlastExtApexImportTool.cpp
@@ -1,944 +1,944 @@
-// This code contains NVIDIA Confidential Information and is disclosed to you
-// under a form of NVIDIA software license agreement provided separately to you.
-//
-// Notice
-// NVIDIA Corporation and its licensors retain all intellectual property and
-// proprietary rights in and to this software and related documentation and
-// any modifications thereto. Any use, reproduction, disclosure, or
-// distribution of this software and related documentation without an express
-// license agreement from NVIDIA Corporation is strictly prohibited.
-//
-// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
-// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
-// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
-// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
-//
-// Information and code furnished is believed to be accurate and reliable.
-// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
-// information or for any infringement of patents or other rights of third parties that may
-// result from its use. No license is granted by implication or otherwise under any patent
-// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
-// This code supersedes and replaces all information previously supplied.
-// NVIDIA Corporation products are not authorized for use as critical
-// components in life support devices or systems without express written approval of
-// NVIDIA Corporation.
-//
-// Copyright (c) 2016-2018 NVIDIA Corporation. All rights reserved.
-
-
-#include "NvBlastExtApexImportTool.h"
-
-#if NV_VC
-#pragma warning(push)
-#pragma warning(disable: 4996) // 'fopen' unsafe warning, from NxFileBuffer.h
-#endif
-
-#include "PxFoundation.h"
-
-#include "NvBlastIndexFns.h"
-#include "NvBlastGlobals.h"
-#include <NvBlastExtExporter.h>
-#include <PxConvexMesh.h>
-#include "PxPhysics.h"
-#include "NvBlastExtAuthoringCollisionBuilder.h"
-#include "NvBlastExtPxAsset.h"
-#include "NvBlastExtAuthoring.h"
-#include "NvBlastExtAuthoringBondGenerator.h"
-#include <nvparameterized\NvParameterized.h>
-#include <nvparameterized\NvParamUtils.h>
-#include <DestructibleAssetParameters.h>
-#include <RenderMeshAssetParameters.h>
-#include <VertexBufferParameters.h>
-#include <VertexFormatParameters.h>
-#include <SubmeshParameters.h>
-#include <CachedOverlaps.h>
-#include "PsFastXml.h"
-#include "PsFileBuffer.h"
-#include <BufferF32x3.h>
-#include <BufferF32x2.h>
-#include <algorithm>
-#include <sstream>
-#include <memory>
-#include <map>
-
-
-#include <NvDefaultTraits.h>
-#include <NvSerializerInternal.h>
-#include <PsMutex.h>
-#include <ModuleDestructibleRegistration.h>
-#include <ModuleDestructibleLegacyRegistration.h>
-#include <ModuleCommonRegistration.h>
-#include <ModuleCommonLegacyRegistration.h>
-#include <ModuleFrameworkRegistration.h>
-#include <ModuleFrameworkLegacyRegistration.h>
-#include <PxPhysicsAPI.h>
-
-#include "NvBlastPxCallbacks.h"
-
-using namespace nvidia;
-using namespace physx;
-using namespace apex;
-
-using nvidia::destructible::DestructibleAssetParameters;
-
-namespace Nv
-{
-namespace Blast
-{
-
-namespace ApexImporter
-{
- /**
- Should be consistent with IntPair in APEX
- */
- struct IntPair
- {
- void set(int32_t _i0, int32_t _i1)
- {
- i0 = _i0;
- i1 = _i1;
- }
-
- int32_t i0, i1;
-
- static int compare(const void* a, const void* b)
- {
- const int32_t diff0 = ((IntPair*)a)->i0 - ((IntPair*)b)->i0;
- return diff0 ? diff0 : (((IntPair*)a)->i1 - ((IntPair*)b)->i1);
- }
- };
-
-bool ApexImportTool::loadAssetFromFile(physx::PxFileBuf* stream, NvParameterized::Serializer::DeserializedData& data)
-{
- if (stream && stream->isOpen())
- {
- NvParameterized::Serializer::SerializeType serType = NvParameterized::Serializer::peekSerializeType(*stream);
- NvParameterized::Serializer::ErrorType serError;
-
- NvParameterized::Traits* traits = new NvParameterized::DefaultTraits(NvParameterized::DefaultTraits::BehaviourFlags::DEFAULT_POLICY);
-
- nvidia::destructible::ModuleDestructibleRegistration::invokeRegistration(traits);
- ModuleDestructibleLegacyRegistration::invokeRegistration(traits);
- ModuleCommonRegistration::invokeRegistration(traits);
- ModuleCommonLegacyRegistration::invokeRegistration(traits);
- ModuleFrameworkLegacyRegistration::invokeRegistration(traits);
- ModuleFrameworkRegistration::invokeRegistration(traits);
- NvParameterized::Serializer* ser = NvParameterized::internalCreateSerializer(serType, traits);
-
- PX_ASSERT(ser);
-
- serError = ser->deserialize(*stream, data);
-
- if (serError == NvParameterized::Serializer::ERROR_NONE && data.size() == 1)
- {
- NvParameterized::Interface* params = data[0];
- if (!physx::shdfnd::strcmp(params->className(), "DestructibleAssetParameters"))
- {
- return true;
- }
- else
- {
- NVBLAST_LOG_ERROR("Error: deserialized data is not an APEX Destructible\n");
- }
- }
- else
- {
- NVBLAST_LOG_ERROR("Error: failed to deserialize\n");
- }
- ser->release();
- }
- return false;
-}
-
-bool ApexImportTool::isValid()
-{
- return m_Foundation && m_PhysxSDK && m_Cooking;
-}
-
-enum ChunkFlags
-{
- SupportChunk = (1 << 0),
- UnfracturableChunk = (1 << 1),
- DescendantUnfractureable = (1 << 2),
- UndamageableChunk = (1 << 3),
- UncrumbleableChunk = (1 << 4),
- RuntimeFracturableChunk = (1 << 5),
- Instanced = (1 << 8),
-};
-
-uint32_t getPartIndex(const DestructibleAssetParameters* prm, uint32_t id)
-{
- auto& sch = prm->chunks.buf[id];
-
- return (sch.flags & ChunkFlags::Instanced) == 0 ? sch.meshPartIndex : prm->chunkInstanceInfo.buf[sch.meshPartIndex].partIndex;
-}
-
-ApexImportTool::ApexImportTool()
-{
- m_Foundation = PxCreateFoundation(PX_FOUNDATION_VERSION, NvBlastGetPxAllocatorCallback(), NvBlastGetPxErrorCallback());
- if (!m_Foundation)
- {
- NVBLAST_LOG_ERROR("Error: failed to create Foundation\n");
- return;
- }
- physx::PxTolerancesScale scale;
- m_PhysxSDK = PxCreatePhysics(PX_PHYSICS_VERSION, *m_Foundation, scale, true);
- if (!m_PhysxSDK)
- {
- NVBLAST_LOG_ERROR("Error: failed to create PhysX\n");
-
- return;
- }
-
- physx::PxCookingParams cookingParams(scale);
- cookingParams.buildGPUData = true;
- m_Cooking = PxCreateCooking(PX_PHYSICS_VERSION, m_PhysxSDK->getFoundation(), cookingParams);
- if (!m_Cooking)
- {
- NVBLAST_LOG_ERROR("Error: failed to create PhysX Cooking\n");
- return;
- }
-
-
-}
-
-
-bool ApexImportTool::getCollisionGeometry(const NvParameterized::Interface* assetPrm, uint32_t chunkCount, std::vector<uint32_t>& chunkReorderInvMap,
- const std::vector<uint32_t>& apexChunkFlags, std::vector<ExtPxAssetDesc::ChunkDesc>& physicsChunks,
- std::vector<ExtPxAssetDesc::SubchunkDesc>& physicsSubchunks, std::vector<std::vector<CollisionHull*> >& hullsDesc)
-{
- physicsChunks.clear();
- physicsChunks.resize(chunkCount);
- // prepare physics asset desc (convexes, transforms)
- std::shared_ptr<ConvexMeshBuilder> collisionBuilder(
- NvBlastExtAuthoringCreateConvexMeshBuilder(m_Cooking, &m_PhysxSDK->getPhysicsInsertionCallback()),
- [](ConvexMeshBuilder* cmb) { cmb->release(); });
-
- const DestructibleAssetParameters* params = static_cast<const DestructibleAssetParameters*>(assetPrm);
-
- int32_t apexHullCount = 0;
- const uint32_t apexChunkCount = params->chunks.arraySizes[0];
-
- for (uint32_t chunkIndex = 0; chunkIndex < chunkCount; ++chunkIndex)
- {
- uint32_t apexChunkIndex = chunkReorderInvMap[chunkIndex];
- if (apexChunkIndex < apexChunkCount)
- {
- uint32_t partIndex = getPartIndex(params, apexChunkIndex);
- uint32_t partConvexHullCount = params->chunkConvexHullStartIndices.buf[partIndex + 1] - params->chunkConvexHullStartIndices.buf[partIndex];
- apexHullCount += partConvexHullCount;
- }
- }
- physicsSubchunks.reserve(chunkCount);
- {
- hullsDesc.clear();
- hullsDesc.resize(chunkCount);
- for (uint32_t chunkIndex = 0; chunkIndex < chunkCount; ++chunkIndex)
- {
- uint32_t apexChunkIndex = chunkReorderInvMap[chunkIndex];
- if (apexChunkIndex < apexChunkCount)
- {
- uint32_t partIndex = getPartIndex(params, apexChunkIndex);
- uint32_t partConvexHullCount = params->chunkConvexHullStartIndices.buf[partIndex + 1] - params->chunkConvexHullStartIndices.buf[partIndex];
- NvParameterized::Interface** cxInterfaceArray = params->chunkConvexHulls.buf + params->chunkConvexHullStartIndices.buf[partIndex];
- physicsChunks[chunkIndex].subchunkCount = partConvexHullCount;
- for (uint32_t hull = 0; hull < partConvexHullCount; ++hull)
- {
- NvParameterized::Handle paramHandle(cxInterfaceArray[hull]);
- int32_t verticesCount = 0;
- paramHandle.getParameter("vertices");
- paramHandle.getArraySize(verticesCount);
- std::vector<PxVec3> vertexData(verticesCount);
- paramHandle.getParamVec3Array(vertexData.data(), verticesCount);
- hullsDesc[chunkIndex].push_back(nullptr);
- hullsDesc[chunkIndex].back() = collisionBuilder.get()->buildCollisionGeometry(verticesCount, vertexData.data());
- PxConvexMesh* convexMesh = collisionBuilder.get()->buildConvexMesh(verticesCount, vertexData.data());
-
- const ExtPxAssetDesc::SubchunkDesc subchunk =
- {
- PxTransform(PxIdentity),
- PxConvexMeshGeometry(convexMesh)
- };
- physicsSubchunks.push_back(subchunk);
- }
- physicsChunks[chunkIndex].subchunks = partConvexHullCount ? (&physicsSubchunks.back() + 1 - partConvexHullCount) : nullptr;
-
- // static flag set
- physicsChunks[chunkIndex].isStatic = (apexChunkFlags[apexChunkIndex] & (1 << 1)) != 0;
- }
- else
- {
- NVBLAST_LOG_ERROR("Error: chunk index is invalid.");
- }
- }
- }
-
- // check that vector didn't grow
- if (static_cast<int32_t>(physicsSubchunks.size()) > apexHullCount)
- {
- NVBLAST_LOG_ERROR("Error: sub chunk count seems to be wrong.");
- return false;
- }
- return true;
-}
-
-PxBounds3 gatherChunkTriangles(std::vector<uint32_t>& chunkToPartMp, const nvidia::apex::RenderMeshAssetParameters* rmAsset, std::vector<uint32_t>& chunkTrianglesOffsets, std::vector<Nv::Blast::Triangle>& chunkTriangles, int32_t posBufferIndex, float scale, PxVec3 offset )
-{
-
- PxBounds3 bnd;
- bnd.setEmpty();
- chunkTrianglesOffsets.clear();
- uint32_t chunkCount = chunkToPartMp.size();
- chunkTrianglesOffsets.resize(chunkCount + 1);
- chunkTrianglesOffsets[0] = 0;
- for (uint32_t chunkIndex = 0; chunkIndex < chunkCount; ++chunkIndex)
- {
- uint32_t part = chunkToPartMp[chunkIndex];
- uint32_t submeshCount = rmAsset->submeshes.arraySizes[0];
- for (uint32_t submeshIndex = 0; submeshIndex < submeshCount; ++submeshIndex)
- {
- nvidia::apex::SubmeshParameters* submeshPrm = static_cast<nvidia::apex::SubmeshParameters*>(rmAsset->submeshes.buf[submeshIndex]);
-
- const uint32_t* indexArray = submeshPrm->indexBuffer.buf + submeshPrm->indexPartition.buf[part];
- uint32_t indexCount = submeshPrm->indexPartition.buf[part + 1] - submeshPrm->indexPartition.buf[part];
-
- nvidia::apex::VertexBufferParameters* vbuf = static_cast<nvidia::apex::VertexBufferParameters*>(submeshPrm->vertexBuffer);
-
- nvidia::apex::BufferF32x3* pbuf = static_cast<nvidia::apex::BufferF32x3*>(vbuf->buffers.buf[posBufferIndex]);
-
- const PxVec3* positions = reinterpret_cast<const PxVec3*>(pbuf->data.buf);
-
- for (uint32_t i = 0; i < indexCount; i += 3)
- {
- Vertex a;
- Vertex b;
- Vertex c;
- bnd.include(positions[indexArray[i]]);
- bnd.include(positions[indexArray[i + 1]]);
- bnd.include(positions[indexArray[i + 2]]);
-
- a.p = positions[indexArray[i]] - offset;
- b.p = positions[indexArray[i + 1]] - offset;
- c.p = positions[indexArray[i + 2]] - offset;
- a.p *= scale;
- b.p *= scale;
- c.p *= scale;
- chunkTriangles.push_back(Nv::Blast::Triangle(a, b, c));
- }
- }
- chunkTrianglesOffsets[chunkIndex + 1] = chunkTriangles.size();
- }
- return bnd;
-}
-
-bool ApexImportTool::importApexAsset(std::vector<uint32_t>& chunkReorderInvMap, NvParameterized::Interface* assetNvIfc,
- std::vector<NvBlastChunkDesc>& chunkDescriptors, std::vector<NvBlastBondDesc>& bondDescriptors, std::vector<uint32_t>& apexChunkFlags)
-{
- ApexImporterConfig configDesc;
- configDesc.setDefaults();
- return importApexAsset(chunkReorderInvMap, assetNvIfc, chunkDescriptors, bondDescriptors, apexChunkFlags, configDesc);
-}
-
-
-bool ApexImportTool::importApexAsset(std::vector<uint32_t>& chunkReorderInvMap, NvParameterized::Interface* assetNvIfc,
- std::vector<NvBlastChunkDesc>& chunkDescriptors, std::vector<NvBlastBondDesc>& bondDescriptors, std::vector<uint32_t>& apexChunkFlags, const ApexImporterConfig& configDesc)
-{
- return importApexAssetInternal(chunkReorderInvMap, assetNvIfc, chunkDescriptors, bondDescriptors, apexChunkFlags, configDesc);
-}
-
-
-
-
-
-bool ApexImportTool::importApexAssetInternal(std::vector<uint32_t>& chunkReorderInvMap, NvParameterized::Interface* assetNvIfc,
- std::vector<NvBlastChunkDesc>& chunkDescriptors, std::vector<NvBlastBondDesc>& bondsDescriptors, std::vector<uint32_t>& apexChunkFlags, const ApexImporterConfig& configDesc)
-{
- if (!assetNvIfc)
- {
- NVBLAST_LOG_ERROR("Error: attempting to import NULL Apex asset.");
- return false;
- }
- DestructibleAssetParameters* params = static_cast<nvidia::destructible::DestructibleAssetParameters*>(assetNvIfc);
-
- int32_t apexChunkCount = params->chunks.arraySizes[0];
- uint32_t rootChunkIndex = 0;
-
- std::vector<uint32_t> chunkToPartMapping(apexChunkCount);
-
- chunkDescriptors.resize(apexChunkCount);
-
- nvidia::apex::RenderMeshAssetParameters* rmParam = static_cast<nvidia::apex::RenderMeshAssetParameters*>(params->renderMeshAsset);
-
- std::vector<PxBounds3> perChunkBounds(apexChunkCount);
- PxBounds3 allRmBound;
- allRmBound.setEmpty();
-
- for (uint32_t i = 0; i < (uint32_t)apexChunkCount; ++i)
- {
- // Use bounds center for centroid
- uint32_t partIndex = getPartIndex(params, i);
- chunkToPartMapping[i] = partIndex;
- const PxBounds3 bounds = rmParam->partBounds.buf[partIndex];
-
- perChunkBounds[i] = bounds;
- allRmBound.include(bounds);
-
- const PxVec3 center = bounds.getCenter();
- memcpy(chunkDescriptors[i].centroid, &center.x, 3 * sizeof(float));
-
- // Find chunk volume
- uint32_t partConvexHullCount = params->chunkConvexHullStartIndices.buf[partIndex + 1] - params->chunkConvexHullStartIndices.buf[partIndex];
- NvParameterized::Interface** cxInterfaceArray = params->chunkConvexHulls.buf + params->chunkConvexHullStartIndices.buf[partIndex];
- chunkDescriptors[i].volume = 0.0f;
- for (uint32_t hull = 0; hull < partConvexHullCount; ++hull)
- {
- NvParameterized::Handle paramHandle(cxInterfaceArray[hull]);
- float hullVolume;
- paramHandle.getParameter("volume");
- paramHandle.getParamF32(hullVolume);
- chunkDescriptors[i].volume += hullVolume;
- }
-
- int16_t parent = params->chunks.buf[i].parentIndex;
- if (parent == -1)
- {
- rootChunkIndex = i;
- chunkDescriptors[i].parentChunkIndex = UINT32_MAX;
- }
- else
- {
- chunkDescriptors[i].parentChunkIndex = parent;
- }
-
- chunkDescriptors[i].flags = 0;
- chunkDescriptors[i].userData = i;
- }
- // Get support graph data from Apex asset //
-
- const NvParameterized::Interface* assetParameterized = assetNvIfc;
- uint32_t maximumSupportDepth = 0;
-
- NvParameterized::Handle parameterHandle(*assetParameterized);
- parameterHandle.getParameter("supportDepth");
- parameterHandle.getParamU32(maximumSupportDepth);
- std::vector<std::pair<uint32_t, uint32_t> > overlapsBuffer;
- nvidia::destructible::CachedOverlaps* overlapsArray = static_cast<nvidia::destructible::CachedOverlaps*>(params->overlapsAtDepth.buf[maximumSupportDepth]);
- uint32_t overlapsCount = overlapsArray->overlaps.arraySizes[0];
- if (overlapsCount != 0)
- {
- for (uint32_t i = 0; i < overlapsCount; ++i)
- {
- uint32_t ov0 = overlapsArray->overlaps.buf[i].i0;
- uint32_t ov1 = overlapsArray->overlaps.buf[i].i1;
-
- chunkDescriptors[ov0].flags = NvBlastChunkDesc::SupportFlag;
- chunkDescriptors[ov1].flags = NvBlastChunkDesc::SupportFlag;
- overlapsBuffer.push_back(std::make_pair(ov0, ov1));
- }
- }
-
- // Format all connections as (chunk with lower index) -> (chunk with higher index) //
-
- for (uint32_t i = 0; i < overlapsBuffer.size(); ++i)
- {
- if (overlapsBuffer[i].first > overlapsBuffer[i].second)
- {
- std::swap(overlapsBuffer[i].first, overlapsBuffer[i].second);
- }
- }
-
- // Unique all connections //
- std::sort(overlapsBuffer.begin(), overlapsBuffer.end());
- overlapsBuffer.resize(std::unique(overlapsBuffer.begin(), overlapsBuffer.end()) - overlapsBuffer.begin());
-
- // Build bond descriptors (acquire area, normal, centroid)
- bondsDescriptors.clear();
- bondsDescriptors.resize(overlapsBuffer.size());
-
- std::shared_ptr<Nv::Blast::BlastBondGenerator> bondGenTool(
- NvBlastExtAuthoringCreateBondGenerator(m_Cooking, &m_PhysxSDK->getPhysicsInsertionCallback()),
- [](Nv::Blast::BlastBondGenerator* bg) {bg->release(); });
-
- std::vector<uint32_t> chunkTrianglesOffsets;
- std::vector<Nv::Blast::Triangle> chunkTriangles;
-
- PxBounds3 bnds = allRmBound;
- PxVec3 offset = bnds.getCenter();
- float scale = 1.0f / PxMax(PxAbs(bnds.getExtents(0)), PxMax(PxAbs(bnds.getExtents(1)), PxAbs(bnds.getExtents(2))));
-
- bnds = gatherChunkTriangles(chunkToPartMapping, rmParam, chunkTrianglesOffsets, chunkTriangles, 0, scale, offset);
-
-
- BondGenerationConfig cf;
- cf.bondMode = BondGenerationConfig::AVERAGE;
- if (configDesc.infSearchMode == configDesc.EXACT)
- {
- cf.bondMode = BondGenerationConfig::EXACT;
- }
- NvBlastBondDesc* bondsDesc;
- std::vector<uint32_t> overlapsA, overlapsB;
- for (auto it : overlapsBuffer)
- {
- overlapsA.push_back(it.first);
- overlapsB.push_back(it.second);
- }
- bondGenTool.get()->createBondBetweenMeshes(chunkTrianglesOffsets.size() - 1, chunkTrianglesOffsets.data(), chunkTriangles.data(),
- overlapsBuffer.size(), overlapsA.data(), overlapsB.data(), bondsDesc, cf);
- memcpy(bondsDescriptors.data(), bondsDesc, sizeof(NvBlastBondDesc) * bondsDescriptors.size());
- NVBLAST_FREE(bondsDesc);
-
- float inverScale = 1.0f / scale;
-
- for (uint32_t i = 0; i < bondsDescriptors.size(); ++i)
- {
- bondsDescriptors[i].bond.area *= inverScale * inverScale;
- bondsDescriptors[i].bond.centroid[0] *= inverScale;
- bondsDescriptors[i].bond.centroid[1] *= inverScale;
- bondsDescriptors[i].bond.centroid[2] *= inverScale;
-
- bondsDescriptors[i].bond.centroid[0] += offset.x;
- bondsDescriptors[i].bond.centroid[1] += offset.y;
- bondsDescriptors[i].bond.centroid[2] += offset.z;
-
- }
-
- /// Delete all bonds with zero area ///
- for (uint32_t i = 0; i < bondsDescriptors.size(); ++i)
- {
- if (bondsDescriptors[i].bond.area == 0)
- {
- bondsDescriptors[i].chunkIndices[0] = bondsDescriptors.back().chunkIndices[0];
- bondsDescriptors[i].chunkIndices[1] = bondsDescriptors.back().chunkIndices[1];
- bondsDescriptors[i].bond = bondsDescriptors.back().bond;
- bondsDescriptors.pop_back();
- --i;
- }
- }
-
- apexChunkFlags.clear();
- apexChunkFlags.resize(chunkDescriptors.size());
- // externally supported chunks
- {
- for (uint32_t i = 0; i < chunkDescriptors.size(); i++)
- {
- uint32_t chunkID = i;
- const NvParameterized::Interface* assetInterface = assetNvIfc;
- NvParameterized::Handle chunksHandle(*assetInterface, "chunks");
- chunksHandle.set(chunkID);
- NvParameterized::Handle flagsHandle(*assetInterface);
- chunksHandle.getChildHandle(assetInterface, "flags", flagsHandle);
- uint32_t flags;
- flagsHandle.getParamU32(flags);
-
- apexChunkFlags[chunkID] = flags;
-
- // world support flag
- if (flags & (1 << 0))
- {
- NvBlastBondDesc bond;
- bond.chunkIndices[0] = i;
- bond.chunkIndices[1] = UINT32_MAX; // invalid index for "world"
- bond.bond.area = 0.1f; // ???
- PxVec3 center = perChunkBounds[i].getCenter();
- memcpy(&bond.bond.centroid, &center.x, sizeof(PxVec3));
- PxVec3 normal = PxVec3(0, 0, 1);
- memcpy(&bond.bond.normal, &normal.x, sizeof(PxVec3));
- bondsDescriptors.push_back(bond);
- }
- }
- }
-
- const uint32_t chunkCount = static_cast<uint32_t>(chunkDescriptors.size());
- const uint32_t bondCount = static_cast<uint32_t>(bondsDescriptors.size());
- std::vector<uint32_t> chunkReorderMap(chunkCount);
- std::vector<NvBlastChunkDesc> scratch(chunkCount);
- NvBlastEnsureAssetExactSupportCoverage(chunkDescriptors.data(), chunkCount, scratch.data(), logLL);
- NvBlastBuildAssetDescChunkReorderMap(chunkReorderMap.data(), chunkDescriptors.data(), chunkCount, scratch.data(), logLL);
- NvBlastApplyAssetDescChunkReorderMapInPlace(chunkDescriptors.data(), chunkCount, bondsDescriptors.data(), bondCount, chunkReorderMap.data(), true, scratch.data(), logLL);
- chunkReorderInvMap.resize(chunkReorderMap.size());
- Nv::Blast::invertMap(chunkReorderInvMap.data(), chunkReorderMap.data(), static_cast<uint32_t>(chunkReorderMap.size()));
- return true;
-}
-
-const float VEC_EPS = 1e-4f;
-
-class MaterialXmlParser : public physx::shdfnd::FastXml::Callback
-{
-public:
- std::string textureFile;
-
-protected:
- // encountered a comment in the XML
- virtual bool processComment(const char* /*comment*/)
- {
- return true;
- }
-
- virtual bool processClose(const char* /*element*/, unsigned int /*depth*/, bool& /*isError*/)
- {
- return true;
- }
-
- // return true to continue processing the XML document, false to skip.
- virtual bool processElement(const char* elementName, // name of the element
- const char* elementData, // element data, null if none
- const physx::shdfnd::FastXml::AttributePairs& attr,
- int /*lineno*/) // line number in the source XML file
- {
- PX_UNUSED(attr);
- if (::strcmp(elementName, "sampler2D") == 0)
- {
- int nameIndex = -1;
- for (int i = 0; i < attr.getNbAttr(); i += 2)
- {
- if (::strcmp(attr.getKey(i), "name") == 0)
- {
- nameIndex = i;
- break;
- }
- }
-
- if (::strcmp(attr.getValue(nameIndex), "diffuseTexture") == 0)
- {
- textureFile = elementData;
- }
- }
-
- return true;
- }
-};
-
-class PxInputDataFromPxFileBuf : public physx::PxInputData
-{
-public:
- PxInputDataFromPxFileBuf(physx::PxFileBuf& fileBuf) : mFileBuf(fileBuf) {}
-
- // physx::PxInputData interface
- virtual uint32_t getLength() const
- {
- return mFileBuf.getFileLength();
- }
-
- virtual void seek(uint32_t offset)
- {
- mFileBuf.seekRead(offset);
- }
-
- virtual uint32_t tell() const
- {
- return mFileBuf.tellRead();
- }
-
- // physx::PxInputStream interface
- virtual uint32_t read(void* dest, uint32_t count)
- {
- return mFileBuf.read(dest, count);
- }
-
- PX_NOCOPY(PxInputDataFromPxFileBuf)
-private:
- physx::PxFileBuf& mFileBuf;
-};
-
-
-std::string getTextureFromMaterial(const char* materialPath)
-{
- PsFileBuffer fileBuffer(materialPath, general_PxIOStream2::PxFileBuf::OPEN_READ_ONLY);
- PxInputDataFromPxFileBuf inputData(fileBuffer);
- MaterialXmlParser parser;
- physx::shdfnd::FastXml* xml = physx::shdfnd::createFastXml(&parser);
- xml->processXml(inputData, false);
-
- xml->release();
-
- // trim folders
- std::string textureFile = parser.textureFile.substr(parser.textureFile.find_last_of("/\\") + 1);
-
- return textureFile;
-}
-
-#define MAX_PATH_LEN 260
-
-bool ApexImportTool::importRendermesh(const std::vector<uint32_t>& chunkReorderInvMap, const NvParameterized::Interface* assetNvIfc, ExporterMeshData* outputData, const char* materialsDir)
-{
- const nvidia::destructible::DestructibleAssetParameters* dasset = static_cast<const nvidia::destructible::DestructibleAssetParameters*>(assetNvIfc);
- const nvidia::apex::RenderMeshAssetParameters* rmAsset = static_cast<const nvidia::apex::RenderMeshAssetParameters*>(dasset->renderMeshAsset);
-
-
- outputData->submeshCount = rmAsset->submeshes.arraySizes[0];
- outputData->submeshMats = new Material[outputData->submeshCount];
- std::vector<Material> materialArray(outputData->submeshCount);
- std::vector<std::string> materialPathes;
- materialPathes.reserve(outputData->submeshCount);
- // gather materials
- {
- for (uint32_t submeshIndex = 0; submeshIndex < outputData->submeshCount; ++submeshIndex)
- {
- const char* materialName = rmAsset->materialNames.buf[submeshIndex].buf;
- if (materialsDir != nullptr)
- {
- std::ostringstream materialPath;
- materialPath << materialsDir << "\\" << materialName;
- std::string texturePath = getTextureFromMaterial(materialPath.str().c_str());
- int32_t bfs = texturePath.length();
- char* texPath = new char[bfs + 1];
- char* matName = new char[bfs + 1];
- memset(texPath, 0, sizeof(char) * (bfs + 1));
- memset(matName, 0, sizeof(char) * (bfs + 1));
- memcpy(texPath, texturePath.data(), sizeof(char) * bfs);
- memcpy(matName, texturePath.data(), sizeof(char) * bfs);
- outputData->submeshMats[submeshIndex].diffuse_tex = texPath;
- outputData->submeshMats[submeshIndex].name = matName;
- }
- else
- {
- int32_t bfs = strnlen(materialName, MAX_PATH_LEN);
- char* texPath = new char[bfs];
- char* matName = new char[bfs];
- memset(texPath, 0, sizeof(char) * (bfs + 1));
- memset(matName, 0, sizeof(char) * (bfs + 1));
- memcpy(texPath, materialName, sizeof(char) * bfs);
- memcpy(matName, materialName, sizeof(char) * bfs);
- outputData->submeshMats[submeshIndex].diffuse_tex = texPath;
- outputData->submeshMats[submeshIndex].name = matName;
- }
- }
- }
- struct vc3Comp
- {
- bool operator()(const PxVec3& a, const PxVec3& b) const
- {
- if (a.x + VEC_EPS < b.x) return true;
- if (a.x - VEC_EPS > b.x) return false;
- if (a.y + VEC_EPS < b.y) return true;
- if (a.y - VEC_EPS > b.y) return false;
- if (a.z + VEC_EPS < b.z) return true;
- return false;
- }
- };
- struct vc2Comp
- {
- bool operator()(const PxVec2& a, const PxVec2& b) const
- {
- if (a.x + VEC_EPS < b.x) return true;
- if (a.x - VEC_EPS > b.x) return false;
- if (a.y + VEC_EPS < b.y) return true;
- return false;
- }
- };
-
- std::vector<PxVec3> compressedPositions;
- std::vector<PxVec3> compressedNormals;
- std::vector<PxVec2> compressedTextures;
-
- std::vector<uint32_t> positionsMapping;
- std::vector<uint32_t> normalsMapping;
- std::vector<uint32_t> texturesMapping;
-
- std::map<PxVec3, uint32_t, vc3Comp> posMap;
- std::map<PxVec3, uint32_t, vc3Comp> normMap;
- std::map<PxVec2, uint32_t, vc2Comp> texMap;
-
-
- // gather data for export
- {
- for (uint32_t submeshIndex = 0; submeshIndex < outputData->submeshCount; ++submeshIndex)
- {
- nvidia::apex::SubmeshParameters* currentSubmesh = static_cast<nvidia::apex::SubmeshParameters*>(rmAsset->submeshes.buf[submeshIndex]);
- nvidia::apex::VertexBufferParameters* vbuf = static_cast<nvidia::apex::VertexBufferParameters*>(currentSubmesh->vertexBuffer);
- nvidia::apex::VertexFormatParameters* vbufFormat = static_cast<nvidia::apex::VertexFormatParameters*>(vbuf->vertexFormat);
- uint32_t indexCount = vbuf->vertexCount;
- // Find position buffer index
- int32_t vbufIds[3]; // 0 - pos, 1 - normals, 2 - t-coord
- vbufIds[0] = vbufIds[1] = vbufIds[2] = -1;
- {
- for (int32_t bid = 0; bid < vbufFormat->bufferFormats.arraySizes[0]; ++bid)
- {
- if (vbufFormat->bufferFormats.buf[bid].semantic == RenderVertexSemantic::POSITION)
- {
- vbufIds[0] = bid;
- }
- if (vbufFormat->bufferFormats.buf[bid].semantic == RenderVertexSemantic::NORMAL)
- {
- vbufIds[1] = bid;
- }
- if (vbufFormat->bufferFormats.buf[bid].semantic == RenderVertexSemantic::TEXCOORD0)
- {
- vbufIds[2] = bid;
- }
- }
- }
- if (vbufIds[0] != -1)
- {
- BufferF32x3* pbuf = static_cast<BufferF32x3*>(vbuf->buffers.buf[vbufIds[0]]);
- const PxVec3* posistions = pbuf->data.buf;
- uint32_t oldSize = (uint32_t)positionsMapping.size();
-
- positionsMapping.resize(oldSize + indexCount);
- for (uint32_t i = 0; i < indexCount; ++i)
- {
- auto it = posMap.find(posistions[i]);
- if (it == posMap.end())
- {
- posMap[posistions[i]] = (uint32_t)compressedPositions.size();
- positionsMapping[oldSize + i] = (uint32_t)compressedPositions.size();
- compressedPositions.push_back(posistions[i]);
- }
- else
- {
- positionsMapping[oldSize + i] = it->second;
- }
- }
- }
-
- if (vbufIds[1] != -1)
- {
- BufferF32x3* pbuf = static_cast<BufferF32x3*>(vbuf->buffers.buf[vbufIds[1]]);
- const PxVec3* normals = pbuf->data.buf;
- uint32_t oldSize = (uint32_t)normalsMapping.size();
- normalsMapping.resize(oldSize + indexCount);
- for (uint32_t i = 0; i < indexCount; ++i)
- {
- auto it = normMap.find(normals[i]);
- if (it == normMap.end())
- {
- normMap[normals[i]] = (uint32_t)compressedNormals.size();
- normalsMapping[oldSize + i] = (uint32_t)compressedNormals.size();
- compressedNormals.push_back(normals[i]);
- }
- else
- {
- normalsMapping[oldSize + i] = it->second;
- }
- }
- }
- if (vbufIds[2] != -1)
- {
- BufferF32x2* pbuf = static_cast<BufferF32x2*>(vbuf->buffers.buf[vbufIds[2]]);
- const PxVec2* texCoord = reinterpret_cast<PxVec2*>(pbuf->data.buf);
- uint32_t oldSize = (uint32_t)texturesMapping.size();
- texturesMapping.resize(oldSize + indexCount);
- for (uint32_t i = 0; i < indexCount; ++i)
- {
- auto it = texMap.find(texCoord[i]);
- if (it == texMap.end())
- {
- texMap[texCoord[i]] = (uint32_t)compressedTextures.size();
- texturesMapping[oldSize + i] = (uint32_t)compressedTextures.size();
- compressedTextures.push_back(texCoord[i]);
- }
- else
- {
- texturesMapping[oldSize + i] = it->second;
- }
- }
- }
- }
- }
- for (uint32_t i = 0; i < compressedTextures.size(); ++i)
- {
- std::swap(compressedTextures[i].x, compressedTextures[i].y);
- }
-
- outputData->positionsCount = (uint32_t)compressedPositions.size();
- //meshData.positions = compressedPositions.data();
- outputData->positions = new PxVec3[outputData->positionsCount];
- memcpy(outputData->positions, compressedPositions.data(), sizeof(PxVec3) * outputData->positionsCount);
- outputData->normalsCount = (uint32_t)compressedNormals.size();
- //meshData.normals = compressedNormals.data();
- outputData->normals = new PxVec3[outputData->normalsCount];
- memcpy(outputData->normals, compressedNormals.data(), sizeof(PxVec3) * outputData->normalsCount);
- outputData->uvsCount = (uint32_t)compressedTextures.size();
- //meshData.uvs = compressedTextures.data();
- outputData->uvs = new PxVec2[outputData->uvsCount];
- memcpy(outputData->uvs, compressedTextures.data(), sizeof(PxVec2) * outputData->uvsCount);
-
- uint32_t apexChunkCount = dasset->chunks.arraySizes[0];
- outputData->meshCount = (uint32_t)chunkReorderInvMap.size();
- outputData->submeshOffsets = new uint32_t[outputData->meshCount * outputData->submeshCount + 1]{ 0 };
-
- //count total number of indices
- for (uint32_t chunkIndex = 0; chunkIndex < apexChunkCount; ++chunkIndex)
- {
- uint32_t apexChunkIndex = chunkReorderInvMap[chunkIndex];
- if (apexChunkIndex >= apexChunkCount)
- {
- PX_ALWAYS_ASSERT();
- continue;
- }
- uint32_t part = getPartIndex(dasset, chunkIndex);
- for (uint32_t submeshIndex = 0; submeshIndex < outputData->submeshCount; ++submeshIndex)
- {
- SubmeshParameters* sm = static_cast<SubmeshParameters*>(rmAsset->submeshes.buf[submeshIndex]);
-
- uint32_t indexCount = sm->indexPartition.buf[part + 1] - sm->indexPartition.buf[part];
- uint32_t* firstIdx = outputData->submeshOffsets + chunkIndex * outputData->submeshCount + submeshIndex;
- *(firstIdx + 1) = *firstIdx + indexCount;
- }
- }
- outputData->posIndex = new uint32_t[outputData->submeshOffsets[outputData->meshCount * outputData->submeshCount]];
- outputData->normIndex = new uint32_t[outputData->submeshOffsets[outputData->meshCount * outputData->submeshCount]];
- outputData->texIndex = new uint32_t[outputData->submeshOffsets[outputData->meshCount * outputData->submeshCount]];
- //copy indices
- for (uint32_t chunkIndex = 0; chunkIndex < outputData->meshCount; ++chunkIndex)
- {
- uint32_t apexChunkIndex = chunkReorderInvMap[chunkIndex];
- if (apexChunkIndex >= apexChunkCount)
- {
- PX_ALWAYS_ASSERT();
- continue;
- }
- uint32_t part = getPartIndex(dasset, chunkIndex);
- uint32_t offset = 0;
- for (uint32_t submeshIndex = 0; submeshIndex < outputData->submeshCount; ++submeshIndex)
- {
- SubmeshParameters* sm = static_cast<SubmeshParameters*>(rmAsset->submeshes.buf[submeshIndex]);
- const uint32_t* indexArray = sm->indexBuffer.buf + sm->indexPartition.buf[part];
- uint32_t indexCount = sm->indexPartition.buf[part + 1] - sm->indexPartition.buf[part];
-
- uint32_t firstIdx = outputData->submeshOffsets[chunkIndex * outputData->submeshCount + submeshIndex];
-
- for (uint32_t i = 0; i < indexCount; ++i)
- {
- outputData->posIndex[firstIdx + i] = positionsMapping[indexArray[i] + offset];
- outputData->normIndex[firstIdx + i] = normalsMapping[indexArray[i] + offset];
- outputData->texIndex[firstIdx + i] = texturesMapping[indexArray[i] + offset];
- }
- nvidia::apex::VertexBufferParameters* vbuf = static_cast<nvidia::apex::VertexBufferParameters*>(sm->vertexBuffer);
- offset += vbuf->vertexCount;
- }
- }
- return true;
-}
-
-
-
-bool ApexImportTool::saveAsset(const NvBlastAsset* asset, PxFileBuf* stream)
-{
- if (!asset)
- {
- NVBLAST_LOG_ERROR("Error: attempting to serialize NULL asset.");
- return false;
- }
- if (!stream)
- {
- NVBLAST_LOG_ERROR("Error: bad output stream.");
- return false;
- }
- const void* assetData = asset;
- uint32_t assetDataSize = NvBlastAssetGetSize(asset, logLL);
- stream->write(assetData, assetDataSize);
- stream->close();
- NVBLAST_LOG_INFO("Saving finished.");
- return true;
-}
-
-
-ApexImportTool::~ApexImportTool()
-{
-}
-
-} // namespace ApexImporter
-
-} // namespace Blast
-} // namespace Nv
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2016-2018 NVIDIA Corporation. All rights reserved.
+
+
+#include "NvBlastExtApexImportTool.h"
+
+#if NV_VC
+#pragma warning(push)
+#pragma warning(disable: 4996) // 'fopen' unsafe warning, from NxFileBuffer.h
+#endif
+
+#include "PxFoundation.h"
+
+#include "NvBlastIndexFns.h"
+#include "NvBlastGlobals.h"
+#include <NvBlastExtExporter.h>
+#include <PxConvexMesh.h>
+#include "PxPhysics.h"
+#include "NvBlastExtAuthoringCollisionBuilder.h"
+#include "NvBlastExtPxAsset.h"
+#include "NvBlastExtAuthoring.h"
+#include "NvBlastExtAuthoringBondGenerator.h"
+#include <nvparameterized\NvParameterized.h>
+#include <nvparameterized\NvParamUtils.h>
+#include <DestructibleAssetParameters.h>
+#include <RenderMeshAssetParameters.h>
+#include <VertexBufferParameters.h>
+#include <VertexFormatParameters.h>
+#include <SubmeshParameters.h>
+#include <CachedOverlaps.h>
+#include "PsFastXml.h"
+#include "PsFileBuffer.h"
+#include <BufferF32x3.h>
+#include <BufferF32x2.h>
+#include <algorithm>
+#include <sstream>
+#include <memory>
+#include <map>
+
+
+#include <NvDefaultTraits.h>
+#include <NvSerializerInternal.h>
+#include <PsMutex.h>
+#include <ModuleDestructibleRegistration.h>
+#include <ModuleDestructibleLegacyRegistration.h>
+#include <ModuleCommonRegistration.h>
+#include <ModuleCommonLegacyRegistration.h>
+#include <ModuleFrameworkRegistration.h>
+#include <ModuleFrameworkLegacyRegistration.h>
+#include <PxPhysicsAPI.h>
+
+#include "NvBlastPxCallbacks.h"
+
+using namespace nvidia;
+using namespace physx;
+using namespace apex;
+
+using nvidia::destructible::DestructibleAssetParameters;
+
+namespace Nv
+{
+namespace Blast
+{
+
+namespace ApexImporter
+{
+ /**
+ Should be consistent with IntPair in APEX
+ */
+ struct IntPair
+ {
+ void set(int32_t _i0, int32_t _i1)
+ {
+ i0 = _i0;
+ i1 = _i1;
+ }
+
+ int32_t i0, i1;
+
+ static int compare(const void* a, const void* b)
+ {
+ const int32_t diff0 = ((IntPair*)a)->i0 - ((IntPair*)b)->i0;
+ return diff0 ? diff0 : (((IntPair*)a)->i1 - ((IntPair*)b)->i1);
+ }
+ };
+
+bool ApexImportTool::loadAssetFromFile(physx::PxFileBuf* stream, NvParameterized::Serializer::DeserializedData& data)
+{
+ if (stream && stream->isOpen())
+ {
+ NvParameterized::Serializer::SerializeType serType = NvParameterized::Serializer::peekSerializeType(*stream);
+ NvParameterized::Serializer::ErrorType serError;
+
+ NvParameterized::Traits* traits = new NvParameterized::DefaultTraits(NvParameterized::DefaultTraits::BehaviourFlags::DEFAULT_POLICY);
+
+ nvidia::destructible::ModuleDestructibleRegistration::invokeRegistration(traits);
+ ModuleDestructibleLegacyRegistration::invokeRegistration(traits);
+ ModuleCommonRegistration::invokeRegistration(traits);
+ ModuleCommonLegacyRegistration::invokeRegistration(traits);
+ ModuleFrameworkLegacyRegistration::invokeRegistration(traits);
+ ModuleFrameworkRegistration::invokeRegistration(traits);
+ NvParameterized::Serializer* ser = NvParameterized::internalCreateSerializer(serType, traits);
+
+ PX_ASSERT(ser);
+
+ serError = ser->deserialize(*stream, data);
+
+ if (serError == NvParameterized::Serializer::ERROR_NONE && data.size() == 1)
+ {
+ NvParameterized::Interface* params = data[0];
+ if (!physx::shdfnd::strcmp(params->className(), "DestructibleAssetParameters"))
+ {
+ return true;
+ }
+ else
+ {
+ NVBLAST_LOG_ERROR("Error: deserialized data is not an APEX Destructible\n");
+ }
+ }
+ else
+ {
+ NVBLAST_LOG_ERROR("Error: failed to deserialize\n");
+ }
+ ser->release();
+ }
+ return false;
+}
+
+bool ApexImportTool::isValid()
+{
+ return m_Foundation && m_PhysxSDK && m_Cooking;
+}
+
+enum ChunkFlags
+{
+ SupportChunk = (1 << 0),
+ UnfracturableChunk = (1 << 1),
+ DescendantUnfractureable = (1 << 2),
+ UndamageableChunk = (1 << 3),
+ UncrumbleableChunk = (1 << 4),
+ RuntimeFracturableChunk = (1 << 5),
+ Instanced = (1 << 8),
+};
+
+uint32_t getPartIndex(const DestructibleAssetParameters* prm, uint32_t id)
+{
+ auto& sch = prm->chunks.buf[id];
+
+ return (sch.flags & ChunkFlags::Instanced) == 0 ? sch.meshPartIndex : prm->chunkInstanceInfo.buf[sch.meshPartIndex].partIndex;
+}
+
+ApexImportTool::ApexImportTool()
+{
+ m_Foundation = PxCreateFoundation(PX_FOUNDATION_VERSION, NvBlastGetPxAllocatorCallback(), NvBlastGetPxErrorCallback());
+ if (!m_Foundation)
+ {
+ NVBLAST_LOG_ERROR("Error: failed to create Foundation\n");
+ return;
+ }
+ physx::PxTolerancesScale scale;
+ m_PhysxSDK = PxCreatePhysics(PX_PHYSICS_VERSION, *m_Foundation, scale, true);
+ if (!m_PhysxSDK)
+ {
+ NVBLAST_LOG_ERROR("Error: failed to create PhysX\n");
+
+ return;
+ }
+
+ physx::PxCookingParams cookingParams(scale);
+ cookingParams.buildGPUData = true;
+ m_Cooking = PxCreateCooking(PX_PHYSICS_VERSION, m_PhysxSDK->getFoundation(), cookingParams);
+ if (!m_Cooking)
+ {
+ NVBLAST_LOG_ERROR("Error: failed to create PhysX Cooking\n");
+ return;
+ }
+
+
+}
+
+
+bool ApexImportTool::getCollisionGeometry(const NvParameterized::Interface* assetPrm, uint32_t chunkCount, std::vector<uint32_t>& chunkReorderInvMap,
+ const std::vector<uint32_t>& apexChunkFlags, std::vector<ExtPxAssetDesc::ChunkDesc>& physicsChunks,
+ std::vector<ExtPxAssetDesc::SubchunkDesc>& physicsSubchunks, std::vector<std::vector<CollisionHull*> >& hullsDesc)
+{
+ physicsChunks.clear();
+ physicsChunks.resize(chunkCount);
+ // prepare physics asset desc (convexes, transforms)
+ std::shared_ptr<ConvexMeshBuilder> collisionBuilder(
+ NvBlastExtAuthoringCreateConvexMeshBuilder(m_Cooking, &m_PhysxSDK->getPhysicsInsertionCallback()),
+ [](ConvexMeshBuilder* cmb) { cmb->release(); });
+
+ const DestructibleAssetParameters* params = static_cast<const DestructibleAssetParameters*>(assetPrm);
+
+ int32_t apexHullCount = 0;
+ const uint32_t apexChunkCount = params->chunks.arraySizes[0];
+
+ for (uint32_t chunkIndex = 0; chunkIndex < chunkCount; ++chunkIndex)
+ {
+ uint32_t apexChunkIndex = chunkReorderInvMap[chunkIndex];
+ if (apexChunkIndex < apexChunkCount)
+ {
+ uint32_t partIndex = getPartIndex(params, apexChunkIndex);
+ uint32_t partConvexHullCount = params->chunkConvexHullStartIndices.buf[partIndex + 1] - params->chunkConvexHullStartIndices.buf[partIndex];
+ apexHullCount += partConvexHullCount;
+ }
+ }
+ physicsSubchunks.reserve(chunkCount);
+ {
+ hullsDesc.clear();
+ hullsDesc.resize(chunkCount);
+ for (uint32_t chunkIndex = 0; chunkIndex < chunkCount; ++chunkIndex)
+ {
+ uint32_t apexChunkIndex = chunkReorderInvMap[chunkIndex];
+ if (apexChunkIndex < apexChunkCount)
+ {
+ uint32_t partIndex = getPartIndex(params, apexChunkIndex);
+ uint32_t partConvexHullCount = params->chunkConvexHullStartIndices.buf[partIndex + 1] - params->chunkConvexHullStartIndices.buf[partIndex];
+ NvParameterized::Interface** cxInterfaceArray = params->chunkConvexHulls.buf + params->chunkConvexHullStartIndices.buf[partIndex];
+ physicsChunks[chunkIndex].subchunkCount = partConvexHullCount;
+ for (uint32_t hull = 0; hull < partConvexHullCount; ++hull)
+ {
+ NvParameterized::Handle paramHandle(cxInterfaceArray[hull]);
+ int32_t verticesCount = 0;
+ paramHandle.getParameter("vertices");
+ paramHandle.getArraySize(verticesCount);
+ std::vector<PxVec3> vertexData(verticesCount);
+ paramHandle.getParamVec3Array(vertexData.data(), verticesCount);
+ hullsDesc[chunkIndex].push_back(nullptr);
+ hullsDesc[chunkIndex].back() = collisionBuilder.get()->buildCollisionGeometry(verticesCount, vertexData.data());
+ PxConvexMesh* convexMesh = collisionBuilder.get()->buildConvexMesh(verticesCount, vertexData.data());
+
+ const ExtPxAssetDesc::SubchunkDesc subchunk =
+ {
+ PxTransform(PxIdentity),
+ PxConvexMeshGeometry(convexMesh)
+ };
+ physicsSubchunks.push_back(subchunk);
+ }
+ physicsChunks[chunkIndex].subchunks = partConvexHullCount ? (&physicsSubchunks.back() + 1 - partConvexHullCount) : nullptr;
+
+ // static flag set
+ physicsChunks[chunkIndex].isStatic = (apexChunkFlags[apexChunkIndex] & (1 << 1)) != 0;
+ }
+ else
+ {
+ NVBLAST_LOG_ERROR("Error: chunk index is invalid.");
+ }
+ }
+ }
+
+ // check that vector didn't grow
+ if (static_cast<int32_t>(physicsSubchunks.size()) > apexHullCount)
+ {
+ NVBLAST_LOG_ERROR("Error: sub chunk count seems to be wrong.");
+ return false;
+ }
+ return true;
+}
+
+PxBounds3 gatherChunkTriangles(std::vector<uint32_t>& chunkToPartMp, const nvidia::apex::RenderMeshAssetParameters* rmAsset, std::vector<uint32_t>& chunkTrianglesOffsets, std::vector<Nv::Blast::Triangle>& chunkTriangles, int32_t posBufferIndex, float scale, PxVec3 offset )
+{
+
+ PxBounds3 bnd;
+ bnd.setEmpty();
+ chunkTrianglesOffsets.clear();
+ uint32_t chunkCount = chunkToPartMp.size();
+ chunkTrianglesOffsets.resize(chunkCount + 1);
+ chunkTrianglesOffsets[0] = 0;
+ for (uint32_t chunkIndex = 0; chunkIndex < chunkCount; ++chunkIndex)
+ {
+ uint32_t part = chunkToPartMp[chunkIndex];
+ uint32_t submeshCount = rmAsset->submeshes.arraySizes[0];
+ for (uint32_t submeshIndex = 0; submeshIndex < submeshCount; ++submeshIndex)
+ {
+ nvidia::apex::SubmeshParameters* submeshPrm = static_cast<nvidia::apex::SubmeshParameters*>(rmAsset->submeshes.buf[submeshIndex]);
+
+ const uint32_t* indexArray = submeshPrm->indexBuffer.buf + submeshPrm->indexPartition.buf[part];
+ uint32_t indexCount = submeshPrm->indexPartition.buf[part + 1] - submeshPrm->indexPartition.buf[part];
+
+ nvidia::apex::VertexBufferParameters* vbuf = static_cast<nvidia::apex::VertexBufferParameters*>(submeshPrm->vertexBuffer);
+
+ nvidia::apex::BufferF32x3* pbuf = static_cast<nvidia::apex::BufferF32x3*>(vbuf->buffers.buf[posBufferIndex]);
+
+ const PxVec3* positions = reinterpret_cast<const PxVec3*>(pbuf->data.buf);
+
+ for (uint32_t i = 0; i < indexCount; i += 3)
+ {
+ Vertex a;
+ Vertex b;
+ Vertex c;
+ bnd.include(positions[indexArray[i]]);
+ bnd.include(positions[indexArray[i + 1]]);
+ bnd.include(positions[indexArray[i + 2]]);
+
+ a.p = positions[indexArray[i]] - offset;
+ b.p = positions[indexArray[i + 1]] - offset;
+ c.p = positions[indexArray[i + 2]] - offset;
+ a.p *= scale;
+ b.p *= scale;
+ c.p *= scale;
+ chunkTriangles.push_back(Nv::Blast::Triangle(a, b, c));
+ }
+ }
+ chunkTrianglesOffsets[chunkIndex + 1] = chunkTriangles.size();
+ }
+ return bnd;
+}
+
+bool ApexImportTool::importApexAsset(std::vector<uint32_t>& chunkReorderInvMap, NvParameterized::Interface* assetNvIfc,
+ std::vector<NvBlastChunkDesc>& chunkDescriptors, std::vector<NvBlastBondDesc>& bondDescriptors, std::vector<uint32_t>& apexChunkFlags)
+{
+ ApexImporterConfig configDesc;
+ configDesc.setDefaults();
+ return importApexAsset(chunkReorderInvMap, assetNvIfc, chunkDescriptors, bondDescriptors, apexChunkFlags, configDesc);
+}
+
+
+bool ApexImportTool::importApexAsset(std::vector<uint32_t>& chunkReorderInvMap, NvParameterized::Interface* assetNvIfc,
+ std::vector<NvBlastChunkDesc>& chunkDescriptors, std::vector<NvBlastBondDesc>& bondDescriptors, std::vector<uint32_t>& apexChunkFlags, const ApexImporterConfig& configDesc)
+{
+ return importApexAssetInternal(chunkReorderInvMap, assetNvIfc, chunkDescriptors, bondDescriptors, apexChunkFlags, configDesc);
+}
+
+
+
+
+
+bool ApexImportTool::importApexAssetInternal(std::vector<uint32_t>& chunkReorderInvMap, NvParameterized::Interface* assetNvIfc,
+ std::vector<NvBlastChunkDesc>& chunkDescriptors, std::vector<NvBlastBondDesc>& bondsDescriptors, std::vector<uint32_t>& apexChunkFlags, const ApexImporterConfig& configDesc)
+{
+ if (!assetNvIfc)
+ {
+ NVBLAST_LOG_ERROR("Error: attempting to import NULL Apex asset.");
+ return false;
+ }
+ DestructibleAssetParameters* params = static_cast<nvidia::destructible::DestructibleAssetParameters*>(assetNvIfc);
+
+ int32_t apexChunkCount = params->chunks.arraySizes[0];
+ uint32_t rootChunkIndex = 0;
+
+ std::vector<uint32_t> chunkToPartMapping(apexChunkCount);
+
+ chunkDescriptors.resize(apexChunkCount);
+
+ nvidia::apex::RenderMeshAssetParameters* rmParam = static_cast<nvidia::apex::RenderMeshAssetParameters*>(params->renderMeshAsset);
+
+ std::vector<PxBounds3> perChunkBounds(apexChunkCount);
+ PxBounds3 allRmBound;
+ allRmBound.setEmpty();
+
+ for (uint32_t i = 0; i < (uint32_t)apexChunkCount; ++i)
+ {
+ // Use bounds center for centroid
+ uint32_t partIndex = getPartIndex(params, i);
+ chunkToPartMapping[i] = partIndex;
+ const PxBounds3 bounds = rmParam->partBounds.buf[partIndex];
+
+ perChunkBounds[i] = bounds;
+ allRmBound.include(bounds);
+
+ const PxVec3 center = bounds.getCenter();
+ memcpy(chunkDescriptors[i].centroid, &center.x, 3 * sizeof(float));
+
+ // Find chunk volume
+ uint32_t partConvexHullCount = params->chunkConvexHullStartIndices.buf[partIndex + 1] - params->chunkConvexHullStartIndices.buf[partIndex];
+ NvParameterized::Interface** cxInterfaceArray = params->chunkConvexHulls.buf + params->chunkConvexHullStartIndices.buf[partIndex];
+ chunkDescriptors[i].volume = 0.0f;
+ for (uint32_t hull = 0; hull < partConvexHullCount; ++hull)
+ {
+ NvParameterized::Handle paramHandle(cxInterfaceArray[hull]);
+ float hullVolume;
+ paramHandle.getParameter("volume");
+ paramHandle.getParamF32(hullVolume);
+ chunkDescriptors[i].volume += hullVolume;
+ }
+
+ int16_t parent = params->chunks.buf[i].parentIndex;
+ if (parent == -1)
+ {
+ rootChunkIndex = i;
+ chunkDescriptors[i].parentChunkIndex = UINT32_MAX;
+ }
+ else
+ {
+ chunkDescriptors[i].parentChunkIndex = parent;
+ }
+
+ chunkDescriptors[i].flags = 0;
+ chunkDescriptors[i].userData = i;
+ }
+ // Get support graph data from Apex asset //
+
+ const NvParameterized::Interface* assetParameterized = assetNvIfc;
+ uint32_t maximumSupportDepth = 0;
+
+ NvParameterized::Handle parameterHandle(*assetParameterized);
+ parameterHandle.getParameter("supportDepth");
+ parameterHandle.getParamU32(maximumSupportDepth);
+ std::vector<std::pair<uint32_t, uint32_t> > overlapsBuffer;
+ nvidia::destructible::CachedOverlaps* overlapsArray = static_cast<nvidia::destructible::CachedOverlaps*>(params->overlapsAtDepth.buf[maximumSupportDepth]);
+ uint32_t overlapsCount = overlapsArray->overlaps.arraySizes[0];
+ if (overlapsCount != 0)
+ {
+ for (uint32_t i = 0; i < overlapsCount; ++i)
+ {
+ uint32_t ov0 = overlapsArray->overlaps.buf[i].i0;
+ uint32_t ov1 = overlapsArray->overlaps.buf[i].i1;
+
+ chunkDescriptors[ov0].flags = NvBlastChunkDesc::SupportFlag;
+ chunkDescriptors[ov1].flags = NvBlastChunkDesc::SupportFlag;
+ overlapsBuffer.push_back(std::make_pair(ov0, ov1));
+ }
+ }
+
+ // Format all connections as (chunk with lower index) -> (chunk with higher index) //
+
+ for (uint32_t i = 0; i < overlapsBuffer.size(); ++i)
+ {
+ if (overlapsBuffer[i].first > overlapsBuffer[i].second)
+ {
+ std::swap(overlapsBuffer[i].first, overlapsBuffer[i].second);
+ }
+ }
+
+ // Unique all connections //
+ std::sort(overlapsBuffer.begin(), overlapsBuffer.end());
+ overlapsBuffer.resize(std::unique(overlapsBuffer.begin(), overlapsBuffer.end()) - overlapsBuffer.begin());
+
+ // Build bond descriptors (acquire area, normal, centroid)
+ bondsDescriptors.clear();
+ bondsDescriptors.resize(overlapsBuffer.size());
+
+ std::shared_ptr<Nv::Blast::BlastBondGenerator> bondGenTool(
+ NvBlastExtAuthoringCreateBondGenerator(m_Cooking, &m_PhysxSDK->getPhysicsInsertionCallback()),
+ [](Nv::Blast::BlastBondGenerator* bg) {bg->release(); });
+
+ std::vector<uint32_t> chunkTrianglesOffsets;
+ std::vector<Nv::Blast::Triangle> chunkTriangles;
+
+ PxBounds3 bnds = allRmBound;
+ PxVec3 offset = bnds.getCenter();
+ float scale = 1.0f / PxMax(PxAbs(bnds.getExtents(0)), PxMax(PxAbs(bnds.getExtents(1)), PxAbs(bnds.getExtents(2))));
+
+ bnds = gatherChunkTriangles(chunkToPartMapping, rmParam, chunkTrianglesOffsets, chunkTriangles, 0, scale, offset);
+
+
+ BondGenerationConfig cf;
+ cf.bondMode = BondGenerationConfig::AVERAGE;
+ if (configDesc.infSearchMode == configDesc.EXACT)
+ {
+ cf.bondMode = BondGenerationConfig::EXACT;
+ }
+ NvBlastBondDesc* bondsDesc;
+ std::vector<uint32_t> overlapsA, overlapsB;
+ for (auto it : overlapsBuffer)
+ {
+ overlapsA.push_back(it.first);
+ overlapsB.push_back(it.second);
+ }
+ bondGenTool.get()->createBondBetweenMeshes(chunkTrianglesOffsets.size() - 1, chunkTrianglesOffsets.data(), chunkTriangles.data(),
+ overlapsBuffer.size(), overlapsA.data(), overlapsB.data(), bondsDesc, cf);
+ memcpy(bondsDescriptors.data(), bondsDesc, sizeof(NvBlastBondDesc) * bondsDescriptors.size());
+ NVBLAST_FREE(bondsDesc);
+
+ float inverScale = 1.0f / scale;
+
+ for (uint32_t i = 0; i < bondsDescriptors.size(); ++i)
+ {
+ bondsDescriptors[i].bond.area *= inverScale * inverScale;
+ bondsDescriptors[i].bond.centroid[0] *= inverScale;
+ bondsDescriptors[i].bond.centroid[1] *= inverScale;
+ bondsDescriptors[i].bond.centroid[2] *= inverScale;
+
+ bondsDescriptors[i].bond.centroid[0] += offset.x;
+ bondsDescriptors[i].bond.centroid[1] += offset.y;
+ bondsDescriptors[i].bond.centroid[2] += offset.z;
+
+ }
+
+ /// Delete all bonds with zero area ///
+ for (uint32_t i = 0; i < bondsDescriptors.size(); ++i)
+ {
+ if (bondsDescriptors[i].bond.area == 0)
+ {
+ bondsDescriptors[i].chunkIndices[0] = bondsDescriptors.back().chunkIndices[0];
+ bondsDescriptors[i].chunkIndices[1] = bondsDescriptors.back().chunkIndices[1];
+ bondsDescriptors[i].bond = bondsDescriptors.back().bond;
+ bondsDescriptors.pop_back();
+ --i;
+ }
+ }
+
+ apexChunkFlags.clear();
+ apexChunkFlags.resize(chunkDescriptors.size());
+ // externally supported chunks
+ {
+ for (uint32_t i = 0; i < chunkDescriptors.size(); i++)
+ {
+ uint32_t chunkID = i;
+ const NvParameterized::Interface* assetInterface = assetNvIfc;
+ NvParameterized::Handle chunksHandle(*assetInterface, "chunks");
+ chunksHandle.set(chunkID);
+ NvParameterized::Handle flagsHandle(*assetInterface);
+ chunksHandle.getChildHandle(assetInterface, "flags", flagsHandle);
+ uint32_t flags;
+ flagsHandle.getParamU32(flags);
+
+ apexChunkFlags[chunkID] = flags;
+
+ // world support flag
+ if (flags & (1 << 0))
+ {
+ NvBlastBondDesc bond;
+ bond.chunkIndices[0] = i;
+ bond.chunkIndices[1] = UINT32_MAX; // invalid index for "world"
+ bond.bond.area = 0.1f; // ???
+ PxVec3 center = perChunkBounds[i].getCenter();
+ memcpy(&bond.bond.centroid, &center.x, sizeof(PxVec3));
+ PxVec3 normal = PxVec3(0, 0, 1);
+ memcpy(&bond.bond.normal, &normal.x, sizeof(PxVec3));
+ bondsDescriptors.push_back(bond);
+ }
+ }
+ }
+
+ const uint32_t chunkCount = static_cast<uint32_t>(chunkDescriptors.size());
+ const uint32_t bondCount = static_cast<uint32_t>(bondsDescriptors.size());
+ std::vector<uint32_t> chunkReorderMap(chunkCount);
+ std::vector<NvBlastChunkDesc> scratch(chunkCount);
+ NvBlastEnsureAssetExactSupportCoverage(chunkDescriptors.data(), chunkCount, scratch.data(), logLL);
+ NvBlastBuildAssetDescChunkReorderMap(chunkReorderMap.data(), chunkDescriptors.data(), chunkCount, scratch.data(), logLL);
+ NvBlastApplyAssetDescChunkReorderMapInPlace(chunkDescriptors.data(), chunkCount, bondsDescriptors.data(), bondCount, chunkReorderMap.data(), true, scratch.data(), logLL);
+ chunkReorderInvMap.resize(chunkReorderMap.size());
+ Nv::Blast::invertMap(chunkReorderInvMap.data(), chunkReorderMap.data(), static_cast<uint32_t>(chunkReorderMap.size()));
+ return true;
+}
+
+const float VEC_EPS = 1e-4f;
+
+class MaterialXmlParser : public physx::shdfnd::FastXml::Callback
+{
+public:
+ std::string textureFile;
+
+protected:
+ // encountered a comment in the XML
+ virtual bool processComment(const char* /*comment*/)
+ {
+ return true;
+ }
+
+ virtual bool processClose(const char* /*element*/, unsigned int /*depth*/, bool& /*isError*/)
+ {
+ return true;
+ }
+
+ // return true to continue processing the XML document, false to skip.
+ virtual bool processElement(const char* elementName, // name of the element
+ const char* elementData, // element data, null if none
+ const physx::shdfnd::FastXml::AttributePairs& attr,
+ int /*lineno*/) // line number in the source XML file
+ {
+ PX_UNUSED(attr);
+ if (::strcmp(elementName, "sampler2D") == 0)
+ {
+ int nameIndex = -1;
+ for (int i = 0; i < attr.getNbAttr(); i += 2)
+ {
+ if (::strcmp(attr.getKey(i), "name") == 0)
+ {
+ nameIndex = i;
+ break;
+ }
+ }
+
+ if (::strcmp(attr.getValue(nameIndex), "diffuseTexture") == 0)
+ {
+ textureFile = elementData;
+ }
+ }
+
+ return true;
+ }
+};
+
+class PxInputDataFromPxFileBuf : public physx::PxInputData
+{
+public:
+ PxInputDataFromPxFileBuf(physx::PxFileBuf& fileBuf) : mFileBuf(fileBuf) {}
+
+ // physx::PxInputData interface
+ virtual uint32_t getLength() const
+ {
+ return mFileBuf.getFileLength();
+ }
+
+ virtual void seek(uint32_t offset)
+ {
+ mFileBuf.seekRead(offset);
+ }
+
+ virtual uint32_t tell() const
+ {
+ return mFileBuf.tellRead();
+ }
+
+ // physx::PxInputStream interface
+ virtual uint32_t read(void* dest, uint32_t count)
+ {
+ return mFileBuf.read(dest, count);
+ }
+
+ PX_NOCOPY(PxInputDataFromPxFileBuf)
+private:
+ physx::PxFileBuf& mFileBuf;
+};
+
+
+std::string getTextureFromMaterial(const char* materialPath)
+{
+ PsFileBuffer fileBuffer(materialPath, general_PxIOStream2::PxFileBuf::OPEN_READ_ONLY);
+ PxInputDataFromPxFileBuf inputData(fileBuffer);
+ MaterialXmlParser parser;
+ physx::shdfnd::FastXml* xml = physx::shdfnd::createFastXml(&parser);
+ xml->processXml(inputData, false);
+
+ xml->release();
+
+ // trim folders
+ std::string textureFile = parser.textureFile.substr(parser.textureFile.find_last_of("/\\") + 1);
+
+ return textureFile;
+}
+
+#define MAX_PATH_LEN 260
+
+bool ApexImportTool::importRendermesh(const std::vector<uint32_t>& chunkReorderInvMap, const NvParameterized::Interface* assetNvIfc, ExporterMeshData* outputData, const char* materialsDir)
+{
+ const nvidia::destructible::DestructibleAssetParameters* dasset = static_cast<const nvidia::destructible::DestructibleAssetParameters*>(assetNvIfc);
+ const nvidia::apex::RenderMeshAssetParameters* rmAsset = static_cast<const nvidia::apex::RenderMeshAssetParameters*>(dasset->renderMeshAsset);
+
+
+ outputData->submeshCount = rmAsset->submeshes.arraySizes[0];
+ outputData->submeshMats = new Material[outputData->submeshCount];
+ std::vector<Material> materialArray(outputData->submeshCount);
+ std::vector<std::string> materialPathes;
+ materialPathes.reserve(outputData->submeshCount);
+ // gather materials
+ {
+ for (uint32_t submeshIndex = 0; submeshIndex < outputData->submeshCount; ++submeshIndex)
+ {
+ const char* materialName = rmAsset->materialNames.buf[submeshIndex].buf;
+ if (materialsDir != nullptr)
+ {
+ std::ostringstream materialPath;
+ materialPath << materialsDir << "\\" << materialName;
+ std::string texturePath = getTextureFromMaterial(materialPath.str().c_str());
+ int32_t bfs = texturePath.length();
+ char* texPath = new char[bfs + 1];
+ char* matName = new char[bfs + 1];
+ memset(texPath, 0, sizeof(char) * (bfs + 1));
+ memset(matName, 0, sizeof(char) * (bfs + 1));
+ memcpy(texPath, texturePath.data(), sizeof(char) * bfs);
+ memcpy(matName, texturePath.data(), sizeof(char) * bfs);
+ outputData->submeshMats[submeshIndex].diffuse_tex = texPath;
+ outputData->submeshMats[submeshIndex].name = matName;
+ }
+ else
+ {
+ int32_t bfs = strnlen(materialName, MAX_PATH_LEN);
+ char* texPath = new char[bfs];
+ char* matName = new char[bfs];
+ memset(texPath, 0, sizeof(char) * (bfs + 1));
+ memset(matName, 0, sizeof(char) * (bfs + 1));
+ memcpy(texPath, materialName, sizeof(char) * bfs);
+ memcpy(matName, materialName, sizeof(char) * bfs);
+ outputData->submeshMats[submeshIndex].diffuse_tex = texPath;
+ outputData->submeshMats[submeshIndex].name = matName;
+ }
+ }
+ }
+ struct vc3Comp
+ {
+ bool operator()(const PxVec3& a, const PxVec3& b) const
+ {
+ if (a.x + VEC_EPS < b.x) return true;
+ if (a.x - VEC_EPS > b.x) return false;
+ if (a.y + VEC_EPS < b.y) return true;
+ if (a.y - VEC_EPS > b.y) return false;
+ if (a.z + VEC_EPS < b.z) return true;
+ return false;
+ }
+ };
+ struct vc2Comp
+ {
+ bool operator()(const PxVec2& a, const PxVec2& b) const
+ {
+ if (a.x + VEC_EPS < b.x) return true;
+ if (a.x - VEC_EPS > b.x) return false;
+ if (a.y + VEC_EPS < b.y) return true;
+ return false;
+ }
+ };
+
+ std::vector<PxVec3> compressedPositions;
+ std::vector<PxVec3> compressedNormals;
+ std::vector<PxVec2> compressedTextures;
+
+ std::vector<uint32_t> positionsMapping;
+ std::vector<uint32_t> normalsMapping;
+ std::vector<uint32_t> texturesMapping;
+
+ std::map<PxVec3, uint32_t, vc3Comp> posMap;
+ std::map<PxVec3, uint32_t, vc3Comp> normMap;
+ std::map<PxVec2, uint32_t, vc2Comp> texMap;
+
+
+ // gather data for export
+ {
+ for (uint32_t submeshIndex = 0; submeshIndex < outputData->submeshCount; ++submeshIndex)
+ {
+ nvidia::apex::SubmeshParameters* currentSubmesh = static_cast<nvidia::apex::SubmeshParameters*>(rmAsset->submeshes.buf[submeshIndex]);
+ nvidia::apex::VertexBufferParameters* vbuf = static_cast<nvidia::apex::VertexBufferParameters*>(currentSubmesh->vertexBuffer);
+ nvidia::apex::VertexFormatParameters* vbufFormat = static_cast<nvidia::apex::VertexFormatParameters*>(vbuf->vertexFormat);
+ uint32_t indexCount = vbuf->vertexCount;
+ // Find position buffer index
+ int32_t vbufIds[3]; // 0 - pos, 1 - normals, 2 - t-coord
+ vbufIds[0] = vbufIds[1] = vbufIds[2] = -1;
+ {
+ for (int32_t bid = 0; bid < vbufFormat->bufferFormats.arraySizes[0]; ++bid)
+ {
+ if (vbufFormat->bufferFormats.buf[bid].semantic == RenderVertexSemantic::POSITION)
+ {
+ vbufIds[0] = bid;
+ }
+ if (vbufFormat->bufferFormats.buf[bid].semantic == RenderVertexSemantic::NORMAL)
+ {
+ vbufIds[1] = bid;
+ }
+ if (vbufFormat->bufferFormats.buf[bid].semantic == RenderVertexSemantic::TEXCOORD0)
+ {
+ vbufIds[2] = bid;
+ }
+ }
+ }
+ if (vbufIds[0] != -1)
+ {
+ BufferF32x3* pbuf = static_cast<BufferF32x3*>(vbuf->buffers.buf[vbufIds[0]]);
+ const PxVec3* posistions = pbuf->data.buf;
+ uint32_t oldSize = (uint32_t)positionsMapping.size();
+
+ positionsMapping.resize(oldSize + indexCount);
+ for (uint32_t i = 0; i < indexCount; ++i)
+ {
+ auto it = posMap.find(posistions[i]);
+ if (it == posMap.end())
+ {
+ posMap[posistions[i]] = (uint32_t)compressedPositions.size();
+ positionsMapping[oldSize + i] = (uint32_t)compressedPositions.size();
+ compressedPositions.push_back(posistions[i]);
+ }
+ else
+ {
+ positionsMapping[oldSize + i] = it->second;
+ }
+ }
+ }
+
+ if (vbufIds[1] != -1)
+ {
+ BufferF32x3* pbuf = static_cast<BufferF32x3*>(vbuf->buffers.buf[vbufIds[1]]);
+ const PxVec3* normals = pbuf->data.buf;
+ uint32_t oldSize = (uint32_t)normalsMapping.size();
+ normalsMapping.resize(oldSize + indexCount);
+ for (uint32_t i = 0; i < indexCount; ++i)
+ {
+ auto it = normMap.find(normals[i]);
+ if (it == normMap.end())
+ {
+ normMap[normals[i]] = (uint32_t)compressedNormals.size();
+ normalsMapping[oldSize + i] = (uint32_t)compressedNormals.size();
+ compressedNormals.push_back(normals[i]);
+ }
+ else
+ {
+ normalsMapping[oldSize + i] = it->second;
+ }
+ }
+ }
+ if (vbufIds[2] != -1)
+ {
+ BufferF32x2* pbuf = static_cast<BufferF32x2*>(vbuf->buffers.buf[vbufIds[2]]);
+ const PxVec2* texCoord = reinterpret_cast<PxVec2*>(pbuf->data.buf);
+ uint32_t oldSize = (uint32_t)texturesMapping.size();
+ texturesMapping.resize(oldSize + indexCount);
+ for (uint32_t i = 0; i < indexCount; ++i)
+ {
+ auto it = texMap.find(texCoord[i]);
+ if (it == texMap.end())
+ {
+ texMap[texCoord[i]] = (uint32_t)compressedTextures.size();
+ texturesMapping[oldSize + i] = (uint32_t)compressedTextures.size();
+ compressedTextures.push_back(texCoord[i]);
+ }
+ else
+ {
+ texturesMapping[oldSize + i] = it->second;
+ }
+ }
+ }
+ }
+ }
+ for (uint32_t i = 0; i < compressedTextures.size(); ++i)
+ {
+ std::swap(compressedTextures[i].x, compressedTextures[i].y);
+ }
+
+ outputData->positionsCount = (uint32_t)compressedPositions.size();
+ //meshData.positions = compressedPositions.data();
+ outputData->positions = new PxVec3[outputData->positionsCount];
+ memcpy(outputData->positions, compressedPositions.data(), sizeof(PxVec3) * outputData->positionsCount);
+ outputData->normalsCount = (uint32_t)compressedNormals.size();
+ //meshData.normals = compressedNormals.data();
+ outputData->normals = new PxVec3[outputData->normalsCount];
+ memcpy(outputData->normals, compressedNormals.data(), sizeof(PxVec3) * outputData->normalsCount);
+ outputData->uvsCount = (uint32_t)compressedTextures.size();
+ //meshData.uvs = compressedTextures.data();
+ outputData->uvs = new PxVec2[outputData->uvsCount];
+ memcpy(outputData->uvs, compressedTextures.data(), sizeof(PxVec2) * outputData->uvsCount);
+
+ uint32_t apexChunkCount = dasset->chunks.arraySizes[0];
+ outputData->meshCount = (uint32_t)chunkReorderInvMap.size();
+ outputData->submeshOffsets = new uint32_t[outputData->meshCount * outputData->submeshCount + 1]{ 0 };
+
+ //count total number of indices
+ for (uint32_t chunkIndex = 0; chunkIndex < apexChunkCount; ++chunkIndex)
+ {
+ uint32_t apexChunkIndex = chunkReorderInvMap[chunkIndex];
+ if (apexChunkIndex >= apexChunkCount)
+ {
+ PX_ALWAYS_ASSERT();
+ continue;
+ }
+ uint32_t part = getPartIndex(dasset, chunkIndex);
+ for (uint32_t submeshIndex = 0; submeshIndex < outputData->submeshCount; ++submeshIndex)
+ {
+ SubmeshParameters* sm = static_cast<SubmeshParameters*>(rmAsset->submeshes.buf[submeshIndex]);
+
+ uint32_t indexCount = sm->indexPartition.buf[part + 1] - sm->indexPartition.buf[part];
+ uint32_t* firstIdx = outputData->submeshOffsets + chunkIndex * outputData->submeshCount + submeshIndex;
+ *(firstIdx + 1) = *firstIdx + indexCount;
+ }
+ }
+ outputData->posIndex = new uint32_t[outputData->submeshOffsets[outputData->meshCount * outputData->submeshCount]];
+ outputData->normIndex = new uint32_t[outputData->submeshOffsets[outputData->meshCount * outputData->submeshCount]];
+ outputData->texIndex = new uint32_t[outputData->submeshOffsets[outputData->meshCount * outputData->submeshCount]];
+ //copy indices
+ for (uint32_t chunkIndex = 0; chunkIndex < outputData->meshCount; ++chunkIndex)
+ {
+ uint32_t apexChunkIndex = chunkReorderInvMap[chunkIndex];
+ if (apexChunkIndex >= apexChunkCount)
+ {
+ PX_ALWAYS_ASSERT();
+ continue;
+ }
+ uint32_t part = getPartIndex(dasset, chunkIndex);
+ uint32_t offset = 0;
+ for (uint32_t submeshIndex = 0; submeshIndex < outputData->submeshCount; ++submeshIndex)
+ {
+ SubmeshParameters* sm = static_cast<SubmeshParameters*>(rmAsset->submeshes.buf[submeshIndex]);
+ const uint32_t* indexArray = sm->indexBuffer.buf + sm->indexPartition.buf[part];
+ uint32_t indexCount = sm->indexPartition.buf[part + 1] - sm->indexPartition.buf[part];
+
+ uint32_t firstIdx = outputData->submeshOffsets[chunkIndex * outputData->submeshCount + submeshIndex];
+
+ for (uint32_t i = 0; i < indexCount; ++i)
+ {
+ outputData->posIndex[firstIdx + i] = positionsMapping[indexArray[i] + offset];
+ outputData->normIndex[firstIdx + i] = normalsMapping[indexArray[i] + offset];
+ outputData->texIndex[firstIdx + i] = texturesMapping[indexArray[i] + offset];
+ }
+ nvidia::apex::VertexBufferParameters* vbuf = static_cast<nvidia::apex::VertexBufferParameters*>(sm->vertexBuffer);
+ offset += vbuf->vertexCount;
+ }
+ }
+ return true;
+}
+
+
+
+bool ApexImportTool::saveAsset(const NvBlastAsset* asset, PxFileBuf* stream)
+{
+ if (!asset)
+ {
+ NVBLAST_LOG_ERROR("Error: attempting to serialize NULL asset.");
+ return false;
+ }
+ if (!stream)
+ {
+ NVBLAST_LOG_ERROR("Error: bad output stream.");
+ return false;
+ }
+ const void* assetData = asset;
+ uint32_t assetDataSize = NvBlastAssetGetSize(asset, logLL);
+ stream->write(assetData, assetDataSize);
+ stream->close();
+ NVBLAST_LOG_INFO("Saving finished.");
+ return true;
+}
+
+
+ApexImportTool::~ApexImportTool()
+{
+}
+
+} // namespace ApexImporter
+
+} // namespace Blast
+} // namespace Nv