diff options
| author | Bryan Galdrikian <[email protected]> | 2017-02-21 12:07:59 -0800 |
|---|---|---|
| committer | Bryan Galdrikian <[email protected]> | 2017-02-21 12:07:59 -0800 |
| commit | 446ce137c6823ba9eff273bdafdaf266287c7c98 (patch) | |
| tree | d20aab3e2ed08d7b3ca71c2f40db6a93ea00c459 /NvBlast/sdk/extensions/import/source | |
| download | blast-1.0.0-beta.tar.xz blast-1.0.0-beta.zip | |
first commitv1.0.0-beta
Diffstat (limited to 'NvBlast/sdk/extensions/import/source')
5 files changed, 1028 insertions, 0 deletions
diff --git a/NvBlast/sdk/extensions/import/source/NvBlastExtApexDestruction.cpp b/NvBlast/sdk/extensions/import/source/NvBlastExtApexDestruction.cpp new file mode 100644 index 0000000..889a8c8 --- /dev/null +++ b/NvBlast/sdk/extensions/import/source/NvBlastExtApexDestruction.cpp @@ -0,0 +1,220 @@ +/* +* Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved. +* +* NVIDIA CORPORATION and its licensors retain all intellectual property +* and proprietary rights in and to this software, 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. +*/ + +#include "NvBlastExtApexDestruction.h" + + +#include "PxPhysicsAPI.h" +#include "Apex.h" +#include <ModuleDestructible.h> +#include <DestructibleAsset.h> +#include "NullRenderer.h" +#include "PsString.h" + +using namespace nvidia; +using namespace apex; + +////////////////////////////////////////////////////////////////////////////// + +PxDefaultAllocator gPxAllocator; +PxDefaultErrorCallback gErrorCallback; +NullRenderResourceManager gNullRenderer; + +///////////////////////////////////////////////////////////////////////////// + +namespace Nv +{ +namespace Blast +{ +using namespace ApexImporter; + +ApexDestruction::ApexDestruction(NvBlastLog log) +{ + m_log = log; + initialize(); +} + +ApexDestruction::ApexDestruction(ApexSDK* apexSdk, ModuleDestructible* moduleDestructible, NvBlastLog log) +{ + m_log = log; + + m_Foundation.reset(&apexSdk->getPhysXSDK()->getFoundation(), false); + m_PhysxSDK.reset(apexSdk->getPhysXSDK(), false); + m_Cooking.reset(apexSdk->getCookingInterface(), false); + m_ApexSDK.reset(apexSdk, false); + for (uint32_t i = 0; i < apexSdk->getNbModules(); ++i) + { + if (!physx::shdfnd::strcmp(apexSdk->getModules()[i]->getName(), "Legacy")) + { + hasLegacyModule = true; + } + } + m_DestructibleModule.reset(moduleDestructible, false); +} + + +bool ApexDestruction::isValid() +{ + return m_PhysxSDK && m_Cooking && m_ApexSDK && m_DestructibleModule && hasLegacyModule; +} + +bool ApexDestruction::initialize() +{ + if (isValid()) + { + return true; + } + + ////////////////////////////////////////////////////////////////////////////// + + m_Foundation.reset(PxCreateFoundation(PX_FOUNDATION_VERSION, gPxAllocator, gErrorCallback)); + if (!m_Foundation) + { + if (m_log) + { + m_log(NvBlastMessage::Error, "Error: failed to create Foundation\n", __FILE__, __LINE__); + } + return false; + } + physx::PxTolerancesScale scale; + m_PhysxSDK.reset(PxCreatePhysics(PX_PHYSICS_VERSION, *m_Foundation, scale, true)); + if (!m_PhysxSDK) + { + if (m_log) + { + m_log(NvBlastMessage::Error, "Error: failed to create PhysX\n", __FILE__, __LINE__); + } + return false; + } + +#if 0 + if (!PxInitExtensions(*mPhysxSDK, 0)) + { + if (m_log) + { + m_log(Error, "Error: failed to init PhysX extensions\n", __FILE__, __LINE__); + } + return false; + } +#endif + + physx::PxCookingParams cookingParams(scale); + cookingParams.buildGPUData = true; + m_Cooking.reset(PxCreateCooking(PX_PHYSICS_VERSION, m_PhysxSDK->getFoundation(), cookingParams)); + if (!m_Cooking) + { + m_log(NvBlastMessage::Error, "Error: failed to create PhysX Cooking\n", __FILE__, __LINE__); + return false; + } + + ////////////////////////////////////////////////////////////////////////////// + + ApexSDKDesc apexSDKDesc; + apexSDKDesc.physXSDK = m_PhysxSDK.get(); + apexSDKDesc.cooking = m_Cooking.get(); + apexSDKDesc.renderResourceManager = &gNullRenderer; + apexSDKDesc.resourceCallback = nullptr; + apexSDKDesc.foundation = &m_PhysxSDK->getFoundation(); + + m_ApexSDK.reset(CreateApexSDK(apexSDKDesc, nullptr, APEX_SDK_VERSION)); + if (!m_ApexSDK) + { + if (m_log) + { + m_log(NvBlastMessage::Error, "Error: failed to create APEX\n", __FILE__, __LINE__); + } + return false; + } + + ////////////////////////////////////////////////////////////////////////////// + + m_DestructibleModule.reset(static_cast<nvidia::apex::ModuleDestructible*>(m_ApexSDK->createModule("Destructible")), ApexReleaser(*m_ApexSDK)); + if (!m_DestructibleModule) + { + if (m_log) + { + m_log(NvBlastMessage::Error, "Error: failed to create ModuleDestructible\n", __FILE__, __LINE__); + } + return false; + } + + if (!m_ApexSDK->createModule("Legacy")) + { + if (m_log) + { + m_log(NvBlastMessage::Error, "Error: failed to create Legacy module\n", __FILE__, __LINE__); + } + return false; + }; + + + float massScaleExponenent = 1.f; + float massScale = 1.f; + + NvParameterized::Interface* params = m_DestructibleModule->getDefaultModuleDesc(); + NvParameterized::Handle paramsHandle(params); + paramsHandle.getParameter("scaledMassExponent"); + paramsHandle.setParamF32(massScaleExponenent); + paramsHandle.getParameter("massScale"); + paramsHandle.setParamF32(massScale); + m_DestructibleModule->init(*params); + + return true; +} + +DestructibleAsset* ApexDestruction::loadAsset(physx::PxFileBuf* stream) +{ + DestructibleAsset* asset = nullptr; + + if (stream && stream->isOpen()) + { + NvParameterized::Serializer::SerializeType serType = apexSDK()->getSerializeType(*stream); + NvParameterized::Serializer::ErrorType serError; + NvParameterized::Serializer* ser = apexSDK()->createSerializer(serType); + PX_ASSERT(ser); + + NvParameterized::Serializer::DeserializedData data; + 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")) + { + asset = static_cast<DestructibleAsset*>(apexSDK()->createAsset(params, "")); + } + else + { + m_log(NvBlastMessage::Error, "Error: deserialized data is not an APEX Destructible\n", __FILE__, __LINE__); + } + } + else + { + m_log(NvBlastMessage::Error, "Error: failed to deserialize\n", __FILE__, __LINE__); + } + ser->release(); + } + + if (!asset) + { + char message[255] = { 0 }; + sprintf(message, "Error: failed to load asset...\n"); + m_log(NvBlastMessage::Error, message, __FILE__, __LINE__); + } + + return asset; +} + +ApexDestruction::~ApexDestruction() +{ +} + +} // namespace Blast +} // namespace Nv diff --git a/NvBlast/sdk/extensions/import/source/NvBlastExtApexDestruction.h b/NvBlast/sdk/extensions/import/source/NvBlastExtApexDestruction.h new file mode 100644 index 0000000..6560aed --- /dev/null +++ b/NvBlast/sdk/extensions/import/source/NvBlastExtApexDestruction.h @@ -0,0 +1,108 @@ +/* +* Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved. +* +* NVIDIA CORPORATION and its licensors retain all intellectual property +* and proprietary rights in and to this software, 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. +*/ + +#ifndef NVBLASTEXTAPEXDESTRUCTION_H +#define NVBLASTEXTAPEXDESTRUCTION_H + +#include "ApexUsingNamespace.h" +#include "NvBlastExtScopedResource.h" +#include "PsUtilities.h" +#include <string> +#include <NvBlastTypes.h> +#include <PxFileBuf.h> + +namespace physx +{ + class PxFoundation; +} + + +namespace Nv +{ +namespace Blast +{ + +namespace ApexImporter +{ + /** + Class for working with APEX Destruction assets. + */ +class ApexDestruction +{ + PX_NOCOPY(ApexDestruction) + +public: + ApexDestruction(NvBlastLog log = NULL); + + ApexDestruction(nvidia::apex::ApexSDK* apexSdk, nvidia::apex::ModuleDestructible* moduleDestructible, NvBlastLog log = NULL); + ~ApexDestruction(); + + ////////////////////////////////////////////////////////////////////////////// + /** + ApexDestruction initialization. If APEX SDK and ModuleDestructible was provided to constructor, they will be used. + Otherwise, PhysXSDK and APEX SDK will be initialized. + */ + bool initialize(); + + /** + /return Return True if tool initialized sucessfully. + */ + bool isValid(); + + /** + Load Apex Destructible asset from PxFileBuf stream + \param[in] stream Apex asset stream + /return Return DestructibleAsset* if success, otherwise nullptr is returned. + */ + nvidia::apex::DestructibleAsset* loadAsset(physx::PxFileBuf* stream); + + /** + /return Return PxFoundation. + */ + physx::PxFoundation* foundation() { return m_Foundation.get(); } + /** + /return Return PxPhysics. + */ + physx::PxPhysics* physxSDK() { return m_PhysxSDK.get(); } + /** + /return Return PxCooking. + */ + physx::PxCooking* cooking() { return m_Cooking.get(); } + /** + /return Return ApexSDK. + */ + nvidia::apex::ApexSDK* apexSDK() { return m_ApexSDK.get(); } + + /** + /return Return ModuleDestructible. + */ + nvidia::apex::ModuleDestructible* destructibleModule() { return m_DestructibleModule.get(); } + +private: + bool hasLegacyModule; + NvBlastLog m_log; + ////////////////////////////////////////////////////////////////////////////// + +protected: + ScopedResource<physx::PxFoundation> m_Foundation; + ScopedResource<physx::PxPhysics> m_PhysxSDK; + ScopedResource<physx::PxCooking> m_Cooking; + ScopedResource<nvidia::apex::ApexSDK> m_ApexSDK; + ScopedResource<nvidia::apex::ModuleDestructible, ApexReleaser> m_DestructibleModule; + +}; + +} // namespace ApexImporter + +} // namespace Blast +} // namespace Nv + + +#endif // NVBLASTEXTAPEXDESTRUCTION_H diff --git a/NvBlast/sdk/extensions/import/source/NvBlastExtApexImportTool.cpp b/NvBlast/sdk/extensions/import/source/NvBlastExtApexImportTool.cpp new file mode 100644 index 0000000..d2def6f --- /dev/null +++ b/NvBlast/sdk/extensions/import/source/NvBlastExtApexImportTool.cpp @@ -0,0 +1,490 @@ +/* +* Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved. +* +* NVIDIA CORPORATION and its licensors retain all intellectual property +* and proprietary rights in and to this software, 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. +*/ + +#include "NvBlastExtApexImportTool.h" + +#if NV_VC +#pragma warning(push) +#pragma warning(disable: 4996) // 'fopen' unsafe warning, from NxFileBuffer.h +#endif + +#include "PxFoundation.h" +#include "PxErrorCallback.h" +#include "PxAllocatorCallback.h" + +#include "NvBlastIndexFns.h" +#include "DestructibleAsset.h" +#include "NvBlastExtApexDestruction.h" +#include <PxConvexMesh.h> +#include "PxPhysics.h" +#include "NvBlastExtAuthoringCollisionBuilder.h" +#include "NvBlastExtPxAsset.h" +#include "NvBlastExtAuthoringTypes.h" +#include "NvBlastExtAuthoringBondGenerator.h" + +using namespace nvidia; +using namespace apex; + +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); + } + }; + +ApexImportTool::ApexImportTool(NvBlastLog log) + : m_apexDestruction(NULL), m_log(log) +{ +} + + +bool ApexImportTool::isValid() +{ + return m_apexDestruction && m_apexDestruction->isValid(); +} + + +bool ApexImportTool::initialize() +{ + if (isValid()) + { + return true; + } + m_log(NvBlastMessage::Info, "APEX initialization \n", __FILE__, __LINE__); + m_apexDestruction = new ApexDestruction(m_log); + return isValid(); +} + + +bool ApexImportTool::initialize(nvidia::apex::ApexSDK* apexSdk, nvidia::apex::ModuleDestructible* moduleDestructible) +{ + if (isValid()) + { + return true; + } + m_log(NvBlastMessage::Info, "APEX initialization \n", __FILE__, __LINE__); + m_apexDestruction = new ApexDestruction(apexSdk, moduleDestructible, m_log); + return isValid(); +} + +DestructibleAsset* ApexImportTool::loadAssetFromFile(physx::PxFileBuf* stream) +{ + return m_apexDestruction->loadAsset(stream); +} + + +bool ApexImportTool::getCollisionGeometry(const nvidia::apex::DestructibleAsset* apexAsset, uint32_t chunkCount, std::vector<uint32_t>& chunkReorderInvMap, + const std::vector<uint32_t>& apexChunkFlags, std::vector<ExtPxAssetDesc::ChunkDesc>& physicsChunks, + std::vector<ExtPxAssetDesc::SubchunkDesc>& physicsSubchunks) +{ + physicsChunks.clear(); + physicsChunks.resize(chunkCount); + // prepare physics asset desc (convexes, transforms) + ConvexMeshBuilder collisionBuilder(m_apexDestruction->cooking(), &m_apexDestruction->apexSDK()->getPhysXSDK()->getPhysicsInsertionCallback()); + int32_t apexHullCount = 0; + const uint32_t apexChunkCount = apexAsset->getChunkCount(); + for (uint32_t chunkIndex = 0; chunkIndex < chunkCount; ++chunkIndex) + { + uint32_t apexChunkIndex = chunkReorderInvMap[chunkIndex]; + if (apexChunkIndex < apexChunkCount) + { + uint32_t partIndex = apexAsset->getPartIndex(apexChunkIndex); + apexHullCount += apexAsset->getPartConvexHullCount(partIndex); + } + } + physicsSubchunks.reserve(chunkCount); + { + for (uint32_t chunkIndex = 0; chunkIndex < chunkCount; ++chunkIndex) + { + uint32_t apexChunkIndex = chunkReorderInvMap[chunkIndex]; + if (apexChunkIndex < apexChunkCount) + { + uint32_t partIndex = apexAsset->getPartIndex(apexChunkIndex); + uint32_t partConvexHullCount = apexAsset->getPartConvexHullCount(partIndex); + NvParameterized::Interface** cxInterfaceArray = apexAsset->getPartConvexHullArray(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); + + PxConvexMesh* convexMesh = collisionBuilder.buildConvexMesh(vertexData); + + 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 + { + // this is earth chunk + physicsChunks[chunkIndex].isStatic = true; + } + } + } + + // check that vector didn't grow + if (static_cast<int32_t>(physicsSubchunks.size()) > apexHullCount) + { + m_log(NvBlastMessage::Error, "Error: sub chunk count seems to be wrong. \n", __FILE__, __LINE__); + return false; + } + return true; +} + +void gatherChunkHullPoints(const DestructibleAsset* apexAsset, std::vector<std::vector<PxVec3> >& hullPoints) +{ + hullPoints.resize(apexAsset->getChunkCount()); + for (uint32_t chunk = 0; chunk < apexAsset->getChunkCount(); ++chunk) + { + int32_t part = apexAsset->getPartIndex(chunk); + NvParameterized::Interface** cxInterfaceArray = apexAsset->getPartConvexHullArray(part); + for (uint32_t hull = 0; hull < apexAsset->getPartConvexHullCount(part); ++hull) + { + NvParameterized::Handle paramHandle(cxInterfaceArray[hull]); + int32_t verticesCount = 0; + paramHandle.getParameter("vertices"); + paramHandle.getArraySize(verticesCount); + uint32_t oldSize = (uint32_t)hullPoints[chunk].size(); + hullPoints[chunk].resize(hullPoints[chunk].size() + verticesCount); + paramHandle.getParamVec3Array(hullPoints[chunk].data() + oldSize, verticesCount); + } + } +} +PxBounds3 gatherChunkTriangles(const DestructibleAsset* apexAsset, std::vector<std::vector<Nv::Blast::Triangle> >& chunkTriangles, int32_t posBufferIndex, float scale, PxVec3 offset ) +{ + + PxBounds3 bnd; + bnd.setEmpty(); + chunkTriangles.clear(); + chunkTriangles.resize(apexAsset->getChunkCount()); + for (uint32_t chunkIndex = 0; chunkIndex < apexAsset->getChunkCount(); ++chunkIndex) + { + uint32_t part = apexAsset->getPartIndex(chunkIndex); + const RenderMeshAsset* rAsset = apexAsset->getRenderMeshAsset(); + uint32_t submeshCount = rAsset->getSubmeshCount(); + for (uint32_t submeshIndex = 0; submeshIndex < submeshCount; ++submeshIndex) + { + const RenderSubmesh& currentSubmesh = rAsset->getSubmesh(submeshIndex); + const uint32_t* indexArray = currentSubmesh.getIndexBuffer(part); + uint32_t indexCount = currentSubmesh.getIndexCount(part); + const PxVec3* positions = reinterpret_cast<const PxVec3*>(currentSubmesh.getVertexBuffer().getBuffer(posBufferIndex)); + + 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[chunkIndex].push_back(Nv::Blast::Triangle(a, b, c)); + } + } + } + return bnd; +} + +bool ApexImportTool::importApexAsset(std::vector<uint32_t>& chunkReorderInvMap, const nvidia::apex::DestructibleAsset* apexAsset, + std::vector<NvBlastChunkDesc>& chunkDescriptors, std::vector<NvBlastBondDesc>& bondDescriptors, std::vector<uint32_t>& apexChunkFlags) +{ + ApexImporterConfig configDesc; + configDesc.setDefaults(); + return importApexAsset(chunkReorderInvMap, apexAsset, chunkDescriptors, bondDescriptors, apexChunkFlags, configDesc); +} + + +bool ApexImportTool::importApexAsset(std::vector<uint32_t>& chunkReorderInvMap, const nvidia::apex::DestructibleAsset* apexAsset, + std::vector<NvBlastChunkDesc>& chunkDescriptors, std::vector<NvBlastBondDesc>& bondDescriptors, std::vector<uint32_t>& apexChunkFlags, const ApexImporterConfig& configDesc) +{ + return importApexAssetInternal(chunkReorderInvMap, apexAsset, chunkDescriptors, bondDescriptors, apexChunkFlags, configDesc); +} + + +bool ApexImportTool::importApexAssetInternal(std::vector<uint32_t>& chunkReorderInvMap, const nvidia::apex::DestructibleAsset* apexAsset, + std::vector<NvBlastChunkDesc>& chunkDescriptors, std::vector<NvBlastBondDesc>& bondsDescriptors, std::vector<uint32_t>& apexChunkFlags, const ApexImporterConfig& configDesc) +{ + + if (!apexAsset) + { + if (m_log != NULL) + { + m_log(NvBlastMessage::Error, "Error: attempting to import NULL Apex asset.\n", __FILE__, __LINE__); + } + return false; + } + + // Build chunk descriptors for asset // + const uint32_t apexChunkCount = apexAsset->getChunkCount(); + chunkDescriptors.clear(); + chunkDescriptors.resize(apexChunkCount); + uint32_t rootChunkIndex = 0; + + for (uint32_t i = 0; i < apexChunkCount; ++i) + { + // Use bounds center for centroid + const PxBounds3 bounds = apexAsset->getChunkActorLocalBounds(i); + const PxVec3 center = bounds.getCenter(); + memcpy(chunkDescriptors[i].centroid, ¢er.x, 3 * sizeof(float)); + + // Find chunk volume + uint32_t partIndex = apexAsset->getPartIndex(i); + uint32_t partConvexHullCount = apexAsset->getPartConvexHullCount(partIndex); + NvParameterized::Interface** cxInterfaceArray = apexAsset->getPartConvexHullArray(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; + } + + int32_t parent = apexAsset->getChunkParentIndex(i); + 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 = apexAsset->getAssetNvParameterized(); + uint32_t maximumSupportDepth = 0; + + NvParameterized::Handle parameterHandle(*assetParameterized); + parameterHandle.getParameter("supportDepth"); + parameterHandle.getParamU32(maximumSupportDepth); + std::vector<std::pair<uint32_t, uint32_t> > overlapsBuffer; + uint32_t overlapsCount = apexAsset->getCachedOverlapCountAtDepth(maximumSupportDepth); + if (overlapsCount != 0) + { + const IntPair* overlap = reinterpret_cast<const IntPair*>(apexAsset->getCachedOverlapsAtDepth(maximumSupportDepth)); + for (uint32_t i = 0; i < overlapsCount; ++i) + { + chunkDescriptors[overlap[i].i0].flags = NvBlastChunkDesc::SupportFlag; + chunkDescriptors[overlap[i].i1].flags = NvBlastChunkDesc::SupportFlag; + overlapsBuffer.push_back(std::make_pair(overlap[i].i0, overlap[i].i1)); + } + } + + // 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()); + + Nv::Blast::BlastBondGenerator bondGenTool(GetApexSDK()->getCookingInterface(), &GetApexSDK()->getPhysXSDK()->getPhysicsInsertionCallback()); + std::vector<std::vector<Nv::Blast::Triangle> > chunkTriangles; + + PxBounds3 bnds = apexAsset->getRenderMeshAsset()->getBounds(); + PxVec3 offset = bnds.getCenter(); + float scale = 1.0f / PxMax(PxAbs(bnds.getExtents(0)), PxMax(PxAbs(bnds.getExtents(1)), PxAbs(bnds.getExtents(2)))); + + bnds = gatherChunkTriangles(apexAsset, chunkTriangles, 0, scale, offset); + + + BondGenerationConfig cf; + cf.bondMode = BondGenerationConfig::AVERAGE; + if (configDesc.infSearchMode == configDesc.EXACT) + { + cf.bondMode = BondGenerationConfig::EXACT; + } + + bondGenTool.createBondBetweenMeshes(chunkTriangles, bondsDescriptors, overlapsBuffer, cf); + + + + 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()); + // special 'earth chunk' + { + uint32_t earthChunkIndex = (uint32_t)chunkDescriptors.size(); + NvBlastChunkDesc earthChunk; + memset(earthChunk.centroid, 0, 3 * sizeof(float)); + earthChunk.volume = 0.0f; + earthChunk.parentChunkIndex = rootChunkIndex; + earthChunk.flags = NvBlastChunkDesc::SupportFlag; + earthChunk.userData = earthChunkIndex; + uint32_t chunksConnectedToEarth = 0; + for (uint32_t i = 0; i < chunkDescriptors.size(); i++) + { + uint32_t chunkID = i; + const NvParameterized::Interface* assetInterface = apexAsset->getAssetNvParameterized(); + 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] = earthChunkIndex; + bond.bond.area = 0.1f; // ??? + PxVec3 center = apexAsset->getChunkActorLocalBounds(chunkID).getCenter(); + memcpy(&bond.bond.centroid, ¢er.x, sizeof(PxVec3)); + PxVec3 normal = PxVec3(0, 0, 1); + memcpy(&bond.bond.normal, &normal.x, sizeof(PxVec3)); + bondsDescriptors.push_back(bond); + chunksConnectedToEarth++; + } + } + if (chunksConnectedToEarth > 0) + { + chunkDescriptors.push_back(earthChunk); + } + } + + 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(), m_log); + NvBlastBuildAssetDescChunkReorderMap(chunkReorderMap.data(), chunkDescriptors.data(), chunkCount, scratch.data(), m_log); + NvBlastApplyAssetDescChunkReorderMapInplace(chunkDescriptors.data(), chunkCount, bondsDescriptors.data(), bondCount, chunkReorderMap.data(), scratch.data(), m_log); + chunkReorderInvMap.resize(chunkReorderMap.size()); + Nv::Blast::invertMap(chunkReorderInvMap.data(), chunkReorderMap.data(), static_cast<uint32_t>(chunkReorderMap.size())); + return true; +} + + +bool ApexImportTool::saveAsset(const NvBlastAsset* asset, PxFileBuf* stream) +{ + if (!asset) + { + if (m_log != NULL) + { + m_log(NvBlastMessage::Error, "Error: attempting to serialize NULL asset.\n", __FILE__, __LINE__); + } + return false; + } + if (!stream) + { + if (m_log != NULL) + { + m_log(NvBlastMessage::Error, "Error: bad output stream.\n", __FILE__, __LINE__); + } + return false; + } + const void* assetData = asset; + uint32_t assetDataSize = NvBlastAssetGetSize(asset, m_log); + stream->write(assetData, assetDataSize); + stream->close(); + if (m_log != NULL) + { + m_log(NvBlastMessage::Info, "Saving finished... \n", __FILE__, __LINE__); + } + return true; +} + + +ApexImportTool::~ApexImportTool() +{ + delete m_apexDestruction; +} + +} // namespace ApexImporter + +} // namespace Blast +} // namespace Nv diff --git a/NvBlast/sdk/extensions/import/source/NvBlastExtScopedResource.cpp b/NvBlast/sdk/extensions/import/source/NvBlastExtScopedResource.cpp new file mode 100644 index 0000000..7cf7492 --- /dev/null +++ b/NvBlast/sdk/extensions/import/source/NvBlastExtScopedResource.cpp @@ -0,0 +1,50 @@ +/* +* Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved. +* +* NVIDIA CORPORATION and its licensors retain all intellectual property +* and proprietary rights in and to this software, 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. +*/ + +#include "NvBlastExtScopedResource.h" + +#include <ApexSDK.h> +#include <RenderMeshAsset.h> +#include <DestructibleAsset.h> +#include <ModuleDestructible.h> + + +namespace Nv +{ +namespace Blast +{ + +namespace ApexImporter +{ + +void ApexReleaser::release(nvidia::apex::RenderMeshAssetAuthoring& a) +{ + if (mApex) + mApex->releaseAssetAuthoring(a); +} + + +void ApexReleaser::release(nvidia::apex::DestructibleAssetAuthoring& a) +{ + if (mApex) + mApex->releaseAssetAuthoring(a); +} + + +void ApexReleaser::release(nvidia::apex::ModuleDestructible& a) +{ + if (mApex) + mApex->releaseModule(&a); +} + +} // namespace ApexImporter + +} // namespace Blast +} // namespace Nv diff --git a/NvBlast/sdk/extensions/import/source/NvBlastExtScopedResource.h b/NvBlast/sdk/extensions/import/source/NvBlastExtScopedResource.h new file mode 100644 index 0000000..e0d35b7 --- /dev/null +++ b/NvBlast/sdk/extensions/import/source/NvBlastExtScopedResource.h @@ -0,0 +1,160 @@ +/* +* Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved. +* +* NVIDIA CORPORATION and its licensors retain all intellectual property +* and proprietary rights in and to this software, 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. +*/ + +#ifndef NVBLASTEXTSCOPEDRESOURCE_H +#define NVBLASTEXTSCOPEDRESOURCE_H + +#include <PxAssert.h> + + +#pragma warning(push) +#pragma warning(disable:4512) + +namespace nvidia +{ +namespace apex +{ +class ApexSDK; +class Asset; +class DestructibleAsset; +class AssetAuthoring; +class ModuleDestructible; +class RenderMeshAssetAuthoring; +class DestructibleAssetAuthoring; +} +} + +namespace Nv +{ +namespace Blast +{ + +namespace ApexImporter +{ + +template <class T> +class DefaultReleaser +{ +public: + DefaultReleaser() { } + PX_INLINE void release(T& t) { t.release(); } +}; + +class ApexReleaser +{ +public: + ApexReleaser() : mApex(nullptr) { } + ApexReleaser(nvidia::apex::ApexSDK& apex) : mApex(&apex) { } + + void release(nvidia::apex::RenderMeshAssetAuthoring&); + void release(nvidia::apex::DestructibleAssetAuthoring&); + void release(nvidia::apex::ModuleDestructible&); + +protected: + bool mbValid; + nvidia::apex::ApexSDK* mApex; +}; + +template< class Releasable, class Releaser = DefaultReleaser<Releasable> > +class ScopedResource +{ +public: + ScopedResource() + : mpReleasable(nullptr), mIsReleasable(true){} + + ScopedResource(Releasable* pReleasable, const Releaser& releaser) + : mpReleasable(pReleasable), + mReleaser(releaser), mIsReleasable(true) { } + + ScopedResource(Releasable* pReleasable, bool isReleasable = true) + : mpReleasable(pReleasable), mIsReleasable(isReleasable) { } + + ~ScopedResource() + { + destroy(); + } + + PX_INLINE operator bool() const + { + return (nullptr != mpReleasable); + } + + PX_INLINE Releasable* get() const + { + return mpReleasable; + } + + PX_INLINE Releasable* release() + { + Releasable* pReleasable = mpReleasable; + mpReleasable = nullptr; + return pReleasable; + } + + PX_INLINE Releasable& operator* () const + { + PX_ASSERT(*this); + return *mpReleasable; + } + + PX_INLINE Releasable* operator-> () const + { + return mpReleasable; + } + + PX_INLINE bool operator==(const ScopedResource& b) const + { + return mpReleasable == b.mpReleasable; + } + + PX_INLINE bool operator!=(const ScopedResource& b) const + { + return !(*this == b); + } + + PX_INLINE void reset(Releasable* pReleasable, bool isReleasable = true) + { + if (mpReleasable == pReleasable) return; + destroy(); + mpReleasable = pReleasable; + mIsReleasable = isReleasable; + } + + PX_INLINE void reset(Releasable* pReleasable, const Releaser& releaser, bool isReleasable = true) + { + reset(pReleasable); + mReleaser = releaser; + mIsReleasable = isReleasable; + } + +private: + + void destroy() + { + if (*this && mIsReleasable) + mReleaser.release(*mpReleasable); + } + + ScopedResource(const ScopedResource&); + ScopedResource& operator=(const ScopedResource&); + + Releasable* mpReleasable; + Releaser mReleaser; + bool mIsReleasable; +}; + +} // namespace ApexImporter + +} // namespace Blast +} // namespace Nv + +#pragma warning(pop) + +#endif // NVBLASTEXTSCOPEDRESOURCE_H |