aboutsummaryrefslogtreecommitdiff
path: root/APEX_1.4/module/clothing/src/ModuleClothingImpl.cpp
diff options
context:
space:
mode:
authorgit perforce import user <a@b>2016-10-25 12:29:14 -0600
committerSheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees>2016-10-25 18:56:37 -0500
commit3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch)
treefa6485c169e50d7415a651bf838f5bcd0fd3bfbd /APEX_1.4/module/clothing/src/ModuleClothingImpl.cpp
downloadphysx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz
physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip
Initial commit:
PhysX 3.4.0 Update @ 21294896 APEX 1.4.0 Update @ 21275617 [CL 21300167]
Diffstat (limited to 'APEX_1.4/module/clothing/src/ModuleClothingImpl.cpp')
-rw-r--r--APEX_1.4/module/clothing/src/ModuleClothingImpl.cpp1210
1 files changed, 1210 insertions, 0 deletions
diff --git a/APEX_1.4/module/clothing/src/ModuleClothingImpl.cpp b/APEX_1.4/module/clothing/src/ModuleClothingImpl.cpp
new file mode 100644
index 00000000..0baec7bb
--- /dev/null
+++ b/APEX_1.4/module/clothing/src/ModuleClothingImpl.cpp
@@ -0,0 +1,1210 @@
+/*
+ * Copyright (c) 2008-2015, 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 "ApexDefs.h"
+
+#include "ApexAuthorableObject.h"
+#include "ApexIsoMesh.h"
+#include "ApexSubdivider.h"
+#include "ApexSharedUtils.h"
+
+#include "RenderMeshAssetIntl.h"
+#include <limits.h>
+#include <new>
+
+#include "PxCudaContextManager.h"
+#include "Factory.h"
+
+#include "ModuleClothingImpl.h"
+#include "ModuleClothingRegistration.h"
+
+#include "ClothingAssetImpl.h"
+#include "ClothingAssetAuthoringImpl.h"
+#include "ClothingPhysicalMeshImpl.h"
+#include "SceneIntl.h"
+
+#include "ClothingScene.h"
+#include "ModulePerfScope.h"
+
+#include "CookingPhysX.h"
+#include "Cooking.h"
+#include "Simulation.h"
+
+#include "ApexSDKIntl.h"
+#include "ApexUsingNamespace.h"
+
+#if APEX_CUDA_SUPPORT
+#include "CuFactory.h"
+#endif
+
+#include "ApexPvdClient.h"
+
+using namespace clothing;
+using namespace physx::pvdsdk;
+
+#define INIT_PVD_CLASSES_PARAMETERIZED( parameterizedClassName ) { \
+ pvdStream.createClass(NamespacedName(APEX_PVD_NAMESPACE, #parameterizedClassName)); \
+ parameterizedClassName* params = DYNAMIC_CAST(parameterizedClassName*)(GetInternalApexSDK()->getParameterizedTraits()->createNvParameterized(#parameterizedClassName)); \
+ client->initPvdClasses(*params->rootParameterDefinition(), #parameterizedClassName); \
+ params->destroy(); }
+
+
+namespace nvidia
+{
+namespace apex
+{
+
+#if defined(_USRDLL) || PX_OSX
+
+/* Modules don't have to link against the framework, they keep their own */
+ApexSDKIntl* gApexSdk = 0;
+ApexSDK* GetApexSDK()
+{
+ return gApexSdk;
+}
+ApexSDKIntl* GetInternalApexSDK()
+{
+ return gApexSdk;
+}
+
+APEX_API Module* CALL_CONV createModule(
+ ApexSDKIntl* inSdk,
+ ModuleIntl** niRef,
+ uint32_t APEXsdkVersion,
+ uint32_t PhysXsdkVersion,
+ ApexCreateError* errorCode)
+{
+ if (APEXsdkVersion != APEX_SDK_VERSION)
+ {
+ if (errorCode)
+ {
+ *errorCode = APEX_CE_WRONG_VERSION;
+ }
+ return NULL;
+ }
+
+ if (PhysXsdkVersion != PX_PHYSICS_VERSION)
+ {
+ if (errorCode)
+ {
+ *errorCode = APEX_CE_WRONG_VERSION;
+ }
+ return NULL;
+ }
+
+ gApexSdk = inSdk;
+ clothing::ModuleClothingImpl* impl = PX_NEW(clothing::ModuleClothingImpl)(inSdk);
+ *niRef = (ModuleIntl*) impl;
+ return (Module*) impl;
+}
+
+#else // !defined(_USRDLL) && !PX_OSX
+
+/* Statically linking entry function */
+void instantiateModuleClothing()
+{
+ using namespace clothing;
+ ApexSDKIntl* sdk = GetInternalApexSDK();
+ clothing::ModuleClothingImpl* impl = PX_NEW(clothing::ModuleClothingImpl)(sdk);
+ sdk->registerExternalModule((Module*) impl, (ModuleIntl*) impl);
+}
+#endif // !defined(_USRDLL) && !PX_OSX
+}
+
+namespace clothing
+{
+
+// This is needed to have an actor assigned to every PxActor, even if they currently don't belong to an ClothingActor
+class DummyActor : public Actor, public UserAllocated, public ApexRWLockable
+{
+public:
+ APEX_RW_LOCKABLE_BOILERPLATE
+
+ DummyActor(Asset* owner) : mOwner(owner) {}
+ void release()
+ {
+ PX_DELETE(this);
+ }
+ Asset* getOwner() const
+ {
+ return mOwner;
+ }
+
+ void getLodRange(float& min, float& max, bool& intOnly) const
+ {
+ PX_UNUSED(min);
+ PX_UNUSED(max);
+ PX_UNUSED(intOnly);
+ }
+
+ float getActiveLod() const
+ {
+ return -1.0f;
+ }
+
+ void forceLod(float lod)
+ {
+ PX_UNUSED(lod);
+ }
+
+ /**
+ \brief Selectively enables/disables debug visualization of a specific APEX actor. Default value it true.
+ */
+ virtual void setEnableDebugVisualization(bool state)
+ {
+ PX_UNUSED(state);
+ }
+
+private:
+ Asset* mOwner;
+};
+
+
+
+// This is needed to for every dummy actor to point to an asset that in turn has the right object type id.
+class DummyAsset : public Asset, public UserAllocated, public ApexRWLockable
+{
+public:
+ APEX_RW_LOCKABLE_BOILERPLATE
+
+ DummyAsset(AuthObjTypeID assetTypeID) : mAssetTypeID(assetTypeID) {};
+
+ void release()
+ {
+ PX_DELETE(this);
+ }
+
+ virtual const char* getName() const
+ {
+ return NULL;
+ }
+ virtual AuthObjTypeID getObjTypeID() const
+ {
+ return mAssetTypeID;
+ }
+ virtual const char* getObjTypeName() const
+ {
+ return NULL;
+ }
+ virtual uint32_t forceLoadAssets()
+ {
+ return 0;
+ }
+ virtual const NvParameterized::Interface* getAssetNvParameterized() const
+ {
+ return NULL;
+ }
+
+ NvParameterized::Interface* getDefaultActorDesc()
+ {
+ PX_ALWAYS_ASSERT();
+ return NULL;
+ };
+ NvParameterized::Interface* getDefaultAssetPreviewDesc()
+ {
+ PX_ALWAYS_ASSERT();
+ return NULL;
+ };
+
+ virtual Actor* createApexActor(const NvParameterized::Interface& /*parms*/, Scene& /*apexScene*/)
+ {
+ PX_ALWAYS_ASSERT();
+ return NULL;
+ }
+
+ virtual AssetPreview* createApexAssetPreview(const ::NvParameterized::Interface& /*params*/, AssetPreviewScene* /*previewScene*/)
+ {
+ PX_ALWAYS_ASSERT();
+ return NULL;
+ }
+
+ virtual bool isValidForActorCreation(const ::NvParameterized::Interface& /*parms*/, Scene& /*apexScene*/) const
+ {
+ return true; // TODO implement this method
+ }
+
+ virtual bool isDirty() const
+ {
+ return false;
+ }
+
+
+ /**
+ * \brief Releases the ApexAsset but returns the NvParameterized::Interface and *ownership* to the caller.
+ */
+ virtual NvParameterized::Interface* releaseAndReturnNvParameterizedInterface(void)
+ {
+ return NULL;
+ }
+
+private:
+ AuthObjTypeID mAssetTypeID;
+};
+
+ModuleClothingImpl::ModuleClothingImpl(ApexSDKIntl* inSdk)
+ : mDummyActor(NULL)
+ , mDummyAsset(NULL)
+ , mModuleParams(NULL)
+ , mApexClothingActorParams(NULL)
+ , mApexClothingPreviewParams(NULL)
+ , mCpuFactory(NULL)
+ , mCpuFactoryReferenceCount(0)
+#if APEX_CUDA_SUPPORT
+ , mGpuDllHandle(NULL)
+ , mPxCreateCuFactoryFunc(NULL)
+#endif
+{
+ mInternalModuleParams.maxNumCompartments = 4;
+ mInternalModuleParams.maxUnusedPhysXResources = 5;
+ mInternalModuleParams.allowAsyncCooking = true;
+ mInternalModuleParams.avgSimFrequencyWindow = 60;
+ mInternalModuleParams.allowApexWorkBetweenSubsteps = true;
+ mInternalModuleParams.interCollisionDistance = 0.0f;
+ mInternalModuleParams.interCollisionStiffness = 1.0f;
+ mInternalModuleParams.interCollisionIterations = 1;
+ mInternalModuleParams.sparseSelfCollision = false;
+ mInternalModuleParams.maxTimeRenderProxyInPool = 100;
+ PX_COMPILE_TIME_ASSERT(sizeof(mInternalModuleParams) == 40); // don't forget to init the new param here (and then update this assert)
+
+ mName = "Clothing";
+ mSdk = inSdk;
+ mApiProxy = this;
+
+ NvParameterized::Traits* traits = mSdk->getParameterizedTraits();
+ if (traits)
+ {
+ ModuleClothingRegistration::invokeRegistration(traits);
+ mApexClothingActorParams = traits->createNvParameterized(ClothingActorParam::staticClassName());
+ mApexClothingPreviewParams = traits->createNvParameterized(ClothingPreviewParam::staticClassName());
+ }
+
+#if APEX_CUDA_SUPPORT
+ // Since we split out the GPU code, we load the module and create the CuFactory ourselves
+ ApexSimpleString gpuClothingDllName;
+ PX_COMPILE_TIME_ASSERT(sizeof(HMODULE) == sizeof(mGpuDllHandle));
+ {
+ ModuleUpdateLoader moduleLoader(UPDATE_LOADER_DLL_NAME);
+
+#define APEX_CLOTHING_GPU_DLL_PREFIX "APEX_ClothingGPU"
+
+#ifdef PX_PHYSX_DLL_NAME_POSTFIX
+# if PX_X86
+ static const char* gpuClothingDllPrefix = APEX_CLOTHING_GPU_DLL_PREFIX PX_STRINGIZE(PX_PHYSX_DLL_NAME_POSTFIX) "_x86";
+# elif PX_X64
+ static const char* gpuClothingDllPrefix = APEX_CLOTHING_GPU_DLL_PREFIX PX_STRINGIZE(PX_PHYSX_DLL_NAME_POSTFIX) "_x64";
+# endif
+#else
+# if PX_X86
+ static const char* gpuClothingDllPrefix = APEX_CLOTHING_GPU_DLL_PREFIX "_x86";
+# elif PX_X64
+ static const char* gpuClothingDllPrefix = APEX_CLOTHING_GPU_DLL_PREFIX "_x64";
+# endif
+#endif
+
+#undef APEX_CLOTHING_GPU_DLL_PREFIX
+
+ gpuClothingDllName = ApexSimpleString(gpuClothingDllPrefix);
+
+ // applications can append strings to the APEX DLL filenames, support this with getCustomDllNamePostfix()
+ gpuClothingDllName += ApexSimpleString(GetInternalApexSDK()->getCustomDllNamePostfix());
+ gpuClothingDllName += ApexSimpleString(".dll");
+
+ mGpuDllHandle = moduleLoader.loadModule(gpuClothingDllName.c_str(), GetInternalApexSDK()->getAppGuid());
+ }
+
+ if (mGpuDllHandle)
+ {
+ mPxCreateCuFactoryFunc = (PxCreateCuFactory_FUNC*)GetProcAddress((HMODULE)mGpuDllHandle, "PxCreateCuFactory");
+ if (mPxCreateCuFactoryFunc == NULL)
+ {
+ APEX_DEBUG_WARNING("Failed to find method PxCreateCuFactory in dll \'%s\'", gpuClothingDllName.c_str());
+ FreeLibrary((HMODULE)mGpuDllHandle);
+ mGpuDllHandle = NULL;
+ }
+ }
+ else if (!gpuClothingDllName.empty())
+ {
+ APEX_DEBUG_WARNING("Failed to load the GPU dll \'%s\'", gpuClothingDllName.c_str());
+ }
+#endif
+}
+
+
+
+AuthObjTypeID ModuleClothingImpl::getModuleID() const
+{
+ return ClothingAssetImpl::mAssetTypeID;
+}
+
+
+
+RenderableIterator* ModuleClothingImpl::createRenderableIterator(const Scene& apexScene)
+{
+ ClothingScene* cs = getClothingScene(apexScene);
+ if (cs)
+ {
+ return cs->createRenderableIterator();
+ }
+
+ return NULL;
+}
+
+#ifdef WITHOUT_APEX_AUTHORING
+
+class ClothingAssetDummyAuthoring : public AssetAuthoring, public UserAllocated
+{
+public:
+ ClothingAssetDummyAuthoring(ModuleClothingImpl* module, ResourceList& list, NvParameterized::Interface* params, const char* name)
+ {
+ PX_UNUSED(module);
+ PX_UNUSED(list);
+ PX_UNUSED(params);
+ PX_UNUSED(name);
+ }
+
+ ClothingAssetDummyAuthoring(ModuleClothingImpl* module, ResourceList& list, const char* name)
+ {
+ PX_UNUSED(module);
+ PX_UNUSED(list);
+ PX_UNUSED(name);
+ }
+
+ ClothingAssetDummyAuthoring(ModuleClothingImpl* module, ResourceList& list)
+ {
+ PX_UNUSED(module);
+ PX_UNUSED(list);
+ }
+
+ virtual ~ClothingAssetDummyAuthoring() {}
+
+ virtual void setToolString(const char* /*toolName*/, const char* /*toolVersion*/, uint32_t /*toolChangelist*/)
+ {
+
+ }
+
+
+ virtual void release()
+ {
+ destroy();
+ }
+
+ // internal
+ void destroy()
+ {
+ PX_DELETE(this);
+ }
+
+ /**
+ * \brief Returns the name of this APEX authorable object type
+ */
+ virtual const char* getObjTypeName() const
+ {
+ return CLOTHING_AUTHORING_TYPE_NAME;
+ }
+
+ /**
+ * \brief Prepares a fully authored Asset Authoring object for a specified platform
+ */
+ virtual bool prepareForPlatform(nvidia::apex::PlatformTag)
+ {
+ PX_ASSERT(0);
+ return false;
+ }
+
+ const char* getName(void) const
+ {
+ return NULL;
+ }
+
+ /**
+ * \brief Save asset's NvParameterized interface, may return NULL
+ */
+ virtual NvParameterized::Interface* getNvParameterized() const
+ {
+ PX_ASSERT(0);
+ return NULL; //ClothingAssetImpl::getAssetNvParameterized();
+ }
+
+ virtual NvParameterized::Interface* releaseAndReturnNvParameterizedInterface(void)
+ {
+ PX_ALWAYS_ASSERT();
+ return NULL;
+ }
+
+};
+
+typedef ApexAuthorableObject<ModuleClothingImpl, ClothingAssetImpl, ClothingAssetDummyAuthoring> ClothingAO;
+#else
+typedef ApexAuthorableObject<ModuleClothingImpl, ClothingAssetImpl, ClothingAssetAuthoringImpl> ClothingAO;
+#endif
+
+NvParameterized::Interface* ModuleClothingImpl::getDefaultModuleDesc()
+{
+ NvParameterized::Traits* traits = mSdk->getParameterizedTraits();
+
+ if (!mModuleParams)
+ {
+ mModuleParams = DYNAMIC_CAST(ClothingModuleParameters*)
+ (traits->createNvParameterized("ClothingModuleParameters"));
+ PX_ASSERT(mModuleParams);
+ }
+ else
+ {
+ mModuleParams->initDefaults();
+ }
+
+ const NvParameterized::Hint* hint = NULL;
+ NvParameterized::Handle h(mModuleParams);
+
+ h.getParameter("maxNumCompartments");
+ PX_ASSERT(h.isValid());
+#if PX_WINDOWS_FAMILY
+ hint = h.parameterDefinition()->hint("defaultValueWindows");
+#else
+ hint = h.parameterDefinition()->hint("defaultValueConsoles");
+#endif
+ PX_ASSERT(hint);
+ if (hint)
+ {
+ mModuleParams->maxNumCompartments = (uint32_t)hint->asUInt();
+ }
+
+ return mModuleParams;
+}
+
+
+
+void ModuleClothingImpl::init(NvParameterized::Interface& desc)
+{
+ if (::strcmp(desc.className(), ClothingModuleParameters::staticClassName()) == 0)
+ {
+ ClothingModuleParameters* params = DYNAMIC_CAST(ClothingModuleParameters*)(&desc);
+ mInternalModuleParams = *params;
+ }
+ else
+ {
+ APEX_INVALID_PARAMETER("The NvParameterized::Interface object is of the wrong type");
+ }
+
+
+ ClothingAO* AOClothingAsset = PX_NEW(ClothingAO)(this, mAssetAuthorableObjectFactories, ClothingAssetParameters::staticClassName());
+ ClothingAssetImpl::mAssetTypeID = AOClothingAsset->getResID();
+ registerBackendFactory(&mBackendFactory);
+
+
+#ifndef WITHOUT_PVD
+ AOClothingAsset->mAssets.setupForPvd(mApiProxy, "ClothingAssets", "ClothingAsset");
+
+ // handle case if module is created after pvd connection
+ pvdsdk::ApexPvdClient* client = mSdk->getApexPvdClient();
+ if (client != NULL)
+ {
+ if (client->isConnected() && client->getPxPvd().getInstrumentationFlags() & PxPvdInstrumentationFlag::eDEBUG)
+ {
+ pvdsdk::PvdDataStream* pvdStream = client->getDataStream();
+ if (pvdStream != NULL)
+ {
+ pvdsdk::NamespacedName pvdModuleName(APEX_PVD_NAMESPACE, getName());
+ pvdStream->createClass(pvdModuleName);
+ initPvdClasses(*pvdStream);
+
+ ModuleBase* nxModule = static_cast<ModuleBase*>(this);
+ pvdStream->createInstance(pvdModuleName, nxModule);
+ pvdStream->pushBackObjectRef(mSdk, "Modules", nxModule);
+ initPvdInstances(*pvdStream);
+ }
+ }
+ }
+#endif
+}
+
+
+
+ClothingPhysicalMesh* ModuleClothingImpl::createEmptyPhysicalMesh()
+{
+ WRITE_ZONE();
+ return createPhysicalMeshInternal(NULL);
+}
+
+
+
+ClothingPhysicalMesh* ModuleClothingImpl::createSingleLayeredMesh(RenderMeshAssetAuthoring* asset, uint32_t subdivisionSize, bool mergeVertices, bool closeHoles, IProgressListener* progress)
+{
+ WRITE_ZONE();
+ return createSingleLayeredMeshInternal(DYNAMIC_CAST(RenderMeshAssetAuthoringIntl*)(asset), subdivisionSize, mergeVertices, closeHoles, progress);
+}
+
+
+
+void ModuleClothingImpl::destroy()
+{
+ mClothingSceneList.clear();
+
+ if (mApexClothingActorParams != NULL)
+ {
+ mApexClothingActorParams->destroy();
+ mApexClothingActorParams = NULL;
+ }
+
+ if (mApexClothingPreviewParams != NULL)
+ {
+ mApexClothingPreviewParams->destroy();
+ mApexClothingPreviewParams = NULL;
+ }
+
+#if APEX_CUDA_SUPPORT
+ for (PxU32 i = 0; i < mGpuFactories.size(); i++)
+ {
+ //APEX_DEBUG_INFO("Release Gpu factory %d", i);
+ PX_DELETE(mGpuFactories[i].factoryGpu);
+ mGpuFactories.replaceWithLast(i);
+ }
+#endif
+ PX_DELETE(mCpuFactory);
+ mCpuFactory = NULL;
+
+#ifndef WITHOUT_PVD
+ destroyPvdInstances();
+#endif
+ if (mModuleParams != NULL)
+ {
+ mModuleParams->destroy();
+ mModuleParams = NULL;
+ }
+
+ if (mDummyActor != NULL)
+ {
+ mDummyActor->release();
+ mDummyActor = NULL;
+ }
+
+ if (mDummyAsset != NULL)
+ {
+ mDummyAsset->release();
+ mDummyAsset = NULL;
+ }
+
+ NvParameterized::Traits* traits = mSdk->getParameterizedTraits();
+
+ ModuleBase::destroy();
+
+ mAssetAuthorableObjectFactories.clear(); // needs to be done before destructor!
+
+#if APEX_CUDA_SUPPORT
+ if (mGpuDllHandle != NULL)
+ {
+ FreeLibrary((HMODULE)mGpuDllHandle);
+ }
+#endif
+
+ if (traits)
+ {
+ ModuleClothingRegistration::invokeUnregistration(traits);
+ }
+ PX_DELETE(this);
+}
+
+
+
+ModuleSceneIntl* ModuleClothingImpl::createInternalModuleScene(SceneIntl& scene, RenderDebugInterface* renderDebug)
+{
+ return PX_NEW(ClothingScene)(*this, scene, renderDebug, mClothingSceneList);
+}
+
+
+
+void ModuleClothingImpl::releaseModuleSceneIntl(ModuleSceneIntl& scene)
+{
+ ClothingScene* clothingScene = DYNAMIC_CAST(ClothingScene*)(&scene);
+ clothingScene->destroy();
+}
+
+
+
+uint32_t ModuleClothingImpl::forceLoadAssets()
+{
+ uint32_t loadedAssetCount = 0;
+ for (uint32_t i = 0; i < mAssetAuthorableObjectFactories.getSize(); i++)
+ {
+ AuthorableObjectIntl* ao = static_cast<AuthorableObjectIntl*>(mAssetAuthorableObjectFactories.getResource(i));
+ loadedAssetCount += ao->forceLoadAssets();
+ }
+ return loadedAssetCount;
+}
+
+
+
+#ifndef WITHOUT_PVD
+void ModuleClothingImpl::initPvdClasses(pvdsdk::PvdDataStream& pvdStream)
+{
+ NamespacedName objRef = getPvdNamespacedNameForType<ObjectRef>();
+
+ // ---------------------------------------
+ // Hierarchy
+
+ // ModuleBase holds ClothingAssets
+ pvdStream.createClass(NamespacedName(APEX_PVD_NAMESPACE, "ClothingAsset"));
+ pvdStream.createProperty(NamespacedName(APEX_PVD_NAMESPACE, getName()), "ClothingAssets", "children", objRef, PropertyType::Array);
+
+ // ClothingAsset holds ClothingActors
+ pvdStream.createClass(NamespacedName(APEX_PVD_NAMESPACE, "ClothingActor"));
+ pvdStream.createProperty(NamespacedName(APEX_PVD_NAMESPACE, "ClothingAsset"), "ClothingActors", "children", objRef, PropertyType::Array);
+
+
+ // ---------------------------------------
+ // NvParameterized
+ pvdsdk::ApexPvdClient* client = GetInternalApexSDK()->getApexPvdClient();
+ PX_ASSERT(client != NULL);
+
+ // ModuleBase Params
+ INIT_PVD_CLASSES_PARAMETERIZED(ClothingModuleParameters);
+ pvdStream.createProperty(NamespacedName(APEX_PVD_NAMESPACE, getName()), "ModuleParams", "", objRef, PropertyType::Scalar);
+
+ // Asset Params
+
+ INIT_PVD_CLASSES_PARAMETERIZED(ClothingPhysicalMeshParameters);
+ INIT_PVD_CLASSES_PARAMETERIZED(ClothingGraphicalLodParameters);
+ INIT_PVD_CLASSES_PARAMETERIZED(ClothingCookedParam);
+ INIT_PVD_CLASSES_PARAMETERIZED(ClothingCookedPhysX3Param);
+ INIT_PVD_CLASSES_PARAMETERIZED(ClothingMaterialLibraryParameters);
+ INIT_PVD_CLASSES_PARAMETERIZED(ClothingAssetParameters);
+ pvdStream.createProperty(NamespacedName(APEX_PVD_NAMESPACE, "ClothingAsset"), "AssetParams", "", objRef, PropertyType::Scalar);
+
+ // Actor Params
+ INIT_PVD_CLASSES_PARAMETERIZED(ClothingActorParam);
+ pvdStream.createProperty(NamespacedName(APEX_PVD_NAMESPACE, "ClothingActor"), "ActorParams", "", objRef, PropertyType::Scalar);
+
+
+ // ---------------------------------------
+ // Additional Properties
+
+ // ---------------------------------------
+}
+
+
+
+void ModuleClothingImpl::initPvdInstances(pvdsdk::PvdDataStream& pvdStream)
+{
+ // if there's more than one AOFactory we don't know any more for sure that its a clothing asset factory, so we have to adapt the code below
+ PX_ASSERT(mAssetAuthorableObjectFactories.getSize() == 1 && "Adapt the code below");
+
+ pvdsdk::ApexPvdClient* client = GetInternalApexSDK()->getApexPvdClient();
+ PX_ASSERT(client != NULL);
+
+ // ModuleBase Params
+ pvdStream.createInstance(NamespacedName(APEX_PVD_NAMESPACE, "ClothingModuleParameters"), mModuleParams);
+ pvdStream.setPropertyValue(mApiProxy, "ModuleParams", DataRef<const uint8_t>((const uint8_t*)&mModuleParams, sizeof(ClothingModuleParameters*)), getPvdNamespacedNameForType<ObjectRef>());
+ // update module properties (should we do this per frame? if so, how?)
+ client->updatePvd(mModuleParams, *mModuleParams);
+
+ // prepare asset list and forward init calls
+ AuthorableObjectIntl* ao = static_cast<AuthorableObjectIntl*>(mAssetAuthorableObjectFactories.getResource(0));
+ ao->mAssets.initPvdInstances(pvdStream);
+}
+
+
+
+void ModuleClothingImpl::destroyPvdInstances()
+{
+ pvdsdk::ApexPvdClient* client = GetInternalApexSDK()->getApexPvdClient();
+ if (client != NULL)
+ {
+ if (client->isConnected() && client->getPxPvd().getInstrumentationFlags() & PxPvdInstrumentationFlag::eDEBUG)
+ {
+ pvdsdk::PvdDataStream* pvdStream = client->getDataStream();
+ {
+ if (pvdStream != NULL)
+ {
+ client->updatePvd(mModuleParams, *mModuleParams, pvdsdk::PvdAction::DESTROY);
+ pvdStream->destroyInstance(mModuleParams);
+ }
+ }
+ }
+ }
+}
+#endif
+
+
+ClothingScene* ModuleClothingImpl::getClothingScene(const Scene& apexScene)
+{
+ const SceneIntl* niScene = DYNAMIC_CAST(const SceneIntl*)(&apexScene);
+ for (uint32_t i = 0 ; i < mClothingSceneList.getSize() ; i++)
+ {
+ ClothingScene* clothingScene = DYNAMIC_CAST(ClothingScene*)(mClothingSceneList.getResource(i));
+ if (clothingScene->mApexScene == niScene)
+ {
+ return clothingScene;
+ }
+ }
+
+ PX_ASSERT(!"Unable to locate an appropriate ClothingScene");
+ return NULL;
+}
+
+
+
+ClothingPhysicalMeshImpl* ModuleClothingImpl::createPhysicalMeshInternal(ClothingPhysicalMeshParameters* mesh)
+{
+ ClothingPhysicalMeshImpl* result = PX_NEW(ClothingPhysicalMeshImpl)(this, mesh, &mPhysicalMeshes);
+ return result;
+}
+
+
+
+void ModuleClothingImpl::releasePhysicalMesh(ClothingPhysicalMeshImpl* physicalMesh)
+{
+ physicalMesh->destroy();
+}
+
+
+
+void ModuleClothingImpl::unregisterAssetWithScenes(ClothingAssetImpl* asset)
+{
+ for (uint32_t i = 0; i < mClothingSceneList.getSize(); i++)
+ {
+ ClothingScene* clothingScene = static_cast<ClothingScene*>(mClothingSceneList.getResource(i));
+ clothingScene->unregisterAsset(asset);
+ }
+}
+
+
+void ModuleClothingImpl::notifyReleaseGraphicalData(ClothingAssetImpl* asset)
+{
+ for (uint32_t i = 0; i < mClothingSceneList.getSize(); i++)
+ {
+ ClothingScene* clothingScene = static_cast<ClothingScene*>(mClothingSceneList.getResource(i));
+ clothingScene->removeRenderProxies(asset);
+ }
+}
+
+
+Actor* ModuleClothingImpl::getDummyActor()
+{
+ mDummyProtector.lock();
+ if (mDummyActor == NULL)
+ {
+ PX_ASSERT(mDummyAsset == NULL);
+ mDummyAsset = PX_NEW(DummyAsset)(getModuleID());
+ mDummyActor = PX_NEW(DummyActor)(mDummyAsset);
+ }
+ mDummyProtector.unlock();
+
+ return mDummyActor;
+}
+
+
+
+void ModuleClothingImpl::registerBackendFactory(BackendFactory* factory)
+{
+ for (uint32_t i = 0; i < mBackendFactories.size(); i++)
+ {
+ if (::strcmp(mBackendFactories[i]->getName(), factory->getName()) == 0)
+ {
+ return;
+ }
+ }
+
+ mBackendFactories.pushBack(factory);
+}
+
+
+
+void ModuleClothingImpl::unregisterBackendFactory(BackendFactory* factory)
+{
+ uint32_t read = 0, write = 0;
+
+ while (read < mBackendFactories.size())
+ {
+ mBackendFactories[write] = mBackendFactories[read];
+
+ if (mBackendFactories[read] == factory)
+ {
+ read++;
+ }
+ else
+ {
+ read++, write++;
+ }
+ }
+
+ while (read < write)
+ {
+ mBackendFactories.popBack();
+ }
+}
+
+
+
+BackendFactory* ModuleClothingImpl::getBackendFactory(const char* simulationBackend)
+{
+ PX_ASSERT(simulationBackend != NULL);
+
+ for (uint32_t i = 0; i < mBackendFactories.size(); i++)
+ {
+ if (mBackendFactories[i]->isMatch(simulationBackend))
+ {
+ return mBackendFactories[i];
+ }
+ }
+
+ //APEX_INVALID_OPERATION("Simulation back end \'%s\' not found, using \'PhysX\' instead\n", simulationBackend);
+
+ PX_ASSERT(mBackendFactories.size() >= 1);
+ return mBackendFactories[0];
+}
+
+
+
+ClothFactory ModuleClothingImpl::createClothFactory(PxCudaContextManager* contextManager)
+{
+ nvidia::Mutex::ScopedLock lock(mFactoryMutex);
+
+#if APEX_CUDA_SUPPORT
+
+ if (contextManager != NULL && contextManager->supportsArchSM20())
+ {
+ for (uint32_t i = 0; i < mGpuFactories.size(); i++)
+ {
+ if (mGpuFactories[i].contextManager == contextManager)
+ {
+ mGpuFactories[i].referenceCount++;
+ //APEX_DEBUG_INFO("Found Gpu factory %d (ref = %d)", i, mGpuFactories[i].referenceCount);
+ return ClothFactory(mGpuFactories[i].factoryGpu, &mFactoryMutex);
+ }
+ }
+
+ // nothing found
+ if (mPxCreateCuFactoryFunc != NULL)
+ {
+ GpuFactoryEntry entry(mPxCreateCuFactoryFunc(contextManager), contextManager);
+ if (entry.factoryGpu != NULL)
+ {
+ //APEX_DEBUG_INFO("Create Gpu factory %d", mGpuFactories.size());
+ entry.referenceCount = 1;
+ mGpuFactories.pushBack(entry);
+ return ClothFactory(entry.factoryGpu, &mFactoryMutex);
+ }
+ }
+
+ return ClothFactory(NULL, &mFactoryMutex);
+ }
+ else
+#else
+ PX_UNUSED(contextManager);
+#endif
+ {
+ if (mCpuFactory == NULL)
+ {
+ mCpuFactory = cloth::Factory::createFactory(cloth::Factory::CPU);
+ //APEX_DEBUG_INFO("Create Cpu factory");
+ PX_ASSERT(mCpuFactoryReferenceCount == 0);
+ }
+
+ mCpuFactoryReferenceCount++;
+ //APEX_DEBUG_INFO("Get Cpu factory (ref = %d)", mCpuFactoryReferenceCount);
+
+ return ClothFactory(mCpuFactory, &mFactoryMutex);
+ }
+}
+
+
+
+void ModuleClothingImpl::releaseClothFactory(PxCudaContextManager* contextManager)
+{
+ nvidia::Mutex::ScopedLock lock(mFactoryMutex);
+
+#if APEX_CUDA_SUPPORT
+ if (contextManager != NULL)
+ {
+ for (uint32_t i = 0; i < mGpuFactories.size(); i++)
+ {
+ if (mGpuFactories[i].contextManager == contextManager)
+ {
+ PX_ASSERT(mGpuFactories[i].referenceCount > 0);
+ mGpuFactories[i].referenceCount--;
+ //APEX_DEBUG_INFO("Found Gpu factory %d (ref = %d)", i, mGpuFactories[i].referenceCount);
+
+ if (mGpuFactories[i].referenceCount == 0)
+ {
+ //APEX_DEBUG_INFO("Release Gpu factory %d", i);
+ PX_DELETE(mGpuFactories[i].factoryGpu);
+ mGpuFactories.replaceWithLast(i);
+ }
+ }
+ }
+ }
+ else
+#else
+ PX_UNUSED(contextManager);
+#endif
+ {
+ PX_ASSERT(mCpuFactoryReferenceCount > 0);
+
+ mCpuFactoryReferenceCount--;
+ //APEX_DEBUG_INFO("Release Cpu factory (ref = %d)", mCpuFactoryReferenceCount);
+
+ if (mCpuFactoryReferenceCount == 0)
+ {
+ PX_DELETE(mCpuFactory);
+ mCpuFactory = NULL;
+ }
+ }
+}
+
+
+
+ClothingPhysicalMesh* ModuleClothingImpl::createSingleLayeredMeshInternal(RenderMeshAssetAuthoringIntl* renderMeshAsset, uint32_t subdivisionSize,
+ bool mergeVertices, bool closeHoles, IProgressListener* progressListener)
+{
+ if (renderMeshAsset->getPartCount() > 1)
+ {
+ APEX_INVALID_PARAMETER("RenderMeshAssetAuthoring has more than one part (%d)", renderMeshAsset->getPartCount());
+ return NULL;
+ }
+
+ if (subdivisionSize > 200)
+ {
+ APEX_INVALID_PARAMETER("subdivisionSize must be smaller or equal to 200 and has been clamped (was %d).", subdivisionSize);
+ subdivisionSize = 200;
+ }
+
+ HierarchicalProgressListener progress(100, progressListener);
+
+
+ uint32_t numGraphicalVertices = 0;
+
+ for (uint32_t i = 0; i < renderMeshAsset->getSubmeshCount(); i++)
+ {
+ const RenderSubmeshIntl& submesh = renderMeshAsset->getInternalSubmesh(i);
+ numGraphicalVertices += submesh.getVertexBuffer().getVertexCount();
+ }
+
+ ClothingPhysicalMeshImpl* physicalMesh = DYNAMIC_CAST(ClothingPhysicalMeshImpl*)(createEmptyPhysicalMesh());
+
+ // set time for registration, merge, close and subdivision
+ uint32_t times[4] = { 20, (uint32_t)(mergeVertices ? 20 : 0), (uint32_t)(closeHoles ? 30 : 0), (uint32_t)(subdivisionSize > 0 ? 30 : 0) };
+ uint32_t sum = times[0] + times[1] + times[2] + times[3];
+ for (uint32_t i = 0; i < 4; i++)
+ {
+ times[i] = 100 * times[i] / sum;
+ }
+
+ progress.setSubtaskWork((int32_t)times[0], "Creating single layered mesh");
+ ApexSubdivider subdivider;
+
+ Array<int32_t> old2New(numGraphicalVertices, -1);
+ uint32_t nbVertices = 0;
+
+ uint32_t vertexOffset = 0;
+
+ for (uint32_t submeshNr = 0; submeshNr < renderMeshAsset->getSubmeshCount(); submeshNr++)
+ {
+ const RenderSubmeshIntl& submesh = renderMeshAsset->getInternalSubmesh(submeshNr);
+
+ // used for physics?
+ const VertexFormat& vf = submesh.getVertexBuffer().getFormat();
+ uint32_t customIndex = (uint32_t)vf.getBufferIndexFromID(vf.getID("USED_FOR_PHYSICS"));
+ RenderDataFormat::Enum outFormat = vf.getBufferFormat(customIndex);
+ const uint8_t* usedForPhysics = NULL;
+ if (outFormat == RenderDataFormat::UBYTE1)
+ {
+ usedForPhysics = (const uint8_t*)submesh.getVertexBuffer().getBuffer(customIndex);
+ }
+
+ customIndex = (uint32_t)vf.getBufferIndexFromID(vf.getID("LATCH_TO_NEAREST_SLAVE"));
+ outFormat = vf.getBufferFormat(customIndex);
+ const uint32_t* latchToNearestSlave = outFormat != RenderDataFormat::UINT1 ? NULL : (uint32_t*)submesh.getVertexBuffer().getBuffer(customIndex);
+
+ customIndex = (uint32_t)vf.getBufferIndexFromID(vf.getID("LATCH_TO_NEAREST_MASTER"));
+ outFormat = vf.getBufferFormat(customIndex);
+ const uint32_t* latchToNearestMaster = outFormat != RenderDataFormat::UINT1 ? NULL : (uint32_t*)submesh.getVertexBuffer().getBuffer(customIndex);
+ PX_ASSERT((latchToNearestSlave != NULL) == (latchToNearestMaster != NULL)); // both NULL or not NULL
+
+ // triangles
+ const uint32_t* indices = submesh.getIndexBuffer(0); // only 1 part supported!
+
+ // vertices
+ RenderDataFormat::Enum format;
+ uint32_t bufferIndex = (uint32_t)vf.getBufferIndexFromID(vf.getSemanticID(RenderVertexSemantic::POSITION));
+ const PxVec3* positions = (const PxVec3*)submesh.getVertexBuffer().getBufferAndFormat(format, bufferIndex);
+ if (format != RenderDataFormat::FLOAT3)
+ {
+ PX_ALWAYS_ASSERT();
+ positions = NULL;
+ }
+
+ const uint32_t submeshIndices = submesh.getIndexCount(0);
+ for (uint32_t meshIndex = 0; meshIndex < submeshIndices; meshIndex += 3)
+ {
+ if (latchToNearestSlave != NULL)
+ {
+ uint32_t numVerticesOk = 0;
+ for (uint32_t i = 0; i < 3; i++)
+ {
+ const uint32_t index = indices[meshIndex + i];
+ numVerticesOk += latchToNearestSlave[index] == 0 ? 1u : 0u;
+ }
+ if (numVerticesOk < 3)
+ {
+ continue; // skip this triangle
+ }
+ }
+ else if (usedForPhysics != NULL)
+ {
+ uint32_t numVerticesOk = 0;
+ for (uint32_t i = 0; i < 3; i++)
+ {
+ const uint32_t index = indices[meshIndex + i];
+ numVerticesOk += usedForPhysics[index] == 0 ? 0u : 1u;
+ }
+ if (numVerticesOk < 3)
+ {
+ continue; // skip this triangle
+ }
+ }
+
+ // add triangle to subdivider
+ for (uint32_t i = 0; i < 3; i++)
+ {
+ const uint32_t localIndex = indices[meshIndex + i];
+ const uint32_t index = localIndex + vertexOffset;
+ if (old2New[index] == -1)
+ {
+ old2New[index] = (int32_t)nbVertices++;
+ uint32_t master = latchToNearestMaster != NULL ? latchToNearestMaster[localIndex] : 0xffffffffu;
+ subdivider.registerVertex(positions[localIndex], master);
+ }
+ }
+
+ const uint32_t i0 = (uint32_t)old2New[indices[meshIndex + 0] + vertexOffset];
+ const uint32_t i1 = (uint32_t)old2New[indices[meshIndex + 1] + vertexOffset];
+ const uint32_t i2 = (uint32_t)old2New[indices[meshIndex + 2] + vertexOffset];
+ subdivider.registerTriangle(i0, i1, i2);
+ }
+ vertexOffset += submesh.getVertexBuffer().getVertexCount();
+ }
+
+ subdivider.endRegistration();
+ progress.completeSubtask();
+
+ if (nbVertices == 0)
+ {
+ APEX_INVALID_PARAMETER("Mesh has no active vertices (see Physics on/off channel)");
+ return NULL;
+ }
+
+ // use subdivider
+ if (mergeVertices)
+ {
+ progress.setSubtaskWork((int32_t)times[1], "Merging");
+ subdivider.mergeVertices(&progress);
+ progress.completeSubtask();
+ }
+
+ if (closeHoles)
+ {
+ progress.setSubtaskWork((int32_t)times[2], "Closing holes");
+ subdivider.closeMesh(&progress);
+ progress.completeSubtask();
+ }
+
+ if (subdivisionSize > 0)
+ {
+ progress.setSubtaskWork((int32_t)times[3], "Subdividing");
+ subdivider.subdivide(subdivisionSize, &progress);
+ progress.completeSubtask();
+ }
+
+ Array<PxVec3> newVertices(subdivider.getNumVertices());
+ Array<uint32_t> newMasterValues(subdivider.getNumVertices());
+ for (uint32_t i = 0; i < newVertices.size(); i++)
+ {
+ subdivider.getVertex(i, newVertices[i], newMasterValues[i]);
+ }
+
+ Array<uint32_t> newIndices(subdivider.getNumTriangles() * 3);
+ for (uint32_t i = 0; i < newIndices.size(); i += 3)
+ {
+ subdivider.getTriangle(i / 3, newIndices[i], newIndices[i + 1], newIndices[i + 2]);
+ }
+
+ physicalMesh->setGeometry(false, newVertices.size(), sizeof(PxVec3), newVertices.begin(),
+ newMasterValues.begin(), newIndices.size(), sizeof(uint32_t), &newIndices[0]);
+
+ return physicalMesh;
+}
+
+
+bool ModuleClothingImpl::ClothingBackendFactory::isMatch(const char* simulationBackend)
+{
+ if (::strcmp(getName(), simulationBackend) == 0)
+ {
+ return true;
+ }
+
+ if (::strcmp(ClothingCookedPhysX3Param::staticClassName(), simulationBackend) == 0
+ || ::strcmp(ClothingCookedParam::staticClassName(), simulationBackend) == 0)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+const char* ModuleClothingImpl::ClothingBackendFactory::getName()
+{
+ return "Embedded";
+}
+
+uint32_t ModuleClothingImpl::ClothingBackendFactory::getCookingVersion()
+{
+ return Cooking::getCookingVersion();
+}
+
+uint32_t ModuleClothingImpl::ClothingBackendFactory::getCookedDataVersion(const NvParameterized::Interface* cookedData)
+{
+ if (cookedData != NULL && isMatch(cookedData->className()))
+ {
+ if (::strcmp(ClothingCookedParam::staticClassName(), cookedData->className()) == 0)
+ {
+ return static_cast<const ClothingCookedParam*>(cookedData)->cookedDataVersion;
+ }
+ else if (::strcmp(ClothingCookedPhysX3Param::staticClassName(), cookedData->className()) == 0)
+ {
+ return static_cast<const ClothingCookedPhysX3Param*>(cookedData)->cookedDataVersion;
+ }
+ else
+ {
+ PX_ALWAYS_ASSERT_MESSAGE("Mechanism to extract cooked data version is not defined and not implemented");
+ }
+ }
+
+ return 0;
+}
+
+CookingAbstract* ModuleClothingImpl::ClothingBackendFactory::createCookingJob()
+{
+ bool withFibers = true;
+ return PX_NEW(Cooking)(withFibers);
+}
+
+void ModuleClothingImpl::ClothingBackendFactory::releaseCookedInstances(NvParameterized::Interface* cookedData)
+{
+ Simulation::releaseFabric(cookedData);
+}
+
+SimulationAbstract* ModuleClothingImpl::ClothingBackendFactory::createSimulation(ClothingScene* clothingScene, bool useHW)
+{
+ return PX_NEW(Simulation)(clothingScene, useHW);
+}
+
+}
+} // namespace nvidia