aboutsummaryrefslogtreecommitdiff
path: root/APEX_1.4/module/clothing
diff options
context:
space:
mode:
Diffstat (limited to 'APEX_1.4/module/clothing')
-rw-r--r--APEX_1.4/module/clothing/embedded/CmPhysXCommon.h55
-rw-r--r--APEX_1.4/module/clothing/embedded/CmTask.h227
-rw-r--r--APEX_1.4/module/clothing/embedded/Cooking.cpp678
-rw-r--r--APEX_1.4/module/clothing/embedded/CreateCuFactory.cpp24
-rw-r--r--APEX_1.4/module/clothing/embedded/CreateCuFactory.h26
-rw-r--r--APEX_1.4/module/clothing/embedded/ExtClothConfig.h94
-rw-r--r--APEX_1.4/module/clothing/embedded/ExtClothCoreUtilityTypes.h243
-rw-r--r--APEX_1.4/module/clothing/embedded/ExtClothFabricCooker.cpp595
-rw-r--r--APEX_1.4/module/clothing/embedded/ExtClothFabricCooker.h61
-rw-r--r--APEX_1.4/module/clothing/embedded/ExtClothGeodesicTetherCooker.cpp1006
-rw-r--r--APEX_1.4/module/clothing/embedded/ExtClothMeshQuadifier.cpp429
-rw-r--r--APEX_1.4/module/clothing/embedded/ExtClothMeshQuadifier.h57
-rw-r--r--APEX_1.4/module/clothing/embedded/ExtClothSimpleTetherCooker.cpp138
-rw-r--r--APEX_1.4/module/clothing/embedded/ExtClothTetherCooker.h117
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/include/Cloth.h309
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/include/Fabric.h80
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/include/Factory.h176
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/include/PhaseConfig.h40
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/include/Range.h132
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/include/Solver.h75
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/include/Types.h51
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/Allocator.cpp30
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/Allocator.h59
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/Array.h54
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/BoundingBox.h88
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/ClothBase.h112
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/ClothImpl.h1247
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/Factory.cpp67
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/IndexPair.h30
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/IterationState.h375
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/MovingAverage.h129
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/PhaseConfig.cpp60
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/PointInterpolator.h153
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/Simd4f.h478
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/Simd4i.h360
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SimdTypes.h150
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/StackAllocator.h139
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwCloth.cpp307
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwCloth.h202
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwClothData.cpp130
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwClothData.h122
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwCollision.cpp1927
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwCollision.h178
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwCollisionHelpers.h68
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwFabric.cpp150
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwFabric.h89
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwFactory.cpp280
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwFactory.h73
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwInterCollision.cpp694
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwInterCollision.h140
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwSelfCollision.cpp404
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwSelfCollision.h68
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwSolver.cpp398
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwSolver.h173
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwSolverKernel.cpp695
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwSolverKernel.h69
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/TripletScheduler.cpp229
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/TripletScheduler.h40
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/Vec4T.h88
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/avx/SwSolveConstraints.cpp916
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/neon/NeonCollision.cpp18
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/neon/NeonSelfCollision.cpp18
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/neon/NeonSolverKernel.cpp33
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/neon/Simd4f.h500
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/neon/Simd4i.h276
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/neon/SimdTypes.h51
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/neon/SwCollisionHelpers.h91
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/scalar/Simd4f.h410
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/scalar/Simd4i.h188
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/scalar/SimdTypes.h86
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/scalar/SwCollisionHelpers.h76
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/sse2/Simd4f.h411
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/sse2/Simd4i.h238
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/sse2/SimdTypes.h70
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/sse2/SwCollisionHelpers.h76
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/sse2/SwSolveConstraints.h379
-rw-r--r--APEX_1.4/module/clothing/embedded/LowLevelCloth/src/windows/CuFactory.h89
-rw-r--r--APEX_1.4/module/clothing/embedded/PxClothFabric.h141
-rw-r--r--APEX_1.4/module/clothing/embedded/PxClothMeshDesc.h151
-rw-r--r--APEX_1.4/module/clothing/embedded/PxClothTypes.h113
-rw-r--r--APEX_1.4/module/clothing/embedded/Simulation.cpp2488
-rw-r--r--APEX_1.4/module/clothing/include/AbstractMeshDescription.h87
-rw-r--r--APEX_1.4/module/clothing/include/ClothStructs.h51
-rw-r--r--APEX_1.4/module/clothing/include/ClothingActorData.h116
-rw-r--r--APEX_1.4/module/clothing/include/ClothingActorImpl.h529
-rw-r--r--APEX_1.4/module/clothing/include/ClothingActorProxy.h392
-rw-r--r--APEX_1.4/module/clothing/include/ClothingActorTasks.h96
-rw-r--r--APEX_1.4/module/clothing/include/ClothingAssetAuthoringImpl.h265
-rw-r--r--APEX_1.4/module/clothing/include/ClothingAssetData.h287
-rw-r--r--APEX_1.4/module/clothing/include/ClothingAssetImpl.h494
-rw-r--r--APEX_1.4/module/clothing/include/ClothingCollisionImpl.h422
-rw-r--r--APEX_1.4/module/clothing/include/ClothingCooking.h114
-rw-r--r--APEX_1.4/module/clothing/include/ClothingGlobals.h39
-rw-r--r--APEX_1.4/module/clothing/include/ClothingPhysicalMeshImpl.h207
-rw-r--r--APEX_1.4/module/clothing/include/ClothingPreviewProxy.h122
-rw-r--r--APEX_1.4/module/clothing/include/ClothingRenderProxyImpl.h123
-rw-r--r--APEX_1.4/module/clothing/include/ClothingScene.h233
-rw-r--r--APEX_1.4/module/clothing/include/Cooking.h167
-rw-r--r--APEX_1.4/module/clothing/include/CookingAbstract.h134
-rw-r--r--APEX_1.4/module/clothing/include/CookingPhysX.h50
-rw-r--r--APEX_1.4/module/clothing/include/ModuleClothingHelpers.h461
-rw-r--r--APEX_1.4/module/clothing/include/ModuleClothingImpl.h268
-rw-r--r--APEX_1.4/module/clothing/include/ModuleEventDefs.h53
-rw-r--r--APEX_1.4/module/clothing/include/ModulePerfScope.h18
-rw-r--r--APEX_1.4/module/clothing/include/Simulation.h315
-rw-r--r--APEX_1.4/module/clothing/include/SimulationAbstract.h261
-rw-r--r--APEX_1.4/module/clothing/include/autogen/ClothingActorParam.h351
-rw-r--r--APEX_1.4/module/clothing/include/autogen/ClothingAssetParameters.h374
-rw-r--r--APEX_1.4/module/clothing/include/autogen/ClothingCookedParam.h297
-rw-r--r--APEX_1.4/module/clothing/include/autogen/ClothingCookedPhysX3Param.h310
-rw-r--r--APEX_1.4/module/clothing/include/autogen/ClothingDebugRenderParams.h270
-rw-r--r--APEX_1.4/module/clothing/include/autogen/ClothingGraphicalLodParameters.h335
-rw-r--r--APEX_1.4/module/clothing/include/autogen/ClothingMaterialLibraryParameters.h277
-rw-r--r--APEX_1.4/module/clothing/include/autogen/ClothingModuleParameters.h240
-rw-r--r--APEX_1.4/module/clothing/include/autogen/ClothingPhysicalMeshParameters.h373
-rw-r--r--APEX_1.4/module/clothing/include/autogen/ClothingPreviewParam.h243
-rw-r--r--APEX_1.4/module/clothing/include/autogen/ModuleClothingRegistration.h141
-rw-r--r--APEX_1.4/module/clothing/src/ClothingActorData.cpp1161
-rw-r--r--APEX_1.4/module/clothing/src/ClothingActorImpl.cpp4852
-rw-r--r--APEX_1.4/module/clothing/src/ClothingActorTasks.cpp99
-rw-r--r--APEX_1.4/module/clothing/src/ClothingAssetAuthoringImpl.cpp3931
-rw-r--r--APEX_1.4/module/clothing/src/ClothingAssetData.cpp874
-rw-r--r--APEX_1.4/module/clothing/src/ClothingAssetImpl.cpp3849
-rw-r--r--APEX_1.4/module/clothing/src/ClothingCollisionImpl.cpp324
-rw-r--r--APEX_1.4/module/clothing/src/ClothingCooking.cpp163
-rw-r--r--APEX_1.4/module/clothing/src/ClothingPhysicalMeshImpl.cpp1576
-rw-r--r--APEX_1.4/module/clothing/src/ClothingRenderProxyImpl.cpp270
-rw-r--r--APEX_1.4/module/clothing/src/ClothingScene.cpp889
-rw-r--r--APEX_1.4/module/clothing/src/CookingAbstract.cpp76
-rw-r--r--APEX_1.4/module/clothing/src/ModuleClothingHelpers.cpp90
-rw-r--r--APEX_1.4/module/clothing/src/ModuleClothingImpl.cpp1210
-rw-r--r--APEX_1.4/module/clothing/src/SimulationAbstract.cpp55
-rw-r--r--APEX_1.4/module/clothing/src/autogen/ClothingActorParam.cpp2394
-rw-r--r--APEX_1.4/module/clothing/src/autogen/ClothingAssetParameters.cpp2046
-rw-r--r--APEX_1.4/module/clothing/src/autogen/ClothingCookedParam.cpp970
-rw-r--r--APEX_1.4/module/clothing/src/autogen/ClothingCookedPhysX3Param.cpp1557
-rw-r--r--APEX_1.4/module/clothing/src/autogen/ClothingDebugRenderParams.cpp1327
-rw-r--r--APEX_1.4/module/clothing/src/autogen/ClothingGraphicalLodParameters.cpp1491
-rw-r--r--APEX_1.4/module/clothing/src/autogen/ClothingMaterialLibraryParameters.cpp1593
-rw-r--r--APEX_1.4/module/clothing/src/autogen/ClothingModuleParameters.cpp583
-rw-r--r--APEX_1.4/module/clothing/src/autogen/ClothingPhysicalMeshParameters.cpp2418
-rw-r--r--APEX_1.4/module/clothing/src/autogen/ClothingPreviewParam.cpp506
142 files changed, 64306 insertions, 0 deletions
diff --git a/APEX_1.4/module/clothing/embedded/CmPhysXCommon.h b/APEX_1.4/module/clothing/embedded/CmPhysXCommon.h
new file mode 100644
index 00000000..ad6ff21b
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/CmPhysXCommon.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PX_PHYSICS_COMMON
+#define PX_PHYSICS_COMMON
+
+//! \file Top level internal include file for PhysX SDK
+
+#include "Ps.h"
+#include "PxFoundation.h"
+
+#ifndef CACHE_LOCAL_CONTACTS_XP
+#define CACHE_LOCAL_CONTACTS_XP 1
+#endif
+
+#if PX_CHECKED
+ #define PX_CHECK_MSG(exp, msg) (!!(exp) || (PxGetFoundation().getErrorCallback().reportError(PxErrorCode::eINVALID_PARAMETER, msg, __FILE__, __LINE__), 0) )
+ #define PX_CHECK(exp) PX_CHECK_MSG(exp, #exp)
+ #define PX_CHECK_AND_RETURN(exp,msg) { if(!(exp)) { PX_CHECK_MSG(exp, msg); return; } }
+ #define PX_CHECK_AND_RETURN_NULL(exp,msg) { if(!(exp)) { PX_CHECK_MSG(exp, msg); return 0; } }
+ #define PX_CHECK_AND_RETURN_VAL(exp,msg,r) { if(!(exp)) { PX_CHECK_MSG(exp, msg); return r; } }
+#else
+ #define PX_CHECK_MSG(exp, msg)
+ #define PX_CHECK(exp)
+ #define PX_CHECK_AND_RETURN(exp,msg)
+ #define PX_CHECK_AND_RETURN_NULL(exp,msg)
+ #define PX_CHECK_AND_RETURN_VAL(exp,msg,r)
+#endif
+
+#if PX_VC
+ // VC compiler defines __FUNCTION__ as a string literal so it is possible to concatenate it with another string
+ // Example: #define PX_CHECK_VALID(x) PX_CHECK_MSG(shdfnd::checkValid(x), __FUNCTION__ ": parameter invalid!")
+ #define PX_CHECK_VALID(x) PX_CHECK_MSG(shdfnd::checkValid(x), __FUNCTION__)
+#elif PX_GCC_FAMILY || PX_GHS
+ // GCC compiler defines __FUNCTION__ as a variable, hence, it is NOT possible concatenate an additional string to it
+ // In GCC, __FUNCTION__ only returns the function name, using __PRETTY_FUNCTION__ will return the full function definition
+ #define PX_CHECK_VALID(x) PX_CHECK_MSG(shdfnd::checkValid(x), __PRETTY_FUNCTION__)
+#else
+ // Generic macro for other compilers
+ #define PX_CHECK_VALID(x) PX_CHECK_MSG(shdfnd::checkValid(x), __FUNCTION__)
+#endif
+
+
+#endif
diff --git a/APEX_1.4/module/clothing/embedded/CmTask.h b/APEX_1.4/module/clothing/embedded/CmTask.h
new file mode 100644
index 00000000..4de05e3b
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/CmTask.h
@@ -0,0 +1,227 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PX_PHYSICS_COMMON_TASK
+#define PX_PHYSICS_COMMON_TASK
+
+#include "PxTask.h"
+#include "PxTaskManager.h"
+#include "CmPhysXCommon.h"
+#include "PsUserAllocated.h"
+#include "PsAtomic.h"
+#include "PsMutex.h"
+#include "PsSync.h"
+#include "PxCpuDispatcher.h"
+#include "PsFPU.h"
+#include "PsInlineArray.h"
+
+namespace nvidia
+{
+namespace Cm
+{
+ // wrapper around the public PxLightCpuTask
+ // internal SDK tasks should be inherited from
+ // this and override the runInternal() method
+ // to ensure that the correct floating point
+ // state is set / reset during execution
+ class Task : public PxLightCpuTask
+ {
+ public:
+
+ virtual void run()
+ {
+ physx::PX_SIMD_GUARD;
+ runInternal();
+ }
+
+ virtual void runInternal()=0;
+ };
+
+ // same as Cm::Task but inheriting from PxBaseTask
+ // instead of PxLightCpuTask
+ class BaseTask : public PxBaseTask
+ {
+ public:
+
+ virtual void run()
+ {
+ physx::PX_SIMD_GUARD;
+ runInternal();
+ }
+
+ virtual void runInternal()=0;
+ };
+
+ template <class T, void (T::*Fn)(PxBaseTask*) >
+ class DelegateTask : public Cm::Task, public shdfnd::UserAllocated
+ {
+ public:
+
+ DelegateTask(T* obj, const char* name) :
+ mObj(obj), mName(name) { }
+
+ virtual void runInternal()
+ {
+ (mObj->*Fn)((PxBaseTask*)mCont);
+ }
+
+ virtual const char* getName() const
+ {
+ return mName;
+ }
+
+ void setObject(T* obj) { mObj = obj; }
+
+ private:
+ T* mObj;
+ const char* mName;
+ };
+
+
+ /**
+ \brief A task that maintains a list of dependent tasks.
+
+ This task maintains a list of dependent tasks that have their reference counts
+ reduced on completion of the task.
+
+ The refcount is incremented every time a dependent task is added.
+ */
+ class FanoutTask : public Cm::BaseTask
+ {
+ PX_NOCOPY(FanoutTask)
+ public:
+ FanoutTask(const char* name) : Cm::BaseTask(), mRefCount(0), mName(name), mNotifySubmission(false) {}
+
+ virtual void runInternal() {}
+
+ virtual const char* getName() const { return mName; }
+
+ /**
+ Swap mDependents with mReferencesToRemove when refcount goes to 0.
+ */
+ virtual void removeReference()
+ {
+ nvidia::Mutex::ScopedLock lock(mMutex);
+ if (!nvidia::atomicDecrement(&mRefCount))
+ {
+ // prevents access to mReferencesToRemove until release
+ nvidia::atomicIncrement(&mRefCount);
+ mNotifySubmission = false;
+ PX_ASSERT(mReferencesToRemove.empty());
+ for (uint32_t i = 0; i < mDependents.size(); i++)
+ mReferencesToRemove.pushBack(mDependents[i]);
+ mDependents.clear();
+ mTm->getCpuDispatcher()->submitTask(*this);
+ }
+ }
+
+ /**
+ \brief Increases reference count
+ */
+ virtual void addReference()
+ {
+ nvidia::Mutex::ScopedLock lock(mMutex);
+ nvidia::atomicIncrement(&mRefCount);
+ mNotifySubmission = true;
+ }
+
+ /**
+ \brief Return the ref-count for this task
+ */
+ PX_INLINE int32_t getReference() const
+ {
+ return mRefCount;
+ }
+
+ /**
+ Sets the task manager. Doesn't increase the reference count.
+ */
+ PX_INLINE void setTaskManager(PxTaskManager& tm)
+ {
+ mTm = &tm;
+ }
+
+ /**
+ Adds a dependent task. It also sets the task manager querying it from the dependent task.
+ The refcount is incremented every time a dependent task is added.
+ */
+ PX_INLINE void addDependent(PxBaseTask& dependent)
+ {
+ nvidia::Mutex::ScopedLock lock(mMutex);
+ nvidia::atomicIncrement(&mRefCount);
+ mTm = dependent.getTaskManager();
+ mDependents.pushBack(&dependent);
+ dependent.addReference();
+ mNotifySubmission = true;
+ }
+
+ /**
+ Reduces reference counts of the continuation task and the dependent tasks, also
+ clearing the copy of continuation and dependents task list.
+ */
+ virtual void release()
+ {
+ nvidia::Mutex::ScopedLock lock(mMutex);
+ for (uint32_t i = 0, n = mReferencesToRemove.size(); i < n; ++i)
+ mReferencesToRemove[i]->removeReference();
+ mReferencesToRemove.clear();
+ // allow access to mReferencesToRemove again
+ if (mNotifySubmission)
+ {
+ removeReference();
+ }
+ else
+ {
+ nvidia::atomicDecrement(&mRefCount);
+ }
+ }
+
+ protected:
+ volatile int32_t mRefCount;
+ const char* mName;
+ nvidia::InlineArray<PxBaseTask*, 4> mDependents;
+ nvidia::InlineArray<PxBaseTask*, 4> mReferencesToRemove;
+ bool mNotifySubmission;
+ nvidia::Mutex mMutex; // guarding mDependents and mNotifySubmission
+ };
+
+
+ /**
+ \brief Specialization of FanoutTask class in order to provide the delegation mechanism.
+ */
+ template <class T, void (T::*Fn)(PxBaseTask*) >
+ class DelegateFanoutTask : public FanoutTask, public shdfnd::UserAllocated
+ {
+ public:
+
+ DelegateFanoutTask(T* obj, const char* name) :
+ FanoutTask(name), mObj(obj) { }
+
+ virtual void runInternal()
+ {
+ PxBaseTask* continuation = mDependents.empty() ? NULL : mDependents[0];
+ (mObj->*Fn)(continuation);
+ }
+
+ void setObject(T* obj) { mObj = obj; }
+
+ private:
+ T* mObj;
+ };
+
+} // namespace Cm
+
+}
+
+#endif
diff --git a/APEX_1.4/module/clothing/embedded/Cooking.cpp b/APEX_1.4/module/clothing/embedded/Cooking.cpp
new file mode 100644
index 00000000..5a9d8251
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/Cooking.cpp
@@ -0,0 +1,678 @@
+/*
+ * 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 "Cooking.h"
+
+#include <PsArray.h>
+#include <PsMathUtils.h>
+#include <PsSort.h>
+#include <Ps.h>
+
+#include <ApexSDKIntl.h>
+
+#include "ClothingCookedPhysX3Param.h"
+
+#include "ExtClothFabricCooker.h"
+#include "ExtClothMeshQuadifier.h"
+
+#include "ModuleClothingHelpers.h"
+
+#include <ctime>
+
+namespace
+{
+ using namespace nvidia;
+
+ struct VirtualParticle
+ {
+ VirtualParticle(uint32_t i0, uint32_t i1, uint32_t i2)
+ {
+ indices[0] = i0;
+ indices[1] = i1;
+ indices[2] = i2;
+ tableIndex = 0;
+ }
+
+ void rotate(uint32_t count)
+ {
+ while (count--)
+ {
+ const uint32_t temp = indices[2];
+ indices[2] = indices[1];
+ indices[1] = indices[0];
+ indices[0] = temp;
+ }
+ }
+
+ uint32_t indices[3];
+ uint32_t tableIndex;
+ };
+
+ struct EdgeAndLength
+ {
+ EdgeAndLength(uint32_t edgeNumber, float length) : mEdgeNumber(edgeNumber), mLength(length) {}
+ uint32_t mEdgeNumber;
+ float mLength;
+
+ bool operator<(const EdgeAndLength& other) const
+ {
+ return mLength < other.mLength;
+ }
+ };
+}
+
+namespace nvidia
+{
+namespace clothing
+{
+
+bool Cooking::mTetraWarning = false;
+
+NvParameterized::Interface* Cooking::execute()
+{
+ ClothingCookedPhysX3Param* rootCookedData = NULL;
+
+ for (uint32_t meshIndex = 0; meshIndex < mPhysicalMeshes.size(); meshIndex++)
+ {
+ if (mPhysicalMeshes[meshIndex].isTetrahedral)
+ {
+ if (!mTetraWarning)
+ {
+ mTetraWarning = true;
+ APEX_INVALID_OPERATION("Tetrahedral meshes are not (yet) supported with the 3.x solver");
+ }
+ continue;
+ }
+
+ ClothingCookedPhysX3Param* cookedData = NULL;
+
+ cookedData = fiberCooker(meshIndex);
+
+ computeVertexWeights(cookedData, meshIndex);
+ fillOutSetsDesc(cookedData);
+
+ createVirtualParticles(cookedData, meshIndex);
+ createSelfcollisionIndices(cookedData, meshIndex);
+
+ if (rootCookedData == NULL)
+ {
+ rootCookedData = cookedData;
+ }
+ else
+ {
+ ClothingCookedPhysX3Param* addCookedData = rootCookedData;
+ while (addCookedData != NULL && addCookedData->nextCookedData != NULL)
+ {
+ addCookedData = static_cast<ClothingCookedPhysX3Param*>(addCookedData->nextCookedData);
+ }
+ addCookedData->nextCookedData = cookedData;
+ }
+ }
+
+ return rootCookedData;
+}
+
+
+
+ClothingCookedPhysX3Param* Cooking::fiberCooker(uint32_t meshIndex) const
+{
+ const uint32_t numSimulatedVertices = mPhysicalMeshes[meshIndex].numSimulatedVertices;
+ const uint32_t numAttached = mPhysicalMeshes[meshIndex].numMaxDistance0Vertices;
+
+ shdfnd::Array<PxVec4> vertices(numSimulatedVertices);
+ for (uint32_t i = 0; i < numSimulatedVertices; i++)
+ vertices[i] = PxVec4(mPhysicalMeshes[meshIndex].vertices[i], 1.0f);
+
+ if (numAttached > 0)
+ {
+ const uint32_t start = numSimulatedVertices - numAttached;
+ for (uint32_t i = start; i < numSimulatedVertices; i++)
+ vertices[i].w = 0.0f;
+ }
+
+ PxClothMeshDesc desc;
+
+ desc.points.data = vertices.begin();
+ desc.points.count = numSimulatedVertices;
+ desc.points.stride = sizeof(PxVec4);
+
+ desc.invMasses.data = &vertices.begin()->w;
+ desc.invMasses.count = numSimulatedVertices;
+ desc.invMasses.stride = sizeof(PxVec4);
+
+ desc.triangles.data = mPhysicalMeshes[meshIndex].indices;
+ desc.triangles.count = mPhysicalMeshes[meshIndex].numSimulatedIndices / 3;
+ desc.triangles.stride = sizeof(uint32_t) * 3;
+
+ PxClothMeshQuadifier quadifier(desc);
+
+ PxClothFabricCooker cooker(quadifier.getDescriptor(), mGravityDirection);
+
+ PxClothFabricDesc fabric = cooker.getDescriptor();
+
+ int32_t nbConstraints = (int32_t)fabric.sets[fabric.nbSets - 1];
+
+ ClothingCookedPhysX3Param* cookedData = NULL;
+
+ bool success = true;
+ if (success)
+ {
+ cookedData = static_cast<ClothingCookedPhysX3Param*>(GetInternalApexSDK()->getParameterizedTraits()->createNvParameterized(ClothingCookedPhysX3Param::staticClassName()));
+
+ NvParameterized::Handle arrayHandle(cookedData);
+ arrayHandle.getParameter("deformableIndices");
+ arrayHandle.resizeArray(nbConstraints * 2);
+ arrayHandle.setParamU32Array(fabric.indices, nbConstraints * 2);
+
+ arrayHandle.getParameter("deformableRestLengths");
+ arrayHandle.resizeArray(nbConstraints);
+ arrayHandle.setParamF32Array(fabric.restvalues, nbConstraints);
+
+ arrayHandle.getParameter("deformableSets");
+ const int32_t numSets = (int32_t)fabric.nbSets;
+ arrayHandle.resizeArray(numSets);
+ for (int32_t i = 0; i < numSets; i++)
+ {
+ arrayHandle.set(i);
+ arrayHandle.set(0);
+ arrayHandle.setParamU32(fabric.sets[(uint32_t)i]);
+ arrayHandle.popIndex();
+ arrayHandle.popIndex();
+ }
+
+ arrayHandle.getParameter("deformablePhaseDescs");
+ arrayHandle.resizeArray((int32_t)fabric.nbPhases);
+
+ for (uint32_t i = 0; i < fabric.nbPhases; i++)
+ {
+ PxClothFabricPhase phase = fabric.phases[i];
+ cookedData->deformablePhaseDescs.buf[i].phaseType = phase.phaseType;
+ cookedData->deformablePhaseDescs.buf[i].setIndex = phase.setIndex;
+ }
+
+ arrayHandle.getParameter("tetherAnchors");
+ arrayHandle.resizeArray((int32_t)fabric.nbTethers);
+ arrayHandle.setParamU32Array(fabric.tetherAnchors, (int32_t)fabric.nbTethers);
+
+ arrayHandle.getParameter("tetherLengths");
+ arrayHandle.resizeArray((int32_t)fabric.nbTethers);
+ arrayHandle.setParamF32Array(fabric.tetherLengths, (int32_t)fabric.nbTethers);
+
+ cookedData->physicalMeshId = meshIndex;
+ cookedData->numVertices = numSimulatedVertices;
+
+ //dumpObj("c:\\lastCooked.obj", meshIndex);
+ //dumpApx("c:\\lastCooked.apx", cookedData);
+
+ cookedData->cookedDataVersion = getCookingVersion();
+ }
+ else
+ {
+#if PX_WINDOWS_FAMILY
+ static int failureCount = 0;
+ char buf[64];
+ sprintf_s(buf, 64, "c:\\cookingFailure_%d.obj", failureCount++);
+ dumpObj(buf, meshIndex);
+
+ APEX_INTERNAL_ERROR("Fiber cooking failure (mesh %d), the failing mesh has been dumped to \'%s\'", meshIndex, buf);
+#else
+ APEX_INTERNAL_ERROR("Fiber cooking failure (mesh %d)", meshIndex);
+#endif
+
+ }
+
+
+ return cookedData;
+}
+
+void Cooking::computeVertexWeights(ClothingCookedPhysX3Param* cookedData, uint32_t meshIndex) const
+{
+ const uint32_t* indices = mPhysicalMeshes[cookedData->physicalMeshId].indices;
+ const PxVec3* positions = mPhysicalMeshes[cookedData->physicalMeshId].vertices;
+ const uint32_t numSimulatedIndices = mPhysicalMeshes[meshIndex].numSimulatedIndices;
+ const uint32_t numSimulatedVertices = mPhysicalMeshes[meshIndex].numSimulatedVertices;
+
+ nvidia::Array<float> weights(numSimulatedVertices, 0.0f);
+
+ PX_ASSERT(numSimulatedIndices % 3 == 0);
+ for (uint32_t i = 0; i < numSimulatedIndices; i += 3)
+ {
+ const PxVec3 v1 = positions[indices[i + 1]] - positions[indices[i]];
+ const PxVec3 v2 = positions[indices[i + 2]] - positions[indices[i]];
+ const float area = v1.cross(v2).magnitude();
+
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ weights[indices[i + j]] += area;
+ }
+ }
+
+ float weightSum = 0.0f;
+ for (uint32_t i = 0; i < numSimulatedVertices; i++)
+ {
+ weightSum += weights[i];
+ }
+
+ const float weightScale = (float)numSimulatedVertices / weightSum;
+
+ for (uint32_t i = 0; i < numSimulatedVertices; i++)
+ {
+ weights[i] *= weightScale;
+ }
+
+ NvParameterized::Handle handle(*cookedData, "deformableInvVertexWeights");
+ if (handle.resizeArray((int32_t)numSimulatedVertices) == NvParameterized::ERROR_NONE)
+ {
+ for (uint32_t i = 0; i < numSimulatedVertices; i++)
+ {
+ cookedData->deformableInvVertexWeights.buf[i] = 1.0f / weights[i];
+ }
+ }
+}
+
+
+
+void Cooking::createVirtualParticles(ClothingCookedPhysX3Param* cookedData, uint32_t meshIndex)
+{
+ const PxVec3* positions = mPhysicalMeshes[cookedData->physicalMeshId].vertices;
+ const uint32_t* indices = mPhysicalMeshes[cookedData->physicalMeshId].indices;
+ const uint32_t numIndices = mPhysicalMeshes[meshIndex].numSimulatedIndices;
+
+ nvidia::Array<VirtualParticle> particles;
+
+ const float minTriangleArea = mVirtualParticleDensity * mPhysicalMeshes[cookedData->physicalMeshId].smallestTriangleArea / 2.0f +
+ (1.0f - mVirtualParticleDensity) * mPhysicalMeshes[cookedData->physicalMeshId].largestTriangleArea;
+ const float coveredTriangleArea = minTriangleArea;
+
+ for (uint32_t i = 0; i < numIndices; i += 3)
+ {
+ VirtualParticle particle(indices[i], indices[i + 1], indices[i + 2]);
+
+ const PxVec3 edge1 = positions[particle.indices[1]] - positions[particle.indices[0]];
+ const PxVec3 edge2 = positions[particle.indices[2]] - positions[particle.indices[0]];
+ const float triangleArea = edge1.cross(edge2).magnitude();
+
+ const float numSpheres = triangleArea / coveredTriangleArea;
+
+ if (numSpheres <= 1.0f)
+ {
+ // do nothing
+ }
+ else if (numSpheres < 2.0f)
+ {
+ // add one virtual particle
+ particles.pushBack(particle);
+ }
+ else
+ {
+ // add two or three, depending on whether it's a slim triangle.
+ EdgeAndLength eal0(0, edge1.magnitude());
+ EdgeAndLength eal1(1, (positions[particle.indices[2]] - positions[particle.indices[1]]).magnitude());
+ EdgeAndLength eal2(2, edge2.magnitude());
+ EdgeAndLength middle = eal0 < eal1 ? eal0 : eal1; // technically this does not have to be the middle of the three, but for the test below it suffices.
+ EdgeAndLength smallest = middle < eal2 ? middle : eal2;
+ if (smallest.mLength * 2.0f < middle.mLength)
+ {
+ // two
+ particle.rotate(smallest.mEdgeNumber);
+ particle.tableIndex = 2;
+ particles.pushBack(particle);
+ particle.tableIndex = 3;
+ particles.pushBack(particle);
+ }
+ else
+ {
+ // three
+ particle.tableIndex = 1;
+ particles.pushBack(particle);
+ particle.rotate(1);
+ particles.pushBack(particle);
+ particle.rotate(1);
+ particles.pushBack(particle);
+ }
+ }
+ }
+
+ if (!particles.empty())
+ {
+ NvParameterized::Handle handle(cookedData);
+ handle.getParameter("virtualParticleIndices");
+ handle.resizeArray((int32_t)particles.size() * 4);
+ handle.getParameter("virtualParticleWeights");
+ handle.resizeArray(3 * 4);
+
+ // table index 0, the center particle
+ cookedData->virtualParticleWeights.buf[0] = 1.0f / 3.0f;
+ cookedData->virtualParticleWeights.buf[1] = 1.0f / 3.0f;
+ cookedData->virtualParticleWeights.buf[2] = 1.0f / 3.0f;
+
+ // table index 1, three particles
+ cookedData->virtualParticleWeights.buf[3] = 0.1f;
+ cookedData->virtualParticleWeights.buf[4] = 0.3f;
+ cookedData->virtualParticleWeights.buf[5] = 0.6f;
+
+ // table index 2, the pointy particle
+ cookedData->virtualParticleWeights.buf[6] = 0.7f;
+ cookedData->virtualParticleWeights.buf[7] = 0.15f;
+ cookedData->virtualParticleWeights.buf[8] = 0.15f;
+
+ // table index 3, the flat particle
+ cookedData->virtualParticleWeights.buf[9] = 0.3f;
+ cookedData->virtualParticleWeights.buf[10] = 0.35f;
+ cookedData->virtualParticleWeights.buf[11] = 0.35f;
+
+ for (uint32_t i = 0; i < particles.size(); i++)
+ {
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ cookedData->virtualParticleIndices.buf[4 * i + j] = particles[i].indices[j];
+ }
+ cookedData->virtualParticleIndices.buf[4 * i + 3] = particles[i].tableIndex; // the table index
+ }
+ }
+}
+
+
+void Cooking::createSelfcollisionIndices(ClothingCookedPhysX3Param* cookedData, uint32_t meshIndex) const
+{
+ const PxVec3* positions = mPhysicalMeshes[cookedData->physicalMeshId].vertices;
+ const uint32_t numVertices = mPhysicalMeshes[meshIndex].numSimulatedVertices;
+
+
+ // we'll start with a full set of indices, and eliminate the ones we don't want. selfCollisionIndices
+ // is an array of indices, i.e. a second layer of indirection
+ Array<uint32_t> selfCollisionIndices;
+ for (uint32_t i = 0; i < numVertices; ++i)
+ {
+ selfCollisionIndices.pushBack(i);
+ }
+
+ float selfcollisionThicknessSq = mSelfcollisionRadius * mSelfcollisionRadius;
+ for (uint32_t v0ii = 0; v0ii < selfCollisionIndices.size(); ++v0ii)
+ {
+ // ii suffix means "index into indices array", i suffix just means "index into vertex array"
+
+ // load the first vertex
+ uint32_t v0i = selfCollisionIndices[v0ii];
+ const PxVec3& v0 = positions[v0i];
+
+ // no need to start at the beginning of the array, those comparisons have already been made.
+ // don't autoincrement the sequence index. if we eliminate an index, we'll replace it with one from
+ // the end, and reevaluate that element
+ for (uint32_t v1ii = v0ii + 1; v1ii < selfCollisionIndices.size(); ) // don't autoincrement iteratorsee if/else
+ {
+ uint32_t v1i = selfCollisionIndices[v1ii];
+ const PxVec3& v1 = positions[v1i];
+
+ // how close is this particle?
+ float v0v1DistanceSq = (v0 - v1).magnitudeSquared();
+ if (v0v1DistanceSq < selfcollisionThicknessSq )
+ {
+ // too close for missiles
+ selfCollisionIndices.replaceWithLast(v1ii);
+
+ // don't move on to the next - replaceWithLast put a fresh index at v1ii, so reevaluate it
+ }
+ else
+ {
+ // it's comfortably distant, so we'll keep it around (for now).
+
+ // we need to be mindful of which element we visit next in the outer loop. we want to minimize the distance between
+ // self colliding particles and not unnecessarily introduce large gaps between them. the easiest way is to pick
+ // the closest non-eliminated particle to the one currently being evaluated, and evaluate it next. if we find one
+ // that's closer than what's currently next in the list, swap it. both of these elements are prior to the next
+ // sinner-loop element, so this doesn't impact the inner loop traversal
+
+ // if we assume the index of the closest known particle is always v0ii + 1, we can just reevaluate it's distance to
+ // v0ii every iteration. slightly expensive, but it eliminates the need to maintain redundant
+ // ClosestDistance/ClosestIndex variables
+ uint32_t vNexti = selfCollisionIndices[v0ii + 1];
+ const PxVec3& nextVertexToEvaluate = positions[vNexti];
+
+ float v0vNextDistanceSq = (v0 - nextVertexToEvaluate).magnitudeSquared();
+ if (v0v1DistanceSq < v0vNextDistanceSq)
+ {
+ nvidia::swap(selfCollisionIndices[v0ii + 1], selfCollisionIndices[v1ii]);
+ }
+
+ // move on to the next
+ ++v1ii;
+ }
+ }
+ }
+
+ NvParameterized::Handle arrayHandle(cookedData);
+ arrayHandle.getParameter("selfCollisionIndices");
+ arrayHandle.resizeArray((int32_t)selfCollisionIndices.size());
+ arrayHandle.setParamU32Array(selfCollisionIndices.begin(), (int32_t)selfCollisionIndices.size());
+}
+
+
+bool Cooking::verifyValidity(const ClothingCookedPhysX3Param* cookedData, uint32_t meshIndex)
+{
+ if (cookedData == NULL)
+ {
+ return false;
+ }
+
+ const char* errorMessage = NULL;
+
+ const uint32_t numSetsDescs = (uint32_t)cookedData->deformableSets.arraySizes[0];
+ const uint32_t numDeformableVertices = mPhysicalMeshes[meshIndex].numSimulatedVertices;
+
+ for (uint32_t validSetsDescs = 0; validSetsDescs < numSetsDescs && errorMessage == NULL; ++validSetsDescs)
+ {
+ const uint32_t fromIndex = validSetsDescs ? cookedData->deformableSets.buf[validSetsDescs - 1].fiberEnd : 0;
+ const uint32_t toIndex = cookedData->deformableSets.buf[validSetsDescs].fiberEnd;
+ if (toIndex <= fromIndex)
+ {
+ errorMessage = "Set without fibers";
+ }
+
+ for (uint32_t f = fromIndex; f < toIndex && errorMessage == NULL; ++f)
+ {
+ uint32_t posIndex1 = cookedData->deformableIndices.buf[2 * f];
+ uint32_t posIndex2 = cookedData->deformableIndices.buf[2 * f + 1];
+
+ if (posIndex2 > (uint32_t)cookedData->deformableIndices.arraySizes[0])
+ {
+ errorMessage = "Fiber index out of bounds";
+ }
+
+ if (posIndex1 >= numDeformableVertices)
+ {
+ errorMessage = "Deformable index out of bounds";
+ }
+ }
+ }
+
+ if (errorMessage != NULL)
+ {
+ APEX_INTERNAL_ERROR("Invalid cooked data: %s", errorMessage);
+ }
+
+ return (errorMessage == NULL);
+}
+
+
+
+
+void Cooking::fillOutSetsDesc(ClothingCookedPhysX3Param* cookedData)
+{
+ const PxVec3* vertices = mPhysicalMeshes[cookedData->physicalMeshId].vertices;
+ for (int32_t sd = 0; sd < cookedData->deformableSets.arraySizes[0]; sd++)
+ {
+ const uint32_t firstFiber = sd ? cookedData->deformableSets.buf[sd - 1].fiberEnd : 0;
+ const uint32_t lastFiber = cookedData->deformableSets.buf[sd].fiberEnd;
+
+ uint32_t numEdges = 0;
+ float avgEdgeLength = 0.0f;
+
+ for (uint32_t f = firstFiber; f < lastFiber; f++)
+ {
+ uint32_t from = cookedData->deformableIndices.buf[f * 2];
+ uint32_t to = cookedData->deformableIndices.buf[f*2+1];
+ numEdges ++;
+ avgEdgeLength += (vertices[to] - vertices[from]).magnitude();
+ }
+
+ if (numEdges > 0)
+ {
+ cookedData->deformableSets.buf[sd].longestFiber = 0;
+ cookedData->deformableSets.buf[sd].shortestFiber = 0;
+ cookedData->deformableSets.buf[sd].numEdges = numEdges;
+ cookedData->deformableSets.buf[sd].avgFiberLength = 0;
+ cookedData->deformableSets.buf[sd].avgEdgeLength = avgEdgeLength / (float)numEdges;
+ }
+ }
+}
+
+
+
+void Cooking::groupPhases(ClothingCookedPhysX3Param* cookedData, uint32_t meshIndex, uint32_t startIndex, uint32_t endIndex, Array<uint32_t>& phaseEnds) const
+{
+ shdfnd::Array<bool> usedInPhase(mPhysicalMeshes[meshIndex].numSimulatedVertices, false);
+ for (uint32_t f = startIndex; f < endIndex; f++)
+ {
+ uint32_t index1 = cookedData->deformableIndices.buf[2 * f + 0];
+ uint32_t index2 = cookedData->deformableIndices.buf[2 * f + 1];
+
+ if (usedInPhase[index1] || usedInPhase[index2])
+ {
+ bool swapped = false;
+
+ // need to replace this with one further ahead
+ for (uint32_t scanAhead = f + 1; scanAhead < endIndex; scanAhead++)
+ {
+ const uint32_t i1 = cookedData->deformableIndices.buf[2 * scanAhead + 0];
+ const uint32_t i2 = cookedData->deformableIndices.buf[2 * scanAhead + 1];
+ if (!usedInPhase[i1] && !usedInPhase[i2])
+ {
+ // swap
+ cookedData->deformableIndices.buf[2 * f + 0] = i1;
+ cookedData->deformableIndices.buf[2 * f + 1] = i2;
+
+ cookedData->deformableIndices.buf[2 * scanAhead + 0] = index1;
+ cookedData->deformableIndices.buf[2 * scanAhead + 1] = index2;
+
+ nvidia::swap(cookedData->deformableRestLengths.buf[2 * f], cookedData->deformableRestLengths.buf[2 * scanAhead]);
+
+ index1 = i1;
+ index2 = i2;
+
+ swapped = true;
+
+ break;
+ }
+ }
+
+ if (!swapped)
+ {
+ phaseEnds.pushBack(f);
+ f--;
+
+ for (uint32_t i = 0; i < usedInPhase.size(); i++)
+ {
+ usedInPhase[i] = false;
+ }
+
+ continue;
+ }
+ }
+
+ usedInPhase[index1] = true;
+ usedInPhase[index2] = true;
+ }
+ phaseEnds.pushBack(endIndex);
+}
+
+
+
+void Cooking::dumpObj(const char* filename, uint32_t meshIndex) const
+{
+ PX_UNUSED(filename);
+
+#if PX_WINDOWS_FAMILY
+ FILE* outputFile = NULL;
+ fopen_s(&outputFile, filename, "w");
+
+ if (outputFile == NULL)
+ {
+ return;
+ }
+
+ fprintf(outputFile, "# PhysX3 Cooking input mesh\n");
+ fprintf(outputFile, "# Mesh %d\n", meshIndex);
+
+ {
+ time_t rawtime;
+ struct tm* timeinfo;
+
+ time(&rawtime);
+ timeinfo = localtime(&rawtime);
+ fprintf(outputFile, "# File Created: %s", asctime(timeinfo));
+ }
+
+ fprintf(outputFile, "\n\n\n");
+
+ const uint32_t numVertices = mPhysicalMeshes[meshIndex].numVertices;
+ const uint32_t numIndices = mPhysicalMeshes[meshIndex].numIndices;
+// const uint32_t numSimulatedVertices = mPhysicalMeshes[meshIndex].numSimulatedVertices;
+// const uint32_t numSimulatedIndices = mPhysicalMeshes[meshIndex].numSimulatedIndices;
+
+ const PxVec3* vert = mPhysicalMeshes[meshIndex].vertices;
+ for (uint32_t i = 0; i < numVertices; i++)
+ {
+ fprintf(outputFile, "v %f %f %f\n", vert[i].x, vert[i].y, vert[i].z);
+ }
+
+ fprintf(outputFile, "\n\n\n");
+
+ const uint32_t* indices = mPhysicalMeshes[meshIndex].indices;
+ for (uint32_t i = 0; i < numIndices; i += 3)
+ {
+ fprintf(outputFile, "f %d %d %d\n", indices[i] + 1, indices[i + 1] + 1, indices[i + 2] + 1);
+ }
+
+ fclose(outputFile);
+#endif
+}
+
+
+
+void Cooking::dumpApx(const char* filename, const NvParameterized::Interface* data) const
+{
+ NvParameterized::Serializer::SerializeType serType = NvParameterized::Serializer::NST_XML;
+
+ if (data == NULL)
+ {
+ return;
+ }
+
+ PxFileBuf* filebuffer = GetInternalApexSDK()->createStream(filename, PxFileBuf::OPEN_WRITE_ONLY);
+
+ if (filebuffer != NULL)
+ {
+ if (filebuffer->isOpen())
+ {
+ NvParameterized::Serializer* serializer = GetInternalApexSDK()->createSerializer(serType);
+ serializer->serialize(*filebuffer, &data, 1);
+
+ serializer->release();
+ }
+
+ filebuffer->release();
+ filebuffer = NULL;
+ }
+}
+
+}
+}
diff --git a/APEX_1.4/module/clothing/embedded/CreateCuFactory.cpp b/APEX_1.4/module/clothing/embedded/CreateCuFactory.cpp
new file mode 100644
index 00000000..8f46c4b5
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/CreateCuFactory.cpp
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "CuFactory.h"
+#include "CreateCuFactory.h"
+
+#if PX_WINDOWS_FAMILY
+
+nvidia::cloth::CuFactory* PxCreateCuFactory(physx::PxCudaContextManager* contextManager)
+{
+ return new nvidia::cloth::CuFactory(contextManager);
+}
+
+#endif //PX_WINDOWS_FAMILY
diff --git a/APEX_1.4/module/clothing/embedded/CreateCuFactory.h b/APEX_1.4/module/clothing/embedded/CreateCuFactory.h
new file mode 100644
index 00000000..60a76426
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/CreateCuFactory.h
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "Factory.h"
+#include "Allocator.h"
+
+#if PX_WINDOWS_FAMILY
+
+/**
+Create CuFactory interface class. This is defined so the CUDA cloth solver can be isolated in its own DLL
+*/
+PX_C_EXPORT __declspec(dllexport) nvidia::cloth::CuFactory* PX_CALL_CONV PxCreateCuFactory(physx::PxCudaContextManager* contextManager);
+
+#endif //PX_WINDOWS_FAMILY
diff --git a/APEX_1.4/module/clothing/embedded/ExtClothConfig.h b/APEX_1.4/module/clothing/embedded/ExtClothConfig.h
new file mode 100644
index 00000000..96d3005e
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/ExtClothConfig.h
@@ -0,0 +1,94 @@
+// 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) 2008-2015 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef EXT_CLOTH_CONFIG_NX
+#define EXT_CLOTH_CONFIG_NX
+
+/** \addtogroup common
+@{ */
+
+#include "Px.h"
+
+// Exposing of the Cloth API. Run API meta data generation in Tools/PhysXMetaDataGenerator when changing.
+#define APEX_USE_CLOTH_API 1
+
+// define API function declaration (public API only needed because of extensions)
+#if defined EXT_CLOTH_STATIC_LIB
+ #define EXT_CLOTH_CORE_API
+#else
+ #if PX_WINDOWS_FAMILY || PX_WINRT
+ #if defined EXT_CLOTH_CORE_EXPORTS
+ #define EXT_CLOTH_CORE_API PX_DLL_EXPORT
+ #else
+ #define EXT_CLOTH_CORE_API PX_DLL_IMPORT
+ #endif
+ #elif PX_UNIX_FAMILY
+ #define EXT_CLOTH_CORE_API PX_UNIX_EXPORT
+ #else
+ #define EXT_CLOTH_CORE_API
+ #endif
+#endif
+
+#if PX_WINDOWS_FAMILY || PX_WINRT && !defined(__CUDACC__)
+ #if defined EXT_CLOTH_COMMON_EXPORTS
+ #define EXT_CLOTH_COMMON_API __declspec(dllexport)
+ #else
+ #define EXT_CLOTH_COMMON_API __declspec(dllimport)
+ #endif
+#elif PX_UNIX_FAMILY
+ #define EXT_CLOTH_COMMON_API PX_UNIX_EXPORT
+#else
+ #define EXT_CLOTH_COMMON_API
+#endif
+
+// Changing these parameters requires recompilation of the SDK
+
+#ifndef PX_DOXYGEN
+namespace physx
+{
+#endif
+ class PxCollection;
+ class PxBase;
+
+ class PxHeightField;
+ class PxHeightFieldDesc;
+
+ class PxTriangleMesh;
+ class PxConvexMesh;
+
+ typedef uint32_t PxTriangleID;
+ typedef uint16_t PxMaterialTableIndex;
+
+#ifndef PX_DOXYGEN
+} // namespace physx
+#endif
+
+/** @} */
+#endif
diff --git a/APEX_1.4/module/clothing/embedded/ExtClothCoreUtilityTypes.h b/APEX_1.4/module/clothing/embedded/ExtClothCoreUtilityTypes.h
new file mode 100644
index 00000000..b764f8f4
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/ExtClothCoreUtilityTypes.h
@@ -0,0 +1,243 @@
+// 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) 2008-2015 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef EXT_CLOTH_CORE_UTILTY_TYPES_H
+#define EXT_CLOTH_CORE_UTILTY_TYPES_H
+/** \addtogroup common
+@{
+*/
+
+#include "PxAssert.h"
+#include "PxFlags.h"
+
+#if !PX_DOXYGEN
+namespace nvidia
+{
+#endif
+
+
+struct PxStridedData
+{
+ /**
+ \brief The offset in bytes between consecutive samples in the data.
+
+ <b>Default:</b> 0
+ */
+ uint32_t stride;
+ const void* data;
+
+ PxStridedData() : stride( 0 ), data( NULL ) {}
+
+ template<typename TDataType>
+ PX_INLINE const TDataType& at( uint32_t idx ) const
+ {
+ uint32_t theStride( stride );
+ if ( theStride == 0 )
+ theStride = sizeof( TDataType );
+ uint32_t offset( theStride * idx );
+ return *(reinterpret_cast<const TDataType*>( reinterpret_cast< const uint8_t* >( data ) + offset ));
+ }
+};
+
+template<typename TDataType>
+struct PxTypedStridedData
+{
+ uint32_t stride;
+ const TDataType* data;
+
+ PxTypedStridedData()
+ : stride( 0 )
+ , data( NULL )
+ {
+ }
+
+};
+
+struct PxBoundedData : public PxStridedData
+{
+ uint32_t count;
+ PxBoundedData() : count( 0 ) {}
+};
+
+template<uint8_t TNumBytes>
+struct PxPadding
+{
+ uint8_t mPadding[TNumBytes];
+ PxPadding()
+ {
+ for ( uint8_t idx =0; idx < TNumBytes; ++idx )
+ mPadding[idx] = 0;
+ }
+};
+
+template <uint32_t NB_ELEMENTS> class PxFixedSizeLookupTable
+{
+//= ATTENTION! =====================================================================================
+// Changing the data layout of this class breaks the binary serialization format. See comments for
+// PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData
+// function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION
+// accordingly.
+//==================================================================================================
+public:
+
+ PxFixedSizeLookupTable()
+ : mNbDataPairs(0)
+ {
+ }
+
+ PxFixedSizeLookupTable(const physx::PxEMPTY) {}
+
+ PxFixedSizeLookupTable(const float* dataPairs, const uint32_t numDataPairs)
+ {
+ memcpy(mDataPairs,dataPairs,sizeof(float)*2*numDataPairs);
+ mNbDataPairs=numDataPairs;
+ }
+
+ PxFixedSizeLookupTable(const PxFixedSizeLookupTable& src)
+ {
+ memcpy(mDataPairs,src.mDataPairs,sizeof(float)*2*src.mNbDataPairs);
+ mNbDataPairs=src.mNbDataPairs;
+ }
+
+ ~PxFixedSizeLookupTable()
+ {
+ }
+
+ PxFixedSizeLookupTable& operator=(const PxFixedSizeLookupTable& src)
+ {
+ memcpy(mDataPairs,src.mDataPairs,sizeof(float)*2*src.mNbDataPairs);
+ mNbDataPairs=src.mNbDataPairs;
+ return *this;
+ }
+
+ PX_FORCE_INLINE void addPair(const float x, const float y)
+ {
+ PX_ASSERT(mNbDataPairs<NB_ELEMENTS);
+ mDataPairs[2*mNbDataPairs+0]=x;
+ mDataPairs[2*mNbDataPairs+1]=y;
+ mNbDataPairs++;
+ }
+
+ PX_FORCE_INLINE float getYVal(const float x) const
+ {
+ if(0==mNbDataPairs)
+ {
+ PX_ASSERT(false);
+ return 0;
+ }
+
+ if(1==mNbDataPairs || x<getX(0))
+ {
+ return getY(0);
+ }
+
+ float x0=getX(0);
+ float y0=getY(0);
+
+ for (uint32_t i = 1; i<mNbDataPairs; i++)
+ {
+ const float x1=getX(i);
+ const float y1=getY(i);
+
+ if((x>=x0)&&(x<x1))
+ {
+ return (y0+(y1-y0)*(x-x0)/(x1-x0));
+ }
+
+ x0=x1;
+ y0=y1;
+ }
+
+ PX_ASSERT(x>=getX(mNbDataPairs-1));
+ return getY(mNbDataPairs-1);
+ }
+
+ uint32_t getNbDataPairs() const {return mNbDataPairs;}
+
+ void clear()
+ {
+ memset(mDataPairs, 0, NB_ELEMENTS*2*sizeof(float));
+ mNbDataPairs = 0;
+ }
+
+ PX_FORCE_INLINE float getX(const uint32_t i) const
+ {
+ return mDataPairs[2*i];
+ }
+ PX_FORCE_INLINE float getY(const uint32_t i) const
+ {
+ return mDataPairs[2*i+1];
+ }
+
+ float mDataPairs[2*NB_ELEMENTS];
+ uint32_t mNbDataPairs;
+ uint32_t mPad[3];
+
+
+};
+
+struct PxMeshFlag
+{
+ enum Enum
+ {
+ /**
+ \brief Specifies if the SDK should flip normals.
+
+ The PhysX libraries assume that the face normal of a triangle with vertices [a,b,c] can be computed as:
+ edge1 = b-a
+ edge2 = c-a
+ face_normal = edge1 x edge2.
+
+ Note: This is the same as a counterclockwise winding in a right handed coordinate system or
+ alternatively a clockwise winding order in a left handed coordinate system.
+
+ If this does not match the winding order for your triangles, raise the below flag.
+ */
+ eFLIPNORMALS = (1<<0),
+ e16_BIT_INDICES = (1<<1) //!< Denotes the use of 16-bit vertex indices
+ };
+};
+
+/**
+\brief collection of set bits defined in PxMeshFlag.
+
+@see PxMeshFlag
+*/
+typedef physx::PxFlags<PxMeshFlag::Enum, uint16_t> PxMeshFlags;
+using physx::PxFlags;
+PX_FLAGS_OPERATORS(PxMeshFlag::Enum, uint16_t)
+
+#if !PX_DOXYGEN
+} // namespace nvidia
+#endif
+
+
+/** @} */
+#endif
diff --git a/APEX_1.4/module/clothing/embedded/ExtClothFabricCooker.cpp b/APEX_1.4/module/clothing/embedded/ExtClothFabricCooker.cpp
new file mode 100644
index 00000000..4df323d7
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/ExtClothFabricCooker.cpp
@@ -0,0 +1,595 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "ExtClothConfig.h"
+#if APEX_USE_CLOTH_API
+
+#include "ExtClothFabricCooker.h"
+#include "ExtClothTetherCooker.h"
+#include "PxVec4.h"
+#include "PsFoundation.h"
+#include "PxErrorCallback.h"
+#include "PsArray.h"
+#include "PsHashMap.h"
+#include "PsSort.h"
+#include "PxIO.h"
+
+#include "PxStrideIterator.h"
+
+#pragma warning(disable:4127)
+
+using namespace nvidia;
+using namespace physx;
+
+struct nvidia::PxFabricCookerImpl
+{
+ bool cook(const PxClothMeshDesc& desc, PxVec3 gravity, bool useGeodesicTether);
+
+ PxClothFabricDesc getDescriptor() const;
+ void save(physx::PxOutputStream& stream, bool platformMismatch) const;
+
+public:
+ uint32_t mNumParticles;
+
+ shdfnd::Array<PxClothFabricPhase> mPhases;
+ shdfnd::Array<uint32_t> mSets; // with 0 prefix
+ shdfnd::Array<float> mRestvalues;
+ shdfnd::Array<uint32_t> mIndices;
+
+ shdfnd::Array<uint32_t> mTetherAnchors;
+ shdfnd::Array<float> mTetherLengths;
+};
+
+PxClothFabricCooker::PxClothFabricCooker(const PxClothMeshDesc& desc, const PxVec3& gravity, bool useGeodesicTether)
+: mImpl(new PxFabricCookerImpl())
+{
+ mImpl->cook(desc, gravity, useGeodesicTether);
+}
+
+PxClothFabricCooker::~PxClothFabricCooker()
+{
+ delete mImpl;
+}
+
+PxClothFabricDesc PxClothFabricCooker::getDescriptor() const
+{
+ return mImpl->getDescriptor();
+}
+
+void PxClothFabricCooker::save(physx::PxOutputStream& stream, bool platformMismatch) const
+{
+ mImpl->save(stream, platformMismatch);
+}
+
+
+namespace
+{
+ // calculate the inclusive prefix sum, equivalent of std::partial_sum
+ template <typename T>
+ void prefixSum(const T* first, const T* last, T* dest)
+ {
+ if (first != last)
+ {
+ *(dest++) = *(first++);
+ for (; first != last; ++first, ++dest)
+ *dest = *(dest-1) + *first;
+ }
+ }
+
+ template <typename T>
+ void gatherAdjacencies(shdfnd::Array<uint32_t>& valency, shdfnd::Array<uint32_t>& adjacencies,
+ const PxBoundedData& triangles, const PxBoundedData& quads)
+ {
+ // count number of edges per vertex
+ PxStrideIterator<const T> tIt, qIt;
+ tIt = physx::PxMakeIterator((const T*)triangles.data, triangles.stride);
+ for(uint32_t i=0; i<triangles.count; ++i, ++tIt, ++qIt)
+ {
+ for(uint32_t j=0; j<3; ++j)
+ valency[tIt.ptr()[j]] += 2;
+ }
+ qIt = physx::PxMakeIterator((const T*)quads.data, quads.stride);
+ for(uint32_t i=0; i<quads.count; ++i, ++tIt, ++qIt)
+ {
+ for(uint32_t j=0; j<4; ++j)
+ valency[qIt.ptr()[j]] += 2;
+ }
+
+ prefixSum(valency.begin(), valency.end(), valency.begin());
+ adjacencies.resize(valency.back());
+
+ // gather adjacent vertices
+ tIt = physx::PxMakeIterator((const T*)triangles.data, triangles.stride);
+ for(uint32_t i=0; i<triangles.count; ++i, ++tIt)
+ {
+ for(uint32_t j=0; j<3; ++j)
+ {
+ adjacencies[--valency[tIt.ptr()[j]]] = tIt.ptr()[(j+1)%3];
+ adjacencies[--valency[tIt.ptr()[j]]] = tIt.ptr()[(j+2)%3];
+ }
+ }
+ qIt = physx::PxMakeIterator((const T*)quads.data, quads.stride);
+ for(uint32_t i=0; i<quads.count; ++i, ++qIt)
+ {
+ for(uint32_t j=0; j<4; ++j)
+ {
+ adjacencies[--valency[qIt.ptr()[j]]] = qIt.ptr()[(j+1)%4];
+ adjacencies[--valency[qIt.ptr()[j]]] = qIt.ptr()[(j+3)%4];
+ }
+ }
+ }
+
+
+ struct Edge
+ {
+ Edge() : mStretching(0.0f), mBending(0.0f), mShearing(0.0f) {}
+
+ void classify()
+ {
+ mStretching += 0.1f;
+ }
+
+ // classify v0-v2 edge based on alternative v0-v1-v2 path
+ void classify(const PxVec4& v0, const PxVec4& v1, const PxVec4& v2)
+ {
+ const PxVec3& p0 = reinterpret_cast<const PxVec3&>(v0);
+ const PxVec3& p1 = reinterpret_cast<const PxVec3&>(v1);
+ const PxVec3& p2 = reinterpret_cast<const PxVec3&>(v2);
+
+ float area = (p1-p0).cross(p2-p1).magnitude();
+ // triangle height / base length
+ // 1.0 = quad edge, 0.2 = quad diagonal + quad edge,
+ float ratio = area / (p2-p0).magnitudeSquared();
+
+ // 0.5 = quad diagonal
+ mShearing += PxMax(0.0f, 0.15f - fabsf(0.45f - ratio));
+ // 0.0 = collinear points
+ mBending += PxMax(0.0f, 0.1f - ratio) * 3;
+ }
+
+ float mStretching;
+ float mBending;
+ float mShearing;
+ };
+
+ typedef shdfnd::Pair<uint32_t, uint32_t> Pair;
+ typedef shdfnd::Pair<Pair, PxClothFabricPhaseType::Enum> Entry;
+
+ // maintain heap status after elements have been pushed (heapify)
+ template<typename T>
+ void pushHeap(shdfnd::Array<T> &heap, const T &value)
+ {
+ heap.pushBack(value);
+ T* begin = heap.begin();
+ T* end = heap.end();
+
+ if (end <= begin)
+ return;
+
+ uint32_t current = uint32_t(end - begin) - 1;
+ while (current > 0)
+ {
+ const uint32_t parent = (current - 1) / 2;
+ if (!(begin[parent] < begin[current]))
+ break;
+
+ shdfnd::swap(begin[parent], begin[current]);
+ current = parent;
+ }
+ }
+
+ // pop one element from the heap
+ template<typename T>
+ T popHeap(shdfnd::Array<T> &heap)
+ {
+ T* begin = heap.begin();
+ T* end = heap.end();
+
+ shdfnd::swap(begin[0], end[-1]); // exchange elements
+
+ // shift down
+ end--;
+
+ uint32_t current = 0;
+ while (begin + (current * 2 + 1) < end)
+ {
+ uint32_t child = current * 2 + 1;
+ if (begin + child + 1 < end && begin[child] < begin[child + 1])
+ ++child;
+
+ if (!(begin[current] < begin[child]))
+ break;
+
+ shdfnd::swap(begin[current], begin[child]);
+ current = child;
+ }
+
+ return heap.popBack();
+ }
+
+ // ---------------------------------------------------------------------------------------
+ // Heap element to sort constraint based on graph color count
+ struct ConstraintGraphColorCount
+ {
+ ConstraintGraphColorCount(int cid, int count)
+ : constraint((uint32_t)cid), colorCount((uint32_t)count) {}
+
+ uint32_t constraint;
+ uint32_t colorCount;
+
+ bool operator < (const ConstraintGraphColorCount& c) const
+ {
+ return colorCount < c.colorCount;
+ }
+ };
+
+ struct ConstraintSorter
+ {
+ public:
+
+ ConstraintSorter(uint32_t* constraints_) : constraints(constraints_) {}
+
+ bool operator()(uint32_t i, uint32_t j) const
+ {
+ uint32_t ci = i*2;
+ uint32_t cj = j*2;
+
+ if (constraints[ci] == constraints[cj])
+ return constraints[ci+1] < constraints[cj+1];
+ else
+ return constraints[ci] < constraints[cj];
+ }
+
+ uint32_t* constraints;
+ };
+
+} // anonymous namespace
+
+bool nvidia::PxFabricCookerImpl::cook(const PxClothMeshDesc& desc, PxVec3 gravity, bool useGeodesicTether)
+{
+ if(!desc.isValid())
+ {
+ shdfnd::getFoundation().getErrorCallback().reportError(PxErrorCode::eINVALID_PARAMETER,
+ "PxFabricCookerImpl::cook: desc.isValid() failed!", __FILE__, __LINE__);
+ return false;
+ }
+
+ gravity = gravity.getNormalized();
+
+ mNumParticles = desc.points.count;
+
+ // assemble points
+ shdfnd::Array<PxVec4> particles;
+ particles.reserve(mNumParticles);
+ PxStrideIterator<const PxVec3> pIt((const PxVec3*)desc.points.data, desc.points.stride);
+ PxStrideIterator<const float> wIt((const float*)desc.invMasses.data, desc.invMasses.stride);
+ for(uint32_t i=0; i<mNumParticles; ++i)
+ particles.pushBack(PxVec4(*pIt++, wIt.ptr() ? *wIt++ : 1.0f));
+
+ // build adjacent vertex list
+ shdfnd::Array<uint32_t> valency(mNumParticles+1, 0);
+ shdfnd::Array<uint32_t> adjacencies;
+ if(desc.flags & PxMeshFlag::e16_BIT_INDICES)
+ gatherAdjacencies<uint16_t>(valency, adjacencies, desc.triangles, desc.quads);
+ else
+ gatherAdjacencies<uint32_t>(valency, adjacencies, desc.triangles, desc.quads);
+
+ // build unique neighbors from adjacencies
+ shdfnd::Array<uint32_t> mark(valency.size(), 0);
+ shdfnd::Array<uint32_t> neighbors; neighbors.reserve(adjacencies.size());
+ for(uint32_t i=1, j=0; i<valency.size(); ++i)
+ {
+ for(; j<valency[i]; ++j)
+ {
+ uint32_t k = adjacencies[j];
+ if(mark[k] != i)
+ {
+ mark[k] = i;
+ neighbors.pushBack(k);
+ }
+ }
+ valency[i] = neighbors.size();
+ }
+
+ // build map of unique edges and classify
+ shdfnd::HashMap<Pair, Edge> edges;
+ for(uint32_t i=0; i<mNumParticles; ++i)
+ {
+ float wi = particles[i].w;
+ // iterate all neighbors
+ uint32_t jlast = valency[i+1];
+ for(uint32_t j=valency[i]; j<jlast; ++j)
+ {
+ // add 1-ring edge
+ uint32_t m = neighbors[j];
+ if(wi + particles[m].w > 0.0f)
+ edges[Pair(PxMin(i, m), PxMax(i, m))].classify();
+
+ // iterate all neighbors of neighbor
+ uint32_t klast = valency[m+1];
+ for(uint32_t k=valency[m]; k<klast; ++k)
+ {
+ uint32_t n = neighbors[k];
+ if(n != i && wi + particles[n].w > 0.0f)
+ {
+ // add 2-ring edge
+ edges[Pair(PxMin(i, n), PxMax(i, n))].classify(
+ particles[i], particles[m], particles[n]);
+ }
+ }
+ }
+ }
+
+ // copy classified edges to constraints array
+ // build histogram of constraints per vertex
+ shdfnd::Array<Entry> constraints;
+ constraints.reserve(edges.size());
+ valency.resize(0); valency.resize(mNumParticles+1, 0);
+
+ const float sqrtHalf = PxSqrt(0.4f);
+ for(shdfnd::HashMap<Pair, Edge>::Iterator eIt = edges.getIterator(); !eIt.done(); ++eIt)
+ {
+ const Edge& edge = eIt->second;
+ const Pair& pair = eIt->first;
+ if((edge.mStretching + edge.mBending + edge.mShearing) > 0.0f)
+ {
+ PxClothFabricPhaseType::Enum type = PxClothFabricPhaseType::eINVALID;
+ if(edge.mBending > PxMax(edge.mStretching, edge.mShearing))
+ type = PxClothFabricPhaseType::eBENDING;
+ else if(edge.mShearing > PxMax(edge.mStretching, edge.mBending))
+ type = PxClothFabricPhaseType::eSHEARING;
+ else
+ {
+ PxVec4 diff = particles[pair.first]-particles[pair.second];
+ float dot = gravity.dot(reinterpret_cast<const PxVec3&>(diff).getNormalized());
+ type = fabsf(dot) < sqrtHalf ? PxClothFabricPhaseType::eHORIZONTAL : PxClothFabricPhaseType::eVERTICAL;
+ }
+ ++valency[pair.first];
+ ++valency[pair.second];
+ constraints.pushBack(Entry(pair, type));
+ }
+ }
+
+ prefixSum(valency.begin(), valency.end(), valency.begin());
+
+ uint32_t numConstraints = constraints.size();
+
+ // build adjacent constraint list
+ adjacencies.resize(0); adjacencies.resize(valency.back(), 0);
+ for(uint32_t i=0; i<numConstraints; ++i)
+ {
+ adjacencies[--valency[constraints[i].first.first]] = i;
+ adjacencies[--valency[constraints[i].first.second]] = i;
+ }
+
+ shdfnd::Array<uint32_t>::ConstIterator aFirst = adjacencies.begin();
+ shdfnd::Array<uint32_t> colors(numConstraints, numConstraints); // constraint -> color, initialily not colored
+ mark.resize(0); mark.resize(numConstraints+1, UINT32_MAX); // color -> constraint index
+ shdfnd::Array<uint32_t> adjColorCount(numConstraints, 0); // # of neighbors that are already colored
+
+ shdfnd::Array<ConstraintGraphColorCount> constraintHeap;
+ constraintHeap.reserve(numConstraints); // set of constraints to color (added in edge distance order)
+
+ // Do graph coloring based on edge distance.
+ // For each constraint, we add its uncolored neighbors to the heap
+ // ,and we pick the constraint with most colored neighbors from the heap.
+ while ( true )
+ {
+ uint32_t constraint = 0;
+ while ( (constraint < numConstraints) && (colors[constraint] != numConstraints))
+ constraint++; // start with the first uncolored constraint
+
+ if (constraint >= numConstraints)
+ break;
+
+ constraintHeap.clear();
+ pushHeap(constraintHeap, ConstraintGraphColorCount((int)constraint, (int)adjColorCount[constraint]));
+ PxClothFabricPhaseType::Enum type = constraints[constraint].second;
+
+ while (!constraintHeap.empty())
+ {
+ ConstraintGraphColorCount heapItem = popHeap(constraintHeap);
+ constraint = heapItem.constraint;
+ if (colors[constraint] != numConstraints)
+ continue; // skip if already colored
+
+ const Pair& pair = constraints[constraint].first;
+ for(uint32_t j=0; j<2; ++j)
+ {
+ uint32_t index = j ? pair.first : pair.second;
+ if(particles[index].w == 0.0f)
+ continue; // don't mark adjacent particles if attached
+
+ for(shdfnd::Array<uint32_t>::ConstIterator aIt = aFirst + valency[index], aEnd = aFirst + valency[index+1]; aIt != aEnd; ++aIt)
+ {
+ uint32_t adjacentConstraint = *aIt;
+ if ((constraints[adjacentConstraint].second != type) || (adjacentConstraint == constraint))
+ continue;
+
+ mark[colors[adjacentConstraint]] = constraint;
+ ++adjColorCount[adjacentConstraint];
+ pushHeap(constraintHeap, ConstraintGraphColorCount((int)adjacentConstraint, (int)adjColorCount[adjacentConstraint]));
+ }
+ }
+
+ // find smallest color with matching type
+ uint32_t color = 0;
+ while((color < mPhases.size() && mPhases[color].phaseType != type) || mark[color] == constraint)
+ ++color;
+
+ // create a new color set
+ if(color == mPhases.size())
+ {
+ PxClothFabricPhase phase(type, mPhases.size());
+ mPhases.pushBack(phase);
+ mSets.pushBack(0);
+ }
+
+ colors[constraint] = color;
+ ++mSets[color];
+ }
+ }
+
+#if 0 // PX_DEBUG
+ printf("set[%u] = ", mSets.size());
+ for(uint32_t i=0; i<mSets.size(); ++i)
+ printf("%u ", mSets[i]);
+#endif
+
+ prefixSum(mSets.begin(), mSets.end(), mSets.begin());
+
+#if 0 // PX_DEBUG
+ printf(" = %u\n", mSets.back());
+#endif
+
+ // write indices and rest lengths
+ // convert mSets to exclusive sum
+ uint32_t back = mSets.back();
+ mSets.pushBack(back);
+ mIndices.resize(numConstraints*2);
+ mRestvalues.resize(numConstraints);
+ for(uint32_t i=0; i<numConstraints; ++i)
+ {
+ uint32_t first = constraints[i].first.first;
+ uint32_t second = constraints[i].first.second;
+
+ uint32_t index = --mSets[colors[i]];
+
+ mIndices[2*index ] = first;
+ mIndices[2*index+1] = second;
+
+ PxVec4 diff = particles[second] - particles[first];
+ mRestvalues[index] = reinterpret_cast<
+ const PxVec3&>(diff).magnitude();
+ }
+
+ // reorder constraints and rest values for more efficient cache access (linear)
+ shdfnd::Array<uint32_t> newIndices(mIndices.size());
+ shdfnd::Array<float> newRestValues(mRestvalues.size());
+
+ // sort each constraint set in vertex order
+ for (uint32_t i=0; i < mSets.size()-1; ++i)
+ {
+ // create a re-ordering list
+ shdfnd::Array<uint32_t> reorder(mSets[i+1]-mSets[i]);
+
+ for (uint32_t r=0; r < reorder.size(); ++r)
+ reorder[r] = r;
+
+ const uint32_t indicesOffset = mSets[i]*2;
+ const uint32_t restOffset = mSets[i];
+
+ ConstraintSorter predicate(&mIndices[indicesOffset]);
+ shdfnd::sort(&reorder[0], reorder.size(), predicate);
+
+ for (uint32_t r=0; r < reorder.size(); ++r)
+ {
+ newIndices[indicesOffset + r*2] = mIndices[indicesOffset + reorder[r]*2];
+ newIndices[indicesOffset + r*2+1] = mIndices[indicesOffset + reorder[r]*2+1];
+ newRestValues[restOffset + r] = mRestvalues[restOffset + reorder[r]];
+ }
+ }
+
+ mIndices = newIndices;
+ mRestvalues = newRestValues;
+
+ PX_ASSERT(mIndices.size() == mRestvalues.size()*2);
+ PX_ASSERT(mRestvalues.size() == mSets.back());
+
+#if 0 // PX_DEBUG
+ for (uint32_t i = 1; i < mSets.size(); i++)
+ {
+ PxClothFabricPhase phase = mPhases[i-1];
+ printf("%d : type %d, size %d\n",
+ i-1, phase.phaseType, mSets[i] - mSets[i-1]);
+ }
+#endif
+
+ if (useGeodesicTether)
+ {
+ PxClothGeodesicTetherCooker tetherCooker(desc);
+ if (tetherCooker.getCookerStatus() == 0)
+ {
+ uint32_t numTethersPerParticle = tetherCooker.getNbTethersPerParticle();
+ uint32_t tetherSize = mNumParticles * numTethersPerParticle;
+ mTetherAnchors.resize(tetherSize);
+ mTetherLengths.resize(tetherSize);
+ tetherCooker.getTetherData(mTetherAnchors.begin(), mTetherLengths.begin());
+ }
+ else
+ useGeodesicTether = false;
+ }
+
+ if (!useGeodesicTether)
+ {
+ PxClothSimpleTetherCooker tetherCooker(desc);
+ if (tetherCooker.getCookerStatus() == 0)
+ {
+ mTetherAnchors.resize(mNumParticles);
+ mTetherLengths.resize(mNumParticles);
+ tetherCooker.getTetherData(mTetherAnchors.begin(), mTetherLengths.begin());
+ }
+ }
+
+ return true;
+}
+
+PxClothFabricDesc nvidia::PxFabricCookerImpl::getDescriptor() const
+{
+ PxClothFabricDesc result;
+
+ result.nbParticles = mNumParticles;
+ result.nbPhases = mPhases.size();
+ result.phases = mPhases.begin();
+ result.nbSets = mSets.size()-1;
+ result.sets = mSets.begin()+1;
+ result.restvalues = mRestvalues.begin();
+ result.indices = mIndices.begin();
+ result.nbTethers = mTetherAnchors.size();
+ result.tetherAnchors = mTetherAnchors.begin();
+ result.tetherLengths = mTetherLengths.begin();
+
+ return result;
+}
+
+void nvidia::PxFabricCookerImpl::save( physx::PxOutputStream& stream, bool /*platformMismatch*/ ) const
+{
+ // version 1 is equivalent to 0x030300 and 0x030301 (PX_PHYSICS_VERSION of 3.3.0 and 3.3.1).
+ // If the stream format changes, the loader code in ScClothFabricCore.cpp
+ // and the version number need to change too.
+ uint32_t version = 1;
+ stream.write(&version, sizeof(uint32_t));
+
+ PxClothFabricDesc desc = getDescriptor();
+
+ // write explicit sizes, others are implicit
+ stream.write(&mNumParticles, sizeof(uint32_t));
+ stream.write(&desc.nbPhases, sizeof(uint32_t));
+ stream.write(&desc.nbSets, sizeof(uint32_t));
+ stream.write(&desc.nbTethers, sizeof(uint32_t));
+
+ uint32_t nbConstraints = desc.sets[desc.nbSets-1];
+
+ // write actual data
+ PX_COMPILE_TIME_ASSERT(sizeof(PxClothFabricPhaseType::Enum) == sizeof(uint32_t));
+ stream.write(desc.phases, desc.nbPhases*sizeof(PxClothFabricPhase));
+ stream.write(desc.sets, desc.nbSets*sizeof(uint32_t));
+
+ stream.write(desc.restvalues, nbConstraints*sizeof(float));
+ stream.write(desc.indices, nbConstraints*2*sizeof(uint32_t));
+
+ stream.write(desc.tetherAnchors, desc.nbTethers*sizeof(uint32_t));
+ stream.write(desc.tetherLengths, desc.nbTethers*sizeof(float));
+}
+
+#endif //APEX_USE_CLOTH_API
diff --git a/APEX_1.4/module/clothing/embedded/ExtClothFabricCooker.h b/APEX_1.4/module/clothing/embedded/ExtClothFabricCooker.h
new file mode 100644
index 00000000..dc6ec2cc
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/ExtClothFabricCooker.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PX_PHYSICS_EXTENSIONS_CLOTH_FABRIC_COOKER_H
+#define PX_PHYSICS_EXTENSIONS_CLOTH_FABRIC_COOKER_H
+
+/** \addtogroup extensions
+ @{
+*/
+
+#include "PxClothMeshDesc.h"
+#include "PxClothFabric.h"
+
+#if PX_DOXYGEN == 0
+namespace nvidia
+{
+#endif
+
+struct PxFabricCookerImpl;
+
+class PxClothFabricCooker
+{
+public:
+ /**
+ \brief Cooks a triangle mesh to a PxClothFabricDesc.
+ \param desc The cloth mesh descriptor on which the generation of the cooked mesh depends.
+ \param gravity A normalized vector which specifies the direction of gravity.
+ This information allows the cooker to generate a fabric with higher quality simulation behavior.
+ \param useGeodesicTether A flag to indicate whether to compute geodesic distance for tether constraints.
+ \note The geodesic option for tether only works for manifold input. For non-manifold input, a simple Euclidean distance will be used.
+ For more detailed cooker status for such cases, try running PxClothGeodesicTetherCooker directly.
+ */
+ PxClothFabricCooker(const PxClothMeshDesc& desc, const physx::PxVec3& gravity, bool useGeodesicTether = true);
+ ~PxClothFabricCooker();
+
+ /** \brief Returns the fabric descriptor to create the fabric. */
+ PxClothFabricDesc getDescriptor() const;
+ /** \brief Saves the fabric data to a platform and version dependent stream. */
+ void save(physx::PxOutputStream& stream, bool platformMismatch) const;
+
+private:
+ PxFabricCookerImpl* mImpl;
+};
+
+#if PX_DOXYGEN == 0
+} // namespace nvidia
+#endif
+
+/** @} */
+#endif // PX_PHYSICS_EXTENSIONS_CLOTH_FABRIC_COOKER_H
diff --git a/APEX_1.4/module/clothing/embedded/ExtClothGeodesicTetherCooker.cpp b/APEX_1.4/module/clothing/embedded/ExtClothGeodesicTetherCooker.cpp
new file mode 100644
index 00000000..e0fea857
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/ExtClothGeodesicTetherCooker.cpp
@@ -0,0 +1,1006 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "ExtClothConfig.h"
+#if APEX_USE_CLOTH_API
+
+#include "ExtClothTetherCooker.h"
+#include "PxStrideIterator.h"
+
+// from shared foundation
+
+#include <PsArray.h>
+#include <PsSort.h>
+#include <Ps.h>
+#include <PsMathUtils.h>
+#include "PxVec4.h"
+#include "PsIntrinsics.h"
+
+using namespace nvidia;
+using namespace physx;
+
+namespace
+{
+ // calculate the inclusive prefix sum, equivalent of std::partial_sum
+ template <typename T>
+ void prefixSum(const T* first, const T* last, T* dest)
+ {
+ if (first != last)
+ {
+ *(dest++) = *(first++);
+ for (; first != last; ++first, ++dest)
+ *dest = *(dest-1) + *first;
+ }
+ }
+
+ template <typename T>
+ void gatherAdjacencies(shdfnd::Array<uint32_t>& valency, shdfnd::Array<uint32_t>& adjacencies,
+ const PxBoundedData& triangles, const PxBoundedData& quads)
+ {
+ // count number of edges per vertex
+ PxStrideIterator<const T> tIt, qIt;
+ tIt = physx::PxMakeIterator((const T*)triangles.data, triangles.stride);
+ for(uint32_t i=0; i<triangles.count; ++i, ++tIt, ++qIt)
+ {
+ for(uint32_t j=0; j<3; ++j)
+ valency[tIt.ptr()[j]] += 2;
+ }
+ qIt = physx::PxMakeIterator((const T*)quads.data, quads.stride);
+ for(uint32_t i=0; i<quads.count; ++i, ++tIt, ++qIt)
+ {
+ for(uint32_t j=0; j<4; ++j)
+ valency[qIt.ptr()[j]] += 2;
+ }
+
+ prefixSum(valency.begin(), valency.end(), valency.begin());
+ adjacencies.resize(valency.back());
+
+ // gather adjacent vertices
+ tIt = physx::PxMakeIterator((const T*)triangles.data, triangles.stride);
+ for(uint32_t i=0; i<triangles.count; ++i, ++tIt)
+ {
+ for(uint32_t j=0; j<3; ++j)
+ {
+ adjacencies[--valency[tIt.ptr()[j]]] = tIt.ptr()[(j+1)%3];
+ adjacencies[--valency[tIt.ptr()[j]]] = tIt.ptr()[(j+2)%3];
+ }
+ }
+ qIt = physx::PxMakeIterator((const T*)quads.data, quads.stride);
+ for(uint32_t i=0; i<quads.count; ++i, ++qIt)
+ {
+ for(uint32_t j=0; j<4; ++j)
+ {
+ adjacencies[--valency[qIt.ptr()[j]]] = qIt.ptr()[(j+1)%4];
+ adjacencies[--valency[qIt.ptr()[j]]] = qIt.ptr()[(j+3)%4];
+ }
+ }
+ }
+
+ template <typename T>
+ void gatherIndices(shdfnd::Array<uint32_t>& indices,
+ const PxBoundedData& triangles, const PxBoundedData& quads)
+ {
+ PxStrideIterator<const T> tIt, qIt;
+
+ indices.reserve(triangles.count * 3 + quads.count * 6);
+
+ tIt = physx::PxMakeIterator((const T*)triangles.data, triangles.stride);
+ for(uint32_t i=0; i<triangles.count; ++i, ++tIt)
+ {
+ indices.pushBack(tIt.ptr()[0]);
+ indices.pushBack(tIt.ptr()[1]);
+ indices.pushBack(tIt.ptr()[2]);
+ }
+ qIt = physx::PxMakeIterator((const T*)quads.data, quads.stride);
+ for(uint32_t i=0; i<quads.count; ++i, ++qIt)
+ {
+ indices.pushBack(qIt.ptr()[0]);
+ indices.pushBack(qIt.ptr()[1]);
+ indices.pushBack(qIt.ptr()[2]);
+ indices.pushBack(qIt.ptr()[0]);
+ indices.pushBack(qIt.ptr()[2]);
+ indices.pushBack(qIt.ptr()[3]);
+ }
+ }
+
+ // maintain heap status after elements have been pushed (heapify)
+ template<typename T>
+ void pushHeap(shdfnd::Array<T> &heap, const T &value)
+ {
+ heap.pushBack(value);
+ T* begin = heap.begin();
+ T* end = heap.end();
+
+ if (end <= begin)
+ return;
+
+ uint32_t current = uint32_t(end - begin) - 1;
+ while (current > 0)
+ {
+ const uint32_t parent = (current - 1) / 2;
+ if (!(begin[parent] < begin[current]))
+ break;
+
+ shdfnd::swap(begin[parent], begin[current]);
+ current = parent;
+ }
+ }
+
+ // pop one element from the heap
+ template<typename T>
+ T popHeap(shdfnd::Array<T> &heap)
+ {
+ T* begin = heap.begin();
+ T* end = heap.end();
+
+ shdfnd::swap(begin[0], end[-1]); // exchange elements
+
+ // shift down
+ end--;
+
+ uint32_t current = 0;
+ while (begin + (current * 2 + 1) < end)
+ {
+ uint32_t child = current * 2 + 1;
+ if (begin + child + 1 < end && begin[child] < begin[child + 1])
+ ++child;
+
+ if (!(begin[current] < begin[child]))
+ break;
+
+ shdfnd::swap(begin[current], begin[child]);
+ current = child;
+ }
+
+ return heap.popBack();
+ }
+
+ // ---------------------------------------------------------------------------------------
+ struct VertexDistanceCount
+ {
+ VertexDistanceCount(int vert, float dist, int count)
+ : vertNr(vert), distance(dist), edgeCount(count) {}
+
+ int vertNr;
+ float distance;
+ int edgeCount;
+ bool operator < (const VertexDistanceCount& v) const
+ {
+ return v.distance < distance;
+ }
+ };
+
+ // ---------------------------------------------------------------------------------------
+ struct PathIntersection
+ {
+ uint32_t vertOrTriangle;
+ uint32_t index; // vertex id or triangle edge id
+ float s; // only used for edge intersection
+ float distance; // computed distance
+
+ public:
+ PathIntersection() {}
+
+ PathIntersection(uint32_t vort, uint32_t in_index, float in_distance, float in_s = 0.0f)
+ : vertOrTriangle(vort), index(in_index), s(in_s), distance(in_distance)
+ {
+ }
+ };
+
+ //---------------------------------------------------------------------------------------
+ struct VertTriangle
+ {
+ VertTriangle(int vert, int triangle)
+ : mVertIndex(vert), mTriangleIndex(triangle)
+ {
+ }
+
+ bool operator<(const VertTriangle &vt) const
+ {
+ return mVertIndex == vt.mVertIndex ?
+ mTriangleIndex < vt.mTriangleIndex : mVertIndex < vt.mVertIndex;
+ }
+
+ int mVertIndex;
+ int mTriangleIndex;
+ };
+
+ // ---------------------------------------------------------------------------------------
+ struct MeshEdge
+ {
+ MeshEdge(int v0, int v1, int halfEdgeIndex)
+ : mFromVertIndex(v0), mToVertIndex(v1), mHalfEdgeIndex(halfEdgeIndex)
+ {
+ if(mFromVertIndex > mToVertIndex)
+ shdfnd::swap(mFromVertIndex, mToVertIndex);
+ }
+
+ bool operator<(const MeshEdge& e) const
+ {
+ return mFromVertIndex == e.mFromVertIndex ?
+ mToVertIndex < e.mToVertIndex : mFromVertIndex < e.mFromVertIndex;
+ }
+
+ bool operator==(const MeshEdge& e) const
+ {
+ return mFromVertIndex == e.mFromVertIndex
+ && mToVertIndex == e.mToVertIndex;
+ }
+
+ int mFromVertIndex, mToVertIndex;
+ int mHalfEdgeIndex;
+ };
+
+ // check if the edge is following triangle order or not
+ bool checkEdgeOrientation(const MeshEdge &e, const shdfnd::Array<uint32_t> &indices)
+ {
+ int offset0 = e.mHalfEdgeIndex % 3;
+ int offset1 = (offset0 < 2) ? 1 : -2;
+
+ int v0 = (int)indices[uint32_t(e.mHalfEdgeIndex)];
+ int v1 = (int)indices[uint32_t(e.mHalfEdgeIndex + offset1)];
+
+ if ((e.mFromVertIndex == v0) && (e.mToVertIndex == v1))
+ return true;
+
+ return false;
+ }
+
+ // check if two index pairs represent same edge regardless of order.
+ inline bool checkEdge(int ei0, int ei1, int ej0, int ej1)
+ {
+ return ( (ei0 == ej0) && (ei1 == ej1) ) ||
+ ( (ei0 == ej1) && (ei1 == ej0) );
+ }
+
+ // compute ray edge intersection
+ bool intersectRayEdge(const PxVec3 &O, const PxVec3 &D, const PxVec3 &A, const PxVec3 &B, float &s, float &t)
+ {
+ // point on edge P = A + s * AB
+ // point on ray R = o + t * d
+ // for this two points to intersect, we have
+ // |AB -d| | s t | = o - A
+ const float eps = 1e-4;
+
+ PxVec3 OA = O - A;
+ PxVec3 AB = B - A;
+
+ float a = AB.dot(AB), b = -AB.dot(D);
+ float c = b, d = D.dot(D);
+
+ float e = AB.dot(OA);
+ float f = -D.dot(OA);
+
+ float det = a * d - b * c;
+ if (fabs(det) < eps) // coplanar case
+ return false;
+
+ float iPX_det = 1.0f / det;
+
+ s = (d * iPX_det) * e + (-b * iPX_det) * f;
+ t = (-c * iPX_det) * e + (a * iPX_det) * f;
+
+ return true;
+ }
+}
+
+
+struct nvidia::PxClothGeodesicTetherCookerImpl
+{
+
+ PxClothGeodesicTetherCookerImpl(const PxClothMeshDesc& desc);
+
+ uint32_t getCookerStatus() const;
+ uint32_t getNbTethersPerParticle() const;
+ void getTetherData(uint32_t* userTetherAnchors, float* userTetherLengths) const;
+
+public:
+ // input
+ const PxClothMeshDesc& mDesc;
+
+ // internal variables
+ uint32_t mNumParticles;
+ shdfnd::Array<PxVec3> mVertices;
+ shdfnd::Array<uint32_t> mIndices;
+ shdfnd::Array<uint8_t> mAttached;
+ shdfnd::Array<uint32_t> mFirstVertTriAdj;
+ shdfnd::Array<uint32_t> mVertTriAdjs;
+ shdfnd::Array<uint32_t> mTriNeighbors; // needs changing for non-manifold support
+
+ // error status
+ uint32_t mCookerStatus;
+
+ // output
+ shdfnd::Array<uint32_t> mTetherAnchors;
+ shdfnd::Array<float> mTetherLengths;
+
+protected:
+ void createTetherData(const PxClothMeshDesc &desc);
+ int computeVertexIntersection(uint32_t parent, uint32_t src, PathIntersection &path);
+ int computeEdgeIntersection(uint32_t parent, uint32_t edge, float in_s, PathIntersection &path);
+ float computeGeodesicDistance(uint32_t i, uint32_t parent, int &errorCode);
+ uint32_t findTriNeighbors();
+ void findVertTriNeighbors();
+
+private:
+ PxClothGeodesicTetherCookerImpl& operator=(const PxClothGeodesicTetherCookerImpl&);
+};
+
+PxClothGeodesicTetherCooker::PxClothGeodesicTetherCooker(const PxClothMeshDesc& desc)
+: mImpl(new PxClothGeodesicTetherCookerImpl(desc))
+{
+}
+
+PxClothGeodesicTetherCooker::~PxClothGeodesicTetherCooker()
+{
+ delete mImpl;
+}
+
+uint32_t PxClothGeodesicTetherCooker::getCookerStatus() const
+{
+ return mImpl->getCookerStatus();
+}
+
+uint32_t PxClothGeodesicTetherCooker::getNbTethersPerParticle() const
+{
+ return mImpl->getNbTethersPerParticle();
+}
+
+void PxClothGeodesicTetherCooker::getTetherData(uint32_t* userTetherAnchors, float* userTetherLengths) const
+{
+ mImpl->getTetherData(userTetherAnchors, userTetherLengths);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+PxClothGeodesicTetherCookerImpl::PxClothGeodesicTetherCookerImpl(const PxClothMeshDesc &desc)
+ :mDesc(desc),
+ mCookerStatus(0)
+{
+ createTetherData(desc);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+void PxClothGeodesicTetherCookerImpl::createTetherData(const PxClothMeshDesc &desc)
+{
+ mNumParticles = desc.points.count;
+
+ if (!desc.invMasses.data)
+ return;
+
+ // assemble points
+ mVertices.resize(mNumParticles);
+ mAttached.resize(mNumParticles);
+ PxStrideIterator<const PxVec3> pIt((const PxVec3*)desc.points.data, desc.points.stride);
+ PxStrideIterator<const float> wIt((const float*)desc.invMasses.data, desc.invMasses.stride);
+ for(uint32_t i=0; i<mNumParticles; ++i)
+ {
+ mVertices[i] = *pIt++;
+ mAttached[i] = uint8_t(wIt.ptr() ? (*wIt++ == 0.0f) : 0);
+ }
+
+ // build triangle indices
+ if(desc.flags & PxMeshFlag::e16_BIT_INDICES)
+ gatherIndices<uint16_t>(mIndices, desc.triangles, desc.quads);
+ else
+ gatherIndices<uint32_t>(mIndices, desc.triangles, desc.quads);
+
+ // build vertex-triangle adjacencies
+ findVertTriNeighbors();
+
+ // build triangle-triangle adjacencies
+ mCookerStatus = findTriNeighbors();
+ if (mCookerStatus != 0)
+ return;
+
+ // build adjacent vertex list
+ shdfnd::Array<uint32_t> valency(mNumParticles+1, 0);
+ shdfnd::Array<uint32_t> adjacencies;
+ if(desc.flags & PxMeshFlag::e16_BIT_INDICES)
+ gatherAdjacencies<uint16_t>(valency, adjacencies, desc.triangles, desc.quads);
+ else
+ gatherAdjacencies<uint32_t>(valency, adjacencies, desc.triangles, desc.quads);
+
+ // build unique neighbors from adjacencies
+ shdfnd::Array<uint32_t> mark(valency.size(), 0);
+ shdfnd::Array<uint32_t> neighbors; neighbors.reserve(adjacencies.size());
+ for(uint32_t i=1, j=0; i<valency.size(); ++i)
+ {
+ for(; j<valency[i]; ++j)
+ {
+ uint32_t k = adjacencies[j];
+ if(mark[k] != i)
+ {
+ mark[k] = i;
+ neighbors.pushBack(k);
+ }
+ }
+ valency[i] = neighbors.size();
+ }
+
+ // create islands of attachment points
+ shdfnd::Array<uint32_t> vertexIsland(mNumParticles);
+ shdfnd::Array<VertexDistanceCount> vertexIslandHeap;
+
+ // put all the attachments in heap
+ for (uint32_t i = 0; i < mNumParticles; ++i)
+ {
+ // we put each attached point with large distance so that
+ // we can prioritize things that are added during mesh traversal.
+ vertexIsland[i] = uint32_t(-1);
+ if (mAttached[i])
+ vertexIslandHeap.pushBack(VertexDistanceCount((int)i, FLT_MAX, 0));
+ }
+ uint32_t attachedCnt = vertexIslandHeap.size();
+
+ // no attached vertices
+ if (vertexIslandHeap.empty())
+ return;
+
+ // identify islands of attached vertices
+ shdfnd::Array<uint32_t> islandIndices;
+ shdfnd::Array<uint32_t> islandFirst;
+ uint32_t islandCnt = 0;
+ uint32_t islandIndexCnt = 0;
+
+ islandIndices.reserve(attachedCnt);
+ islandFirst.reserve(attachedCnt+1);
+
+ // while the island heap is not empty
+ while (!vertexIslandHeap.empty())
+ {
+ // pop vi from heap
+ VertexDistanceCount vi = popHeap(vertexIslandHeap);
+
+ // new cluster
+ if (vertexIsland[(uint32_t)vi.vertNr] == uint32_t(-1))
+ {
+ islandFirst.pushBack(islandIndexCnt++);
+ vertexIsland[(uint32_t)vi.vertNr] = islandCnt++;
+ vi.distance = 0;
+ islandIndices.pushBack((uint32_t)vi.vertNr);
+ }
+
+ // for each adjacent vj that's not visited
+ const uint32_t begin = (uint32_t)valency[(uint32_t)vi.vertNr];
+ const uint32_t end = (uint32_t)valency[uint32_t(vi.vertNr + 1)];
+ for (uint32_t j = begin; j < end; ++j)
+ {
+ const uint32_t vj = neighbors[j];
+
+ // do not expand unattached vertices
+ if (!mAttached[vj])
+ continue;
+
+ // already visited
+ if (vertexIsland[vj] != uint32_t(-1))
+ continue;
+
+ islandIndices.pushBack(vj);
+ islandIndexCnt++;
+ vertexIsland[vj] = vertexIsland[uint32_t(vi.vertNr)];
+ pushHeap(vertexIslandHeap, VertexDistanceCount((int)vj, vi.distance + 1.0f, 0));
+ }
+ }
+
+ islandFirst.pushBack(islandIndexCnt);
+
+ PX_ASSERT(islandCnt == (islandFirst.size() - 1));
+
+ /////////////////////////////////////////////////////////
+ uint32_t bufferSize = mNumParticles * islandCnt;
+ PX_ASSERT(bufferSize > 0);
+
+ shdfnd::Array<float> vertexDistanceBuffer(bufferSize, PX_MAX_F32);
+ shdfnd::Array<uint32_t> vertexParentBuffer(bufferSize, 0);
+ shdfnd::Array<VertexDistanceCount> vertexHeap;
+
+ // now process each island
+ for (uint32_t i = 0; i < islandCnt; i++)
+ {
+ vertexHeap.clear();
+ float* vertexDistance = &vertexDistanceBuffer[0] + (i * mNumParticles);
+ uint32_t* vertexParent = &vertexParentBuffer[0] + (i * mNumParticles);
+
+ // initialize parent and distance
+ for (uint32_t j = 0; j < mNumParticles; ++j)
+ {
+ vertexParent[j] = j;
+ vertexDistance[j] = PX_MAX_F32;
+ }
+
+ // put all the attached vertices in this island to heap
+ const uint32_t beginIsland = islandFirst[i];
+ const uint32_t endIsland = islandFirst[i+1];
+ for (uint32_t j = beginIsland; j < endIsland; j++)
+ {
+ uint32_t vj = islandIndices[j];
+ vertexDistance[vj] = 0.0f;
+ vertexHeap.pushBack(VertexDistanceCount((int)vj, 0.0f, 0));
+ }
+
+ // no attached vertices in this island (error?)
+ PX_ASSERT(vertexHeap.empty() == false);
+ if (vertexHeap.empty())
+ continue;
+
+ // while heap is not empty
+ while (!vertexHeap.empty())
+ {
+ // pop vi from heap
+ VertexDistanceCount vi = popHeap(vertexHeap);
+
+ // obsolete entry ( we already found better distance)
+ if (vi.distance > vertexDistance[vi.vertNr])
+ continue;
+
+ // for each adjacent vj that's not visited
+ const int32_t begin = (int32_t)valency[(uint32_t)vi.vertNr];
+ const int32_t end = (int32_t)valency[uint32_t(vi.vertNr + 1)];
+ for (int32_t j = begin; j < end; ++j)
+ {
+ const int32_t vj = (int32_t)neighbors[(uint32_t)j];
+ PxVec3 edge = mVertices[(uint32_t)vj] - mVertices[(uint32_t)vi.vertNr];
+ const float edgeLength = edge.magnitude();
+ float newDistance = vi.distance + edgeLength;
+
+ if (newDistance < vertexDistance[vj])
+ {
+ vertexDistance[vj] = newDistance;
+ vertexParent[vj] = vertexParent[vi.vertNr];
+
+ pushHeap(vertexHeap, VertexDistanceCount(vj, newDistance, 0));
+ }
+ }
+ }
+ }
+
+ const uint32_t maxTethersPerParticle = 4; // max tethers
+ const uint32_t nbTethersPerParticle = (islandCnt > maxTethersPerParticle) ? maxTethersPerParticle : islandCnt;
+
+ uint32_t nbTethers = nbTethersPerParticle * mNumParticles;
+ mTetherAnchors.resize(nbTethers);
+ mTetherLengths.resize(nbTethers);
+
+ // now process the parent and distance and add to fibers
+ for (uint32_t i = 0; i < mNumParticles; i++)
+ {
+ // we use the heap to sort out N-closest island
+ vertexHeap.clear();
+ for (uint32_t j = 0; j < islandCnt; j++)
+ {
+ int parent = (int)vertexParentBuffer[j * mNumParticles + i];
+ float edgeDistance = vertexDistanceBuffer[j * mNumParticles + i];
+ pushHeap(vertexHeap, VertexDistanceCount(parent, edgeDistance, 0));
+ }
+
+ // take out N-closest island from the heap
+ for (uint32_t j = 0; j < nbTethersPerParticle; j++)
+ {
+ VertexDistanceCount vi = popHeap(vertexHeap);
+ uint32_t parent = (uint32_t)vi.vertNr;
+ float distance = 0.0f;
+
+ if (parent != i)
+ {
+ float euclideanDistance = (mVertices[i] - mVertices[parent]).magnitude();
+ float dijkstraDistance = vi.distance;
+ int errorCode = 0;
+ float geodesicDistance = computeGeodesicDistance(i,parent, errorCode);
+ if (errorCode < 0)
+ geodesicDistance = dijkstraDistance;
+ distance = PxMax(euclideanDistance, geodesicDistance);
+ }
+
+ uint32_t tetherLoc = j * mNumParticles + i;
+ mTetherAnchors[ tetherLoc ] = parent;
+ mTetherLengths[ tetherLoc ] = distance;
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+uint32_t PxClothGeodesicTetherCookerImpl::getCookerStatus() const
+{
+ return mCookerStatus;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+uint32_t PxClothGeodesicTetherCookerImpl::getNbTethersPerParticle() const
+{
+ return mTetherAnchors.size() / mNumParticles;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+void
+PxClothGeodesicTetherCookerImpl::getTetherData(uint32_t* userTetherAnchors, float* userTetherLengths) const
+{
+ intrinsics::memCopy(userTetherAnchors, mTetherAnchors.begin(), mTetherAnchors.size() * sizeof(uint32_t));
+ intrinsics::memCopy(userTetherLengths, mTetherLengths.begin(), mTetherLengths.size() * sizeof(float));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// find triangle-triangle adjacency (return non-zero if there is an error)
+uint32_t PxClothGeodesicTetherCookerImpl::findTriNeighbors()
+{
+ shdfnd::Array<MeshEdge> edges;
+
+ mTriNeighbors.resize(mIndices.size(), uint32_t(-1));
+
+ // assemble all edges
+ uint32_t numTriangles = mIndices.size() / 3;
+ for (uint32_t i = 0; i < numTriangles; ++i)
+ {
+ uint32_t i0 = mIndices[3 * i];
+ uint32_t i1 = mIndices[3 * i + 1];
+ uint32_t i2 = mIndices[3 * i + 2];
+ edges.pushBack(MeshEdge((int)i0, (int)i1, int(3*i)));
+ edges.pushBack(MeshEdge((int)i1, (int)i2, int(3*i+1)));
+ edges.pushBack(MeshEdge((int)i2, (int)i0, int(3*i+2)));
+ }
+
+ shdfnd::sort(edges.begin(), edges.size());
+
+ int numEdges = (int)edges.size();
+ for(int i=0; i < numEdges; )
+ {
+ const MeshEdge& e0 = edges[(uint32_t)i];
+ bool orientation0 = checkEdgeOrientation(e0, mIndices);
+
+ int j = i;
+ while(++i < numEdges && edges[(uint32_t)i] == e0)
+ ;
+
+ if(i - j > 2)
+ return 1; // non-manifold
+
+ while(++j < i)
+ {
+ const MeshEdge& e1 = edges[(uint32_t)j];
+ bool orientation1 = checkEdgeOrientation(e1, mIndices);
+ mTriNeighbors[(uint32_t)e0.mHalfEdgeIndex] = (uint32_t)e1.mHalfEdgeIndex/3;
+ mTriNeighbors[(uint32_t)e1.mHalfEdgeIndex] = (uint32_t)e0.mHalfEdgeIndex/3;
+
+ if (orientation0 == orientation1)
+ return 2; // bad winding
+ }
+ }
+
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// find vertex triangle adjacency information
+void PxClothGeodesicTetherCookerImpl::findVertTriNeighbors()
+{
+ shdfnd::Array<VertTriangle> vertTriangles;
+ vertTriangles.reserve(mIndices.size());
+
+ int numTriangles = (int)mIndices.size() / 3;
+ for (int i = 0; i < numTriangles; ++i)
+ {
+ vertTriangles.pushBack(VertTriangle((int)mIndices[uint32_t(3*i)], i));
+ vertTriangles.pushBack(VertTriangle((int)mIndices[uint32_t(3*i+1)], i));
+ vertTriangles.pushBack(VertTriangle((int)mIndices[uint32_t(3*i+2)], i));
+ }
+
+ shdfnd::sort(vertTriangles.begin(), vertTriangles.size(), shdfnd::Less<VertTriangle>());
+ mFirstVertTriAdj.resize(mNumParticles);
+ mVertTriAdjs.reserve(mIndices.size());
+
+ for (uint32_t i = 0; i < (uint32_t)vertTriangles.size(); )
+ {
+ int v = vertTriangles[i].mVertIndex;
+
+ mFirstVertTriAdj[(uint32_t)v] = i;
+
+ while ((i < mIndices.size()) && (vertTriangles[i].mVertIndex == v))
+ {
+ int t = vertTriangles[i].mTriangleIndex;
+ mVertTriAdjs.pushBack((uint32_t)t);
+ i++;
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// compute intersection of a ray from a source vertex in direction toward parent
+int PxClothGeodesicTetherCookerImpl::computeVertexIntersection(uint32_t parent, uint32_t src, PathIntersection &path)
+{
+ if (src == parent)
+ {
+ path = PathIntersection(true, src, 0.0);
+ return 0;
+ }
+
+ float maxdot = -1.0f;
+ int closestVert = -1;
+
+ // gradient is toward the parent vertex
+ PxVec3 g = (mVertices[parent] - mVertices[src]).getNormalized();
+
+ // for every triangle incident on this vertex, we intersect against opposite edge of the triangle
+ uint32_t sfirst = mFirstVertTriAdj[src];
+ uint32_t slast = (src < ((uint32_t)mNumParticles-1)) ? mFirstVertTriAdj[src+1] : (uint32_t)mVertTriAdjs.size();
+ for (uint32_t adj = sfirst; adj < slast; adj++)
+ {
+ uint32_t tid = mVertTriAdjs[adj];
+
+ uint32_t i0 = mIndices[tid*3];
+ uint32_t i1 = mIndices[tid*3+1];
+ uint32_t i2 = mIndices[tid*3+2];
+
+ int eid = 0;
+ if (i0 == src) eid = 1;
+ else if (i1 == src) eid = 2;
+ else if (i2 == src) eid = 0;
+ else continue; // error
+
+ // reshuffle so that src is located at i2
+ i0 = mIndices[tid*3 + eid];
+ i1 = mIndices[tid*3 + (eid+1)%3];
+ i2 = src;
+
+ PxVec3 p0 = mVertices[i0];
+ PxVec3 p1 = mVertices[i1];
+ PxVec3 p2 = mVertices[i2];
+
+ // check if we hit source immediately from this triangle
+ if (i0 == parent)
+ {
+ path = PathIntersection(true, parent, (p0 - p2).magnitude());
+ return 1;
+ }
+
+ if (i1 == parent)
+ {
+ path = PathIntersection(true, parent, (p1 - p2).magnitude());
+ return 1;
+ }
+
+ // ray direction is the gradient projected on the plane of this triangle
+ PxVec3 n = ((p0 - p2).cross(p1 - p2)).getNormalized();
+ PxVec3 d = (g - g.dot(n) * n).getNormalized();
+
+ // find intersection of ray (p2, d) against the edge (p0,p1)
+ float s, t;
+ bool result = intersectRayEdge(p2, d, p0, p1, s, t);
+ if (result == false)
+ continue;
+
+ // t should be positive, otherwise we just hit the triangle in opposite direction, so ignore
+ const float eps = 1e-5;
+ if (t > -eps)
+ {
+ PxVec3 ip; // intersection point
+ if (( s > -eps ) && (s < (1.0f + eps)))
+ {
+ // if intersection point is too close to each vertex, we record a vertex intersection
+ if ( ( s < eps) || (s > (1.0f-eps)))
+ {
+ path.vertOrTriangle = true;
+ path.index = (s < eps) ? i0 : i1;
+ path.distance = (p2 - mVertices[path.index]).magnitude();
+ }
+ else // found an edge instersection
+ {
+ ip = p0 + s * (p1 - p0);
+ path = PathIntersection(false, tid*3 + eid, (p2 - ip).magnitude(), s);
+ }
+ return 1;
+ }
+ }
+
+ // for fall back (see below)
+ PxVec3 d0 = (p0 - p2).getNormalized();
+ PxVec3 d1 = (p1 - p2).getNormalized();
+ float d0dotg = d0.dot(d);
+ float d1dotg = d1.dot(d);
+
+ if (d0dotg > maxdot)
+ {
+ closestVert = (int)i0;
+ maxdot = d0dotg;
+ }
+ if (d1dotg > maxdot)
+ {
+ closestVert = (int)i1;
+ maxdot = d1dotg;
+ }
+ } // end for (uint32_t adj = sfirst...
+
+ // Fall back to use greedy (Dijkstra-like) path selection.
+ // This happens as triangles are curved and we may not find intersection on any triangle.
+ // In this case, we choose a vertex closest to the gradient direction.
+ if (closestVert > 0)
+ {
+ path = PathIntersection(true, (uint32_t)closestVert, (mVertices[src] - mVertices[(uint32_t)closestVert]).magnitude());
+ return 1;
+ }
+
+ // Error, (possibly dangling vertex)
+ return -1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// compute intersection of a ray from a source vertex in direction toward parent
+int PxClothGeodesicTetherCookerImpl::computeEdgeIntersection(uint32_t parent, uint32_t edge, float in_s, PathIntersection &path)
+{
+ int tid = (int)edge / 3;
+ int eid = (int)edge % 3;
+
+ uint32_t e0 = mIndices[uint32_t(tid*3 + eid)];
+ uint32_t e1 = mIndices[uint32_t(tid*3 + (eid+1)%3)];
+
+ PxVec3 v0 = mVertices[e0];
+ PxVec3 v1 = mVertices[e1];
+
+ PxVec3 v = v0 + in_s * (v1 - v0);
+ PxVec3 g = mVertices[parent] - v;
+
+ uint32_t triNbr = mTriNeighbors[edge];
+
+ if (triNbr == uint32_t(-1)) // boundary edge
+ {
+ float dir = g.dot(v1-v0);
+ uint32_t vid = (dir > 0) ? e1 : e0;
+ path = PathIntersection(true, vid, (mVertices[vid] - v).magnitude());
+ return 1;
+ }
+
+ uint32_t i0 = mIndices[triNbr*3];
+ uint32_t i1 = mIndices[triNbr*3+1];
+ uint32_t i2 = mIndices[triNbr*3+2];
+
+ // vertex is sorted s.t i0,i1 contains the edge point
+ if ( checkEdge((int)i0, (int)i1, (int)e0, (int)e1)) {
+ eid = 0;
+ }
+ else if ( checkEdge((int)i1, (int)i2, (int)e0, (int)e1)) {
+ eid = 1;
+ uint32_t tmp = i2;
+ i2 = i0;
+ i0 = i1;
+ i1 = tmp;
+ }
+ else if ( checkEdge((int)i2, (int)i0, (int)e0, (int)e1))
+ {
+ eid = 2;
+ uint32_t tmp = i0;
+ i0 = i2;
+ i2 = i1;
+ i1 = tmp;
+ }
+
+ // we hit the parent
+ if (i2 == parent)
+ {
+ path = PathIntersection(true, i2, (mVertices[i2] - v).magnitude());
+ return 1;
+ }
+
+ PxVec3 p0 = mVertices[i0];
+ PxVec3 p1 = mVertices[i1];
+ PxVec3 p2 = mVertices[i2];
+
+ // project gradient vector on the plane of the triangle
+ PxVec3 n = ((p0 - p2).cross(p1 - p2)).getNormalized();
+ g = (g - g.dot(n) * n).getNormalized();
+
+ float s = 0.0f, t = 0.0f;
+ const float eps = 1e-5;
+ PxVec3 ip;
+
+ // intersect against edge form p2 to p0
+ if (intersectRayEdge(v, g, p2, p0, s, t) && ( s >= -eps) && ( s <= (1.0f+eps) ) && (t > -eps))
+ {
+ if ( ( s < eps) || (s > (1.0f-eps)))
+ {
+ path.vertOrTriangle = true;
+ path.index = (s < eps) ? i2 : i0;
+ path.distance = (mVertices[path.index] - v).magnitude();
+ }
+ else
+ {
+ ip = p2 + s * (p0 - p2);
+ path = PathIntersection(false, triNbr*3 + (eid + 2) % 3, (ip - v).magnitude(), s);
+
+ }
+
+ return 1;
+ }
+
+ // intersect against edge form p1 to p2
+ if (intersectRayEdge(v, g, p1, p2, s, t) && ( s >= -eps) && ( s <= (1.0f+eps) ) && (t > -eps))
+ {
+ if ( ( s < eps) || (s > (1.0f-eps)))
+ {
+ path.vertOrTriangle = true;
+ path.index = (s < eps) ? i1 : i2;
+ path.distance = (mVertices[path.index] - v).magnitude();
+ }
+ else
+ {
+ ip = p1 + s * (p2 - p1);
+ path = PathIntersection(false, triNbr*3 + (eid + 1) % 3, (ip - v).magnitude(), s);
+ }
+
+ return 1;
+ }
+
+ // fallback to pick closer vertex when no edges intersect
+ float dir = g.dot(v1-v0);
+ path.vertOrTriangle = true;
+ path.index = (dir > 0) ? e1 : e0;
+ path.distance = (mVertices[path.index] - v).magnitude();
+
+ return 1;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// compute geodesic distance and path from vertex i to its parent
+float PxClothGeodesicTetherCookerImpl::computeGeodesicDistance(uint32_t i, uint32_t parent, int &errorCode)
+{
+ if (i == parent)
+ return 0.0f;
+
+ PathIntersection path;
+
+ errorCode = 0;
+
+ // find intial intersection
+ int status = computeVertexIntersection(parent, i, path);
+ if (status < 0)
+ {
+ errorCode = -1;
+ return 0;
+ }
+
+ int pathcnt = 0;
+ float geodesicDistance = 0;
+
+ while (status > 0)
+ {
+ geodesicDistance += path.distance;
+
+ if (path.vertOrTriangle)
+ status = computeVertexIntersection(parent, path.index, path);
+ else
+ status = computeEdgeIntersection(parent, path.index, path.s, path);
+
+ // cannot find valid path
+ if (status < 0)
+ {
+ errorCode = -2;
+ return 0.0f;
+ }
+
+ // possibly cycles, too many path
+ if (pathcnt > 1000)
+ {
+ errorCode = -3;
+ return 0.0f;
+ }
+
+ pathcnt++;
+ }
+
+ return geodesicDistance;
+}
+
+
+
+
+#endif //APEX_USE_CLOTH_API
+
+
diff --git a/APEX_1.4/module/clothing/embedded/ExtClothMeshQuadifier.cpp b/APEX_1.4/module/clothing/embedded/ExtClothMeshQuadifier.cpp
new file mode 100644
index 00000000..f94cb1f0
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/ExtClothMeshQuadifier.cpp
@@ -0,0 +1,429 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "ExtClothConfig.h"
+#if APEX_USE_CLOTH_API
+
+#include "ExtClothMeshQuadifier.h"
+#include "PxStrideIterator.h"
+
+// from shared foundation
+#include <PsArray.h>
+#include <PsSort.h>
+#include <Ps.h>
+#include <PsMathUtils.h>
+
+using namespace nvidia;
+using namespace physx;
+
+struct nvidia::PxClothMeshQuadifierImpl
+{
+ PxClothMeshQuadifierImpl(const PxClothMeshDesc& desc);
+ PxClothMeshDesc getDescriptor() const;
+
+public:
+ PxClothMeshDesc mDesc;
+ shdfnd::Array<uint32_t> mQuads;
+ shdfnd::Array<uint32_t> mTriangles;
+};
+
+PxClothMeshQuadifier::PxClothMeshQuadifier(const PxClothMeshDesc& desc)
+: mImpl(new PxClothMeshQuadifierImpl(desc))
+{
+}
+
+PxClothMeshQuadifier::~PxClothMeshQuadifier()
+{
+ delete mImpl;
+}
+
+PxClothMeshDesc PxClothMeshQuadifier::getDescriptor() const
+{
+ return mImpl->getDescriptor();
+}
+
+namespace
+{
+ struct UniqueEdge
+ {
+ PX_FORCE_INLINE bool operator()(const UniqueEdge& e1, const UniqueEdge& e2) const
+ {
+ return e1 < e2;
+ }
+
+ PX_FORCE_INLINE bool operator==(const UniqueEdge& other) const
+ {
+ return vertex0 == other.vertex0 && vertex1 == other.vertex1;
+ }
+ PX_FORCE_INLINE bool operator<(const UniqueEdge& other) const
+ {
+ if (vertex0 != other.vertex0)
+ {
+ return vertex0 < other.vertex0;
+ }
+
+ return vertex1 < other.vertex1;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////
+ UniqueEdge()
+ : vertex0(0), vertex1(0), vertex2(0), vertex3(0xffffffff),
+ maxAngle(0.0f), isQuadDiagonal(false), isUsed(false) {}
+
+ UniqueEdge(uint32_t v0, uint32_t v1, uint32_t v2)
+ : vertex0(PxMin(v0, v1)), vertex1(PxMax(v0, v1)), vertex2(v2), vertex3(0xffffffff),
+ maxAngle(0.0f), isQuadDiagonal(false), isUsed(false) {}
+
+
+ uint32_t vertex0, vertex1;
+ uint32_t vertex2, vertex3;
+ float maxAngle;
+ bool isQuadDiagonal;
+ bool isUsed;
+ };
+
+ struct SortHiddenEdges
+ {
+ SortHiddenEdges(shdfnd::Array<UniqueEdge>& uniqueEdges) : mUniqueEdges(uniqueEdges) {}
+
+ bool operator()(uint32_t a, uint32_t b) const
+ {
+ return mUniqueEdges[a].maxAngle < mUniqueEdges[b].maxAngle;
+ }
+
+ private:
+ SortHiddenEdges& operator=(const SortHiddenEdges&);
+
+ shdfnd::Array<UniqueEdge>& mUniqueEdges;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ template <typename T>
+ void copyIndices(const PxClothMeshDesc &desc, shdfnd::Array<uint32_t> &triangles, shdfnd::Array<uint32_t> &quads)
+ {
+ triangles.resize(desc.triangles.count*3);
+ PxStrideIterator<const T> tIt = physx::PxMakeIterator((const T*)desc.triangles.data, desc.triangles.stride);
+ for(uint32_t i=0; i<desc.triangles.count; ++i, ++tIt)
+ for(uint32_t j=0; j<3; ++j)
+ triangles[i*3+j] = tIt.ptr()[j];
+
+ quads.resize(desc.quads.count*4);
+ PxStrideIterator<const T> qIt = physx::PxMakeIterator((const T*)desc.quads.data, desc.quads.stride);
+ for(uint32_t i=0; i<desc.quads.count; ++i, ++qIt)
+ for(uint32_t j=0; j<4; ++j)
+ quads[i*4+j] = qIt.ptr()[j];
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ void computeUniqueEdges(shdfnd::Array<UniqueEdge> &uniqueEdges, const PxVec3* positions, const shdfnd::Array<uint32_t>& triangles)
+ {
+ uniqueEdges.resize(0);
+ uniqueEdges.reserve(triangles.size());
+ uint32_t indexMap[3][3] = { { 0, 1, 2 }, { 1, 2, 0 }, { 0, 2, 1 } };
+
+ const float rightAngle = PxCos(physx::shdfnd::degToRad(85.0f));
+
+ for(uint32_t i=0; i<triangles.size(); i+=3)
+ {
+ UniqueEdge edges[3];
+ float edgeLengths[3];
+ float edgeAngles[3];
+
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ edges[j] = UniqueEdge(triangles[i+indexMap[j][0]], triangles[i+indexMap[j][1]], triangles[i+indexMap[j][2]]);
+ edgeLengths[j] = (positions[edges[j].vertex0] - positions[edges[j].vertex1]).magnitude();
+ const PxVec3 v1 = positions[edges[j].vertex2] - positions[edges[j].vertex0];
+ const PxVec3 v2 = positions[edges[j].vertex2] - positions[edges[j].vertex1];
+ edgeAngles[j] = PxAbs(v1.dot(v2)) / (v1.magnitude() * v2.magnitude());
+ }
+
+ // find the longest edge
+ uint32_t longest = 0;
+ for (uint32_t j = 1; j < 3; j++)
+ {
+ if (edgeLengths[j] > edgeLengths[longest])
+ longest = j;
+ }
+
+ // check it's angle
+ if (edgeAngles[longest] < rightAngle)
+ edges[longest].isQuadDiagonal = true;
+
+ for (uint32_t j = 0; j < 3; j++)
+ uniqueEdges.pushBack(edges[j]);
+ }
+
+ physx::shdfnd::sort(uniqueEdges.begin(), uniqueEdges.size(), UniqueEdge(0, 0, 0));
+
+ uint32_t writeIndex = 0, readStart = 0, readEnd = 0;
+ uint32_t numQuadEdges = 0;
+ while (readEnd < uniqueEdges.size())
+ {
+ while (readEnd < uniqueEdges.size() && uniqueEdges[readStart] == uniqueEdges[readEnd])
+ readEnd++;
+
+ const uint32_t count = readEnd - readStart;
+
+ UniqueEdge uniqueEdge = uniqueEdges[readStart];
+
+ if (count == 2)
+ // know the other diagonal
+ uniqueEdge.vertex3 = uniqueEdges[readStart + 1].vertex2;
+ else
+ uniqueEdge.isQuadDiagonal = false;
+
+ for (uint32_t i = 1; i < count; i++)
+ uniqueEdge.isQuadDiagonal &= uniqueEdges[readStart + i].isQuadDiagonal;
+
+ numQuadEdges += uniqueEdge.isQuadDiagonal ? 1 : 0;
+
+ uniqueEdges[writeIndex] = uniqueEdge;
+
+ writeIndex++;
+ readStart = readEnd;
+ }
+
+ uniqueEdges.resize(writeIndex, UniqueEdge(0, 0, 0));
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////
+ uint32_t findUniqueEdge(const shdfnd::Array<UniqueEdge> &uniqueEdges, uint32_t index1, uint32_t index2)
+ {
+ UniqueEdge searchFor(index1, index2, 0);
+
+ uint32_t curMin = 0;
+ uint32_t curMax = uniqueEdges.size();
+ while (curMax > curMin)
+ {
+ uint32_t middle = (curMin + curMax) >> 1;
+
+ const UniqueEdge& probe = uniqueEdges[middle];
+ if (probe < searchFor)
+ curMin = middle + 1;
+ else
+ curMax = middle;
+ }
+
+ return curMin;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ void refineUniqueEdges(shdfnd::Array<UniqueEdge> &uniqueEdges, const PxVec3* positions)
+ {
+ shdfnd::Array<uint32_t> hideEdges;
+ hideEdges.reserve(uniqueEdges.size());
+
+ for (uint32_t i = 0; i < uniqueEdges.size(); i++)
+ {
+ UniqueEdge& uniqueEdge = uniqueEdges[i];
+ uniqueEdge.maxAngle = 0.0f;
+ uniqueEdge.isQuadDiagonal = false; // just to be sure
+
+ if (uniqueEdge.vertex3 != 0xffffffff)
+ {
+ uint32_t indices[4] = { uniqueEdge.vertex0, uniqueEdge.vertex2, uniqueEdge.vertex1, uniqueEdge.vertex3 };
+
+ // compute max angle of the quad
+ for (uint32_t j = 0; j < 4; j++)
+ {
+ PxVec3 e0 = positions[indices[ j + 0 ]] - positions[indices[(j + 1) % 4]];
+ PxVec3 e1 = positions[indices[(j + 1) % 4]] - positions[indices[(j + 2) % 4]];
+
+ float denominator = e0.magnitude() * e1.magnitude();
+ if (denominator != 0.0f)
+ {
+ float cosAngle = PxAbs(e0.dot(e1)) / denominator;
+ uniqueEdge.maxAngle = PxMax(uniqueEdge.maxAngle, cosAngle);
+ }
+ }
+
+ hideEdges.pushBack(i);
+ }
+ }
+
+ shdfnd::sort(hideEdges.begin(), hideEdges.size(), SortHiddenEdges(uniqueEdges));
+
+ const float maxAngle = PxSin(physx::shdfnd::degToRad(60.0f));
+
+ uint32_t numHiddenEdges = 0;
+
+ for (uint32_t i = 0; i < hideEdges.size(); i++)
+ {
+ UniqueEdge& uniqueEdge = uniqueEdges[hideEdges[i]];
+
+ // find some stop criterion
+ if (uniqueEdge.maxAngle > maxAngle)
+ break;
+
+ // check if all four adjacent edges are still visible?
+ uint32_t indices[5] = { uniqueEdge.vertex0, uniqueEdge.vertex2, uniqueEdge.vertex1, uniqueEdge.vertex3, uniqueEdge.vertex0 };
+
+ uint32_t numVisible = 0;
+ for (uint32_t j = 0; j < 4; j++)
+ {
+ const uint32_t edgeIndex = findUniqueEdge(uniqueEdges, indices[j], indices[j + 1]);
+ PX_ASSERT(edgeIndex < uniqueEdges.size());
+
+ numVisible += uniqueEdges[edgeIndex].isQuadDiagonal ? 0 : 1;
+ }
+
+ if (numVisible == 4)
+ {
+ uniqueEdge.isQuadDiagonal = true;
+ numHiddenEdges++;
+ }
+ }
+ }
+
+
+ // calculate the inclusive prefix sum, equivalent of std::partial_sum
+ template <typename T>
+ void prefixSum(const T* first, const T* last, T* dest)
+ {
+ if (first != last)
+ {
+ *(dest++) = *(first++);
+ for (; first != last; ++first, ++dest)
+ *dest = *(dest-1) + *first;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ void quadifyTriangles(const shdfnd::Array<UniqueEdge> &uniqueEdges, shdfnd::Array<uint32_t>& triangles, shdfnd::Array<uint32_t> &quads)
+ {
+ shdfnd::Array<uint32_t> valency(uniqueEdges.size()+1, 0); // edge valency
+ shdfnd::Array<uint32_t> adjacencies; // adjacency from unique edge to triangles
+ uint32_t numTriangles = triangles.size() / 3;
+
+ // compute edge valency w.r.t triangles
+ for(uint32_t i=0; i<numTriangles; ++i)
+ {
+ for (uint32_t j=0; j < 3; j++)
+ {
+ uint32_t uniqueEdgeIndex = findUniqueEdge(uniqueEdges, triangles[i*3+j], triangles[i*3+(j+1)%3]);
+ ++valency[uniqueEdgeIndex];
+ }
+ }
+
+ // compute adjacency from each edge to triangle, the value also encodes which side of the triangle this edge belongs to
+ prefixSum(valency.begin(), valency.end(), valency.begin());
+ adjacencies.resize(valency.back());
+ for(uint32_t i=0; i<numTriangles; ++i)
+ {
+ for (uint32_t j=0; j < 3; j++)
+ {
+ uint32_t uniqueEdgeIndex = findUniqueEdge(uniqueEdges, triangles[i*3+j], triangles[i*3+(j+1)%3]);
+ adjacencies[--valency[uniqueEdgeIndex]] = i*3+j;
+ }
+ }
+
+ // now go through unique edges that are identified as diagonal, and build a quad out of two adjacent triangles
+ shdfnd::Array<uint32_t> mark(numTriangles, 0);
+ for (uint32_t i = 0; i < uniqueEdges.size(); i++)
+ {
+ const UniqueEdge& edge = uniqueEdges[i];
+ if (edge.isQuadDiagonal)
+ {
+ uint32_t vi = valency[i];
+ if ((valency[i+1]-vi) != 2)
+ continue; // we do not quadify around non-manifold edges
+
+ uint32_t adj0 = adjacencies[vi], adj1 = adjacencies[vi+1];
+ uint32_t tid0 = adj0 / 3, tid1 = adj1 / 3;
+ uint32_t eid0 = adj0 % 3, eid1 = adj1 % 3;
+
+ quads.pushBack(triangles[tid0 * 3 + eid0]);
+ quads.pushBack(triangles[tid1 * 3 + (eid1+2)%3]);
+ quads.pushBack(triangles[tid0 * 3 + (eid0+1)%3]);
+ quads.pushBack(triangles[tid0 * 3 + (eid0+2)%3]);
+
+ mark[tid0] = 1;
+ mark[tid1] = 1;
+#if 0 // PX_DEBUG
+ printf("Deleting %d, %d, %d - %d, %d, %d, creating %d, %d, %d, %d\n",
+ triangles[tid0*3],triangles[tid0*3+1],triangles[tid0*3+2],
+ triangles[tid1*3],triangles[tid1*3+1],triangles[tid1*3+2],
+ v0,v3,v1,v2);
+#endif
+ }
+ }
+
+ // add remaining triangles that are not marked as already quadified
+ shdfnd::Array<uint32_t> oldTriangles = triangles;
+ triangles.resize(0);
+ for (uint32_t i = 0; i < numTriangles; i++)
+ {
+ if (mark[i]) continue;
+
+ triangles.pushBack(oldTriangles[i*3]);
+ triangles.pushBack(oldTriangles[i*3+1]);
+ triangles.pushBack(oldTriangles[i*3+2]);
+ }
+ }
+
+} // namespace
+
+
+///////////////////////////////////////////////////////////////////////////////
+PxClothMeshQuadifierImpl::PxClothMeshQuadifierImpl(const PxClothMeshDesc &desc)
+ :mDesc(desc)
+{
+ shdfnd::Array<PxVec3> particles(desc.points.count);
+ PxStrideIterator<const PxVec3> pIt((const PxVec3*)desc.points.data, desc.points.stride);
+ for(uint32_t i=0; i<desc.points.count; ++i)
+ particles[i] = *pIt++;
+
+ // copy triangle indices
+ if(desc.flags & PxMeshFlag::e16_BIT_INDICES)
+ copyIndices<uint16_t>(desc, mTriangles, mQuads);
+ else
+ copyIndices<uint32_t>(desc, mTriangles, mQuads);
+
+ shdfnd::Array<UniqueEdge> uniqueEdges;
+
+ computeUniqueEdges(uniqueEdges, particles.begin(), mTriangles);
+
+ refineUniqueEdges(uniqueEdges, particles.begin());
+
+// printf("before %d triangles, %d quads\n", mTriangles.size()/3, mQuads.size()/4);
+ quadifyTriangles(uniqueEdges, mTriangles, mQuads);
+
+// printf("after %d triangles, %d quads\n", mTriangles.size()/3, mQuads.size()/4);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+PxClothMeshDesc
+PxClothMeshQuadifierImpl::getDescriptor() const
+{
+ // copy points and other data
+ PxClothMeshDesc desc = mDesc;
+
+ // for now use only 32 bit for temporary indices out of quadifier
+ desc.flags &= ~PxMeshFlag::e16_BIT_INDICES;
+
+ desc.triangles.count = mTriangles.size() / 3;
+ desc.triangles.data = mTriangles.begin();
+ desc.triangles.stride = 3 * sizeof(uint32_t);
+
+ desc.quads.count = mQuads.size() / 4;
+ desc.quads.data = mQuads.begin();
+ desc.quads.stride = 4 * sizeof(uint32_t);
+
+ PX_ASSERT(desc.isValid());
+
+ return desc;
+}
+#endif //APEX_USE_CLOTH_API
+
+
diff --git a/APEX_1.4/module/clothing/embedded/ExtClothMeshQuadifier.h b/APEX_1.4/module/clothing/embedded/ExtClothMeshQuadifier.h
new file mode 100644
index 00000000..653622f6
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/ExtClothMeshQuadifier.h
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PX_PHYSICS_EXTENSIONS_CLOTH_EDGE_QUADIFIER_H
+#define PX_PHYSICS_EXTENSIONS_CLOTH_EDGE_QUADIFIER_H
+
+#include "ExtClothConfig.h"
+#include "PxClothMeshDesc.h"
+
+#if PX_DOXYGEN == 0
+namespace nvidia
+{
+#endif
+
+struct PxClothMeshQuadifierImpl;
+
+class PxClothMeshQuadifier
+{
+public:
+ /**
+ \brief Convert triangles of PxClothMeshDesc to quads.
+ \details In PxCloth, quad dominant mesh representations are preferable to pre-triangulated versions.
+ In cases where the mesh has been already triangulated, this class provides a meachanism to
+ convert (quadify) some triangles back to quad representations.
+ \see PxClothFabricCooker
+ \param desc The cloth mesh descriptor prepared for cooking
+ */
+ PxClothMeshQuadifier(const PxClothMeshDesc &desc);
+ ~PxClothMeshQuadifier();
+
+ /**
+ \brief Returns a mesh descriptor with some triangle pairs converted to quads.
+ \note The returned descriptor is valid only within the lifespan of PxClothMeshQuadifier class.
+ */
+ PxClothMeshDesc getDescriptor() const;
+
+private:
+ PxClothMeshQuadifierImpl* mImpl;
+
+};
+
+#if PX_DOXYGEN == 0
+} // namespace nvidia
+#endif
+
+#endif // PX_PHYSICS_EXTENSIONS_CLOTH_EDGE_QUADIFIER_H
diff --git a/APEX_1.4/module/clothing/embedded/ExtClothSimpleTetherCooker.cpp b/APEX_1.4/module/clothing/embedded/ExtClothSimpleTetherCooker.cpp
new file mode 100644
index 00000000..e5570186
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/ExtClothSimpleTetherCooker.cpp
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "ExtClothConfig.h"
+#if APEX_USE_CLOTH_API
+
+#include "ExtClothTetherCooker.h"
+#include "PxStrideIterator.h"
+#include "PxVec4.h"
+#include "PsIntrinsics.h"
+#include "PsArray.h"
+
+using namespace nvidia;
+using namespace physx;
+
+struct nvidia::PxClothSimpleTetherCookerImpl
+{
+ PxClothSimpleTetherCookerImpl(const PxClothMeshDesc& desc);
+
+ uint32_t getCookerStatus() const;
+ void getTetherData(uint32_t* userTetherAnchors, float* userTetherLengths) const;
+
+public:
+ // output
+ shdfnd::Array<uint32_t> mTetherAnchors;
+ shdfnd::Array<float> mTetherLengths;
+
+protected:
+ void createTetherData(const PxClothMeshDesc &desc);
+
+ uint32_t mCookerStatus;
+};
+
+PxClothSimpleTetherCooker::PxClothSimpleTetherCooker(const PxClothMeshDesc& desc)
+: mImpl(new PxClothSimpleTetherCookerImpl(desc))
+{
+}
+
+PxClothSimpleTetherCooker::~PxClothSimpleTetherCooker()
+{
+ delete mImpl;
+}
+
+uint32_t PxClothSimpleTetherCooker::getCookerStatus() const
+{
+ return mImpl->getCookerStatus();
+}
+
+void PxClothSimpleTetherCooker::getTetherData(uint32_t* userTetherAnchors, float* userTetherLengths) const
+{
+ mImpl->getTetherData(userTetherAnchors, userTetherLengths);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+PxClothSimpleTetherCookerImpl::PxClothSimpleTetherCookerImpl(const PxClothMeshDesc &desc) : mCookerStatus(1)
+{
+ createTetherData(desc);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+void PxClothSimpleTetherCookerImpl::createTetherData(const PxClothMeshDesc &desc)
+{
+ uint32_t numParticles = desc.points.count;
+
+ if (!desc.invMasses.data)
+ return;
+
+ // assemble points
+ shdfnd::Array<PxVec4> particles;
+ particles.reserve(numParticles);
+ PxStrideIterator<const PxVec3> pIt((const PxVec3*)desc.points.data, desc.points.stride);
+ PxStrideIterator<const float> wIt((const float*)desc.invMasses.data, desc.invMasses.stride);
+ for(uint32_t i=0; i<numParticles; ++i)
+ particles.pushBack(PxVec4(*pIt++, wIt.ptr() ? *wIt++ : 1.0f));
+
+ // compute tether data
+ shdfnd::Array<uint32_t> attachedIndices;
+ for(uint32_t i=0; i < numParticles; ++i)
+ if(particles[i].w == 0.0f)
+ attachedIndices.pushBack(i);
+
+ uint32_t n = attachedIndices.empty() ? 0 : numParticles;
+ for(uint32_t i=0; i < n; ++i)
+ {
+ mTetherAnchors.reserve(numParticles);
+ mTetherLengths.reserve(numParticles);
+
+ PxVec3 position = reinterpret_cast<const PxVec3&>(particles[i]);
+ float minSqrDist = FLT_MAX;
+ uint32_t minIndex = numParticles;
+ const uint32_t *aIt, *aEnd = attachedIndices.end();
+ for(aIt = attachedIndices.begin(); aIt != aEnd; ++aIt)
+ {
+ float sqrDist = (reinterpret_cast<const PxVec3&>(
+ particles[*aIt]) - position).magnitudeSquared();
+ if(minSqrDist > sqrDist)
+ minSqrDist = sqrDist, minIndex = *aIt;
+ }
+
+ mTetherAnchors.pushBack(minIndex);
+ mTetherLengths.pushBack(PxSqrt(minSqrDist));
+ }
+
+ PX_ASSERT(mTetherAnchors.size() == mTetherLengths.size());
+ if (numParticles == mTetherAnchors.size() && numParticles == mTetherLengths.size())
+ {
+ mCookerStatus = 0;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+uint32_t PxClothSimpleTetherCookerImpl::getCookerStatus() const
+{
+ return mCookerStatus;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+void
+PxClothSimpleTetherCookerImpl::getTetherData(uint32_t* userTetherAnchors, float* userTetherLengths) const
+{
+ intrinsics::memCopy(userTetherAnchors, mTetherAnchors.begin(), mTetherAnchors.size() * sizeof(uint32_t));
+ intrinsics::memCopy(userTetherLengths, mTetherLengths.begin(), mTetherLengths.size() * sizeof(float));
+}
+
+
+#endif //APEX_USE_CLOTH_API
+
+
diff --git a/APEX_1.4/module/clothing/embedded/ExtClothTetherCooker.h b/APEX_1.4/module/clothing/embedded/ExtClothTetherCooker.h
new file mode 100644
index 00000000..2c5d720a
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/ExtClothTetherCooker.h
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PX_PHYSICS_EXTENSIONS_CLOTH_TETHER_COOKER_H
+#define PX_PHYSICS_EXTENSIONS_CLOTH_TETHER_COOKER_H
+
+#include "ExtClothConfig.h"
+#include "PxClothMeshDesc.h"
+
+#if PX_DOXYGEN == 0
+namespace nvidia
+{
+#endif
+
+struct PxClothSimpleTetherCookerImpl;
+
+class PxClothSimpleTetherCooker
+{
+public:
+ /**
+ \brief Compute tether data from PxClothMeshDesc with simple distance measure.
+ \details The tether constraint in PxCloth requires rest distance and anchor index to be precomputed during cooking time.
+ This cooker computes a simple Euclidean distance to closest anchor point.
+ The Euclidean distance measure works reasonably for flat cloth and flags and computation time is very fast.
+ With this cooker, there is only one tether anchor point per particle.
+ \see PxClothTetherGeodesicCooker for more accurate distance estimation.
+ \param desc The cloth mesh descriptor prepared for cooking
+ */
+ PxClothSimpleTetherCooker(const PxClothMeshDesc &desc);
+ ~PxClothSimpleTetherCooker();
+
+ /**
+ \brief Returns cooker status
+ \details This function returns cooker status after cooker computation is done.
+ A non-zero return value indicates a failure.
+ */
+ uint32_t getCookerStatus() const;
+
+ /**
+ \brief Returns computed tether data.
+ \details This function returns anchor indices for each particle as well as desired distance between the tether anchor and the particle.
+ The user buffers should be at least as large as number of particles.
+ */
+ void getTetherData(uint32_t* userTetherAnchors, float* userTetherLengths) const;
+
+private:
+ PxClothSimpleTetherCookerImpl* mImpl;
+
+};
+
+
+struct PxClothGeodesicTetherCookerImpl;
+
+class PxClothGeodesicTetherCooker
+{
+public:
+ /**
+ \brief Compute tether data from PxClothMeshDesc using geodesic distance.
+ \details The tether constraint in PxCloth requires rest distance and anchor index to be precomputed during cooking time.
+ The provided tether cooker computes optimal tether distance with geodesic distance computation.
+ For curved and complex meshes, geodesic distance provides the best behavior for tether constraints.
+ But the cooking time is slower than the simple cooker.
+ \see PxClothSimpleTetherCooker
+ \param desc The cloth mesh descriptor prepared for cooking
+ \note The geodesic distance is optimized to work for intended use in tether constraint.
+ This is by no means a general purpose geodesic computation code for arbitrary meshes.
+ \note The geodesic cooker does not work with non-manifold input such as edges having more than two incident triangles,
+ or adjacent triangles following inconsitent winding order (e.g. clockwise vs counter-clockwise).
+ */
+ PxClothGeodesicTetherCooker(const PxClothMeshDesc &desc);
+ ~PxClothGeodesicTetherCooker();
+
+ /**
+ \brief Returns cooker status
+ \details This function returns cooker status after cooker computation is done.
+ A non-zero return value indicates a failure, 1 for non-manifold and 2 for inconsistent winding.
+ */
+ uint32_t getCookerStatus() const;
+
+ /**
+ \brief Returns number of tether anchors per particle
+ \note Returned number indicates the maximum anchors.
+ If some particles are assigned fewer anchors, the anchor indices will be uint32_t(-1)
+ \note If there is no attached point in the input mesh descriptor, this will return 0 and no tether data will be generated.
+ */
+ uint32_t getNbTethersPerParticle() const;
+
+ /**
+ \brief Returns computed tether data.
+ \details This function returns anchor indices for each particle as well as desired distance between the tether anchor and the particle.
+ The user buffers should be at least as large as number of particles * number of tethers per particle.
+ \see getNbTethersPerParticle()
+ */
+ void getTetherData(uint32_t* userTetherAnchors, float* userTetherLengths) const;
+
+private:
+ PxClothGeodesicTetherCookerImpl* mImpl;
+
+};
+
+
+#if PX_DOXYGEN == 0
+} // namespace nvidia
+#endif
+
+#endif // PX_PHYSICS_EXTENSIONS_CLOTH_TETHER_COOKER_H
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/include/Cloth.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/include/Cloth.h
new file mode 100644
index 00000000..6f24e51f
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/include/Cloth.h
@@ -0,0 +1,309 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "Range.h"
+#include "PhaseConfig.h"
+
+struct ID3D11Buffer;
+
+namespace nvidia
+{
+#if APEX_UE4
+ namespace Cm
+ {
+ class Task;
+ }
+#endif
+
+namespace cloth
+{
+
+class Factory;
+class Fabric;
+class Cloth;
+
+template <typename T>
+struct MappedRange : public Range<T>
+{
+ MappedRange(T* first, T* last, const Cloth& cloth, void (Cloth::*lock)() const, void (Cloth::*unlock)() const)
+ : Range<T>(first, last), mCloth(cloth), mLock(lock), mUnlock(unlock)
+ {
+ }
+
+ MappedRange(const MappedRange& other)
+ : Range<T>(other), mCloth(other.mCloth), mLock(other.mLock), mUnlock(other.mUnlock)
+ {
+ (mCloth.*mLock)();
+ }
+
+ ~MappedRange()
+ {
+ (mCloth.*mUnlock)();
+ }
+
+ private:
+ MappedRange& operator=(const MappedRange&);
+
+ const Cloth& mCloth;
+ void (Cloth::*mLock)() const;
+ void (Cloth::*mUnlock)() const;
+};
+
+struct GpuParticles
+{
+ PxVec4* mCurrent;
+ PxVec4* mPrevious;
+ ID3D11Buffer* mBuffer;
+};
+
+// abstract cloth instance
+class Cloth
+{
+ Cloth& operator=(const Cloth&);
+
+ protected:
+ Cloth()
+ {
+ }
+ Cloth(const Cloth&)
+ {
+ }
+
+ public:
+ virtual ~Cloth()
+ {
+ }
+
+ // same as factory.clone(*this)
+ virtual Cloth* clone(Factory& factory) const = 0;
+
+ virtual Fabric& getFabric() const = 0;
+ virtual Factory& getFactory() const = 0;
+
+ /* particle properties */
+
+ virtual uint32_t getNumParticles() const = 0;
+ virtual void lockParticles() const = 0;
+ virtual void unlockParticles() const = 0;
+ // return particle data for current and previous frame
+ // setting current invMass to zero locks particle.
+ virtual MappedRange<PxVec4> getCurrentParticles() = 0;
+ virtual MappedRange<const PxVec4> getCurrentParticles() const = 0;
+ virtual MappedRange<PxVec4> getPreviousParticles() = 0;
+ virtual MappedRange<const PxVec4> getPreviousParticles() const = 0;
+ virtual GpuParticles getGpuParticles() = 0;
+
+ // set position of cloth after next call to simulate()
+ virtual void setTranslation(const PxVec3& trans) = 0;
+ virtual void setRotation(const PxQuat& rot) = 0;
+
+ // get current position of cloth
+ virtual const PxVec3& getTranslation() const = 0;
+ virtual const PxQuat& getRotation() const = 0;
+
+ // zero inertia derived from method calls above (once)
+ virtual void clearInertia() = 0;
+
+ // adjust the position of the cloth without affecting the dynamics (to call after a world origin shift, for example)
+ virtual void teleport(const PxVec3& delta) = 0;
+
+ /* solver parameters */
+
+ // return delta time used for previous iteration
+ virtual float getPreviousIterationDt() const = 0;
+
+ // gravity in global coordinates
+ virtual void setGravity(const PxVec3&) = 0;
+ virtual PxVec3 getGravity() const = 0;
+
+ // damping of local particle velocity (1/stiffnessFrequency)
+ // 0 (default): velocity is unaffected, 1: velocity is zero'ed
+ virtual void setDamping(const PxVec3&) = 0;
+ virtual PxVec3 getDamping() const = 0;
+
+ // portion of local frame velocity applied to particles
+ // 0 (default): particles are unaffected
+ // same as damping: damp global particle velocity
+ virtual void setLinearDrag(const PxVec3&) = 0;
+ virtual PxVec3 getLinearDrag() const = 0;
+ virtual void setAngularDrag(const PxVec3&) = 0;
+ virtual PxVec3 getAngularDrag() const = 0;
+
+ // portion of local frame accelerations applied to particles
+ // 0: particles are unaffected, 1 (default): physically correct
+ virtual void setLinearInertia(const PxVec3&) = 0;
+ virtual PxVec3 getLinearInertia() const = 0;
+ virtual void setAngularInertia(const PxVec3&) = 0;
+ virtual PxVec3 getAngularInertia() const = 0;
+ virtual void setCentrifugalInertia(const PxVec3&) = 0;
+ virtual PxVec3 getCentrifugalInertia() const = 0;
+
+ // target solver iterations per second
+ virtual void setSolverFrequency(float) = 0;
+ virtual float getSolverFrequency() const = 0;
+
+ // damp, drag, stiffness exponent per second
+ virtual void setStiffnessFrequency(float) = 0;
+ virtual float getStiffnessFrequency() const = 0;
+
+ // filter width for averaging dt^2 factor of gravity and
+ // external acceleration, in numbers of iterations (default=30).
+ virtual void setAcceleationFilterWidth(uint32_t) = 0;
+ virtual uint32_t getAccelerationFilterWidth() const = 0;
+
+ // setup edge constraint solver iteration
+ virtual void setPhaseConfig(Range<const PhaseConfig> configs) = 0;
+
+ /* collision parameters */
+
+ virtual void setSpheres(Range<const PxVec4>, uint32_t first, uint32_t last) = 0;
+ virtual uint32_t getNumSpheres() const = 0;
+
+ virtual void setCapsules(Range<const uint32_t>, uint32_t first, uint32_t last) = 0;
+ virtual uint32_t getNumCapsules() const = 0;
+
+ virtual void setPlanes(Range<const PxVec4>, uint32_t first, uint32_t last) = 0;
+ virtual uint32_t getNumPlanes() const = 0;
+
+ virtual void setConvexes(Range<const uint32_t>, uint32_t first, uint32_t last) = 0;
+ virtual uint32_t getNumConvexes() const = 0;
+
+ virtual void setTriangles(Range<const PxVec3>, uint32_t first, uint32_t last) = 0;
+ virtual void setTriangles(Range<const PxVec3>, Range<const PxVec3>, uint32_t first) = 0;
+ virtual uint32_t getNumTriangles() const = 0;
+
+ // check if we use ccd or not
+ virtual bool isContinuousCollisionEnabled() const = 0;
+ // set if we use ccd or not (disabled by default)
+ virtual void enableContinuousCollision(bool) = 0;
+
+ // controls how quickly mass is increased during collisions
+ virtual float getCollisionMassScale() const = 0;
+ virtual void setCollisionMassScale(float) = 0;
+
+ // friction
+ virtual void setFriction(float) = 0;
+ virtual float getFriction() const = 0;
+
+ // set virtual particles for collision handling.
+ // each indices element consists of 3 particle
+ // indices and an index into the lerp weights array.
+ virtual void setVirtualParticles(Range<const uint32_t[4]> indices, Range<const PxVec3> weights) = 0;
+ virtual uint32_t getNumVirtualParticles() const = 0;
+ virtual uint32_t getNumVirtualParticleWeights() const = 0;
+
+ /* tether constraint parameters */
+
+ virtual void setTetherConstraintScale(float scale) = 0;
+ virtual float getTetherConstraintScale() const = 0;
+ virtual void setTetherConstraintStiffness(float stiffness) = 0;
+ virtual float getTetherConstraintStiffness() const = 0;
+
+ /* motion constraint parameters */
+
+ // return reference to motion constraints (position, radius)
+ // The entire range must be written after calling this function.
+ virtual Range<PxVec4> getMotionConstraints() = 0;
+ virtual void clearMotionConstraints() = 0;
+ virtual uint32_t getNumMotionConstraints() const = 0;
+ virtual void setMotionConstraintScaleBias(float scale, float bias) = 0;
+ virtual float getMotionConstraintScale() const = 0;
+ virtual float getMotionConstraintBias() const = 0;
+ virtual void setMotionConstraintStiffness(float stiffness) = 0;
+ virtual float getMotionConstraintStiffness() const = 0;
+
+ /* separation constraint parameters */
+
+ // return reference to separation constraints (position, radius)
+ // The entire range must be written after calling this function.
+ virtual Range<PxVec4> getSeparationConstraints() = 0;
+ virtual void clearSeparationConstraints() = 0;
+ virtual uint32_t getNumSeparationConstraints() const = 0;
+
+ /* clear interpolation */
+
+ // assign current to previous positions for
+ // collision spheres, motion, and separation constraints
+ virtual void clearInterpolation() = 0;
+
+ /* particle acceleration parameters */
+
+ // return reference to particle accelerations (in local coordinates)
+ // The entire range must be written after calling this function.
+ virtual Range<PxVec4> getParticleAccelerations() = 0;
+ virtual void clearParticleAccelerations() = 0;
+ virtual uint32_t getNumParticleAccelerations() const = 0;
+
+ /* self collision */
+
+ virtual void setSelfCollisionDistance(float distance) = 0;
+ virtual float getSelfCollisionDistance() const = 0;
+ virtual void setSelfCollisionStiffness(float stiffness) = 0;
+ virtual float getSelfCollisionStiffness() const = 0;
+
+ virtual void setSelfCollisionIndices(Range<const uint32_t>) = 0;
+ virtual uint32_t getNumSelfCollisionIndices() const = 0;
+
+ /* rest positions */
+
+ // set rest particle positions used during self-collision
+ virtual void setRestPositions(Range<const PxVec4>) = 0;
+ virtual uint32_t getNumRestPositions() const = 0;
+
+ /* bounding box */
+
+ // current particle position bounds in local space
+ virtual const PxVec3& getBoundingBoxCenter() const = 0;
+ virtual const PxVec3& getBoundingBoxScale() const = 0;
+
+ /* sleeping (disabled by default) */
+
+ // max particle velocity (per axis) to pass sleep test
+ virtual void setSleepThreshold(float) = 0;
+ virtual float getSleepThreshold() const = 0;
+ // test sleep condition every nth millisecond
+ virtual void setSleepTestInterval(uint32_t) = 0;
+ virtual uint32_t getSleepTestInterval() const = 0;
+ // put cloth to sleep when n consecutive sleep tests pass
+ virtual void setSleepAfterCount(uint32_t) = 0;
+ virtual uint32_t getSleepAfterCount() const = 0;
+ virtual uint32_t getSleepPassCount() const = 0;
+ virtual bool isAsleep() const = 0;
+ virtual void putToSleep() = 0;
+ virtual void wakeUp() = 0;
+
+ virtual void setHalfPrecisionOption(bool isAllowed) = 0;
+ virtual bool getHalfPrecisionOption() const = 0;
+
+#if APEX_UE4
+ virtual void simulate(float dt) = 0;
+#endif
+
+ virtual void setUserData(void*) = 0;
+ virtual void* getUserData() const = 0;
+};
+
+// wrappers to prevent non-const overload from marking particles dirty
+inline MappedRange<const PxVec4> readCurrentParticles(const Cloth& cloth)
+{
+ return cloth.getCurrentParticles();
+}
+inline MappedRange<const PxVec4> readPreviousParticles(const Cloth& cloth)
+{
+ return cloth.getPreviousParticles();
+}
+
+} // namespace cloth
+} // namespace nvidia
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/include/Fabric.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/include/Fabric.h
new file mode 100644
index 00000000..f271b397
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/include/Fabric.h
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "Types.h"
+#include "PxAssert.h"
+#include "Range.h"
+
+namespace nvidia
+{
+namespace cloth
+{
+
+class Factory;
+
+// abstract cloth constraints and triangle indices
+class Fabric
+{
+ protected:
+ Fabric(const Fabric&);
+ Fabric& operator=(const Fabric&);
+
+ protected:
+ Fabric() : mRefCount(0)
+ {
+ }
+
+ public:
+ virtual ~Fabric()
+ {
+ PX_ASSERT(!mRefCount);
+ }
+
+ virtual Factory& getFactory() const = 0;
+
+ virtual uint32_t getNumPhases() const = 0;
+ virtual uint32_t getNumRestvalues() const = 0;
+
+ virtual uint32_t getNumSets() const = 0;
+ virtual uint32_t getNumIndices() const = 0;
+
+ virtual uint32_t getNumParticles() const = 0;
+
+ virtual uint32_t getNumTethers() const = 0;
+
+ virtual void scaleRestvalues(float) = 0;
+ virtual void scaleTetherLengths(float) = 0;
+
+ uint16_t getRefCount() const
+ {
+ return mRefCount;
+ }
+ void incRefCount()
+ {
+ ++mRefCount;
+ PX_ASSERT(mRefCount > 0);
+ }
+ void decRefCount()
+ {
+ PX_ASSERT(mRefCount > 0);
+ --mRefCount;
+ }
+
+ protected:
+ uint16_t mRefCount;
+};
+
+} // namespace cloth
+} // namespace nvidia
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/include/Factory.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/include/Factory.h
new file mode 100644
index 00000000..651b3b0c
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/include/Factory.h
@@ -0,0 +1,176 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "Types.h"
+#include "Range.h"
+
+typedef struct CUstream_st* CUstream;
+
+namespace physx
+{
+ namespace profile
+ {
+ class PxProfileZone;
+ }
+ class PxTaskManager;
+}
+
+namespace nvidia
+{
+namespace cloth
+{
+
+class Fabric;
+class Cloth;
+class Solver;
+class Character;
+
+/// abstract factory to create context-specific simulation components
+/// such as cloth, solver, collision, etc.
+class Factory
+{
+ public:
+ enum Platform
+ {
+ CPU,
+ CUDA,
+ DirectCompute
+ };
+
+ protected:
+ Factory(Platform platform) : mPlatform(platform)
+ {
+ }
+ Factory(const Factory&);
+ Factory& operator=(const Factory&);
+
+ public:
+ static Factory* createFactory(Platform, void* = 0);
+
+ virtual ~Factory()
+ {
+ }
+
+ Platform getPlatform() const
+ {
+ return mPlatform;
+ }
+
+ /**
+ Create fabric data used to setup cloth object.
+ @param numParticles number of particles, must be larger than any particle index
+ @param phases map from phase to set index
+ @param sets inclusive prefix sum of restvalue count per set
+ @param restvalues array of constraint rest values
+ @param indices array of particle index pair per constraint
+ */
+ virtual Fabric* createFabric(uint32_t numParticles, Range<const uint32_t> phases, Range<const uint32_t> sets,
+ Range<const float> restvalues, Range<const uint32_t> indices,
+ Range<const uint32_t> anchors, Range<const float> tetherLengths) = 0;
+
+ /**
+ Create cloth object.
+ @param particles initial particle positions.
+ @param fabric edge distance constraint structure
+ */
+ virtual Cloth* createCloth(Range<const PxVec4> particles, Fabric& fabric) = 0;
+
+ /**
+ Create cloth solver object.
+ @param profiler performance event receiver.
+ @param taskMgr PxTaskManager used for simulation.
+ */
+ virtual Solver* createSolver(profile::PxProfileZone* profiler, PxTaskManager* taskMgr) = 0;
+
+ /**
+ Create a copy of a cloth instance
+ @param cloth the instance to be cloned, need not match the factory type
+ */
+ virtual Cloth* clone(const Cloth& cloth) = 0;
+
+ /**
+ Extract original data from a fabric object
+ @param fabric to extract from, must match factory type
+ @param phases pre-allocated memory range to write phases
+ @param sets pre-allocated memory range to write sets
+ @param restvalues pre-allocated memory range to write restvalues
+ @param indices pre-allocated memory range to write indices
+ */
+ virtual void extractFabricData(const Fabric& fabric, Range<uint32_t> phases, Range<uint32_t> sets,
+ Range<float> restvalues, Range<uint32_t> indices, Range<uint32_t> anchors,
+ Range<float> tetherLengths) const = 0;
+
+ /**
+ Extract current collision spheres and capsules from a cloth object
+ @param cloth the instance to extract from, must match factory type
+ @param spheres pre-allocated memory range to write spheres
+ @param capsules pre-allocated memory range to write capsules
+ @param planes pre-allocated memory range to write planes
+ @param convexes pre-allocated memory range to write convexes
+ @param triangles pre-allocated memory range to write triangles
+ */
+ virtual void extractCollisionData(const Cloth& cloth, Range<PxVec4> spheres, Range<uint32_t> capsules,
+ Range<PxVec4> planes, Range<uint32_t> convexes, Range<PxVec3> triangles) const = 0;
+
+ /**
+ Extract current motion constraints from a cloth object
+ @param cloth the instance to extract from, must match factory type
+ @param destConstraints pre-allocated memory range to write constraints
+ */
+ virtual void extractMotionConstraints(const Cloth& cloth, Range<PxVec4> destConstraints) const = 0;
+
+ /**
+ Extract current separation constraints from a cloth object
+ @param cloth the instance to extract from, must match factory type
+ @param destConstraints pre-allocated memory range to write constraints
+ */
+ virtual void extractSeparationConstraints(const Cloth& cloth, Range<PxVec4> destConstraints) const = 0;
+
+ /**
+ Extract current particle accelerations from a cloth object
+ @param cloth the instance to extract from, must match factory type
+ @param destAccelerations pre-allocated memory range to write accelerations
+ */
+ virtual void extractParticleAccelerations(const Cloth& cloth, Range<PxVec4> destAccelerations) const = 0;
+
+ /**
+ Extract virtual particles from a cloth object
+ @param cloth the instance to extract from, must match factory type
+ @param destIndices pre-allocated memory range to write indices
+ @param destWeights pre-allocated memory range to write weights
+ */
+ virtual void extractVirtualParticles(const Cloth& cloth, Range<uint32_t[4]> destIndices,
+ Range<PxVec3> destWeights) const = 0;
+
+ /**
+ Extract self collision indices from cloth object.
+ @param cloth the instance to extract from, must match factory type
+ @param destIndices pre-allocated memory range to write indices
+ */
+ virtual void extractSelfCollisionIndices(const Cloth& cloth, Range<uint32_t> destIndices) const = 0;
+
+ /**
+ Extract particle rest positions from cloth object.
+ @param cloth the instance to extract from, must match factory type
+ @param destRestPositions pre-allocated memory range to write rest positions
+ */
+ virtual void extractRestPositions(const Cloth& cloth, Range<PxVec4> destRestPositions) const = 0;
+
+ protected:
+ const Platform mPlatform;
+};
+
+} // namespace cloth
+} // namespace nvidia
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/include/PhaseConfig.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/include/PhaseConfig.h
new file mode 100644
index 00000000..4edf4802
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/include/PhaseConfig.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "Types.h"
+
+namespace nvidia
+{
+namespace cloth
+{
+
+struct PhaseConfig
+{
+ PhaseConfig(uint16_t index = uint16_t(-1));
+
+ uint16_t mPhaseIndex;
+ uint16_t mPadding;
+
+ // target convergence rate per iteration (1/solverFrequency)
+ float mStiffness;
+
+ float mStiffnessMultiplier;
+
+ float mCompressionLimit;
+ float mStretchLimit;
+};
+
+} // namespace cloth
+} // namespace nvidia
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/include/Range.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/include/Range.h
new file mode 100644
index 00000000..7d48e195
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/include/Range.h
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "PxAssert.h"
+#include "Types.h"
+
+namespace nvidia
+{
+namespace cloth
+{
+
+template <class T>
+struct Range
+{
+ Range();
+
+ Range(T* first, T* last);
+
+ template <typename S>
+ Range(const Range<S>& other);
+
+ uint32_t size() const;
+ bool empty() const;
+
+ void popFront();
+ void popBack();
+
+ T* begin() const;
+ T* end() const;
+
+ T& front() const;
+ T& back() const;
+
+ T& operator[](uint32_t i) const;
+
+ private:
+ T* mFirst;
+ T* mLast; // past last element
+};
+
+template <typename T>
+Range<T>::Range()
+: mFirst(0), mLast(0)
+{
+}
+
+template <typename T>
+Range<T>::Range(T* first, T* last)
+: mFirst(first), mLast(last)
+{
+}
+
+template <typename T>
+template <typename S>
+Range<T>::Range(const Range<S>& other)
+: mFirst(other.begin()), mLast(other.end())
+{
+}
+
+template <typename T>
+uint32_t Range<T>::size() const
+{
+ return uint32_t(mLast - mFirst);
+}
+
+template <typename T>
+bool Range<T>::empty() const
+{
+ return mFirst >= mLast;
+}
+
+template <typename T>
+void Range<T>::popFront()
+{
+ PX_ASSERT(mFirst < mLast);
+ ++mFirst;
+}
+
+template <typename T>
+void Range<T>::popBack()
+{
+ PX_ASSERT(mFirst < mLast);
+ --mLast;
+}
+
+template <typename T>
+T* Range<T>::begin() const
+{
+ return mFirst;
+}
+
+template <typename T>
+T* Range<T>::end() const
+{
+ return mLast;
+}
+
+template <typename T>
+T& Range<T>::front() const
+{
+ PX_ASSERT(mFirst < mLast);
+ return *mFirst;
+}
+
+template <typename T>
+T& Range<T>::back() const
+{
+ PX_ASSERT(mFirst < mLast);
+ return mLast[-1];
+}
+
+template <typename T>
+T& Range<T>::operator[](uint32_t i) const
+{
+ PX_ASSERT(mFirst + i < mLast);
+ return mFirst[i];
+}
+
+} // namespace cloth
+} // namespace nvidia
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/include/Solver.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/include/Solver.h
new file mode 100644
index 00000000..585aab63
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/include/Solver.h
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "Types.h"
+
+namespace physx
+{
+ class PxBaseTask;
+}
+
+namespace nvidia
+{
+namespace cloth
+{
+
+class Cloth;
+
+// called during inter-collision, user0 and user1 are the user data from each cloth
+typedef bool (*InterCollisionFilter)(void* user0, void* user1);
+
+/// base class for solvers
+class Solver
+{
+ protected:
+ Solver(const Solver&);
+ Solver& operator=(const Solver&);
+
+ protected:
+ Solver()
+ {
+ }
+
+ public:
+ virtual ~Solver()
+ {
+ }
+
+ /// add cloth object, returns true if successful
+ virtual void addCloth(Cloth*) = 0;
+
+ /// remove cloth object
+ virtual void removeCloth(Cloth*) = 0;
+
+ /// simulate one time step
+ virtual PxBaseTask& simulate(float dt, PxBaseTask&) = 0;
+
+ // inter-collision parameters
+ virtual void setInterCollisionDistance(float distance) = 0;
+ virtual float getInterCollisionDistance() const = 0;
+ virtual void setInterCollisionStiffness(float stiffness) = 0;
+ virtual float getInterCollisionStiffness() const = 0;
+ virtual void setInterCollisionNbIterations(uint32_t nbIterations) = 0;
+ virtual uint32_t getInterCollisionNbIterations() const = 0;
+ virtual void setInterCollisionFilter(InterCollisionFilter filter) = 0;
+
+// virtual uint32_t getNumSharedPositions( const Cloth* ) const = 0;
+
+ /// returns true if an unrecoverable error has occurred
+ virtual bool hasError() const = 0;
+};
+
+} // namespace cloth
+} // namespace nvidia
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/include/Types.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/include/Types.h
new file mode 100644
index 00000000..e80a3009
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/include/Types.h
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#ifndef __CUDACC__
+#include "ApexUsingNamespace.h"
+#include "Px.h"
+#include "PxVec3.h"
+#include "PxVec4.h"
+#include "PxQuat.h"
+#endif
+
+// Factory.cpp gets included in both PhysXGPU and LowLevelCloth projects
+// CuFactory can only be created in PhysXGPU project
+// DxFactory can only be created in PhysXGPU (win) or LowLevelCloth (xbox1)
+#if defined(PX_PHYSX_GPU_EXPORTS) || PX_XBOXONE
+#define ENABLE_CUFACTORY ((PX_WINDOWS_FAMILY && (PX_WINRT==0)) || PX_LINUX)
+
+//TEMPORARY DISABLE DXFACTORY
+#define ENABLE_DXFACTORY 0
+//#define ENABLE_DXFACTORY ((PX_WINDOWS_FAMILY && (PX_WINRT==0)) || PX_XBOXONE)
+#else
+#define ENABLE_CUFACTORY 0
+#define ENABLE_DXFACTORY 0
+#endif
+
+#ifndef _MSC_VER
+#include <stdint.h>
+#else
+// typedef standard integer types
+typedef unsigned __int8 uint8_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+typedef __int16 int16_t;
+typedef __int32 int32_t;
+#if _MSC_VER < 1600
+#define nullptr NULL
+#endif
+#endif
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/Allocator.cpp b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/Allocator.cpp
new file mode 100644
index 00000000..c6c297ca
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/Allocator.cpp
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "Allocator.h"
+#include "PsAllocator.h"
+
+namespace nvidia
+{
+
+void* cloth::allocate(size_t n)
+{
+ return n ? nvidia::getAllocator().allocate(n, "", __FILE__, __LINE__) : 0;
+}
+
+void cloth::deallocate(void* ptr)
+{
+ if(ptr)
+ nvidia::getAllocator().deallocate(ptr);
+}
+}
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/Allocator.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/Allocator.h
new file mode 100644
index 00000000..c0488b43
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/Allocator.h
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "Types.h"
+#include "PsArray.h"
+#include "PsAllocator.h"
+#include "PsAlignedMalloc.h"
+
+namespace nvidia
+{
+namespace cloth
+{
+
+void* allocate(size_t);
+void deallocate(void*);
+
+/* templated typedefs for convenience */
+
+template <typename T>
+struct Vector
+{
+ typedef nvidia::Array<T, nvidia::NonTrackingAllocator> Type;
+};
+
+template <typename T, size_t alignment>
+struct AlignedVector
+{
+ typedef nvidia::Array<T, nvidia::AlignedAllocator<alignment> > Type;
+};
+
+struct UserAllocated
+{
+ virtual ~UserAllocated()
+ {
+ }
+ static void* operator new(size_t n)
+ {
+ return allocate(n);
+ }
+ static void operator delete(void* ptr)
+ {
+ deallocate(ptr);
+ }
+};
+
+} // namespace cloth
+}
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/Array.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/Array.h
new file mode 100644
index 00000000..e9da59aa
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/Array.h
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "PxVec4.h"
+#include "PxQuat.h"
+#include "PxVec3.h"
+#include "ApexUsingNamespace.h"
+
+namespace nvidia
+{
+
+namespace cloth
+{
+
+inline float (&array(PxVec3& v))[3]
+{
+ return reinterpret_cast<float(&)[3]>(v);
+}
+inline const float (&array(const PxVec3& v))[3]
+{
+ return reinterpret_cast<const float(&)[3]>(v);
+}
+inline float (&array(PxVec4& v))[4]
+{
+ return reinterpret_cast<float(&)[4]>(v);
+}
+inline const float (&array(const PxVec4& v))[4]
+{
+ return reinterpret_cast<const float(&)[4]>(v);
+}
+inline float (&array(PxQuat& q))[4]
+{
+ return reinterpret_cast<float(&)[4]>(q);
+}
+inline const float (&array(const PxQuat& q))[4]
+{
+ return reinterpret_cast<const float(&)[4]>(q);
+}
+
+} // namespace cloth
+
+} // namespace nvidia
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/BoundingBox.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/BoundingBox.h
new file mode 100644
index 00000000..339f6f12
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/BoundingBox.h
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "Simd4f.h"
+#include <float.h>
+
+namespace nvidia
+{
+
+namespace cloth
+{
+
+template <typename Simd4f>
+struct BoundingBox
+{
+ Simd4f mLower;
+ Simd4f mUpper;
+};
+
+template <typename Simd4f>
+inline BoundingBox<Simd4f> loadBounds(const float* ptr)
+{
+ BoundingBox<Simd4f> result;
+ result.mLower = load(ptr);
+ result.mUpper = load(ptr + 3);
+ return result;
+}
+
+template <typename Simd4f>
+inline BoundingBox<Simd4f> emptyBounds()
+{
+ BoundingBox<Simd4f> result;
+
+ result.mLower = simd4f(FLT_MAX);
+ result.mUpper = -result.mLower;
+
+ return result;
+}
+
+template <typename Simd4f>
+inline BoundingBox<Simd4f> expandBounds(const BoundingBox<Simd4f>& bounds, const Simd4f* pIt, const Simd4f* pEnd)
+{
+ BoundingBox<Simd4f> result = bounds;
+ for(; pIt != pEnd; ++pIt)
+ {
+ result.mLower = min(result.mLower, *pIt);
+ result.mUpper = max(result.mUpper, *pIt);
+ }
+ return result;
+}
+
+template <typename Simd4f>
+inline BoundingBox<Simd4f> expandBounds(const BoundingBox<Simd4f>& a, const BoundingBox<Simd4f>& b)
+{
+ BoundingBox<Simd4f> result;
+ result.mLower = min(a.mLower, b.mLower);
+ result.mUpper = max(a.mUpper, b.mUpper);
+ return result;
+}
+
+template <typename Simd4f>
+inline BoundingBox<Simd4f> intersectBounds(const BoundingBox<Simd4f>& a, const BoundingBox<Simd4f>& b)
+{
+ BoundingBox<Simd4f> result;
+ result.mLower = max(a.mLower, b.mLower);
+ result.mUpper = min(a.mUpper, b.mUpper);
+ return result;
+}
+
+template <typename Simd4f>
+inline bool isEmptyBounds(const BoundingBox<Simd4f>& a)
+{
+ return anyGreater(a.mLower, a.mUpper) != 0;
+}
+}
+}
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/ClothBase.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/ClothBase.h
new file mode 100644
index 00000000..641fc70f
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/ClothBase.h
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "PsMathUtils.h"
+
+namespace nvidia
+{
+namespace cloth
+{
+
+/* helper functions shared between SwCloth and CuCloth */
+
+template <typename Cloth>
+void initialize(Cloth& cloth, const PxVec4* pIt, const PxVec4* pEnd)
+{
+ // initialize particles bounding box
+ PxVec4 lower(FLT_MAX), upper = -lower;
+ for(; pIt != pEnd; ++pIt)
+ {
+ lower = lower.minimum(*pIt);
+ upper = upper.maximum(*pIt);
+ }
+ PxVec4 center = (upper + lower) * 0.5f;
+ PxVec4 extent = (upper - lower) * 0.5f;
+ cloth.mParticleBoundsCenter = reinterpret_cast<const PxVec3&>(center);
+ cloth.mParticleBoundsHalfExtent = reinterpret_cast<const PxVec3&>(extent);
+
+ cloth.mGravity = PxVec3(0.0f);
+ cloth.mLogDamping = PxVec3(0.0f);
+ cloth.mLinearLogDrag = PxVec3(0.0f);
+ cloth.mAngularLogDrag = PxVec3(0.0f);
+ cloth.mLinearInertia = PxVec3(1.0f);
+ cloth.mAngularInertia = PxVec3(1.0f);
+ cloth.mCentrifugalInertia = PxVec3(1.0f);
+ cloth.mSolverFrequency = 60.0f;
+ cloth.mStiffnessFrequency = 10.0f;
+ cloth.mTargetMotion = PxTransform(PxIdentity);
+ cloth.mCurrentMotion = PxTransform(PxIdentity);
+ cloth.mLinearVelocity = PxVec3(0.0f);
+ cloth.mAngularVelocity = PxVec3(0.0f);
+ cloth.mPrevIterDt = 0.0f;
+ cloth.mIterDtAvg = MovingAverage(30);
+ cloth.mTetherConstraintLogStiffness = float(-FLT_MAX_EXP);
+ cloth.mTetherConstraintScale = 1.0f;
+ cloth.mMotionConstraintScale = 1.0f;
+ cloth.mMotionConstraintBias = 0.0f;
+ cloth.mMotionConstraintLogStiffness = float(-FLT_MAX_EXP);
+ cloth.mEnableContinuousCollision = false;
+ cloth.mCollisionMassScale = 0.0f;
+ cloth.mFriction = 0.0f;
+ cloth.mSelfCollisionDistance = 0.0f;
+ cloth.mSelfCollisionLogStiffness = float(-FLT_MAX_EXP);
+ cloth.mSleepTestInterval = uint32_t(-1);
+ cloth.mSleepAfterCount = uint32_t(-1);
+ cloth.mSleepThreshold = 0.0f;
+ cloth.mSleepPassCounter = 0;
+ cloth.mSleepTestCounter = 0;
+}
+
+template <typename DstCloth, typename SrcCloth>
+void copy(DstCloth& dstCloth, const SrcCloth& srcCloth)
+{
+ dstCloth.mParticleBoundsCenter = srcCloth.mParticleBoundsCenter;
+ dstCloth.mParticleBoundsHalfExtent = srcCloth.mParticleBoundsHalfExtent;
+ dstCloth.mGravity = srcCloth.mGravity;
+ dstCloth.mLogDamping = srcCloth.mLogDamping;
+ dstCloth.mLinearLogDrag = srcCloth.mLinearLogDrag;
+ dstCloth.mAngularLogDrag = srcCloth.mAngularLogDrag;
+ dstCloth.mLinearInertia = srcCloth.mLinearInertia;
+ dstCloth.mAngularInertia = srcCloth.mAngularInertia;
+ dstCloth.mCentrifugalInertia = srcCloth.mCentrifugalInertia;
+ dstCloth.mSolverFrequency = srcCloth.mSolverFrequency;
+ dstCloth.mStiffnessFrequency = srcCloth.mStiffnessFrequency;
+ dstCloth.mTargetMotion = srcCloth.mTargetMotion;
+ dstCloth.mCurrentMotion = srcCloth.mCurrentMotion;
+ dstCloth.mLinearVelocity = srcCloth.mLinearVelocity;
+ dstCloth.mAngularVelocity = srcCloth.mAngularVelocity;
+ dstCloth.mPrevIterDt = srcCloth.mPrevIterDt;
+ dstCloth.mIterDtAvg = srcCloth.mIterDtAvg;
+ dstCloth.mTetherConstraintLogStiffness = srcCloth.mTetherConstraintLogStiffness;
+ dstCloth.mTetherConstraintScale = srcCloth.mTetherConstraintScale;
+ dstCloth.mMotionConstraintScale = srcCloth.mMotionConstraintScale;
+ dstCloth.mMotionConstraintBias = srcCloth.mMotionConstraintBias;
+ dstCloth.mMotionConstraintLogStiffness = srcCloth.mMotionConstraintLogStiffness;
+ dstCloth.mEnableContinuousCollision = srcCloth.mEnableContinuousCollision;
+ dstCloth.mCollisionMassScale = srcCloth.mCollisionMassScale;
+ dstCloth.mFriction = srcCloth.mFriction;
+ dstCloth.mSelfCollisionDistance = srcCloth.mSelfCollisionDistance;
+ dstCloth.mSelfCollisionLogStiffness = srcCloth.mSelfCollisionLogStiffness;
+ dstCloth.mSleepTestInterval = srcCloth.mSleepTestInterval;
+ dstCloth.mSleepAfterCount = srcCloth.mSleepAfterCount;
+ dstCloth.mSleepThreshold = srcCloth.mSleepThreshold;
+ dstCloth.mSleepPassCounter = srcCloth.mSleepPassCounter;
+ dstCloth.mSleepTestCounter = srcCloth.mSleepTestCounter;
+ dstCloth.mIsAllowedHalfPrecisionSolver = srcCloth.mIsAllowedHalfPrecisionSolver;
+ dstCloth.mUserData = srcCloth.mUserData;
+}
+
+} // namespace cloth
+} // namespace nvidia
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/ClothImpl.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/ClothImpl.h
new file mode 100644
index 00000000..22206016
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/ClothImpl.h
@@ -0,0 +1,1247 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "Cloth.h"
+#include "Fabric.h"
+#include "Allocator.h"
+#include "PsMathUtils.h"
+
+namespace nvidia
+{
+namespace cloth
+{
+
+// SwCloth or CuCloth aggregate implementing the Cloth interface
+// Member specializations are implemented in Sw/CuCloth.cpp
+template <typename T>
+class ClothImpl : public UserAllocated, public Cloth
+{
+ ClothImpl(const ClothImpl&);
+
+ public:
+ ClothImpl& operator=(const ClothImpl&);
+
+ typedef T ClothType;
+ typedef typename ClothType::FactoryType FactoryType;
+ typedef typename ClothType::FabricType FabricType;
+ typedef typename ClothType::ContextLockType ContextLockType;
+
+ ClothImpl(Factory&, Fabric&, Range<const PxVec4>);
+ ClothImpl(Factory&, const ClothImpl&);
+
+ virtual Cloth* clone(Factory& factory) const;
+
+ virtual Fabric& getFabric() const;
+ virtual Factory& getFactory() const;
+
+ virtual uint32_t getNumParticles() const;
+ virtual void lockParticles() const;
+ virtual void unlockParticles() const;
+ virtual MappedRange<PxVec4> getCurrentParticles();
+ virtual MappedRange<const PxVec4> getCurrentParticles() const;
+ virtual MappedRange<PxVec4> getPreviousParticles();
+ virtual MappedRange<const PxVec4> getPreviousParticles() const;
+ virtual GpuParticles getGpuParticles();
+
+ virtual void setTranslation(const PxVec3& trans);
+ virtual void setRotation(const PxQuat& rot);
+
+ virtual const PxVec3& getTranslation() const;
+ virtual const PxQuat& getRotation() const;
+
+ virtual void clearInertia();
+
+ virtual void teleport(const PxVec3& delta);
+
+ virtual float getPreviousIterationDt() const;
+ virtual void setGravity(const PxVec3& gravity);
+ virtual PxVec3 getGravity() const;
+ virtual void setDamping(const PxVec3& damping);
+ virtual PxVec3 getDamping() const;
+ virtual void setLinearDrag(const PxVec3& drag);
+ virtual PxVec3 getLinearDrag() const;
+ virtual void setAngularDrag(const PxVec3& drag);
+ virtual PxVec3 getAngularDrag() const;
+ virtual void setLinearInertia(const PxVec3& inertia);
+ virtual PxVec3 getLinearInertia() const;
+ virtual void setAngularInertia(const PxVec3& inertia);
+ virtual PxVec3 getAngularInertia() const;
+ virtual void setCentrifugalInertia(const PxVec3& inertia);
+ virtual PxVec3 getCentrifugalInertia() const;
+
+ virtual void setSolverFrequency(float frequency);
+ virtual float getSolverFrequency() const;
+
+ virtual void setStiffnessFrequency(float frequency);
+ virtual float getStiffnessFrequency() const;
+
+ virtual void setAcceleationFilterWidth(uint32_t);
+ virtual uint32_t getAccelerationFilterWidth() const;
+
+ virtual void setPhaseConfig(Range<const PhaseConfig> configs);
+
+ virtual void setSpheres(Range<const PxVec4>, uint32_t first, uint32_t last);
+ virtual uint32_t getNumSpheres() const;
+
+ virtual void setCapsules(Range<const uint32_t>, uint32_t first, uint32_t last);
+ virtual uint32_t getNumCapsules() const;
+
+ virtual void setPlanes(Range<const PxVec4>, uint32_t first, uint32_t last);
+ virtual uint32_t getNumPlanes() const;
+
+ virtual void setConvexes(Range<const uint32_t>, uint32_t first, uint32_t last);
+ virtual uint32_t getNumConvexes() const;
+
+ virtual void setTriangles(Range<const PxVec3>, uint32_t first, uint32_t last);
+ virtual void setTriangles(Range<const PxVec3>, Range<const PxVec3>, uint32_t first);
+ virtual uint32_t getNumTriangles() const;
+
+ virtual bool isContinuousCollisionEnabled() const;
+ virtual void enableContinuousCollision(bool);
+
+ virtual float getCollisionMassScale() const;
+ virtual void setCollisionMassScale(float);
+ virtual void setFriction(float friction);
+ virtual float getFriction() const;
+
+ virtual void setVirtualParticles(Range<const uint32_t[4]>, Range<const PxVec3>);
+ virtual uint32_t getNumVirtualParticles() const;
+ virtual uint32_t getNumVirtualParticleWeights() const;
+
+ virtual void setTetherConstraintScale(float scale);
+ virtual float getTetherConstraintScale() const;
+ virtual void setTetherConstraintStiffness(float stiffness);
+ virtual float getTetherConstraintStiffness() const;
+
+ virtual Range<PxVec4> getMotionConstraints();
+ virtual void clearMotionConstraints();
+ virtual uint32_t getNumMotionConstraints() const;
+ virtual void setMotionConstraintScaleBias(float scale, float bias);
+ virtual float getMotionConstraintScale() const;
+ virtual float getMotionConstraintBias() const;
+ virtual void setMotionConstraintStiffness(float stiffness);
+ virtual float getMotionConstraintStiffness() const;
+
+ virtual Range<PxVec4> getSeparationConstraints();
+ virtual void clearSeparationConstraints();
+ virtual uint32_t getNumSeparationConstraints() const;
+
+ virtual void clearInterpolation();
+
+ virtual Range<PxVec4> getParticleAccelerations();
+ virtual void clearParticleAccelerations();
+ virtual uint32_t getNumParticleAccelerations() const;
+
+ virtual void setSelfCollisionDistance(float);
+ virtual float getSelfCollisionDistance() const;
+ virtual void setSelfCollisionStiffness(float);
+ virtual float getSelfCollisionStiffness() const;
+
+ virtual void setSelfCollisionIndices(Range<const uint32_t>);
+ virtual uint32_t getNumSelfCollisionIndices() const;
+
+ virtual void setRestPositions(Range<const PxVec4>);
+ virtual uint32_t getNumRestPositions() const;
+
+ virtual const PxVec3& getBoundingBoxCenter() const;
+ virtual const PxVec3& getBoundingBoxScale() const;
+
+ virtual void setSleepThreshold(float);
+ virtual float getSleepThreshold() const;
+ virtual void setSleepTestInterval(uint32_t);
+ virtual uint32_t getSleepTestInterval() const;
+ virtual void setSleepAfterCount(uint32_t);
+ virtual uint32_t getSleepAfterCount() const;
+ virtual uint32_t getSleepPassCount() const;
+ virtual bool isAsleep() const;
+ virtual void putToSleep();
+ virtual void wakeUp();
+
+ virtual void setHalfPrecisionOption(bool isAllowed);
+ virtual bool getHalfPrecisionOption() const;
+
+#if APEX_UE4
+ virtual void simulate(float dt);
+#endif
+
+ virtual void setUserData(void*);
+ virtual void* getUserData() const;
+
+ // helper function
+ template <typename U>
+ MappedRange<U> getMappedParticles(U* data) const;
+
+ ClothType mCloth;
+};
+
+class SwCloth;
+typedef ClothImpl<SwCloth> SwClothImpl;
+
+class CuCloth;
+typedef ClothImpl<CuCloth> CuClothImpl;
+
+class DxCloth;
+typedef ClothImpl<DxCloth> DxClothImpl;
+
+template <typename T>
+ClothImpl<T>::ClothImpl(Factory& factory, Fabric& fabric, Range<const PxVec4> particles)
+: mCloth(static_cast<FactoryType&>(factory), static_cast<FabricType&>(fabric), particles)
+{
+ // fabric and cloth need to be created by the same factory
+ PX_ASSERT(&fabric.getFactory() == &factory);
+}
+
+template <typename T>
+ClothImpl<T>::ClothImpl(Factory& factory, const ClothImpl& impl)
+: mCloth(static_cast<FactoryType&>(factory), impl.mCloth)
+{
+}
+
+template <typename T>
+inline Fabric& ClothImpl<T>::getFabric() const
+{
+ return mCloth.mFabric;
+}
+
+template <typename T>
+inline Factory& ClothImpl<T>::getFactory() const
+{
+ return mCloth.mFactory;
+}
+
+template <typename T>
+inline void ClothImpl<T>::setTranslation(const PxVec3& trans)
+{
+ PxVec3 t = reinterpret_cast<const PxVec3&>(trans);
+ if(t == mCloth.mTargetMotion.p)
+ return;
+
+ mCloth.mTargetMotion.p = t;
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline void ClothImpl<T>::setRotation(const PxQuat& q)
+{
+ if((q - mCloth.mTargetMotion.q).magnitudeSquared() == 0.0f)
+ return;
+
+ mCloth.mTargetMotion.q = q;
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline const PxVec3& ClothImpl<T>::getTranslation() const
+{
+ return mCloth.mTargetMotion.p;
+}
+
+template <typename T>
+inline const PxQuat& ClothImpl<T>::getRotation() const
+{
+ return mCloth.mTargetMotion.q;
+}
+
+template <typename T>
+inline void ClothImpl<T>::clearInertia()
+{
+ mCloth.mCurrentMotion = mCloth.mTargetMotion;
+ mCloth.mLinearVelocity = PxVec3(0.0f);
+ mCloth.mAngularVelocity = PxVec3(0.0f);
+
+ mCloth.wakeUp();
+}
+
+// Fixed 4505:local function has been removed
+template <typename T>
+inline void ClothImpl<T>::teleport(const PxVec3& delta)
+{
+ mCloth.mCurrentMotion.p += delta;
+ mCloth.mTargetMotion.p += delta;
+}
+
+template <typename T>
+inline float ClothImpl<T>::getPreviousIterationDt() const
+{
+ return mCloth.mPrevIterDt;
+}
+
+template <typename T>
+inline void ClothImpl<T>::setGravity(const PxVec3& gravity)
+{
+ PxVec3 value = gravity;
+ if(value == mCloth.mGravity)
+ return;
+
+ mCloth.mGravity = value;
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline PxVec3 ClothImpl<T>::getGravity() const
+{
+ return mCloth.mGravity;
+}
+
+inline float safeLog2(float x)
+{
+ return x ? physx::shdfnd::log2(x) : -FLT_MAX_EXP;
+}
+
+inline PxVec3 safeLog2(const PxVec3& v)
+{
+ return PxVec3(safeLog2(v.x), safeLog2(v.y), safeLog2(v.z));
+}
+
+inline float safeExp2(float x)
+{
+ if(x <= -FLT_MAX_EXP)
+ return 0.0f;
+ else
+ return physx::shdfnd::exp2(x);
+}
+
+inline PxVec3 safeExp2(const PxVec3& v)
+{
+ return PxVec3(safeExp2(v.x), safeExp2(v.y), safeExp2(v.z));
+}
+
+template <typename T>
+inline void ClothImpl<T>::setDamping(const PxVec3& damping)
+{
+ PxVec3 value = safeLog2(PxVec3(1.f) - damping);
+ if(value == mCloth.mLogDamping)
+ return;
+
+ mCloth.mLogDamping = value;
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline PxVec3 ClothImpl<T>::getDamping() const
+{
+ return PxVec3(1.f) - safeExp2(mCloth.mLogDamping);
+}
+
+template <typename T>
+inline void ClothImpl<T>::setLinearDrag(const PxVec3& drag)
+{
+ PxVec3 value = safeLog2(PxVec3(1.f) - drag);
+ if(value == mCloth.mLinearLogDrag)
+ return;
+
+ mCloth.mLinearLogDrag = value;
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline PxVec3 ClothImpl<T>::getLinearDrag() const
+{
+ return PxVec3(1.f) - safeExp2(mCloth.mLinearLogDrag);
+}
+
+template <typename T>
+inline void ClothImpl<T>::setAngularDrag(const PxVec3& drag)
+{
+ PxVec3 value = safeLog2(PxVec3(1.f) - drag);
+ if(value == mCloth.mAngularLogDrag)
+ return;
+
+ mCloth.mAngularLogDrag = value;
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline PxVec3 ClothImpl<T>::getAngularDrag() const
+{
+ return PxVec3(1.f) - safeExp2(mCloth.mAngularLogDrag);
+}
+
+template <typename T>
+inline void ClothImpl<T>::setLinearInertia(const PxVec3& inertia)
+{
+ PxVec3 value = inertia;
+ if(value == mCloth.mLinearInertia)
+ return;
+
+ mCloth.mLinearInertia = value;
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline PxVec3 ClothImpl<T>::getLinearInertia() const
+{
+ return mCloth.mLinearInertia;
+}
+
+template <typename T>
+inline void ClothImpl<T>::setAngularInertia(const PxVec3& inertia)
+{
+ PxVec3 value = inertia;
+ if(value == mCloth.mAngularInertia)
+ return;
+
+ mCloth.mAngularInertia = value;
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline PxVec3 ClothImpl<T>::getAngularInertia() const
+{
+ return mCloth.mAngularInertia;
+}
+
+template <typename T>
+inline void ClothImpl<T>::setCentrifugalInertia(const PxVec3& inertia)
+{
+ PxVec3 value = inertia;
+ if(value == mCloth.mCentrifugalInertia)
+ return;
+
+ mCloth.mCentrifugalInertia = value;
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline PxVec3 ClothImpl<T>::getCentrifugalInertia() const
+{
+ return mCloth.mCentrifugalInertia;
+}
+
+template <typename T>
+inline void ClothImpl<T>::setSolverFrequency(float frequency)
+{
+ if(frequency == mCloth.mSolverFrequency)
+ return;
+
+ mCloth.mSolverFrequency = frequency;
+ mCloth.mClothCostDirty = true;
+ mCloth.mIterDtAvg.reset();
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline float ClothImpl<T>::getSolverFrequency() const
+{
+ return mCloth.mSolverFrequency;
+}
+
+template <typename T>
+inline void ClothImpl<T>::setStiffnessFrequency(float frequency)
+{
+ if(frequency == mCloth.mStiffnessFrequency)
+ return;
+
+ mCloth.mStiffnessFrequency = frequency;
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline float ClothImpl<T>::getStiffnessFrequency() const
+{
+ return mCloth.mStiffnessFrequency;
+}
+
+template <typename T>
+inline void ClothImpl<T>::setAcceleationFilterWidth(uint32_t n)
+{
+ mCloth.mIterDtAvg.resize(n);
+}
+
+template <typename T>
+inline uint32_t ClothImpl<T>::getAccelerationFilterWidth() const
+{
+ return mCloth.mIterDtAvg.size();
+}
+
+// move a subarray
+template <typename Iter>
+void move(Iter it, uint32_t first, uint32_t last, uint32_t result)
+{
+ if(result > first)
+ {
+ result += last - first;
+ while(first < last)
+ it[--result] = it[--last];
+ }
+ else
+ {
+ while(first < last)
+ it[result++] = it[first++];
+ }
+}
+
+// update capsule index
+inline bool updateIndex(uint32_t& index, uint32_t first, int32_t delta)
+{
+ return index >= first && int32_t(index += delta) < int32_t(first);
+}
+
+template <typename T>
+inline void ClothImpl<T>::setSpheres(Range<const PxVec4> spheres, uint32_t first, uint32_t last)
+{
+ uint32_t oldSize = uint32_t(mCloth.mStartCollisionSpheres.size());
+ uint32_t newSize = uint32_t(spheres.size()) + oldSize - last + first;
+
+ PX_ASSERT(newSize <= 32);
+ PX_ASSERT(first <= oldSize);
+ PX_ASSERT(last <= oldSize);
+
+#if PX_DEBUG
+ for(const PxVec4* it = spheres.begin(); it < spheres.end(); ++it)
+ PX_ASSERT(it->w >= 0.0f);
+#endif
+
+ if(!oldSize && !newSize)
+ return;
+
+ if(!oldSize)
+ {
+ ContextLockType contextLock(mCloth.mFactory);
+ mCloth.mStartCollisionSpheres.assign(spheres.begin(), spheres.end());
+ mCloth.notifyChanged();
+ }
+ else
+ {
+ if(PxMax(oldSize, newSize) >
+ PxMin(mCloth.mStartCollisionSpheres.capacity(), mCloth.mTargetCollisionSpheres.capacity()))
+ {
+ ContextLockType contextLock(mCloth.mFactory);
+ mCloth.mStartCollisionSpheres.reserve(newSize);
+ mCloth.mTargetCollisionSpheres.reserve(PxMax(oldSize, newSize));
+ }
+
+ typename T::MappedVec4fVectorType start = mCloth.mStartCollisionSpheres;
+ typename T::MappedVec4fVectorType target = mCloth.mTargetCollisionSpheres;
+
+ // fill target from start
+ for(uint32_t i = target.size(); i < oldSize; ++i)
+ target.pushBack(start[i]);
+
+ // resize to larger of oldSize and newSize
+ start.resize(PxMax(oldSize, newSize), PxVec4(0.0f));
+ target.resize(PxMax(oldSize, newSize), PxVec4(0.0f));
+
+ if(int32_t delta = int32_t(newSize - oldSize))
+ {
+ // move past-range elements to new place
+ move(start.begin(), last, oldSize, last + delta);
+ move(target.begin(), last, oldSize, last + delta);
+
+ // fill new elements from spheres
+ for(uint32_t i = last; i < last + delta; ++i)
+ start[i] = spheres[i - first];
+
+ // adjust capsule indices
+ typename T::MappedIndexVectorType indices = mCloth.mCapsuleIndices;
+ Vector<IndexPair>::Type::Iterator cIt, cEnd = indices.end();
+ for(cIt = indices.begin(); cIt != cEnd;)
+ {
+ bool removed = false;
+ removed |= updateIndex(cIt->first, last + PxMin(0, delta), int32_t(delta));
+ removed |= updateIndex(cIt->second, last + PxMin(0, delta), int32_t(delta));
+ if(!removed)
+ ++cIt;
+ else
+ {
+ indices.replaceWithLast(cIt);
+ cEnd = indices.end();
+ }
+ }
+
+ start.resize(newSize);
+ target.resize(newSize);
+
+ mCloth.notifyChanged();
+ }
+
+ // fill target elements with spheres
+ for(uint32_t i = 0; i < spheres.size(); ++i)
+ target[first + i] = spheres[i];
+ }
+
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline uint32_t ClothImpl<T>::getNumSpheres() const
+{
+ return uint32_t(mCloth.mStartCollisionSpheres.size());
+}
+
+// Fixed 4505:local function has been removed
+template <typename T>
+inline void ClothImpl<T>::setCapsules(Range<const uint32_t> capsules, uint32_t first, uint32_t last)
+{
+ uint32_t oldSize = mCloth.mCapsuleIndices.size();
+ uint32_t newSize = uint32_t(capsules.size() / 2) + oldSize - last + first;
+
+ PX_ASSERT(newSize <= 32);
+ PX_ASSERT(first <= oldSize);
+ PX_ASSERT(last <= oldSize);
+
+ const IndexPair* srcIndices = reinterpret_cast<const IndexPair*>(capsules.begin());
+
+ if(mCloth.mCapsuleIndices.capacity() < newSize)
+ {
+ ContextLockType contextLock(mCloth.mFactory);
+ mCloth.mCapsuleIndices.reserve(newSize);
+ }
+
+ // resize to larger of oldSize and newSize
+ mCloth.mCapsuleIndices.resize(PxMax(oldSize, newSize));
+
+ typename T::MappedIndexVectorType dstIndices = mCloth.mCapsuleIndices;
+
+ if(uint32_t delta = newSize - oldSize)
+ {
+ // move past-range elements to new place
+ move(dstIndices.begin(), last, oldSize, last + delta);
+
+ // fill new elements from capsules
+ for(uint32_t i = last; i < last + delta; ++i)
+ dstIndices[i] = srcIndices[i - first];
+
+ dstIndices.resize(newSize);
+ mCloth.notifyChanged();
+ }
+
+ // fill existing elements from capsules
+ for(uint32_t i = first; i < last; ++i)
+ dstIndices[i] = srcIndices[i - first];
+
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline uint32_t ClothImpl<T>::getNumCapsules() const
+{
+ return uint32_t(mCloth.mCapsuleIndices.size());
+}
+
+template <typename T>
+inline void ClothImpl<T>::setPlanes(Range<const PxVec4> planes, uint32_t first, uint32_t last)
+{
+ uint32_t oldSize = uint32_t(mCloth.mStartCollisionPlanes.size());
+ uint32_t newSize = uint32_t(planes.size()) + oldSize - last + first;
+
+ PX_ASSERT(newSize <= 32);
+ PX_ASSERT(first <= oldSize);
+ PX_ASSERT(last <= oldSize);
+
+ if(!oldSize && !newSize)
+ return;
+
+ if(!oldSize)
+ {
+ ContextLockType contextLock(mCloth.mFactory);
+ mCloth.mStartCollisionPlanes.assign(planes.begin(), planes.end());
+ mCloth.notifyChanged();
+ }
+ else
+ {
+ if(PxMax(oldSize, newSize) >
+ PxMin(mCloth.mStartCollisionPlanes.capacity(), mCloth.mTargetCollisionPlanes.capacity()))
+ {
+ ContextLockType contextLock(mCloth.mFactory);
+ mCloth.mStartCollisionPlanes.reserve(newSize);
+ mCloth.mTargetCollisionPlanes.reserve(PxMax(oldSize, newSize));
+ }
+
+ // fill target from start
+ for(uint32_t i = mCloth.mTargetCollisionPlanes.size(); i < oldSize; ++i)
+ mCloth.mTargetCollisionPlanes.pushBack(mCloth.mStartCollisionPlanes[i]);
+
+ // resize to larger of oldSize and newSize
+ mCloth.mStartCollisionPlanes.resize(PxMax(oldSize, newSize), PxZero);
+ mCloth.mTargetCollisionPlanes.resize(PxMax(oldSize, newSize), PxZero);
+
+ if(int32_t delta = int32_t(newSize - oldSize))
+ {
+ // move past-range elements to new place
+ move(mCloth.mStartCollisionPlanes.begin(), last, oldSize, last + delta);
+ move(mCloth.mTargetCollisionPlanes.begin(), last, oldSize, last + delta);
+
+ // fill new elements from planes
+ for(uint32_t i = last; i < last + delta; ++i)
+ mCloth.mStartCollisionPlanes[i] = planes[i - first];
+
+ // adjust convex indices
+ uint32_t mask = (uint32_t(1) << (last + PxMin(delta, 0))) - 1;
+ Vector<uint32_t>::Type::Iterator cIt, cEnd = mCloth.mConvexMasks.end();
+ for(cIt = mCloth.mConvexMasks.begin(); cIt != cEnd;)
+ {
+ uint32_t convex = (*cIt & mask);
+ if(delta < 0)
+ convex |= *cIt >> -delta & ~mask;
+ else
+ convex |= (*cIt & ~mask) << delta;
+ if(convex)
+ *cIt++ = convex;
+ else
+ {
+ mCloth.mConvexMasks.replaceWithLast(cIt);
+ cEnd = mCloth.mConvexMasks.end();
+ }
+ }
+
+ mCloth.mStartCollisionPlanes.resize(newSize);
+ mCloth.mTargetCollisionPlanes.resize(newSize);
+
+ mCloth.notifyChanged();
+ }
+
+ // fill target elements with planes
+ for(uint32_t i = 0; i < planes.size(); ++i)
+ mCloth.mTargetCollisionPlanes[first + i] = planes[i];
+ }
+
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline uint32_t ClothImpl<T>::getNumPlanes() const
+{
+ return uint32_t(mCloth.mStartCollisionPlanes.size());
+}
+
+template <typename T>
+inline void ClothImpl<T>::setConvexes(Range<const uint32_t> convexes, uint32_t first, uint32_t last)
+{
+ uint32_t oldSize = mCloth.mConvexMasks.size();
+ uint32_t newSize = uint32_t(convexes.size()) + oldSize - last + first;
+
+ PX_ASSERT(newSize <= 32);
+ PX_ASSERT(first <= oldSize);
+ PX_ASSERT(last <= oldSize);
+
+ if(mCloth.mConvexMasks.capacity() < newSize)
+ {
+ ContextLockType contextLock(mCloth.mFactory);
+ mCloth.mConvexMasks.reserve(newSize);
+ }
+
+ // resize to larger of oldSize and newSize
+ mCloth.mConvexMasks.resize(PxMax(oldSize, newSize));
+
+ if(uint32_t delta = newSize - oldSize)
+ {
+ // move past-range elements to new place
+ move(mCloth.mConvexMasks.begin(), last, oldSize, last + delta);
+
+ // fill new elements from capsules
+ for(uint32_t i = last; i < last + delta; ++i)
+ mCloth.mConvexMasks[i] = convexes[i - first];
+
+ mCloth.mConvexMasks.resize(newSize);
+ mCloth.notifyChanged();
+ }
+
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline uint32_t ClothImpl<T>::getNumConvexes() const
+{
+ return uint32_t(mCloth.mConvexMasks.size());
+}
+
+template <typename T>
+inline void ClothImpl<T>::setTriangles(Range<const PxVec3> triangles, uint32_t first, uint32_t last)
+{
+ // convert from triangle to vertex count
+ first *= 3;
+ last *= 3;
+
+ triangles = mCloth.clampTriangleCount(triangles, last - first);
+ PX_ASSERT(0 == triangles.size() % 3);
+
+ uint32_t oldSize = uint32_t(mCloth.mStartCollisionTriangles.size());
+ uint32_t newSize = uint32_t(triangles.size()) + oldSize - last + first;
+
+ PX_ASSERT(first <= oldSize);
+ PX_ASSERT(last <= oldSize);
+
+ if(!oldSize && !newSize)
+ return;
+
+ if(!oldSize)
+ {
+ ContextLockType contextLock(mCloth.mFactory);
+ mCloth.mStartCollisionTriangles.assign(triangles.begin(), triangles.end());
+ mCloth.notifyChanged();
+ }
+ else
+ {
+ if(PxMax(oldSize, newSize) >
+ PxMin(mCloth.mStartCollisionTriangles.capacity(), mCloth.mTargetCollisionTriangles.capacity()))
+ {
+ ContextLockType contextLock(mCloth.mFactory);
+ mCloth.mStartCollisionTriangles.reserve(newSize);
+ mCloth.mTargetCollisionTriangles.reserve(PxMax(oldSize, newSize));
+ }
+
+ // fill target from start
+ for(uint32_t i = mCloth.mTargetCollisionTriangles.size(); i < oldSize; ++i)
+ mCloth.mTargetCollisionTriangles.pushBack(mCloth.mStartCollisionTriangles[i]);
+
+ // resize to larger of oldSize and newSize
+ mCloth.mStartCollisionTriangles.resize(PxMax(oldSize, newSize));
+ mCloth.mTargetCollisionTriangles.resize(PxMax(oldSize, newSize));
+
+ if(uint32_t delta = newSize - oldSize)
+ {
+ // move past-range elements to new place
+ move(mCloth.mStartCollisionTriangles.begin(), last, oldSize, last + delta);
+ move(mCloth.mTargetCollisionTriangles.begin(), last, oldSize, last + delta);
+
+ // fill new elements from triangles
+ for(uint32_t i = last; i < last + delta; ++i)
+ mCloth.mStartCollisionTriangles[i] = triangles[i - first];
+
+ mCloth.mStartCollisionTriangles.resize(newSize);
+ mCloth.mTargetCollisionTriangles.resize(newSize);
+
+ mCloth.notifyChanged();
+ }
+
+ // fill target elements with triangles
+ for(uint32_t i = 0; i < triangles.size(); ++i)
+ mCloth.mTargetCollisionTriangles[first + i] = triangles[i];
+ }
+
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline void ClothImpl<T>::setTriangles(Range<const PxVec3> startTriangles, Range<const PxVec3> targetTriangles,
+ uint32_t first)
+{
+ PX_ASSERT(startTriangles.size() == targetTriangles.size());
+
+ // convert from triangle to vertex count
+ first *= 3;
+
+ uint32_t last = uint32_t(mCloth.mStartCollisionTriangles.size());
+
+ startTriangles = mCloth.clampTriangleCount(startTriangles, last - first);
+ targetTriangles = mCloth.clampTriangleCount(targetTriangles, last - first);
+
+ uint32_t oldSize = uint32_t(mCloth.mStartCollisionTriangles.size());
+ uint32_t newSize = uint32_t(startTriangles.size()) + oldSize - last + first;
+
+ PX_ASSERT(first <= oldSize);
+ PX_ASSERT(last == oldSize); // this path only supports replacing the tail
+
+ if(!oldSize && !newSize)
+ return;
+
+ if(newSize > PxMin(mCloth.mStartCollisionTriangles.capacity(), mCloth.mTargetCollisionTriangles.capacity()))
+ {
+ ContextLockType contextLock(mCloth.mFactory);
+ mCloth.mStartCollisionTriangles.reserve(newSize);
+ mCloth.mTargetCollisionTriangles.reserve(newSize);
+ }
+
+ uint32_t retainSize = oldSize - last + first;
+ mCloth.mStartCollisionTriangles.resize(retainSize);
+ mCloth.mTargetCollisionTriangles.resize(retainSize);
+
+ for(uint32_t i = 0, n = startTriangles.size(); i < n; ++i)
+ {
+ mCloth.mStartCollisionTriangles.pushBack(startTriangles[i]);
+ mCloth.mTargetCollisionTriangles.pushBack(targetTriangles[i]);
+ }
+
+ if(newSize - oldSize)
+ mCloth.notifyChanged();
+
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline uint32_t ClothImpl<T>::getNumTriangles() const
+{
+ return uint32_t(mCloth.mStartCollisionTriangles.size()) / 3;
+}
+
+template <typename T>
+inline bool ClothImpl<T>::isContinuousCollisionEnabled() const
+{
+ return mCloth.mEnableContinuousCollision;
+}
+
+template <typename T>
+inline void ClothImpl<T>::enableContinuousCollision(bool enable)
+{
+ if(enable == mCloth.mEnableContinuousCollision)
+ return;
+
+ mCloth.mEnableContinuousCollision = enable;
+ mCloth.notifyChanged();
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline float ClothImpl<T>::getCollisionMassScale() const
+{
+ return mCloth.mCollisionMassScale;
+}
+
+template <typename T>
+inline void ClothImpl<T>::setCollisionMassScale(float scale)
+{
+ if(scale == mCloth.mCollisionMassScale)
+ return;
+
+ mCloth.mCollisionMassScale = scale;
+ mCloth.notifyChanged();
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline void ClothImpl<T>::setFriction(float friction)
+{
+ mCloth.mFriction = friction;
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline float ClothImpl<T>::getFriction() const
+{
+ return mCloth.mFriction;
+}
+
+template <typename T>
+inline uint32_t ClothImpl<T>::getNumVirtualParticleWeights() const
+{
+ return uint32_t(mCloth.mVirtualParticleWeights.size());
+}
+
+template <typename T>
+inline void ClothImpl<T>::setTetherConstraintScale(float scale)
+{
+ if(scale == mCloth.mTetherConstraintScale)
+ return;
+
+ mCloth.mTetherConstraintScale = scale;
+ mCloth.notifyChanged();
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline float ClothImpl<T>::getTetherConstraintScale() const
+{
+ return mCloth.mTetherConstraintScale;
+}
+
+template <typename T>
+inline void ClothImpl<T>::setTetherConstraintStiffness(float stiffness)
+{
+ float value = safeLog2(1 - stiffness);
+ if(value == mCloth.mTetherConstraintLogStiffness)
+ return;
+
+ mCloth.mTetherConstraintLogStiffness = value;
+ mCloth.notifyChanged();
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline float ClothImpl<T>::getTetherConstraintStiffness() const
+{
+ return 1 - safeExp2(mCloth.mTetherConstraintLogStiffness);
+}
+
+template <typename T>
+inline Range<PxVec4> ClothImpl<T>::getMotionConstraints()
+{
+ mCloth.wakeUp();
+ return mCloth.push(mCloth.mMotionConstraints);
+}
+
+template <typename T>
+inline void ClothImpl<T>::clearMotionConstraints()
+{
+ mCloth.clear(mCloth.mMotionConstraints);
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline uint32_t ClothImpl<T>::getNumMotionConstraints() const
+{
+ return uint32_t(mCloth.mMotionConstraints.mStart.size());
+}
+
+template <typename T>
+inline void ClothImpl<T>::setMotionConstraintScaleBias(float scale, float bias)
+{
+ if(scale == mCloth.mMotionConstraintScale && bias == mCloth.mMotionConstraintBias)
+ return;
+
+ mCloth.mMotionConstraintScale = scale;
+ mCloth.mMotionConstraintBias = bias;
+ mCloth.notifyChanged();
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline float ClothImpl<T>::getMotionConstraintScale() const
+{
+ return mCloth.mMotionConstraintScale;
+}
+
+template <typename T>
+inline float ClothImpl<T>::getMotionConstraintBias() const
+{
+ return mCloth.mMotionConstraintBias;
+}
+
+template <typename T>
+inline void ClothImpl<T>::setMotionConstraintStiffness(float stiffness)
+{
+ float value = safeLog2(1 - stiffness);
+ if(value == mCloth.mMotionConstraintLogStiffness)
+ return;
+
+ mCloth.mMotionConstraintLogStiffness = value;
+ mCloth.notifyChanged();
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline float ClothImpl<T>::getMotionConstraintStiffness() const
+{
+ return 1 - safeExp2(mCloth.mMotionConstraintLogStiffness);
+}
+
+template <typename T>
+inline Range<PxVec4> ClothImpl<T>::getSeparationConstraints()
+{
+ mCloth.wakeUp();
+ return mCloth.push(mCloth.mSeparationConstraints);
+}
+
+template <typename T>
+inline void ClothImpl<T>::clearSeparationConstraints()
+{
+ mCloth.clear(mCloth.mSeparationConstraints);
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline void ClothImpl<T>::clearInterpolation()
+{
+ if(!mCloth.mTargetCollisionSpheres.empty())
+ {
+ nvidia::swap(mCloth.mStartCollisionSpheres, mCloth.mTargetCollisionSpheres);
+ mCloth.mTargetCollisionSpheres.resize(0);
+ }
+ mCloth.mMotionConstraints.pop();
+ mCloth.mSeparationConstraints.pop();
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline uint32_t ClothImpl<T>::getNumSeparationConstraints() const
+{
+ return uint32_t(mCloth.mSeparationConstraints.mStart.size());
+}
+
+template <typename T>
+inline uint32_t ClothImpl<T>::getNumParticleAccelerations() const
+{
+ return uint32_t(mCloth.mParticleAccelerations.size());
+}
+
+template <typename T>
+inline uint32_t ClothImpl<T>::getNumSelfCollisionIndices() const
+{
+ return uint32_t(mCloth.mSelfCollisionIndices.size());
+}
+
+// Fixed 4505:local function has been removed
+template <typename T>
+inline void ClothImpl<T>::setRestPositions(Range<const PxVec4> restPositions)
+{
+ PX_ASSERT(restPositions.empty() || restPositions.size() == getNumParticles());
+ ContextLockType contextLock(mCloth.mFactory);
+ mCloth.mRestPositions.assign(restPositions.begin(), restPositions.end());
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline uint32_t ClothImpl<T>::getNumRestPositions() const
+{
+ return uint32_t(mCloth.mRestPositions.size());
+}
+
+template <typename T>
+inline void ClothImpl<T>::setSelfCollisionDistance(float distance)
+{
+ if(distance == mCloth.mSelfCollisionDistance)
+ return;
+
+ mCloth.mSelfCollisionDistance = distance;
+ mCloth.notifyChanged();
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline float ClothImpl<T>::getSelfCollisionDistance() const
+{
+ return mCloth.mSelfCollisionDistance;
+}
+
+template <typename T>
+inline void ClothImpl<T>::setSelfCollisionStiffness(float stiffness)
+{
+ float value = safeLog2(1 - stiffness);
+ if(value == mCloth.mSelfCollisionLogStiffness)
+ return;
+
+ mCloth.mSelfCollisionLogStiffness = value;
+ mCloth.notifyChanged();
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline float ClothImpl<T>::getSelfCollisionStiffness() const
+{
+ return 1 - safeExp2(mCloth.mSelfCollisionLogStiffness);
+}
+
+template <typename T>
+inline const PxVec3& ClothImpl<T>::getBoundingBoxCenter() const
+{
+ return mCloth.mParticleBoundsCenter;
+}
+
+template <typename T>
+inline const PxVec3& ClothImpl<T>::getBoundingBoxScale() const
+{
+ return mCloth.mParticleBoundsHalfExtent;
+}
+
+template <typename T>
+inline void ClothImpl<T>::setSleepThreshold(float threshold)
+{
+ if(threshold == mCloth.mSleepThreshold)
+ return;
+
+ mCloth.mSleepThreshold = threshold;
+ mCloth.notifyChanged();
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline float ClothImpl<T>::getSleepThreshold() const
+{
+ return mCloth.mSleepThreshold;
+}
+
+template <typename T>
+inline void ClothImpl<T>::setSleepTestInterval(uint32_t interval)
+{
+ if(interval == mCloth.mSleepTestInterval)
+ return;
+
+ mCloth.mSleepTestInterval = interval;
+ mCloth.notifyChanged();
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline uint32_t ClothImpl<T>::getSleepTestInterval() const
+{
+ return mCloth.mSleepTestInterval;
+}
+
+template <typename T>
+inline void ClothImpl<T>::setSleepAfterCount(uint32_t afterCount)
+{
+ if(afterCount == mCloth.mSleepAfterCount)
+ return;
+
+ mCloth.mSleepAfterCount = afterCount;
+ mCloth.notifyChanged();
+ mCloth.wakeUp();
+}
+
+template <typename T>
+inline uint32_t ClothImpl<T>::getSleepAfterCount() const
+{
+ return mCloth.mSleepAfterCount;
+}
+
+template <typename T>
+inline uint32_t ClothImpl<T>::getSleepPassCount() const
+{
+ return mCloth.mSleepPassCounter;
+}
+
+template <typename T>
+inline bool ClothImpl<T>::isAsleep() const
+{
+ return mCloth.isSleeping();
+}
+
+template <typename T>
+inline void ClothImpl<T>::putToSleep()
+{
+ mCloth.mSleepPassCounter = mCloth.mSleepAfterCount;
+}
+
+template <typename T>
+inline void ClothImpl<T>::wakeUp()
+{
+ mCloth.wakeUp();
+}
+
+
+template <typename T>
+inline void ClothImpl<T>::setHalfPrecisionOption(bool isAllowed)
+{
+ mCloth.mIsAllowedHalfPrecisionSolver = isAllowed;
+}
+
+template <typename T>
+inline bool ClothImpl<T>::getHalfPrecisionOption() const
+{
+ return mCloth.mIsAllowedHalfPrecisionSolver;
+}
+
+template <typename T>
+inline void ClothImpl<T>::setUserData(void* data)
+{
+ mCloth.mUserData = data;
+}
+
+template <typename T>
+inline void* ClothImpl<T>::getUserData() const
+{
+ return mCloth.mUserData;
+}
+
+template <typename T>
+template <typename U>
+inline MappedRange<U> ClothImpl<T>::getMappedParticles(U* data) const
+{
+ return MappedRange<U>(data, data + getNumParticles(), *this, &Cloth::lockParticles, &Cloth::unlockParticles);
+}
+
+} // namespace cloth
+
+} // namespace nvidia
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/Factory.cpp b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/Factory.cpp
new file mode 100644
index 00000000..6e49c85f
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/Factory.cpp
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "SwFactory.h"
+
+#if ENABLE_CUFACTORY
+#include "CuFactory.h"
+#endif
+
+#if ENABLE_DXFACTORY
+#include "windows/DxFactory.h"
+//#include "PxGraphicsContextManager.h"
+#pragma warning(disable : 4668 4917 4365 4061 4005)
+#if PX_XBOXONE
+#include <d3d11_x.h>
+#else
+#include <d3d11.h>
+#endif
+#endif
+
+namespace nvidia
+{
+namespace cloth
+{
+uint32_t getNextFabricId()
+{
+ static uint32_t sNextFabricId = 0;
+ return sNextFabricId++;
+}
+}
+}
+
+using namespace nvidia;
+
+cloth::Factory* cloth::Factory::createFactory(Platform platform, void* contextManager)
+{
+ PX_UNUSED(contextManager);
+
+ if(platform == Factory::CPU)
+ return new SwFactory;
+
+#if ENABLE_CUFACTORY
+ if(platform == Factory::CUDA)
+ return new CuFactory((PxCudaContextManager*)contextManager);
+#endif
+
+#if ENABLE_DXFACTORY
+ if(platform == Factory::DirectCompute)
+ {
+ //physx::PxGraphicsContextManager* graphicsContextManager = (physx::PxGraphicsContextManager*)contextManager;
+ //if(graphicsContextManager->getDevice()->GetFeatureLevel() >= D3D_FEATURE_LEVEL_11_0)
+ // return new DxFactory(graphicsContextManager);
+ }
+#endif
+
+ return 0;
+}
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/IndexPair.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/IndexPair.h
new file mode 100644
index 00000000..89dd9090
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/IndexPair.h
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "Types.h"
+
+namespace nvidia
+{
+namespace cloth
+{
+
+struct IndexPair
+{
+ uint32_t first;
+ uint32_t second;
+};
+
+} // namespace cloth
+} // namespace nvidia
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/IterationState.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/IterationState.h
new file mode 100644
index 00000000..527cf163
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/IterationState.h
@@ -0,0 +1,375 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "Types.h"
+#include "Array.h"
+#include "PxTransform.h"
+#include "PxMat44.h"
+#include "PsMathUtils.h"
+#include "Simd4f.h"
+#include "Simd4i.h"
+
+namespace nvidia
+{
+
+/* function object to perform solver iterations on one cloth */
+
+// todo: performance optimization: cache this object and test if velocity/iterDt has changed
+// c'tor takes about 5% of the iteration time of a 20x20 cloth
+
+namespace cloth
+{
+
+/* helper functions */
+
+inline PxVec3 log(const PxQuat& q)
+{
+ float theta = q.getImaginaryPart().magnitude();
+ float scale = theta > PX_EPS_REAL ? PxAsin(theta) / theta : 1.0f;
+ scale = intrinsics::fsel(q.w, scale, -scale);
+ return PxVec3(q.x * scale, q.y * scale, q.z * scale);
+}
+
+inline PxQuat exp(const PxVec3& v)
+{
+ float theta = v.magnitude();
+ float scale = theta > PX_EPS_REAL ? PxSin(theta) / theta : 1.0f;
+ return PxQuat(v.x * scale, v.y * scale, v.z * scale, cos(theta));
+}
+
+template <typename Simd4f, uint32_t N>
+inline void assign(Simd4f (&columns)[N], const PxMat44& matrix)
+{
+ for(uint32_t i = 0; i < N; ++i)
+ columns[i] = load(array(matrix[i]));
+}
+
+template <typename Simd4f>
+inline Simd4f transform(const Simd4f (&columns)[3], const Simd4f& vec)
+{
+ return splat<0>(vec) * columns[0] + splat<1>(vec) * columns[1] + splat<2>(vec) * columns[2];
+}
+
+template <typename Simd4f>
+inline Simd4f transform(const Simd4f (&columns)[3], const Simd4f& translate, const Simd4f& vec)
+{
+ return translate + splat<0>(vec) * columns[0] + splat<1>(vec) * columns[1] + splat<2>(vec) * columns[2];
+}
+
+template <typename>
+struct IterationState; // forward declaration
+
+struct IterationStateFactory
+{
+ template <typename MyCloth>
+ IterationStateFactory(MyCloth& cloth, float frameDt);
+
+ template <typename Simd4f, typename MyCloth>
+ IterationState<Simd4f> create(MyCloth const& cloth) const;
+
+ template <typename Simd4f>
+ static Simd4f lengthSqr(Simd4f const& v)
+ {
+ return dot3(v, v);
+ }
+
+ template <typename Simd4f>
+ static PxVec3 castToPxVec3(const Simd4f& v)
+ {
+ return *reinterpret_cast<const PxVec3*>(reinterpret_cast<const char*>(&v));
+ }
+
+ int mNumIterations;
+ float mInvNumIterations;
+ float mIterDt, mIterDtRatio, mIterDtAverage;
+ PxQuat mCurrentRotation;
+ PxVec3 mPrevLinearVelocity;
+ PxVec3 mPrevAngularVelocity;
+};
+
+/* solver iterations helper functor */
+template <typename Simd4f>
+struct IterationState
+{
+ // call after each iteration
+ void update();
+
+ inline float getCurrentAlpha() const;
+ inline float getPreviousAlpha() const;
+
+ public:
+ Simd4f mRotationMatrix[3];
+ Simd4f mCurBias; // in local space
+ Simd4f mPrevBias; // in local space
+
+ Simd4f mPrevMatrix[3];
+ Simd4f mCurMatrix[3];
+ Simd4f mDampScaleUpdate;
+
+ // iteration counter
+ uint32_t mRemainingIterations;
+
+ // reciprocal total number of iterations
+ float mInvNumIterations;
+
+ // time step size per iteration
+ float mIterDt;
+
+ bool mIsTurning; // if false, mPositionScale = mPrevMatrix[0]
+};
+
+} // namespace cloth
+
+template <typename Simd4f>
+inline float cloth::IterationState<Simd4f>::getCurrentAlpha() const
+{
+ return getPreviousAlpha() + mInvNumIterations;
+}
+
+template <typename Simd4f>
+inline float cloth::IterationState<Simd4f>::getPreviousAlpha() const
+{
+ return 1.0f - mRemainingIterations * mInvNumIterations;
+}
+
+template <typename MyCloth>
+cloth::IterationStateFactory::IterationStateFactory(MyCloth& cloth, float frameDt)
+{
+ mNumIterations = PxMax(1, int(frameDt * cloth.mSolverFrequency + 0.5f));
+ mInvNumIterations = 1.0f / mNumIterations;
+ mIterDt = frameDt * mInvNumIterations;
+
+ mIterDtRatio = cloth.mPrevIterDt ? mIterDt / cloth.mPrevIterDt : 1.0f;
+ mIterDtAverage = cloth.mIterDtAvg.empty() ? mIterDt : cloth.mIterDtAvg.average();
+
+ mCurrentRotation = cloth.mCurrentMotion.q;
+ mPrevLinearVelocity = cloth.mLinearVelocity;
+ mPrevAngularVelocity = cloth.mAngularVelocity;
+
+ // update cloth
+ float invFrameDt = 1.0f / frameDt;
+ cloth.mLinearVelocity = invFrameDt * (cloth.mTargetMotion.p - cloth.mCurrentMotion.p);
+ PxQuat dq = cloth.mTargetMotion.q * cloth.mCurrentMotion.q.getConjugate();
+ cloth.mAngularVelocity = log(dq) * invFrameDt;
+
+ cloth.mPrevIterDt = mIterDt;
+ cloth.mIterDtAvg.push((uint32_t)mNumIterations, mIterDt);
+ cloth.mCurrentMotion = cloth.mTargetMotion;
+}
+
+/*
+momentum conservation:
+m2*x2 - m1*x1 = m1*x1 - m0*x0 + g*dt2, m = r+t
+r2*x2+t2 = 2(r1*x1+t1) - (r0*x0+t0) + g*dt2
+r2*x2 = r1*x1 + r1*x1 - r0*x0 - (t2-2t1+t0) + g*dt2
+substitue r1*x1 - r0*x0 = r1*(x1-x0) + (r1-r0)*x0
+and r1*x1 = r2*x1 - (r2-r1)*x1
+
+x2 = x1 + r2'*g*dt2
+ + r2'r1*(x1-x0) //< damp
+ + (r2'r1-r2'r0)*x0 - (1-r2'r1)*x1 - r2'*(t2-2t1+t0) //< inertia
+ + (1-r2'r1)x1 + t2-t1 //< drag (not momentum conserving)
+
+x2 = x0 + a0*x0 + a1*x1 + b with
+a0 = (inertia-damp)*r2'r1 - inertia*r2'r0 - eye
+a1 = (1-inertia-drag)*eye + (damp+inertia+drag)*r2'r1
+b = r2'*(g*dt2 - (inertia+drag)*(t2-t1) + inertia*(t1-t0))
+
+Velocities are used to deal with multiple iterations and varying dt. Only b needs
+to updated from one iteration to the next. Specifically, it is multiplied
+by (r2'r1)^1/numIterations. a0 and a1 are unaffected by that multiplication.
+
+The centrifugal and coriolis forces of non-inertial (turning) reference frame are
+not generally captured in these formulas. The 'inertia' term above contains radial
+acceleration plus centrifugal and coriolis force for a single iteration.
+For multiple iterations, or when the centrifugal forces are scaled differently
+than angular inertia, we need to add explicit centrifugal and coriolis forces.
+We only use them to correct the above formula because their discretization is
+not accurate.
+
+Possible improvements: multiply coriolis and centrifugal matrix by curInvRotation
+from the left. Do the alpha trick of linearInertia also for angularInertia, write
+prevParticle after multiplying it with matrix.
+
+If you change anything in this function, make sure that ClothCustomFloating and
+ClothInertia haven't regressed for any choice of solver frequency.
+*/
+
+template <typename Simd4f, typename MyCloth>
+cloth::IterationState<Simd4f> cloth::IterationStateFactory::create(MyCloth const& cloth) const
+{
+ IterationState<Simd4f> result;
+
+ result.mRemainingIterations = (uint32_t)mNumIterations;
+ result.mInvNumIterations = mInvNumIterations;
+ result.mIterDt = mIterDt;
+
+ Simd4f curLinearVelocity = load(array(cloth.mLinearVelocity));
+ Simd4f prevLinearVelocity = load(array(mPrevLinearVelocity));
+
+ Simd4f iterDt = simd4f(mIterDt);
+ Simd4f dampExponent = simd4f(cloth.mStiffnessFrequency) * iterDt;
+
+ // gravity delta per iteration
+ Simd4f gravity = load(array(cloth.mGravity)) * (Simd4f)simd4f(sqr(mIterDtAverage));
+
+ // scale of local particle velocity per iteration
+ Simd4f dampScale = simdf::exp2(load(array(cloth.mLogDamping)) * dampExponent);
+ // adjust for the change in time step during the first iteration
+ Simd4f firstDampScale = dampScale * simd4f(mIterDtRatio);
+
+ // portion of negative frame velocity to transfer to particle
+ Simd4f linearDrag =
+ (simd4f(_1) - simdf::exp2(load(array(cloth.mLinearLogDrag)) * dampExponent)) * iterDt * curLinearVelocity;
+
+ // portion of frame acceleration to transfer to particle
+ Simd4f linearInertia = load(array(cloth.mLinearInertia)) * iterDt * (prevLinearVelocity - curLinearVelocity);
+
+ // for inertia, we want to violate newton physics to
+ // match velocity and position as given by the user, which means:
+ // vt = v0 + a*t and xt = x0 + v0*t + (!) a*t^2
+ // this is achieved by applying a different portion to cur and prev
+ // position, compared to the normal +0.5 and -0.5 for '... 1/2 a*t^2'.
+ // specifically, the portion is alpha=(n+1)/2n and 1-alpha.
+
+ float linearAlpha = (mNumIterations + 1) * 0.5f * mInvNumIterations;
+ Simd4f curLinearInertia = linearInertia * simd4f(linearAlpha);
+
+ // rotate to local space (use mRotationMatrix temporarily to hold matrix)
+ PxMat44 invRotation(mCurrentRotation.getConjugate());
+ assign(result.mRotationMatrix, invRotation);
+
+ Simd4f maskXYZ = simd4f(simd4i(~0, ~0, ~0, 0));
+
+ // Previously, we split the bias between previous and current position to
+ // get correct disretized position and velocity. However, this made a
+ // hanging cloth experience a downward velocity, which is problematic
+ // when scaled by the iterDt ratio and results in jitter under variable
+ // timesteps. Instead, we now apply the entire bias to current position
+ // and accept a less noticeable error for a free falling cloth.
+
+ Simd4f bias = gravity - linearDrag;
+ result.mCurBias = transform(result.mRotationMatrix, curLinearInertia + bias) & maskXYZ;
+ result.mPrevBias = transform(result.mRotationMatrix, linearInertia - curLinearInertia) & maskXYZ;
+
+ result.mIsTurning = mPrevAngularVelocity.magnitudeSquared() + cloth.mAngularVelocity.magnitudeSquared() > 0.0f;
+
+ if(result.mIsTurning)
+ {
+ Simd4f curAngularVelocity = load(array(invRotation.rotate(cloth.mAngularVelocity)));
+ Simd4f prevAngularVelocity = load(array(invRotation.rotate(mPrevAngularVelocity)));
+
+ // rotation for one iteration in local space
+ Simd4f curInvAngle = -iterDt * curAngularVelocity;
+ Simd4f prevInvAngle = -iterDt * prevAngularVelocity;
+
+ PxQuat curInvRotation = exp(castToPxVec3(curInvAngle));
+ PxQuat prevInvRotation = exp(castToPxVec3(prevInvAngle));
+
+ PxMat44 curMatrix(curInvRotation);
+ PxMat44 prevMatrix(prevInvRotation * curInvRotation);
+
+ assign(result.mRotationMatrix, curMatrix);
+
+ Simd4f angularDrag = simd4f(_1) - simdf::exp2(load(array(cloth.mAngularLogDrag)) * dampExponent);
+ Simd4f centrifugalInertia = load(array(cloth.mCentrifugalInertia));
+ Simd4f angularInertia = load(array(cloth.mAngularInertia));
+ Simd4f angularAcceleration = curAngularVelocity - prevAngularVelocity;
+
+ Simd4f epsilon = simd4f(sqrt(FLT_MIN)); // requirement: sqr(epsilon) > 0
+ Simd4f velocityLengthSqr = lengthSqr(curAngularVelocity) + epsilon;
+ Simd4f dragLengthSqr = lengthSqr(Simd4f(curAngularVelocity * angularDrag)) + epsilon;
+ Simd4f centrifugalLengthSqr = lengthSqr(Simd4f(curAngularVelocity * centrifugalInertia)) + epsilon;
+ Simd4f accelerationLengthSqr = lengthSqr(angularAcceleration) + epsilon;
+ Simd4f inertiaLengthSqr = lengthSqr(Simd4f(angularAcceleration * angularInertia)) + epsilon;
+
+ float dragScale = array(rsqrt(velocityLengthSqr * dragLengthSqr) * dragLengthSqr)[0];
+ float inertiaScale =
+ mInvNumIterations * array(rsqrt(accelerationLengthSqr * inertiaLengthSqr) * inertiaLengthSqr)[0];
+
+ // magic factor found by comparing to global space simulation:
+ // some centrifugal force is in inertia part, remainder is 2*(n-1)/n
+ // after scaling the inertia part, we get for centrifugal:
+ float centrifugalAlpha = (2 * mNumIterations - 1) * mInvNumIterations;
+ float centrifugalScale =
+ centrifugalAlpha * array(rsqrt(velocityLengthSqr * centrifugalLengthSqr) * centrifugalLengthSqr)[0] -
+ inertiaScale;
+
+ // slightly better in ClothCustomFloating than curInvAngle alone
+ Simd4f centrifugalVelocity = (prevInvAngle + curInvAngle) * simd4f(0.5f);
+ const Simd4f data = lengthSqr(centrifugalVelocity);
+ float centrifugalSqrLength = array(data)[0] * centrifugalScale;
+
+ Simd4f coriolisVelocity = centrifugalVelocity * simd4f(centrifugalScale);
+ PxMat33 coriolisMatrix = physx::shdfnd::star(castToPxVec3(coriolisVelocity));
+
+ const float* dampScalePtr = array(firstDampScale);
+ const float* centrifugalPtr = array(centrifugalVelocity);
+
+ for(unsigned int j = 0; j < 3; ++j)
+ {
+ float centrifugalJ = -centrifugalPtr[j] * centrifugalScale;
+ for(unsigned int i = 0; i < 3; ++i)
+ {
+ float damping = dampScalePtr[j];
+ float coriolis = coriolisMatrix(i, j);
+ float centrifugal = centrifugalPtr[i] * centrifugalJ;
+
+ prevMatrix(i, j) = centrifugal - coriolis + curMatrix(i, j) * (inertiaScale - damping) -
+ prevMatrix(i, j) * inertiaScale;
+ curMatrix(i, j) = centrifugal + coriolis + curMatrix(i, j) * (inertiaScale + damping + dragScale);
+ }
+ curMatrix(j, j) += centrifugalSqrLength - inertiaScale - dragScale;
+ prevMatrix(j, j) += centrifugalSqrLength;
+ }
+
+ assign(result.mPrevMatrix, prevMatrix);
+ assign(result.mCurMatrix, curMatrix);
+ }
+ else
+ {
+ Simd4f minusOne = -(Simd4f)simd4f(_1);
+ result.mRotationMatrix[0] = minusOne;
+ result.mPrevMatrix[0] = select(maskXYZ, firstDampScale, minusOne);
+ }
+
+ // difference of damp scale between first and other iterations
+ result.mDampScaleUpdate = (dampScale - firstDampScale) & maskXYZ;
+
+ return result;
+}
+
+template <typename Simd4f>
+void cloth::IterationState<Simd4f>::update()
+{
+ if(mIsTurning)
+ {
+ // only need to turn bias, matrix is unaffected (todo: verify)
+ mCurBias = transform(mRotationMatrix, mCurBias);
+ mPrevBias = transform(mRotationMatrix, mPrevBias);
+ }
+
+ // remove time step ratio in damp scale after first iteration
+ for(uint32_t i = 0; i < 3; ++i)
+ {
+ mPrevMatrix[i] = mPrevMatrix[i] - mRotationMatrix[i] * mDampScaleUpdate;
+ mCurMatrix[i] = mCurMatrix[i] + mRotationMatrix[i] * mDampScaleUpdate;
+ }
+ mDampScaleUpdate = simd4f(_0); // only once
+
+ --mRemainingIterations;
+}
+
+} // namespace nvidia
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/MovingAverage.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/MovingAverage.h
new file mode 100644
index 00000000..76eb7f4c
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/MovingAverage.h
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "Allocator.h"
+
+namespace nvidia
+{
+namespace cloth
+{
+
+struct MovingAverage
+{
+ struct Element
+ {
+ uint32_t mCount;
+ float mValue;
+ };
+
+ public:
+ MovingAverage(uint32_t n = 1) : mCount(0), mSize(n)
+ {
+ }
+
+ bool empty() const
+ {
+ return mData.empty();
+ }
+
+ uint32_t size() const
+ {
+ return mSize;
+ }
+
+ void resize(uint32_t n)
+ {
+ PX_ASSERT(n);
+ mSize = n;
+ trim();
+ }
+
+ void reset()
+ {
+ mData.resize(0);
+ mCount = 0;
+ }
+
+ void push(uint32_t n, float value)
+ {
+ n = PxMin(n, mSize);
+
+ if(mData.empty() || mData.back().mValue != value)
+ {
+ Element element = { n, value };
+ mData.pushBack(element);
+ }
+ else
+ {
+ mData.back().mCount += n;
+ }
+
+ mCount += n;
+ trim();
+ }
+
+ float average() const
+ {
+ PX_ASSERT(!mData.empty());
+
+ float sum = 0.0f;
+ Vector<Element>::Type::ConstIterator it = mData.begin(), end = mData.end();
+ for(; it != end; ++it)
+ sum += it->mCount * it->mValue;
+
+ // linear weight ramps at both ends for smoother average
+ uint32_t n = mCount / 8;
+ float ramp = 0.0f, temp = 0.0f;
+ uint32_t countLo = (it = mData.begin())->mCount;
+ uint32_t countHi = (--end)->mCount;
+ for(uint32_t i = 0; i < n; ++i)
+ {
+ if(i == countLo)
+ countLo += (++it)->mCount;
+ if(i == countHi)
+ countHi += (--end)->mCount;
+
+ temp += it->mValue + end->mValue;
+ ramp += temp;
+ }
+
+ uint32_t num = (mCount - n) * (n + 1);
+ return (sum * (n + 1) - ramp) / num;
+ }
+
+ private:
+ // remove oldest (front) values until mCount<=mSize
+ void trim()
+ {
+ Vector<Element>::Type::Iterator it = mData.begin();
+ for(uint32_t k = mSize; k < mCount; it += k <= mCount)
+ {
+ k += it->mCount;
+ it->mCount = k - mCount;
+ }
+
+ if(it != mData.begin())
+ mData.assign(it, mData.end());
+
+ mCount = PxMin(mCount, mSize);
+ }
+
+ Vector<Element>::Type mData;
+
+ uint32_t mCount;
+ uint32_t mSize;
+};
+}
+}
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/PhaseConfig.cpp b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/PhaseConfig.cpp
new file mode 100644
index 00000000..310c43d6
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/PhaseConfig.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "PhaseConfig.h"
+#include "ApexUsingNamespace.h"
+#include "PsMathUtils.h"
+
+namespace nvidia
+{
+namespace cloth
+{
+PhaseConfig transform(const PhaseConfig&);
+}
+}
+
+using namespace nvidia;
+
+namespace
+{
+float safeLog2(float x)
+{
+ float saturated = PxMax(0.0f, PxMin(x, 1.0f));
+ return saturated ? physx::shdfnd::log2(saturated) : -FLT_MAX_EXP;
+}
+}
+
+cloth::PhaseConfig::PhaseConfig(uint16_t index)
+: mPhaseIndex(index)
+, mPadding(0xffff)
+, mStiffness(1.0f)
+, mStiffnessMultiplier(1.0f)
+, mCompressionLimit(1.0f)
+, mStretchLimit(1.0f)
+{
+}
+
+// convert from user input to solver format
+cloth::PhaseConfig cloth::transform(const PhaseConfig& config)
+{
+ PhaseConfig result(config.mPhaseIndex);
+
+ result.mStiffness = safeLog2(1.0f - config.mStiffness);
+ result.mStiffnessMultiplier = safeLog2(config.mStiffnessMultiplier);
+
+ // negative for compression, positive for stretch
+ result.mCompressionLimit = 1.f - 1.f / config.mCompressionLimit;
+ result.mStretchLimit = 1.f - 1.f / config.mStretchLimit;
+
+ return result;
+}
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/PointInterpolator.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/PointInterpolator.h
new file mode 100644
index 00000000..fe130156
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/PointInterpolator.h
@@ -0,0 +1,153 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "Types.h"
+#include "Simd4f.h"
+
+namespace nvidia
+{
+
+namespace cloth
+{
+
+// acts as a poor mans random access iterator
+template <typename Simd4f, typename BaseIterator>
+class LerpIterator
+{
+
+ LerpIterator& operator=(const LerpIterator&); // not implemented
+
+ public:
+ LerpIterator(BaseIterator start, BaseIterator target, float alpha)
+ : mAlpha(simd4f(alpha)), mStart(start), mTarget(target)
+ {
+ }
+
+ // return the interpolated point at a given index
+ inline Simd4f operator[](size_t index) const
+ {
+ return mStart[index] + (mTarget[index] - mStart[index]) * mAlpha;
+ }
+
+ inline Simd4f operator*() const
+ {
+ return (*this)[0];
+ }
+
+ // prefix increment only
+ inline LerpIterator& operator++()
+ {
+ ++mStart;
+ ++mTarget;
+ return *this;
+ }
+
+ private:
+ // interpolation parameter
+ const Simd4f mAlpha;
+
+ BaseIterator mStart;
+ BaseIterator mTarget;
+};
+
+template <typename Simd4f, size_t Stride>
+class UnalignedIterator
+{
+
+ UnalignedIterator& operator=(const UnalignedIterator&); // not implemented
+
+ public:
+ UnalignedIterator(const float* pointer) : mPointer(pointer)
+ {
+ }
+
+ inline Simd4f operator[](size_t index) const
+ {
+ return load(mPointer + index * Stride);
+ }
+
+ inline Simd4f operator*() const
+ {
+ return (*this)[0];
+ }
+
+ // prefix increment only
+ inline UnalignedIterator& operator++()
+ {
+ mPointer += Stride;
+ return *this;
+ }
+
+ private:
+ const float* mPointer;
+};
+
+// acts as an iterator but returns a constant
+template <typename Simd4f>
+class ConstantIterator
+{
+ public:
+ ConstantIterator(const Simd4f& value) : mValue(value)
+ {
+ }
+
+ inline Simd4f operator*() const
+ {
+ return mValue;
+ }
+
+ inline ConstantIterator& operator++()
+ {
+ return *this;
+ }
+
+ private:
+ ConstantIterator& operator=(const ConstantIterator&);
+ const Simd4f mValue;
+};
+
+// wraps an iterator with constant scale and bias
+template <typename Simd4f, typename BaseIterator>
+class ScaleBiasIterator
+{
+ public:
+ ScaleBiasIterator(BaseIterator base, const Simd4f& scale, const Simd4f& bias)
+ : mScale(scale), mBias(bias), mBaseIterator(base)
+ {
+ }
+
+ inline Simd4f operator*() const
+ {
+ return (*mBaseIterator) * mScale + mBias;
+ }
+
+ inline ScaleBiasIterator& operator++()
+ {
+ ++mBaseIterator;
+ return *this;
+ }
+
+ private:
+ ScaleBiasIterator& operator=(const ScaleBiasIterator&);
+
+ const Simd4f mScale;
+ const Simd4f mBias;
+
+ BaseIterator mBaseIterator;
+};
+
+} // namespace cloth
+
+} // namespace nvidia
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/Simd4f.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/Simd4f.h
new file mode 100644
index 00000000..8755a010
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/Simd4f.h
@@ -0,0 +1,478 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "SimdTypes.h"
+
+#if NVMATH_FUSE_MULTIPLY_ADD
+
+/*! \brief Expression template to fuse multiply-adds.
+ * \relates Simd4f */
+struct ProductExpr
+{
+ inline ProductExpr(Simd4f const& v0_, Simd4f const& v1_) : v0(v0_), v1(v1_)
+ {
+ }
+ inline operator Simd4f() const;
+ const Simd4f v0, v1;
+
+ private:
+ ProductExpr& operator=(const ProductExpr&); // not implemented
+};
+
+inline Simd4f operator+(const ProductExpr&, const Simd4f&);
+inline Simd4f operator+(const Simd4f& v, const ProductExpr&);
+inline Simd4f operator+(const ProductExpr&, const ProductExpr&);
+inline Simd4f operator-(const Simd4f& v, const ProductExpr&);
+inline Simd4f operator-(const ProductExpr&, const ProductExpr&);
+
+#else // NVMATH_FUSE_MULTIPLY_ADD
+typedef Simd4f ProductExpr;
+#endif // NVMATH_FUSE_MULTIPLY_ADD
+
+template <typename T>
+struct Simd4fFactory
+{
+ Simd4fFactory(T v_) : v(v_)
+ {
+ }
+ inline operator Simd4f() const;
+ inline operator Scalar4f() const;
+ Simd4fFactory& operator=(const Simd4fFactory&); // not implemented
+ T v;
+};
+
+template <>
+struct Simd4fFactory<detail::FourTuple>
+{
+ Simd4fFactory(float x, float y, float z, float w)
+ {
+ v[0] = x, v[1] = y, v[2] = z, v[3] = w;
+ }
+ Simd4fFactory(const Simd4fFactory<const float&>& f)
+ {
+ v[3] = v[2] = v[1] = v[0] = f.v;
+ }
+ inline operator Simd4f() const;
+ inline operator Scalar4f() const;
+ Simd4fFactory& operator=(const Simd4fFactory&); // not implemented
+ PX_ALIGN(16, float) v[4];
+};
+
+template <int i>
+struct Simd4fFactory<detail::IntType<i> >
+{
+ inline operator Simd4f() const;
+ inline operator Scalar4f() const;
+};
+
+// forward declaration
+template <typename>
+struct Simd4iFactory;
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// expression template
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if NVMATH_SIMD
+inline Simd4f operator&(const ComplementExpr<Simd4f>&, const Simd4f&);
+inline Simd4f operator&(const Simd4f&, const ComplementExpr<Simd4f>&);
+#endif
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// operators
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+// note: operator?= missing because they don't have corresponding intrinsics.
+
+/*! \brief Test for equality of two vectors.
+* \return Vector of per element result mask (all bits set for 'true', none set for 'false').
+* \note QNaPs aren't handled on SPU: comparing two QNaPs will return true.
+* \relates Simd4f */
+inline Simd4f operator==(const Simd4f& v0, const Simd4f& v1);
+
+// no operator!= because VMX128 does not support it, use ~operator== and handle QNaPs
+
+/*! \brief Less-compare all elements of two vectors.
+* \return Vector of per element result mask (all bits set for 'true', none set for 'false').
+* \note QNaPs aren't handled on SPU: comparisons against QNaPs don't necessarily return false.
+* \relates Simd4f */
+inline Simd4f operator<(const Simd4f& v0, const Simd4f& v1);
+
+/*! \brief Less-or-equal-compare all elements of two vectors.
+* \return Vector of per element result mask (all bits set for 'true', none set for 'false').
+* \note QNaPs aren't handled on SPU: comparisons against QNaPs don't necessarily return false.
+* \relates Simd4f */
+inline Simd4f operator<=(const Simd4f& v0, const Simd4f& v1);
+
+/*! \brief Greater-compare all elements of two vectors.
+* \return Vector of per element result mask (all bits set for 'true', none set for 'false').
+* \note QNaPs aren't handled on SPU: comparisons against QNaPs don't necessarily return false.
+* \relates Simd4f */
+inline Simd4f operator>(const Simd4f& v0, const Simd4f& v1);
+
+/*! \brief Greater-or-equal-compare all elements of two vectors.
+* \return Vector of per element result mask (all bits set for 'true', none set for 'false').
+* \note QNaPs aren't handled on SPU: comparisons against QNaPs don't necessarily return false.
+* \relates Simd4f */
+inline Simd4f operator>=(const Simd4f& v0, const Simd4f& v1);
+
+/*! \brief Vector bit-wise NOT operator
+* \return A vector holding the bit-negate of \a v.
+* \relates Simd4f */
+inline ComplementExpr<Simd4f> operator~(const Simd4f& v);
+
+/*! \brief Vector bit-wise AND operator
+* \return A vector holding the bit-wise AND of \a v0 and \a v1.
+* \relates Simd4f */
+inline Simd4f operator&(const Simd4f& v0, const Simd4f& v1);
+
+/*! \brief Vector bit-wise OR operator
+* \return A vector holding the bit-wise OR of \a v0 and \a v1.
+* \relates Simd4f */
+inline Simd4f operator|(const Simd4f& v0, const Simd4f& v1);
+
+/*! \brief Vector bit-wise XOR operator
+* \return A vector holding the bit-wise XOR of \a v0 and \a v1.
+* \relates Simd4f */
+inline Simd4f operator^(const Simd4f& v0, const Simd4f& v1);
+
+/*! \brief Vector logical left shift.
+* \return A vector with 4 elements of \a v0, each shifted left by \a shift bits.
+* \relates Simd4f */
+inline Simd4f operator<<(const Simd4f& v, int shift);
+
+/*! \brief Vector logical right shift.
+* \return A vector with 4 elements of \a v0, each shifted right by \a shift bits.
+* \relates Simd4f */
+inline Simd4f operator>>(const Simd4f& v, int shift);
+
+#if NVMATH_SHIFT_BY_VECTOR
+/*! \brief Vector logical left shift.
+* \return A vector with 4 elements of \a v0, each shifted left by \a shift bits.
+* \relates Simd4f */
+inline Simd4f operator<<(const Simd4f& v, const Simd4f& shift);
+
+/*! \brief Vector logical right shift.
+* \return A vector with 4 elements of \a v0, each shifted right by \a shift bits.
+* \relates Simd4f */
+inline Simd4f operator>>(const Simd4f& v, const Simd4f& shift);
+#endif
+
+/*! \brief Unary vector addition operator.
+* \return A vector holding the component-wise copy of \a v.
+* \relates Simd4f */
+inline Simd4f operator+(const Simd4f& v);
+
+/*! \brief Vector addition operator
+* \return A vector holding the component-wise sum of \a v0 and \a v1.
+* \relates Simd4f */
+inline Simd4f operator+(const Simd4f& v0, const Simd4f& v1);
+
+/*! \brief Unary vector negation operator.
+* \return A vector holding the component-wise negation of \a v.
+* \relates Simd4f */
+inline Simd4f operator-(const Simd4f& v);
+
+/*! \brief Vector subtraction operator.
+* \return A vector holding the component-wise difference of \a v0 and \a v1.
+* \relates Simd4f */
+inline Simd4f operator-(const Simd4f& v0, const Simd4f& v1);
+
+/*! \brief Vector multiplication.
+* \return Element-wise product of \a v0 and \a v1.
+* \note For VMX, returns expression template to fuse multiply-add.
+* \relates Simd4f */
+inline ProductExpr operator*(const Simd4f& v0, const Simd4f& v1);
+
+/*! \brief Vector division.
+* \return Element-wise division of \a v0 and \a v1.
+* \relates Simd4f */
+inline Simd4f operator/(const Simd4f& v0, const Simd4f& v1);
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// functions
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+/*! \brief Load float value into all vector components.
+* \relates Simd4f */
+inline Simd4fFactory<const float&> simd4f(const float& s)
+{
+ return Simd4fFactory<const float&>(s);
+}
+
+/*! \brief Load 4 float values into vector.
+* \relates Simd4f */
+inline Simd4fFactory<detail::FourTuple> simd4f(float x, float y, float z, float w)
+{
+ return Simd4fFactory<detail::FourTuple>(x, y, z, w);
+}
+
+/*! \brief Create vector from literal.
+* \return Vector with all elements set to i.
+* \relates Simd4f */
+template <int i>
+inline Simd4fFactory<detail::IntType<i> > simd4f(detail::IntType<i> const&)
+{
+ return Simd4fFactory<detail::IntType<i> >();
+}
+
+/*! \brief Reinterpret Simd4i as Simd4f.
+* \return A copy of \a v, but cast as Simd4f.
+* \relates Simd4f */
+inline Simd4f simd4f(const Simd4i& v);
+
+/*! \brief Reinterpret Simd4iFactory as Simd4fFactory.
+* \relates Simd4f */
+template <typename T>
+inline Simd4fFactory<T> simd4f(const Simd4iFactory<T>& v)
+{
+ return reinterpret_cast<const Simd4fFactory<T>&>(v);
+}
+
+/*! \brief return reference to contiguous array of vector elements
+* \relates Simd4f */
+inline float (&array(Simd4f& v))[4];
+
+/*! \brief return constant reference to contiguous array of vector elements
+* \relates Simd4f */
+inline const float (&array(const Simd4f& v))[4];
+
+/*! \brief Create vector from float array.
+* \relates Simd4f */
+inline Simd4fFactory<const float*> load(const float* ptr)
+{
+ return ptr;
+}
+
+/*! \brief Create vector from aligned float array.
+* \note \a ptr needs to be 16 byte aligned.
+* \relates Simd4f */
+inline Simd4fFactory<detail::AlignedPointer<float> > loadAligned(const float* ptr)
+{
+ return detail::AlignedPointer<float>(ptr);
+}
+
+/*! \brief Create vector from aligned float array.
+* \param offset pointer offset in bytes.
+* \note \a ptr+offset needs to be 16 byte aligned.
+* \relates Simd4f */
+inline Simd4fFactory<detail::OffsetPointer<float> > loadAligned(const float* ptr, unsigned int offset)
+{
+ return detail::OffsetPointer<float>(ptr, offset);
+}
+
+/*! \brief Store vector \a v to float array \a ptr.
+* \relates Simd4f */
+inline void store(float* ptr, Simd4f const& v);
+
+/*! \brief Store vector \a v to aligned float array \a ptr.
+* \note \a ptr needs to be 16 byte aligned.
+* \relates Simd4f */
+inline void storeAligned(float* ptr, Simd4f const& v);
+
+/*! \brief Store vector \a v to aligned float array \a ptr.
+* \param offset pointer offset in bytes.
+* \note \a ptr+offset needs to be 16 byte aligned.
+* \relates Simd4f */
+inline void storeAligned(float* ptr, unsigned int offset, Simd4f const& v);
+
+/*! \brief replicate i-th component into all vector components.
+* \return Vector with all elements set to \a v[i].
+* \relates Simd4f */
+template <size_t i>
+inline Simd4f splat(Simd4f const& v);
+
+/*! \brief Select \a v0 or \a v1 based on \a mask.
+* \return mask ? v0 : v1
+* \relates Simd4f */
+inline Simd4f select(Simd4f const& mask, Simd4f const& v0, Simd4f const& v1);
+
+/*! \brief Per element absolute value.
+* \return Vector with absolute values of \a v.
+* \relates Simd4f */
+inline Simd4f abs(const Simd4f& v);
+
+/*! \brief Per element floor value.
+* \note Result undefined for QNaN elements.
+* \note On SSE and NEON, returns v-1 if v is negative integer value
+* \relates Simd4f */
+inline Simd4f floor(const Simd4f& v);
+
+/*! \brief Per-component minimum of two vectors
+* \note Result undefined for QNaN elements.
+* \relates Simd4f */
+inline Simd4f max(const Simd4f& v0, const Simd4f& v1);
+
+/*! \brief Per-component minimum of two vectors
+* \note Result undefined for QNaN elements.
+* \relates Simd4f */
+inline Simd4f min(const Simd4f& v0, const Simd4f& v1);
+
+/*! \brief Return reciprocal estimate of a vector.
+* \return Vector of per-element reciprocal estimate.
+* \relates Simd4f */
+inline Simd4f recip(const Simd4f& v);
+
+/*! \brief Return reciprocal of a vector.
+* \return Vector of per-element reciprocal.
+* \note Performs \a n Newton-Raphson iterations on initial estimate.
+* \relates Simd4f */
+template <int n>
+inline Simd4f recipT(const Simd4f& v);
+
+/*! \brief Return square root of a vector.
+* \return Vector of per-element square root.
+* \note The behavior is undefined for negative elements.
+* \relates Simd4f */
+inline Simd4f sqrt(const Simd4f& v);
+
+/*! \brief Return inverse square root estimate of a vector.
+* \return Vector of per-element inverse square root estimate.
+* \note The behavior is undefined for negative, zero, and infinity elements.
+* \relates Simd4f */
+inline Simd4f rsqrt(const Simd4f& v);
+
+/*! \brief Return inverse square root of a vector.
+* \return Vector of per-element inverse square root.
+* \note Performs \a n Newton-Raphson iterations on initial estimate.
+* \note The behavior is undefined for negative and infinity elements.
+* \relates Simd4f */
+template <int n>
+inline Simd4f rsqrtT(const Simd4f& v);
+
+/*! \brief Return 2 raised to the power of v.
+* \note Result undefined for QNaN elements.
+* \relates Simd4f */
+inline Simd4f exp2(const Simd4f& v);
+
+#if NVMATH_SIMD
+namespace simdf
+{
+// PSP2 is confused resolving about exp2, forwarding works
+inline Simd4f exp2(const Simd4f& v)
+{
+ return ::exp2(v);
+}
+}
+#endif
+
+/*! \brief Return logarithm of v to base 2.
+* \note Result undefined for QNaN elements.
+* \relates Simd4f */
+inline Simd4f log2(const Simd4f& v);
+
+/*! \brief Return dot product of two 3-vectors.
+* \note The result is replicated across all 4 components.
+* \relates Simd4f */
+inline Simd4f dot3(const Simd4f& v0, const Simd4f& v1);
+
+/*! \brief Return cross product of two 3-vectors.
+* \note The 4th component is undefined.
+* \relates Simd4f */
+inline Simd4f cross3(const Simd4f& v0, const Simd4f& v1);
+
+/*! \brief Transposes 4x4 matrix represented by \a x, \a y, \a z, and \a w.
+* \relates Simd4f */
+inline void transpose(Simd4f& x, Simd4f& y, Simd4f& z, Simd4f& w);
+
+/*! \brief returns non-zero if all elements or \a v0 and \a v1 are equal
+* \note QNaPs aren't handled on SPU: comparing two QNaPs will return true.
+* \relates Simd4f */
+inline int allEqual(const Simd4f& v0, const Simd4f& v1);
+
+/*! \brief returns non-zero if all elements or \a v0 and \a v1 are equal
+* \param outMask holds the result of \a v0 == \a v1.
+* \note QNaPs aren't handled on SPU: comparing two QNaPs will return true.
+* \relates Simd4f */
+inline int allEqual(const Simd4f& v0, const Simd4f& v1, Simd4f& outMask);
+
+/*! \brief returns non-zero if any elements or \a v0 and \a v1 are equal
+* \note QNaPs aren't handled on SPU: comparing two QNaPs will return true.
+* \relates Simd4f */
+inline int anyEqual(const Simd4f& v0, const Simd4f& v1);
+
+/*! \brief returns non-zero if any elements or \a v0 and \a v1 are equal
+* \param outMask holds the result of \a v0 == \a v1.
+* \note QNaPs aren't handled on SPU: comparing two QNaPs will return true.
+* \relates Simd4f */
+inline int anyEqual(const Simd4f& v0, const Simd4f& v1, Simd4f& outMask);
+
+/*! \brief returns non-zero if all elements or \a v0 and \a v1 are greater
+* \note QNaPs aren't handled on SPU: comparisons against QNaPs don't necessarily return false.
+* \relates Simd4f */
+inline int allGreater(const Simd4f& v0, const Simd4f& v1);
+
+/*! \brief returns non-zero if all elements or \a v0 and \a v1 are greater
+* \param outMask holds the result of \a v0 == \a v1.
+* \note QNaPs aren't handled on SPU: comparisons against QNaPs don't necessarily return false.
+* \relates Simd4f */
+inline int allGreater(const Simd4f& v0, const Simd4f& v1, Simd4f& outMask);
+
+/*! \brief returns non-zero if any elements or \a v0 and \a v1 are greater
+* \note QNaPs aren't handled on SPU: comparisons against QNaPs don't necessarily return false.
+* \relates Simd4f */
+inline int anyGreater(const Simd4f& v0, const Simd4f& v1);
+
+/*! \brief returns non-zero if any elements or \a v0 and \a v1 are greater
+* \param outMask holds the result of \a v0 == \a v1.
+* \note QNaPs aren't handled on SPU: comparisons against QNaPs don't necessarily return false.
+* \relates Simd4f */
+inline int anyGreater(const Simd4f& v0, const Simd4f& v1, Simd4f& outMask);
+
+/*! \brief returns non-zero if all elements or \a v0 and \a v1 are greater or equal
+* \note QNaPs aren't handled on SPU: comparisons against QNaPs don't necessarily return false.
+* \relates Simd4f */
+inline int allGreaterEqual(const Simd4f& v0, const Simd4f& v1);
+
+/*! \brief returns non-zero if all elements or \a v0 and \a v1 are greater or equal
+* \param outMask holds the result of \a v0 == \a v1.
+* \note QNaPs aren't handled on SPU: comparisons against QNaPs don't necessarily return false.
+* \relates Simd4f */
+inline int allGreaterEqual(const Simd4f& v0, const Simd4f& v1, Simd4f& outMask);
+
+/*! \brief returns non-zero if any elements or \a v0 and \a v1 are greater or equal
+* \note QNaPs aren't handled on SPU: comparisons against QNaPs don't necessarily return false.
+* \relates Simd4f */
+inline int anyGreaterEqual(const Simd4f& v0, const Simd4f& v1);
+
+/*! \brief returns non-zero if any elements or \a v0 and \a v1 are greater or equal
+* \param outMask holds the result of \a v0 == \a v1.
+* \note QNaPs aren't handled on SPU: comparisons against QNaPs don't necessarily return false.
+* \relates Simd4f */
+inline int anyGreaterEqual(const Simd4f& v0, const Simd4f& v1, Simd4f& outMask);
+
+/*! \brief returns non-zero if all elements are true
+* \note Undefined if parameter is not result of a comparison.
+* \relates Simd4f */
+inline int allTrue(const Simd4f& v);
+
+/*! \brief returns non-zero if any element is true
+* \note Undefined if parameter is not result of a comparison.
+* \relates Simd4f */
+inline int anyTrue(const Simd4f& v);
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// platform specific includes
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if NVMATH_SSE2
+#include "sse2/Simd4f.h"
+#elif NVMATH_NEON
+#include "neon/Simd4f.h"
+#endif
+
+#if NVMATH_SCALAR
+#include "scalar/Simd4f.h"
+#endif
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/Simd4i.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/Simd4i.h
new file mode 100644
index 00000000..d237e1fa
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/Simd4i.h
@@ -0,0 +1,360 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "SimdTypes.h"
+
+template <typename T>
+struct Simd4iFactory
+{
+ Simd4iFactory(T v_) : v(v_)
+ {
+ }
+ inline operator Simd4i() const;
+ inline operator Scalar4i() const;
+ Simd4iFactory& operator=(const Simd4iFactory&); // not implemented
+ T v;
+};
+
+template <>
+struct Simd4iFactory<detail::FourTuple>
+{
+ Simd4iFactory(int x, int y, int z, int w)
+ {
+ v[0] = x, v[1] = y, v[2] = z, v[3] = w;
+ }
+ Simd4iFactory(const Simd4iFactory<const int&>& f)
+ {
+ v[3] = v[2] = v[1] = v[0] = f.v;
+ }
+ inline operator Simd4i() const;
+ inline operator Scalar4i() const;
+ Simd4iFactory& operator=(const Simd4iFactory&); // not implemented
+ PX_ALIGN(16, int) v[4];
+};
+
+template <int i>
+struct Simd4iFactory<detail::IntType<i> >
+{
+ inline operator Simd4i() const;
+ inline operator Scalar4i() const;
+};
+
+// forward declaration
+template <typename>
+struct Simd4fFactory;
+
+// map Simd4f/Scalar4f to Simd4i/Scalar4i
+template <typename>
+struct Simd4fToSimd4i;
+template <>
+struct Simd4fToSimd4i<Simd4f>
+{
+ typedef Simd4i Type;
+};
+template <>
+struct Simd4fToSimd4i<Scalar4f>
+{
+ typedef Scalar4i Type;
+};
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// expression template
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if NVMATH_DISTINCT_TYPES
+inline Simd4i operator&(const ComplementExpr<Simd4i>&, const Simd4i&);
+inline Simd4i operator&(const Simd4i&, const ComplementExpr<Simd4i>&);
+#endif
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// operators
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if NVMATH_DISTINCT_TYPES
+
+/*! \brief Vector bit-wise NOT operator
+* \return A vector holding the bit-negate of \a v.
+* \relates Simd4i */
+inline ComplementExpr<Simd4i> operator~(const Simd4i& v);
+
+/*! \brief Vector bit-wise AND operator
+* \return A vector holding the bit-wise AND of \a v0 and \a v1.
+* \relates Simd4i */
+inline Simd4i operator&(const Simd4i& v0, const Simd4i& v1);
+
+/*! \brief Vector bit-wise OR operator
+* \return A vector holding the bit-wise OR of \a v0 and \a v1.
+* \relates Simd4i */
+inline Simd4i operator|(const Simd4i& v0, const Simd4i& v1);
+
+/*! \brief Vector bit-wise XOR operator
+* \return A vector holding the bit-wise XOR of \a v0 and \a v1.
+* \relates Simd4i */
+inline Simd4i operator^(const Simd4i& v0, const Simd4i& v1);
+
+/*! \brief Vector logical left shift.
+* \return A vector with 4 elements of \a v0, each shifted left by \a shift bits.
+* \relates Simd4i */
+inline Simd4i operator<<(const Simd4i& v, int shift);
+
+/*! \brief Vector logical right shift.
+* \return A vector with 4 elements of \a v0, each shifted right by \a shift bits.
+* \relates Simd4i */
+inline Simd4i operator>>(const Simd4i& v, int shift);
+
+#if NVMATH_SHIFT_BY_VECTOR
+
+/*! \brief Vector logical left shift.
+* \return A vector with 4 elements of \a v0, each shifted left by \a shift bits.
+* \relates Simd4i */
+inline Simd4i operator<<(const Simd4i& v, const Simd4i& shift);
+
+/*! \brief Vector logical right shift.
+* \return A vector with 4 elements of \a v0, each shifted right by \a shift bits.
+* \relates Simd4i */
+inline Simd4i operator>>(const Simd4i& v, const Simd4i& shift);
+
+#endif // NVMATH_SHIFT_BY_VECTOR
+
+#endif // NVMATH_DISTINCT_TYPES
+
+namespace simdi // disambiguate for VMX
+{
+// note: operator?= missing because they don't have corresponding intrinsics.
+
+/*! \brief Test for equality of two vectors.
+* \return Vector of per element result mask (all bits set for 'true', none set for 'false').
+* \relates Simd4i */
+inline Simd4i operator==(const Simd4i& v0, const Simd4i& v1);
+
+// no !=, <=, >= because VMX128/SSE don't support it, use ~equal etc.
+
+/*! \brief Less-compare all elements of two *signed* vectors.
+* \return Vector of per element result mask (all bits set for 'true', none set for 'false').
+* \relates Simd4i */
+inline Simd4i operator<(const Simd4i& v0, const Simd4i& v1);
+
+/*! \brief Greater-compare all elements of two *signed* vectors.
+* \return Vector of per element result mask (all bits set for 'true', none set for 'false').
+* \relates Simd4i */
+inline Simd4i operator>(const Simd4i& v0, const Simd4i& v1);
+
+/*! \brief Vector addition operator
+* \return A vector holding the component-wise sum of \a v0 and \a v1.
+* \relates Simd4i */
+inline Simd4i operator+(const Simd4i& v0, const Simd4i& v1);
+
+/*! \brief Unary vector negation operator.
+* \return A vector holding the component-wise negation of \a v.
+* \relates Simd4i */
+inline Simd4i operator-(const Simd4i& v);
+
+/*! \brief Vector subtraction operator.
+* \return A vector holding the component-wise difference of \a v0 and \a v1.
+* \relates Simd4i */
+inline Simd4i operator-(const Simd4i& v0, const Simd4i& v1);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// functions
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+/*! \brief Load int value into all vector components.
+* \relates Simd4i */
+inline Simd4iFactory<const int&> simd4i(const int& s)
+{
+ return Simd4iFactory<const int&>(s);
+}
+
+/*! \brief Load 4 int values into vector.
+* \relates Simd4i */
+inline Simd4iFactory<detail::FourTuple> simd4i(int x, int y, int z, int w)
+{
+ return Simd4iFactory<detail::FourTuple>(x, y, z, w);
+}
+
+/*! \brief Create vector from literal.
+* \return Vector with all elements set to \c i.
+* \relates Simd4i */
+template <int i>
+inline Simd4iFactory<detail::IntType<i> > simd4i(const detail::IntType<i>&)
+{
+ return Simd4iFactory<detail::IntType<i> >();
+}
+
+template <>
+inline Simd4iFactory<detail::IntType<1> > simd4i(const detail::IntType<1>&)
+{
+ return Simd4iFactory<detail::IntType<1> >();
+}
+
+template <>
+inline Simd4iFactory<detail::IntType<int(0x80000000)> > simd4i(const detail::IntType<int(0x80000000)>&)
+{
+ return Simd4iFactory<detail::IntType<int(0x80000000)> >();
+}
+
+template <>
+inline Simd4iFactory<detail::IntType<-1> > simd4i(const detail::IntType<-1>&)
+{
+ return Simd4iFactory<detail::IntType<-1> >();
+}
+
+/*! \brief Reinterpret Simd4f as Simd4i.
+* \return A copy of \a v, but cast as Simd4i.
+* \relates Simd4i */
+inline Simd4i simd4i(const Simd4f& v);
+
+/*! \brief Reinterpret Simd4fFactory as Simd4iFactory.
+* \relates Simd4i */
+template <typename T>
+inline Simd4iFactory<T> simd4i(const Simd4fFactory<T>& v)
+{
+ return reinterpret_cast<const Simd4iFactory<T>&>(v);
+}
+
+namespace simdi
+{
+
+/*! \brief return reference to contiguous array of vector elements
+* \relates Simd4i */
+inline int (&array(Simd4i& v))[4];
+
+/*! \brief return constant reference to contiguous array of vector elements
+* \relates Simd4i */
+inline const int (&array(const Simd4i& v))[4];
+
+} // namespace simdi
+
+/*! \brief Create vector from int array.
+* \relates Simd4i */
+inline Simd4iFactory<const int*> load(const int* ptr)
+{
+ return ptr;
+}
+
+/*! \brief Create vector from aligned int array.
+* \note \a ptr needs to be 16 byte aligned.
+* \relates Simd4i */
+inline Simd4iFactory<detail::AlignedPointer<int> > loadAligned(const int* ptr)
+{
+ return detail::AlignedPointer<int>(ptr);
+}
+
+/*! \brief Create vector from aligned float array.
+* \param offset pointer offset in bytes.
+* \note \a ptr+offset needs to be 16 byte aligned.
+* \relates Simd4i */
+inline Simd4iFactory<detail::OffsetPointer<int> > loadAligned(const int* ptr, unsigned int offset)
+{
+ return detail::OffsetPointer<int>(ptr, offset);
+}
+
+/*! \brief Store vector \a v to int array \a ptr.
+* \relates Simd4i */
+inline void store(int* ptr, const Simd4i& v);
+
+/*! \brief Store vector \a v to aligned int array \a ptr.
+* \note \a ptr needs to be 16 byte aligned.
+* \relates Simd4i */
+inline void storeAligned(int* ptr, const Simd4i& v);
+
+/*! \brief Store vector \a v to aligned int array \a ptr.
+* \param offset pointer offset in bytes.
+* \note \a ptr+offset needs to be 16 byte aligned.
+* \relates Simd4i */
+inline void storeAligned(int* ptr, unsigned int offset, const Simd4i& v);
+
+#if NVMATH_DISTINCT_TYPES
+
+/*! \brief replicate i-th component into all vector components.
+* \return Vector with all elements set to \a v[i].
+* \relates Simd4i */
+template <size_t i>
+inline Simd4i splat(const Simd4i& v);
+
+/*! \brief Select \a v0 or \a v1 based on \a mask.
+* \return mask ? v0 : v1
+* \relates Simd4i */
+inline Simd4i select(const Simd4i& mask, const Simd4i& v0, const Simd4i& v1);
+
+#endif // NVMATH_DISTINCT_TYPES
+
+namespace simdi // disambiguate for VMX
+{
+/*! \brief returns non-zero if all elements or \a v0 and \a v1 are equal
+* \relates Simd4i */
+inline int allEqual(const Simd4i& v0, const Simd4i& v1);
+
+/*! \brief returns non-zero if all elements or \a v0 and \a v1 are equal
+* \param outMask holds the result of \a v0 == \a v1.
+* \relates Simd4i */
+inline int allEqual(const Simd4i& v0, const Simd4i& v1, Simd4i& outMask);
+
+/*! \brief returns non-zero if any elements or \a v0 and \a v1 are equal
+* \relates Simd4i */
+inline int anyEqual(const Simd4i& v0, const Simd4i& v1);
+
+/*! \brief returns non-zero if any elements or \a v0 and \a v1 are equal
+* \param outMask holds the result of \a v0 == \a v1.
+* \relates Simd4i */
+inline int anyEqual(const Simd4i& v0, const Simd4i& v1, Simd4i& outMask);
+
+/*! \brief returns non-zero if all *signed* elements or \a v0 and \a v1 are greater
+* \relates Simd4i */
+inline int allGreater(const Simd4i& v0, const Simd4i& v1);
+
+/*! \brief returns non-zero if all *signed* elements or \a v0 and \a v1 are greater
+* \param outMask holds the result of \a v0 == \a v1.
+* \relates Simd4i */
+inline int allGreater(const Simd4i& v0, const Simd4i& v1, Simd4i& outMask);
+
+/*! \brief returns non-zero if any elements or \a v0 and \a v1 are greater
+* \relates Simd4i */
+inline int anyGreater(const Simd4i& v0, const Simd4i& v1);
+
+/*! \brief returns non-zero if any elements or \a v0 and \a v1 are greater
+* \param outMask holds the result of \a v0 == \a v1.
+* \relates Simd4i */
+inline int anyGreater(const Simd4i& v0, const Simd4i& v1, Simd4i& outMask);
+}
+
+#if NVMATH_DISTINCT_TYPES
+
+/*! \brief returns non-zero if all elements are true
+* \note undefined if parameter is not result of a comparison.
+* \relates Simd4i */
+inline int allTrue(const Simd4i& v);
+
+/*! \brief returns non-zero if any element is true
+* \note undefined if parameter is not result of a comparison.
+* \relates Simd4i */
+inline int anyTrue(const Simd4i& v);
+
+#endif // NVMATH_DISTINCT_TYPES
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// platform specific includes
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if NVMATH_SSE2
+#include "sse2/Simd4i.h"
+#elif NVMATH_NEON
+#include "neon/Simd4i.h"
+#endif
+
+#if NVMATH_SCALAR
+#include "scalar/Simd4i.h"
+#endif
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SimdTypes.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SimdTypes.h
new file mode 100644
index 00000000..e44e876a
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SimdTypes.h
@@ -0,0 +1,150 @@
+// 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) 2008-2015 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include <cmath>
+
+// ps4 compiler defines _M_X64 without value
+#if((defined _M_IX86) || (defined _M_X64) || (defined __i386__) || (defined __x86_64__))
+#define NVMATH_SSE2 1
+#else
+#define NVMATH_SSE2 0
+#endif
+#define NVMATH_NEON (defined _M_ARM || defined __ARM_NEON__)
+
+// which simd types are implemented (one or both are all valid options)
+#define NVMATH_SIMD (NVMATH_SSE2 || NVMATH_NEON)
+#define NVMATH_SCALAR !NVMATH_SIMD
+// #define NVMATH_SCALAR 1
+
+// use template expression to fuse multiply-adds into a single instruction
+#define NVMATH_FUSE_MULTIPLY_ADD (NVMATH_NEON)
+// support shift by vector operarations
+#define NVMATH_SHIFT_BY_VECTOR (NVMATH_NEON)
+// Simd4f and Simd4i map to different types
+#define NVMATH_DISTINCT_TYPES (NVMATH_SSE2 || NVMATH_NEON)
+// support inline assembler
+#define NVMATH_INLINE_ASSEMBLER !((defined _M_ARM) || (defined SN_TARGET_PSP2) || (defined __arm64__))
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// expression template
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+/*! \brief Expression template to fuse and-not. */
+template <typename T>
+struct ComplementExpr
+{
+ inline ComplementExpr(T const& v_) : v(v_)
+ {
+ }
+ inline operator T() const;
+ const T v;
+
+ private:
+ ComplementExpr& operator=(const ComplementExpr&); // not implemented
+};
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// helper functions
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+template <typename T>
+T sqr(const T& x)
+{
+ return x * x;
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// details
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+namespace detail
+{
+template <typename T>
+struct AlignedPointer
+{
+ AlignedPointer(const T* p) : ptr(p)
+ {
+ }
+ const T* ptr;
+};
+
+template <typename T>
+struct OffsetPointer
+{
+ OffsetPointer(const T* p, unsigned int off) : ptr(p), offset(off)
+ {
+ }
+ const T* ptr;
+ unsigned int offset;
+};
+
+struct FourTuple
+{
+};
+
+// zero and one literals
+template <int i>
+struct IntType
+{
+};
+}
+
+// Supress warnings
+#if defined(__GNUC__) || defined(__SNC__)
+#define NVMATH_UNUSED __attribute__((unused))
+#else
+#define NVMATH_UNUSED
+#endif
+
+static detail::IntType<0> _0 NVMATH_UNUSED;
+static detail::IntType<1> _1 NVMATH_UNUSED;
+static detail::IntType<int(0x80000000)> _sign NVMATH_UNUSED;
+static detail::IntType<-1> _true NVMATH_UNUSED;
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// platform specific includes
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if NVMATH_SSE2
+#include "sse2/SimdTypes.h"
+#elif NVMATH_NEON
+#include "neon/SimdTypes.h"
+#else
+struct Simd4f;
+struct Simd4i;
+#endif
+
+#if NVMATH_SCALAR
+#include "scalar/SimdTypes.h"
+#else
+struct Scalar4f;
+struct Scalar4i;
+#endif
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/StackAllocator.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/StackAllocator.h
new file mode 100644
index 00000000..f8c6b2dc
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/StackAllocator.h
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include <PxAssert.h>
+
+#if PX_LINUX_FAMILY
+#include <stdint.h> // intptr_t
+#endif
+
+template <size_t align>
+class StackAllocator
+{
+ typedef unsigned char byte;
+
+ // todo: switch to offsets so size is consistent on x64
+ // mSize is just for book keeping so could be 4 bytes
+ struct Header
+ {
+ Header* mPrev;
+ size_t mSize : 31;
+ size_t mFree : 1;
+ };
+
+ StackAllocator(const StackAllocator&);
+ StackAllocator& operator=(const StackAllocator&);
+
+ public:
+ StackAllocator(void* buffer, size_t bufferSize)
+ : mBuffer(reinterpret_cast<byte*>(buffer)), mBufferSize(bufferSize), mFreeStart(mBuffer), mTop(0)
+ {
+ }
+
+ ~StackAllocator()
+ {
+ PX_ASSERT(userBytes() == 0);
+ }
+
+ void* allocate(size_t numBytes)
+ {
+ // this is non-standard
+ if(!numBytes)
+ return 0;
+
+ uintptr_t unalignedStart = uintptr_t(mFreeStart) + sizeof(Header);
+
+ byte* allocStart = reinterpret_cast<byte*>((unalignedStart + (align - 1)) & ~(align - 1));
+ byte* allocEnd = allocStart + numBytes;
+
+ // ensure there is space for the alloc
+ PX_ASSERT(allocEnd <= mBuffer + mBufferSize);
+
+ Header* h = getHeader(allocStart);
+ h->mPrev = mTop;
+ h->mSize = numBytes;
+ h->mFree = false;
+
+ mTop = h;
+ mFreeStart = allocEnd;
+
+ return allocStart;
+ }
+
+ void deallocate(void* p)
+ {
+ if(!p)
+ return;
+
+ Header* h = getHeader(p);
+ h->mFree = true;
+
+ // unwind the stack to the next live alloc
+ while(mTop && mTop->mFree)
+ {
+ mFreeStart = reinterpret_cast<byte*>(mTop);
+ mTop = mTop->mPrev;
+ }
+ }
+
+ private:
+ // return the header for an allocation
+ inline Header* getHeader(void* p) const
+ {
+ PX_ASSERT((reinterpret_cast<uintptr_t>(p) & (align - 1)) == 0);
+ PX_ASSERT(reinterpret_cast<byte*>(p) >= mBuffer + sizeof(Header));
+ PX_ASSERT(reinterpret_cast<byte*>(p) < mBuffer + mBufferSize);
+
+ return reinterpret_cast<Header*>(p) - 1;
+ }
+
+ public:
+ // total user-allocated bytes not including any overhead
+ size_t userBytes() const
+ {
+ size_t total = 0;
+ Header* iter = mTop;
+ while(iter)
+ {
+ total += iter->mSize;
+ iter = iter->mPrev;
+ }
+
+ return total;
+ }
+
+ // total user-allocated bytes + overhead
+ size_t totalUsedBytes() const
+ {
+ return mFreeStart - mBuffer;
+ }
+
+ size_t remainingBytes() const
+ {
+ return mBufferSize - totalUsedBytes();
+ }
+
+ size_t wastedBytes() const
+ {
+ return totalUsedBytes() - userBytes();
+ }
+
+ private:
+ byte* const mBuffer;
+ const size_t mBufferSize;
+
+ byte* mFreeStart; // start of free space
+ Header* mTop; // top allocation header
+};
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwCloth.cpp b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwCloth.cpp
new file mode 100644
index 00000000..2283a319
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwCloth.cpp
@@ -0,0 +1,307 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "SwCloth.h"
+#include "SwFabric.h"
+#include "SwFactory.h"
+#include "TripletScheduler.h"
+#include "ClothBase.h"
+
+namespace nvidia
+{
+namespace cloth
+{
+PhaseConfig transform(const PhaseConfig&); // from PhaseConfig.cpp
+}
+}
+
+using namespace nvidia;
+using namespace physx::shdfnd;
+using namespace nvidia;
+
+cloth::SwCloth::SwCloth(SwFactory& factory, SwFabric& fabric, Range<const PxVec4> particles)
+: mFactory(factory)
+, mFabric(fabric)
+, mNumVirtualParticles(0)
+#if APEX_UE4
+, mSimulationTask(NULL)
+#endif
+, mUserData(0)
+{
+ PX_ASSERT(!particles.empty());
+
+ initialize(*this, particles.begin(), particles.end());
+
+#if PX_WINDOWS_FAMILY
+ const uint32_t kSimdWidth = 8; // avx
+#else
+ const uint32_t kSimdWidth = 4; // sse
+#endif
+
+ mCurParticles.reserve(particles.size() + kSimdWidth - 1);
+ mCurParticles.assign(reinterpret_cast<const PxVec4*>(particles.begin()),
+ reinterpret_cast<const PxVec4*>(particles.end()));
+
+ // 7 dummy particles used in SIMD solver
+ mCurParticles.resize(particles.size() + kSimdWidth - 1, PxVec4(0.0f));
+ mPrevParticles = mCurParticles;
+
+ mCurParticles.resize(particles.size());
+ mPrevParticles.resize(particles.size());
+
+ mFabric.incRefCount();
+}
+
+namespace
+{
+// copy vector and make same capacity
+void copyVector(cloth::Vec4fAlignedVector& dst, const cloth::Vec4fAlignedVector& src)
+{
+ dst.reserve(src.capacity());
+ dst.assign(src.begin(), src.end());
+
+ // ensure valid dummy data
+ dst.resize(src.capacity(), PxVec4(0.0f));
+ dst.resize(src.size());
+}
+}
+
+// copy constructor, supports rebinding to a different factory
+cloth::SwCloth::SwCloth(SwFactory& factory, const SwCloth& cloth)
+: mFactory(factory)
+, mFabric(cloth.mFabric)
+, mClothCostDirty(true)
+, mPhaseConfigs(cloth.mPhaseConfigs)
+, mCapsuleIndices(cloth.mCapsuleIndices)
+, mStartCollisionSpheres(cloth.mStartCollisionSpheres)
+, mTargetCollisionSpheres(cloth.mTargetCollisionSpheres)
+, mStartCollisionPlanes(cloth.mStartCollisionPlanes)
+, mTargetCollisionPlanes(cloth.mTargetCollisionPlanes)
+, mStartCollisionTriangles(cloth.mStartCollisionTriangles)
+, mTargetCollisionTriangles(cloth.mTargetCollisionTriangles)
+, mVirtualParticleIndices(cloth.mVirtualParticleIndices)
+, mVirtualParticleWeights(cloth.mVirtualParticleWeights)
+, mNumVirtualParticles(cloth.mNumVirtualParticles)
+, mSelfCollisionIndices(cloth.mSelfCollisionIndices)
+, mRestPositions(cloth.mRestPositions)
+#if APEX_UE4
+, mSimulationTask(NULL)
+#endif
+{
+ copy(*this, cloth);
+
+ // carry over capacity (using as dummy particles)
+ copyVector(mCurParticles, cloth.mCurParticles);
+ copyVector(mPrevParticles, cloth.mPrevParticles);
+ copyVector(mMotionConstraints.mStart, cloth.mMotionConstraints.mStart);
+ copyVector(mMotionConstraints.mTarget, cloth.mMotionConstraints.mTarget);
+ copyVector(mSeparationConstraints.mStart, cloth.mSeparationConstraints.mStart);
+ copyVector(mSeparationConstraints.mTarget, cloth.mSeparationConstraints.mTarget);
+ copyVector(mParticleAccelerations, cloth.mParticleAccelerations);
+
+ mFabric.incRefCount();
+}
+
+cloth::SwCloth::~SwCloth()
+{
+ mFabric.decRefCount();
+}
+
+cloth::Range<PxVec4> cloth::SwCloth::push(SwConstraints& constraints)
+{
+ uint32_t n = mCurParticles.size();
+
+ if(!constraints.mTarget.capacity())
+ constraints.mTarget.resize((n + 3) & ~3, PxVec4(0.0f)); // reserve multiple of 4 for SIMD
+
+ constraints.mTarget.resizeUninitialized(n);
+ PxVec4* data = &constraints.mTarget.front();
+ Range<PxVec4> result(data, data + constraints.mTarget.size());
+
+ if(constraints.mStart.empty()) // initialize start first
+ constraints.mStart.swap(constraints.mTarget);
+
+ return result;
+}
+
+void cloth::SwCloth::clear(SwConstraints& constraints)
+{
+ Vec4fAlignedVector().swap(constraints.mStart);
+ Vec4fAlignedVector().swap(constraints.mTarget);
+}
+
+cloth::Range<const PxVec3> cloth::SwCloth::clampTriangleCount(Range<const PxVec3> range, uint32_t)
+{
+ return range;
+}
+
+#include "ClothImpl.h"
+
+namespace nvidia
+{
+namespace cloth
+{
+
+template <>
+Cloth* ClothImpl<SwCloth>::clone(Factory& factory) const
+{
+ return factory.clone(*this);
+}
+
+template <>
+uint32_t ClothImpl<SwCloth>::getNumParticles() const
+{
+ return mCloth.mCurParticles.size();
+}
+
+template <>
+void ClothImpl<SwCloth>::lockParticles() const
+{
+}
+
+template <>
+void ClothImpl<SwCloth>::unlockParticles() const
+{
+}
+
+template <>
+MappedRange<PxVec4> ClothImpl<SwCloth>::getCurrentParticles()
+{
+ return getMappedParticles(&mCloth.mCurParticles.front());
+}
+
+template <>
+MappedRange<const PxVec4> ClothImpl<SwCloth>::getCurrentParticles() const
+{
+ return getMappedParticles(&mCloth.mCurParticles.front());
+}
+
+template <>
+MappedRange<PxVec4> ClothImpl<SwCloth>::getPreviousParticles()
+{
+ return getMappedParticles(&mCloth.mPrevParticles.front());
+}
+
+template <>
+MappedRange<const PxVec4> ClothImpl<SwCloth>::getPreviousParticles() const
+{
+ return getMappedParticles(&mCloth.mPrevParticles.front());
+}
+
+template <>
+GpuParticles ClothImpl<SwCloth>::getGpuParticles()
+{
+ GpuParticles result = { 0, 0, 0 };
+ return result;
+}
+
+template <>
+void ClothImpl<SwCloth>::setPhaseConfig(Range<const PhaseConfig> configs)
+{
+ mCloth.mPhaseConfigs.resize(0);
+
+ // transform phase config to use in solver
+ for(; !configs.empty(); configs.popFront())
+ if(configs.front().mStiffness > 0.0f)
+ mCloth.mPhaseConfigs.pushBack(transform(configs.front()));
+
+ mCloth.wakeUp();
+}
+
+template <>
+void ClothImpl<SwCloth>::setSelfCollisionIndices(Range<const uint32_t> indices)
+{
+ ContextLockType lock(mCloth.mFactory);
+ mCloth.mSelfCollisionIndices.assign(indices.begin(), indices.end());
+ mCloth.notifyChanged();
+ mCloth.wakeUp();
+}
+
+template <>
+uint32_t ClothImpl<SwCloth>::getNumVirtualParticles() const
+{
+ return uint32_t(mCloth.mNumVirtualParticles);
+}
+
+template <>
+Range<PxVec4> ClothImpl<SwCloth>::getParticleAccelerations()
+{
+ if(mCloth.mParticleAccelerations.empty())
+ {
+ uint32_t n = mCloth.mCurParticles.size();
+ mCloth.mParticleAccelerations.resize(n, PxVec4(0.0f));
+ }
+
+ mCloth.wakeUp();
+
+ PxVec4* data = &mCloth.mParticleAccelerations.front();
+ return Range<PxVec4>(data, data + mCloth.mParticleAccelerations.size());
+}
+
+template <>
+void ClothImpl<SwCloth>::clearParticleAccelerations()
+{
+ Vec4fAlignedVector().swap(mCloth.mParticleAccelerations);
+ mCloth.wakeUp();
+}
+
+template <>
+void ClothImpl<SwCloth>::setVirtualParticles(Range<const uint32_t[4]> indices, Range<const PxVec3> weights)
+{
+ mCloth.mNumVirtualParticles = 0;
+
+ // shuffle indices to form independent SIMD sets
+ uint16_t numParticles = uint16_t(mCloth.mCurParticles.size());
+ TripletScheduler scheduler(indices);
+ scheduler.simd(numParticles, 4);
+
+ // convert indices to byte offset
+ Vec4us dummy(numParticles, uint16_t(numParticles + 1), uint16_t(numParticles + 2), 0);
+ Vector<uint32_t>::Type::ConstIterator sIt = scheduler.mSetSizes.begin();
+ Vector<uint32_t>::Type::ConstIterator sEnd = scheduler.mSetSizes.end();
+ TripletScheduler::ConstTripletIter tIt = scheduler.mTriplets.begin(), tLast;
+ mCloth.mVirtualParticleIndices.resize(0);
+ mCloth.mVirtualParticleIndices.reserve(indices.size() + 3 * uint32_t(sEnd - sIt));
+ for(; sIt != sEnd; ++sIt)
+ {
+ uint32_t setSize = *sIt;
+ for(tLast = tIt + setSize; tIt != tLast; ++tIt, ++mCloth.mNumVirtualParticles)
+ mCloth.mVirtualParticleIndices.pushBack(Vec4us(*tIt));
+ mCloth.mVirtualParticleIndices.resize((mCloth.mVirtualParticleIndices.size() + 3) & ~3, dummy);
+ }
+ Vector<Vec4us>::Type(mCloth.mVirtualParticleIndices.begin(), mCloth.mVirtualParticleIndices.end())
+ .swap(mCloth.mVirtualParticleIndices);
+
+ // precompute 1/dot(w,w)
+ Vec4fAlignedVector().swap(mCloth.mVirtualParticleWeights);
+ mCloth.mVirtualParticleWeights.reserve(weights.size());
+ for(; !weights.empty(); weights.popFront())
+ {
+ PxVec3 w = reinterpret_cast<const PxVec3&>(weights.front());
+ float scale = 1 / w.magnitudeSquared();
+ mCloth.mVirtualParticleWeights.pushBack(PxVec4(w.x, w.y, w.z, scale));
+ }
+
+ mCloth.notifyChanged();
+}
+
+#if APEX_UE4
+template <>
+void ClothImpl<SwCloth>::simulate(float dt)
+{
+ (*SwCloth::sSimulationFunction)(mCloth.mSimulationTask, dt);
+}
+#endif
+
+} // namespace cloth
+} // namespace nvidia
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwCloth.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwCloth.h
new file mode 100644
index 00000000..3d0569af
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwCloth.h
@@ -0,0 +1,202 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "Cloth.h"
+#include "Range.h"
+#include "MovingAverage.h"
+#include "PhaseConfig.h"
+#include "IndexPair.h"
+#include "Vec4T.h"
+#include "Array.h"
+#include "PxTransform.h"
+
+namespace nvidia
+{
+
+namespace cloth
+{
+
+class SwFabric;
+class SwFactory;
+#if APEX_UE4
+class SwCloth;
+#endif
+
+typedef AlignedVector<PxVec4, 16>::Type Vec4fAlignedVector;
+
+struct SwConstraints
+{
+ void pop()
+ {
+ if(!mTarget.empty())
+ {
+ mStart.swap(mTarget);
+ mTarget.resize(0);
+ }
+ }
+
+ Vec4fAlignedVector mStart;
+ Vec4fAlignedVector mTarget;
+};
+
+class SwCloth
+{
+ SwCloth& operator=(const SwCloth&); // not implemented
+ struct SwContextLock
+ {
+ SwContextLock(const SwFactory&)
+ {
+ }
+ };
+
+ public:
+ typedef SwFactory FactoryType;
+ typedef SwFabric FabricType;
+ typedef SwContextLock ContextLockType;
+
+ typedef Vec4fAlignedVector& MappedVec4fVectorType;
+ typedef Vector<IndexPair>::Type& MappedIndexVectorType;
+
+ SwCloth(SwFactory&, SwFabric&, Range<const PxVec4>);
+ SwCloth(SwFactory&, const SwCloth&);
+ ~SwCloth(); // not virtual on purpose
+
+ public:
+ bool isSleeping() const
+ {
+ return mSleepPassCounter >= mSleepAfterCount;
+ }
+ void wakeUp()
+ {
+ mSleepPassCounter = 0;
+ }
+
+ void notifyChanged()
+ {
+ }
+
+ void setParticleBounds(const float*);
+
+ Range<PxVec4> push(SwConstraints&);
+ static void clear(SwConstraints&);
+
+ static Range<const PxVec3> clampTriangleCount(Range<const PxVec3>, uint32_t);
+
+ public:
+ SwFactory& mFactory;
+ SwFabric& mFabric;
+
+ bool mClothCostDirty;
+
+ // current and previous-iteration particle positions
+ Vec4fAlignedVector mCurParticles;
+ Vec4fAlignedVector mPrevParticles;
+
+ PxVec3 mParticleBoundsCenter;
+ PxVec3 mParticleBoundsHalfExtent;
+
+ PxVec3 mGravity;
+ PxVec3 mLogDamping;
+ PxVec3 mLinearLogDrag;
+ PxVec3 mAngularLogDrag;
+ PxVec3 mLinearInertia;
+ PxVec3 mAngularInertia;
+ PxVec3 mCentrifugalInertia;
+ float mSolverFrequency;
+ float mStiffnessFrequency;
+
+ PxTransform mTargetMotion;
+ PxTransform mCurrentMotion;
+ PxVec3 mLinearVelocity;
+ PxVec3 mAngularVelocity;
+
+ float mPrevIterDt;
+ MovingAverage mIterDtAvg;
+
+ Vector<PhaseConfig>::Type mPhaseConfigs; // transformed!
+
+ // tether constraints stuff
+ float mTetherConstraintLogStiffness;
+ float mTetherConstraintScale;
+
+ // motion constraints stuff
+ SwConstraints mMotionConstraints;
+ float mMotionConstraintScale;
+ float mMotionConstraintBias;
+ float mMotionConstraintLogStiffness;
+
+ // separation constraints stuff
+ SwConstraints mSeparationConstraints;
+
+ // particle acceleration stuff
+ Vec4fAlignedVector mParticleAccelerations;
+
+ // collision stuff
+ Vector<IndexPair>::Type mCapsuleIndices;
+ Vec4fAlignedVector mStartCollisionSpheres;
+ Vec4fAlignedVector mTargetCollisionSpheres;
+ Vector<uint32_t>::Type mConvexMasks;
+ Vec4fAlignedVector mStartCollisionPlanes;
+ Vec4fAlignedVector mTargetCollisionPlanes;
+ Vector<PxVec3>::Type mStartCollisionTriangles;
+ Vector<PxVec3>::Type mTargetCollisionTriangles;
+ bool mEnableContinuousCollision;
+ float mCollisionMassScale;
+ float mFriction;
+
+ // virtual particles
+ Vector<Vec4us>::Type mVirtualParticleIndices;
+ Vec4fAlignedVector mVirtualParticleWeights;
+ uint32_t mNumVirtualParticles;
+
+ // self collision
+ float mSelfCollisionDistance;
+ float mSelfCollisionLogStiffness;
+
+ Vector<uint32_t>::Type mSelfCollisionIndices;
+
+ Vec4fAlignedVector mRestPositions;
+
+ // sleeping
+ uint32_t mSleepTestInterval; // how often to test for movement
+ uint32_t mSleepAfterCount; // number of tests to pass before sleep
+ float mSleepThreshold; // max movement delta to pass test
+ uint32_t mSleepPassCounter; // how many tests passed
+ uint32_t mSleepTestCounter; // how many iterations since tested
+
+ // unused for CPU simulation
+ bool mIsAllowedHalfPrecisionSolver;
+
+#if APEX_UE4
+ void* mSimulationTask;
+ static void(*const sSimulationFunction)(void*, float);
+#endif
+
+ void* mUserData;
+
+} PX_ALIGN_SUFFIX(16);
+
+} // namespace cloth
+
+// bounds = lower[3], upper[3]
+inline void cloth::SwCloth::setParticleBounds(const float* bounds)
+{
+ for(uint32_t i = 0; i < 3; ++i)
+ {
+ mParticleBoundsCenter[i] = (bounds[3 + i] + bounds[i]) * 0.5f;
+ mParticleBoundsHalfExtent[i] = (bounds[3 + i] - bounds[i]) * 0.5f;
+ }
+}
+}
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwClothData.cpp b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwClothData.cpp
new file mode 100644
index 00000000..bc09612f
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwClothData.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "SwClothData.h"
+#include "SwCloth.h"
+#include "SwFabric.h"
+#include "Simd4f.h"
+#include "PsUtilities.h"
+
+using namespace nvidia;
+
+cloth::SwClothData::SwClothData(SwCloth& cloth, const SwFabric& fabric)
+{
+ mNumParticles = uint32_t(cloth.mCurParticles.size());
+ mCurParticles = array(cloth.mCurParticles.front());
+ mPrevParticles = array(cloth.mPrevParticles.front());
+
+ const float* center = array(cloth.mParticleBoundsCenter);
+ const float* extent = array(cloth.mParticleBoundsHalfExtent);
+ for(uint32_t i = 0; i < 3; ++i)
+ {
+ mCurBounds[i] = center[i] - extent[i];
+ mCurBounds[i + 3] = center[i] + extent[i];
+ }
+
+ // avoid reading uninitialized data into mCurBounds, even though it's never used.
+ mPrevBounds[0] = 0.0f;
+
+ mConfigBegin = cloth.mPhaseConfigs.empty() ? 0 : &cloth.mPhaseConfigs.front();
+ mConfigEnd = mConfigBegin + cloth.mPhaseConfigs.size();
+
+ mPhases = &fabric.mPhases.front();
+ mNumPhases = uint32_t(fabric.mPhases.size());
+
+ mSets = &fabric.mSets.front();
+ mNumSets = uint32_t(fabric.mSets.size());
+
+ mRestvalues = &fabric.mRestvalues.front();
+ mNumRestvalues = uint32_t(fabric.mRestvalues.size());
+
+ mIndices = &fabric.mIndices.front();
+ mNumIndices = uint32_t(fabric.mIndices.size());
+
+ float stiffnessExponent = cloth.mStiffnessFrequency * cloth.mPrevIterDt * 0.69314718055994531f; // logf(2.0f);
+
+ mTethers = fabric.mTethers.begin();
+ mNumTethers = uint32_t(fabric.mTethers.size());
+ mTetherConstraintStiffness = 1.0f - exp(stiffnessExponent * cloth.mTetherConstraintLogStiffness);
+ mTetherConstraintScale = cloth.mTetherConstraintScale * fabric.mTetherLengthScale;
+
+ mStartMotionConstraints = cloth.mMotionConstraints.mStart.size() ? array(cloth.mMotionConstraints.mStart.front()) : 0;
+ mTargetMotionConstraints =
+ !cloth.mMotionConstraints.mTarget.empty() ? array(cloth.mMotionConstraints.mTarget.front()) : 0;
+ mMotionConstraintStiffness = 1.0f - exp(stiffnessExponent * cloth.mMotionConstraintLogStiffness);
+
+ mStartSeparationConstraints =
+ cloth.mSeparationConstraints.mStart.size() ? array(cloth.mSeparationConstraints.mStart.front()) : 0;
+ mTargetSeparationConstraints =
+ !cloth.mSeparationConstraints.mTarget.empty() ? array(cloth.mSeparationConstraints.mTarget.front()) : 0;
+
+ mParticleAccelerations = cloth.mParticleAccelerations.size() ? array(cloth.mParticleAccelerations.front()) : 0;
+
+ mStartCollisionSpheres = cloth.mStartCollisionSpheres.empty() ? 0 : array(cloth.mStartCollisionSpheres.front());
+ mTargetCollisionSpheres =
+ cloth.mTargetCollisionSpheres.empty() ? mStartCollisionSpheres : array(cloth.mTargetCollisionSpheres.front());
+ mNumSpheres = uint32_t(cloth.mStartCollisionSpheres.size());
+
+ mCapsuleIndices = cloth.mCapsuleIndices.empty() ? 0 : &cloth.mCapsuleIndices.front();
+ mNumCapsules = uint32_t(cloth.mCapsuleIndices.size());
+
+ mStartCollisionPlanes = cloth.mStartCollisionPlanes.empty() ? 0 : array(cloth.mStartCollisionPlanes.front());
+ mTargetCollisionPlanes =
+ cloth.mTargetCollisionPlanes.empty() ? mStartCollisionPlanes : array(cloth.mTargetCollisionPlanes.front());
+ mNumPlanes = uint32_t(cloth.mStartCollisionPlanes.size());
+
+ mConvexMasks = cloth.mConvexMasks.empty() ? 0 : &cloth.mConvexMasks.front();
+ mNumConvexes = uint32_t(cloth.mConvexMasks.size());
+
+ mStartCollisionTriangles = cloth.mStartCollisionTriangles.empty() ? 0 : array(cloth.mStartCollisionTriangles.front());
+ mTargetCollisionTriangles = cloth.mTargetCollisionTriangles.empty() ? mStartCollisionTriangles
+ : array(cloth.mTargetCollisionTriangles.front());
+ mNumTriangles = uint32_t(cloth.mStartCollisionTriangles.size()) / 3;
+
+ mVirtualParticlesBegin = cloth.mVirtualParticleIndices.empty() ? 0 : array(cloth.mVirtualParticleIndices.front());
+ mVirtualParticlesEnd = mVirtualParticlesBegin + 4 * cloth.mVirtualParticleIndices.size();
+ mVirtualParticleWeights = cloth.mVirtualParticleWeights.empty() ? 0 : array(cloth.mVirtualParticleWeights.front());
+ mNumVirtualParticleWeights = uint32_t(cloth.mVirtualParticleWeights.size());
+
+ mEnableContinuousCollision = cloth.mEnableContinuousCollision;
+ mCollisionMassScale = cloth.mCollisionMassScale;
+ mFrictionScale = cloth.mFriction;
+
+ mSelfCollisionDistance = cloth.mSelfCollisionDistance;
+ mSelfCollisionStiffness = 1.0f - exp(stiffnessExponent * cloth.mSelfCollisionLogStiffness);
+
+ mSelfCollisionIndices = cloth.mSelfCollisionIndices.empty() ? 0 : cloth.mSelfCollisionIndices.begin();
+ mNumSelfCollisionIndices = mSelfCollisionIndices ? cloth.mSelfCollisionIndices.size() : mNumParticles;
+
+ mRestPositions = cloth.mRestPositions.size() ? array(cloth.mRestPositions.front()) : 0;
+
+ mSleepPassCounter = cloth.mSleepPassCounter;
+ mSleepTestCounter = cloth.mSleepTestCounter;
+}
+
+void cloth::SwClothData::reconcile(SwCloth& cloth) const
+{
+ cloth.setParticleBounds(mCurBounds);
+ cloth.mSleepTestCounter = mSleepTestCounter;
+ cloth.mSleepPassCounter = mSleepPassCounter;
+}
+
+void cloth::SwClothData::verify() const
+{
+ // checks needs to be run after the constructor because
+
+ PX_ASSERT(!mNumCapsules ||
+ mNumSpheres > *nvidia::maxElement(&mCapsuleIndices->first, &(mCapsuleIndices + mNumCapsules)->first));
+
+ PX_ASSERT(!mNumConvexes || (1u << mNumPlanes) - 1 >= *nvidia::maxElement(mConvexMasks, mConvexMasks + mNumConvexes));
+}
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwClothData.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwClothData.h
new file mode 100644
index 00000000..3aaa6a2b
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwClothData.h
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "Px.h"
+#include "Types.h"
+
+namespace nvidia
+{
+namespace cloth
+{
+
+class SwCloth;
+class SwFabric;
+struct PhaseConfig;
+struct IndexPair;
+struct SwTether;
+
+// reference to cloth instance bulk data (POD)
+struct SwClothData
+{
+ SwClothData(SwCloth&, const SwFabric&);
+ void reconcile(SwCloth&) const;
+ void verify() const;
+
+ // particle data
+ uint32_t mNumParticles;
+ float* mCurParticles;
+ float* mPrevParticles;
+
+ float mCurBounds[6]; // lower[3], upper[3]
+ float mPrevBounds[6];
+ float mPadding; // write as simd
+
+ // distance constraints
+ const PhaseConfig* mConfigBegin;
+ const PhaseConfig* mConfigEnd;
+
+ const uint32_t* mPhases;
+ uint32_t mNumPhases;
+
+ const uint32_t* mSets;
+ uint32_t mNumSets;
+
+ const float* mRestvalues;
+ uint32_t mNumRestvalues;
+
+ const uint16_t* mIndices;
+ uint32_t mNumIndices;
+
+ const SwTether* mTethers;
+ uint32_t mNumTethers;
+ float mTetherConstraintStiffness;
+ float mTetherConstraintScale;
+
+ // motion constraint data
+ const float* mStartMotionConstraints;
+ const float* mTargetMotionConstraints;
+ float mMotionConstraintStiffness;
+
+ // separation constraint data
+ const float* mStartSeparationConstraints;
+ const float* mTargetSeparationConstraints;
+
+ // particle acceleration data
+ const float* mParticleAccelerations;
+
+ // collision stuff
+ const float* mStartCollisionSpheres;
+ const float* mTargetCollisionSpheres;
+ uint32_t mNumSpheres;
+
+ const IndexPair* mCapsuleIndices;
+ uint32_t mNumCapsules;
+
+ const float* mStartCollisionPlanes;
+ const float* mTargetCollisionPlanes;
+ uint32_t mNumPlanes;
+
+ const uint32_t* mConvexMasks;
+ uint32_t mNumConvexes;
+
+ const float* mStartCollisionTriangles;
+ const float* mTargetCollisionTriangles;
+ uint32_t mNumTriangles;
+
+ const uint16_t* mVirtualParticlesBegin;
+ const uint16_t* mVirtualParticlesEnd;
+
+ const float* mVirtualParticleWeights;
+ uint32_t mNumVirtualParticleWeights;
+
+ bool mEnableContinuousCollision;
+ float mFrictionScale;
+ float mCollisionMassScale;
+
+ float mSelfCollisionDistance;
+ float mSelfCollisionStiffness;
+
+ uint32_t mNumSelfCollisionIndices;
+ const uint32_t* mSelfCollisionIndices;
+
+ float* mRestPositions;
+
+ // sleep data
+ uint32_t mSleepPassCounter;
+ uint32_t mSleepTestCounter;
+
+} PX_ALIGN_SUFFIX(16);
+}
+}
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwCollision.cpp b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwCollision.cpp
new file mode 100644
index 00000000..581d276b
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwCollision.cpp
@@ -0,0 +1,1927 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "SwCollision.h"
+#include "SwCloth.h"
+#include "SwClothData.h"
+#include "IterationState.h"
+#include "BoundingBox.h"
+#include "PointInterpolator.h"
+#include "SwCollisionHelpers.h"
+#include "PxAssert.h"
+#include <string.h> // for memset
+
+using namespace nvidia;
+
+// the particle trajectory needs to penetrate more than 0.2 * radius to trigger continuous collision
+template <typename Simd4f>
+const Simd4f cloth::SwCollision<Simd4f>::sSkeletonWidth = simd4f(sqr(1 - 0.2f) - 1);
+
+#if NVMATH_SSE2
+const Simd4i cloth::Gather<Simd4i>::sIntSignBit = simd4i(_sign);
+const Simd4i cloth::Gather<Simd4i>::sSignedMask = sIntSignBit | simd4i(0x7);
+#elif NVMATH_NEON
+const Simd4i cloth::Gather<Simd4i>::sPack = simd4i(0x00000000, 0x04040404, 0x08080808, 0x0c0c0c0c);
+const Simd4i cloth::Gather<Simd4i>::sOffset = simd4i(0x03020100);
+const Simd4i cloth::Gather<Simd4i>::sShift = simd4i(detail::IntType<2>());
+const Simd4i cloth::Gather<Simd4i>::sMask = simd4i(detail::IntType<7>());
+#endif
+
+namespace
+{
+typedef Simd4fFactory<detail::FourTuple> Simd4fConstant;
+
+const Simd4fConstant sEpsilon = simd4f(FLT_EPSILON);
+const Simd4fConstant sMax = simd4f(FLT_MAX);
+const Simd4fConstant sMaskX = simd4f(simd4i(~0, 0, 0, 0));
+const Simd4fConstant sMaskZ = simd4f(simd4i(0, 0, ~0, 0));
+const Simd4fConstant sMaskW = simd4f(simd4i(0, 0, 0, ~0));
+const Simd4fConstant sZero = simd4f(0.0f);
+const Simd4fConstant sOne = simd4f(1.0f);
+const Simd4fConstant sNegOne = simd4f(-1.0f);
+const Simd4fConstant sHalf = simd4f(0.5f);
+const Simd4fConstant sOneXYZ = simd4f(1.0f, 1.0f, 1.0f, 0.0f);
+const Simd4fConstant sGridLength = simd4f(8 - 1e-3f); // sGridSize
+const Simd4fConstant sGridExpand = simd4f(1e-4f);
+const Simd4fConstant sMinusFloatMaxXYZ = simd4f(-FLT_MAX, -FLT_MAX, -FLT_MAX, 0.0f);
+
+#if PX_PROFILE || PX_DEBUG
+template <typename Simd4f>
+uint32_t horizontalSum(const Simd4f& x)
+{
+ const float* p = array(x);
+ return uint32_t(0.5f + p[0] + p[1] + p[2] + p[3]);
+}
+#endif
+
+// 7 elements are written to ptr!
+template <typename Simd4f>
+void storeBounds(float* ptr, const cloth::BoundingBox<Simd4f>& bounds)
+{
+ store(ptr, bounds.mLower);
+ store(ptr + 3, bounds.mUpper);
+}
+}
+
+struct cloth::SphereData
+{
+ PxVec3 center;
+ float radius;
+};
+
+struct cloth::ConeData
+{
+ PxVec3 center;
+ float radius; // cone radius at center
+ PxVec3 axis;
+ float slope; // tan(alpha)
+
+ float sqrCosine; // cos^2(alpha)
+ float halfLength;
+
+ uint32_t firstMask;
+ uint32_t bothMask;
+};
+
+struct cloth::TriangleData
+{
+ PxVec3 base;
+ float edge0DotEdge1;
+
+ PxVec3 edge0;
+ float edge0SqrLength;
+
+ PxVec3 edge1;
+ float edge1SqrLength;
+
+ PxVec3 normal;
+ float padding;
+
+ float det;
+ float denom;
+
+ float edge0InvSqrLength;
+ float edge1InvSqrLength;
+};
+
+namespace nvidia
+{
+namespace cloth
+{
+template <typename Simd4f>
+BoundingBox<Simd4f> expandBounds(const BoundingBox<Simd4f>& bbox, const SphereData* sIt, const SphereData* sEnd)
+{
+ BoundingBox<Simd4f> result = bbox;
+ for(; sIt != sEnd; ++sIt)
+ {
+ Simd4f p = loadAligned(array(sIt->center));
+ Simd4f r = splat<3>(p);
+ result.mLower = min(result.mLower, p - r);
+ result.mUpper = max(result.mUpper, p + r);
+ }
+ return result;
+}
+}
+}
+
+namespace
+{
+template <typename Simd4f, typename SrcIterator>
+void generateSpheres(Simd4f* dIt, const SrcIterator& src, uint32_t count)
+{
+ // have to copy out iterator to ensure alignment is maintained
+ for(SrcIterator sIt = src; 0 < count--; ++sIt, ++dIt)
+ *dIt = max(sMinusFloatMaxXYZ, *sIt); // clamp radius to 0
+}
+
+void generateCones(cloth::ConeData* dst, const cloth::SphereData* sourceSpheres, const cloth::IndexPair* capsuleIndices,
+ uint32_t numCones)
+{
+ cloth::ConeData* cIt = dst;
+ for(const cloth::IndexPair* iIt = capsuleIndices, *iEnd = iIt + numCones; iIt != iEnd; ++iIt, ++cIt)
+ {
+ PxVec4 first = reinterpret_cast<const PxVec4&>(sourceSpheres[iIt->first]);
+ PxVec4 second = reinterpret_cast<const PxVec4&>(sourceSpheres[iIt->second]);
+
+ PxVec4 center = (second + first) * 0.5f;
+ PxVec4 axis = (second - first) * 0.5f;
+
+ float sqrAxisLength = axis.x * axis.x + axis.y * axis.y + axis.z * axis.z;
+ float sqrConeLength = sqrAxisLength - sqr(axis.w);
+
+ float invAxisLength = 1 / sqrtf(sqrAxisLength);
+ float invConeLength = 1 / sqrtf(sqrConeLength);
+
+ if(sqrConeLength <= 0.0f)
+ invAxisLength = invConeLength = 0.0f;
+
+ float axisLength = sqrAxisLength * invAxisLength;
+ float slope = axis.w * invConeLength;
+
+ cIt->center = PxVec3(center.x, center.y, center.z);
+ cIt->radius = (axis.w + first.w) * invConeLength * axisLength;
+ cIt->axis = PxVec3(axis.x, axis.y, axis.z) * invAxisLength;
+ cIt->slope = slope;
+
+ cIt->sqrCosine = 1.0f - sqr(axis.w * invAxisLength);
+ cIt->halfLength = axisLength;
+
+ uint32_t firstMask = 0x1u << iIt->first;
+ cIt->firstMask = firstMask;
+ cIt->bothMask = firstMask | 0x1u << iIt->second;
+ }
+}
+
+template <typename Simd4f, typename SrcIterator>
+void generatePlanes(Simd4f* dIt, const SrcIterator& src, uint32_t count)
+{
+ // have to copy out iterator to ensure alignment is maintained
+ for(SrcIterator sIt = src; 0 < count--; ++sIt, ++dIt)
+ *dIt = *sIt;
+}
+
+template <typename Simd4f, typename SrcIterator>
+void generateTriangles(cloth::TriangleData* dIt, const SrcIterator& src, uint32_t count)
+{
+ // have to copy out iterator to ensure alignment is maintained
+ for(SrcIterator sIt = src; 0 < count--; ++dIt)
+ {
+ Simd4f p0 = *sIt;
+ ++sIt;
+ Simd4f p1 = *sIt;
+ ++sIt;
+ Simd4f p2 = *sIt;
+ ++sIt;
+
+ Simd4f edge0 = p1 - p0;
+ Simd4f edge1 = p2 - p0;
+ Simd4f normal = cross3(edge0, edge1);
+
+ Simd4f edge0SqrLength = dot3(edge0, edge0);
+ Simd4f edge1SqrLength = dot3(edge1, edge1);
+ Simd4f edge0DotEdge1 = dot3(edge0, edge1);
+ Simd4f normalInvLength = rsqrt(dot3(normal, normal));
+
+ Simd4f det = edge0SqrLength * edge1SqrLength - edge0DotEdge1 * edge0DotEdge1;
+ Simd4f denom = edge0SqrLength + edge1SqrLength - edge0DotEdge1 - edge0DotEdge1;
+
+ // there are definitely faster ways...
+ Simd4f aux = select(sMaskX, det, denom);
+ aux = select(sMaskZ, edge0SqrLength, aux);
+ aux = select(sMaskW, edge1SqrLength, aux);
+
+ storeAligned(&dIt->base.x, select(sMaskW, edge0DotEdge1, p0));
+ storeAligned(&dIt->edge0.x, select(sMaskW, edge0SqrLength, edge0));
+ storeAligned(&dIt->edge1.x, select(sMaskW, edge1SqrLength, edge1));
+ storeAligned(&dIt->normal.x, normal * normalInvLength);
+ storeAligned(&dIt->det, recipT<1>(aux));
+ }
+}
+
+} // namespace
+
+template <typename Simd4f>
+cloth::SwCollision<Simd4f>::CollisionData::CollisionData()
+: mSpheres(0), mCones(0)
+{
+}
+
+template <typename Simd4f>
+cloth::SwCollision<Simd4f>::SwCollision(SwClothData& clothData, SwKernelAllocator& alloc, profile::PxProfileZone* profiler)
+: mClothData(clothData), mAllocator(alloc), mProfiler(profiler)
+{
+ allocate(mCurData);
+
+ if(mClothData.mEnableContinuousCollision || mClothData.mFrictionScale > 0.0f)
+ {
+ allocate(mPrevData);
+
+ generateSpheres(reinterpret_cast<Simd4f*>(mPrevData.mSpheres),
+ reinterpret_cast<const Simd4f*>(clothData.mStartCollisionSpheres), clothData.mNumSpheres);
+
+ generateCones(mPrevData.mCones, mPrevData.mSpheres, clothData.mCapsuleIndices, clothData.mNumCapsules);
+ }
+}
+
+template <typename Simd4f>
+cloth::SwCollision<Simd4f>::~SwCollision()
+{
+ deallocate(mCurData);
+ deallocate(mPrevData);
+}
+
+template <typename Simd4f>
+void cloth::SwCollision<Simd4f>::operator()(const IterationState<Simd4f>& state)
+{
+ mNumCollisions = 0;
+
+ collideConvexes(state); // discrete convex collision, no friction
+ collideTriangles(state); // discrete triangle collision, no friction
+
+ computeBounds();
+
+ if(!mClothData.mNumSpheres)
+ return;
+
+ bool lastIteration = state.mRemainingIterations == 1;
+
+ const Simd4f* targetSpheres = reinterpret_cast<const Simd4f*>(mClothData.mTargetCollisionSpheres);
+
+ // generate sphere and cone collision data
+ if(!lastIteration)
+ {
+ // interpolate spheres
+ LerpIterator<Simd4f, const Simd4f*> pIter(reinterpret_cast<const Simd4f*>(mClothData.mStartCollisionSpheres),
+ targetSpheres, state.getCurrentAlpha());
+ generateSpheres(reinterpret_cast<Simd4f*>(mCurData.mSpheres), pIter, mClothData.mNumSpheres);
+ }
+ else
+ {
+ // otherwise use the target spheres directly
+ generateSpheres(reinterpret_cast<Simd4f*>(mCurData.mSpheres), targetSpheres, mClothData.mNumSpheres);
+ }
+
+ // generate cones even if test below fails because
+ // continuous collision might need it in next iteration
+ generateCones(mCurData.mCones, mCurData.mSpheres, mClothData.mCapsuleIndices, mClothData.mNumCapsules);
+
+ if(buildAcceleration())
+ {
+ if(mClothData.mEnableContinuousCollision)
+ collideContinuousParticles();
+
+ mergeAcceleration((uint32_t*)mSphereGrid);
+ mergeAcceleration((uint32_t*)mConeGrid);
+
+ if(!mClothData.mEnableContinuousCollision)
+ collideParticles();
+
+ collideVirtualParticles();
+ }
+
+ if(mPrevData.mSpheres)
+ nvidia::swap(mCurData, mPrevData);
+}
+
+template <typename Simd4f>
+size_t cloth::SwCollision<Simd4f>::estimateTemporaryMemory(const SwCloth& cloth)
+{
+ size_t numTriangles = cloth.mStartCollisionTriangles.size();
+ size_t numPlanes = cloth.mStartCollisionPlanes.size();
+
+ const size_t kTriangleDataSize = sizeof(TriangleData) * numTriangles;
+ const size_t kPlaneDataSize = sizeof(PxVec4) * numPlanes * 2;
+
+ return PxMax(kTriangleDataSize, kPlaneDataSize);
+}
+
+template <typename Simd4f>
+size_t cloth::SwCollision<Simd4f>::estimatePersistentMemory(const SwCloth& cloth)
+{
+ size_t numCapsules = cloth.mCapsuleIndices.size();
+ size_t numSpheres = cloth.mStartCollisionSpheres.size();
+
+ size_t sphereDataSize = sizeof(SphereData) * numSpheres * 2;
+ size_t coneDataSize = sizeof(ConeData) * numCapsules * 2;
+
+ return sphereDataSize + coneDataSize;
+}
+
+template <typename Simd4f>
+void cloth::SwCollision<Simd4f>::allocate(CollisionData& data)
+{
+ data.mSpheres = static_cast<SphereData*>(mAllocator.allocate(sizeof(SphereData) * mClothData.mNumSpheres));
+
+ data.mCones = static_cast<ConeData*>(mAllocator.allocate(sizeof(ConeData) * mClothData.mNumCapsules));
+}
+
+template <typename Simd4f>
+void cloth::SwCollision<Simd4f>::deallocate(const CollisionData& data)
+{
+ mAllocator.deallocate(data.mSpheres);
+ mAllocator.deallocate(data.mCones);
+}
+
+template <typename Simd4f>
+void cloth::SwCollision<Simd4f>::computeBounds()
+{
+#if PX_PROFILE
+ ProfileZone zone("cloth::SwSolverKernel::computeBounds", mProfiler);
+#endif
+
+ Simd4f* prevIt = reinterpret_cast<Simd4f*>(mClothData.mPrevParticles);
+ Simd4f* curIt = reinterpret_cast<Simd4f*>(mClothData.mCurParticles);
+ Simd4f* curEnd = curIt + mClothData.mNumParticles;
+ Simd4f floatMaxXYZ = -(Simd4f)sMinusFloatMaxXYZ;
+
+ Simd4f lower = simd4f(FLT_MAX), upper = -lower;
+ for(; curIt < curEnd; ++curIt, ++prevIt)
+ {
+ Simd4f current = *curIt;
+ lower = min(lower, current);
+ upper = max(upper, current);
+ // if(current.w > 0) current.w = previous.w
+ *curIt = select(current > floatMaxXYZ, *prevIt, current);
+ }
+
+ BoundingBox<Simd4f> curBounds;
+ curBounds.mLower = lower;
+ curBounds.mUpper = upper;
+
+ // don't change this order, storeBounds writes 7 floats
+ BoundingBox<Simd4f> prevBounds = loadBounds<Simd4f>(mClothData.mCurBounds);
+ storeBounds(mClothData.mCurBounds, curBounds);
+ storeBounds(mClothData.mPrevBounds, prevBounds);
+}
+
+namespace
+{
+template <typename Simd4i>
+Simd4i andNotIsZero(const Simd4i& left, const Simd4i& right)
+{
+ return simdi::operator==(left & ~right, simd4i(_0));
+}
+}
+
+// build per-axis mask arrays of spheres on the right/left of grid cell
+template <typename Simd4f>
+void cloth::SwCollision<Simd4f>::buildSphereAcceleration(const SphereData* sIt)
+{
+ static const int maxIndex = sGridSize - 1;
+
+ const SphereData* sEnd = sIt + mClothData.mNumSpheres;
+ for(uint32_t mask = 0x1; sIt != sEnd; ++sIt, mask <<= 1)
+ {
+ Simd4f sphere = loadAligned(array(sIt->center));
+ Simd4f radius = splat<3>(sphere);
+
+ Simd4i first = intFloor(max((sphere - radius) * mGridScale + mGridBias, sZero));
+ Simd4i last = intFloor(min((sphere + radius) * mGridScale + mGridBias, sGridLength));
+
+ const int* firstIdx = simdi::array(first);
+ const int* lastIdx = simdi::array(last);
+
+ uint32_t* firstIt = (uint32_t*)mSphereGrid;
+ uint32_t* lastIt = firstIt + 3 * sGridSize;
+
+ for(uint32_t i = 0; i < 3; ++i, firstIt += sGridSize, lastIt += sGridSize)
+ {
+ for(int j = firstIdx[i]; j <= maxIndex; ++j)
+ firstIt[j] |= mask;
+
+ for(int j = lastIdx[i]; j >= 0; --j)
+ lastIt[j] |= mask;
+ }
+ }
+}
+
+// generate cone masks from sphere masks
+template <typename Simd4f>
+void cloth::SwCollision<Simd4f>::buildConeAcceleration()
+{
+ const ConeData* coneIt = mCurData.mCones;
+ const ConeData* coneEnd = coneIt + mClothData.mNumCapsules;
+ for(uint32_t coneMask = 0x1; coneIt != coneEnd; ++coneIt, coneMask <<= 1)
+ {
+ if(coneIt->radius == 0.0f)
+ continue;
+
+ uint32_t spheresMask = coneIt->bothMask;
+
+ uint32_t* sphereIt = (uint32_t*)mSphereGrid;
+ uint32_t* sphereEnd = sphereIt + 6 * sGridSize;
+ uint32_t* gridIt = (uint32_t*)mConeGrid;
+ for(; sphereIt != sphereEnd; ++sphereIt, ++gridIt)
+ if(*sphereIt & spheresMask)
+ *gridIt |= coneMask;
+ }
+}
+
+// convert right/left mask arrays into single overlap array
+template <typename Simd4f>
+void cloth::SwCollision<Simd4f>::mergeAcceleration(uint32_t* firstIt)
+{
+ uint32_t* firstEnd = firstIt + 3 * sGridSize;
+ uint32_t* lastIt = firstEnd;
+ for(; firstIt != firstEnd; ++firstIt, ++lastIt)
+ *firstIt &= *lastIt;
+}
+
+// build mask of spheres/cones touching a regular grid along each axis
+template <typename Simd4f>
+bool cloth::SwCollision<Simd4f>::buildAcceleration()
+{
+ // determine sphere bbox
+ BoundingBox<Simd4f> sphereBounds =
+ expandBounds(emptyBounds<Simd4f>(), mCurData.mSpheres, mCurData.mSpheres + mClothData.mNumSpheres);
+ BoundingBox<Simd4f> particleBounds = loadBounds<Simd4f>(mClothData.mCurBounds);
+ if(mClothData.mEnableContinuousCollision)
+ {
+ sphereBounds = expandBounds(sphereBounds, mPrevData.mSpheres, mPrevData.mSpheres + mClothData.mNumSpheres);
+ particleBounds = expandBounds(particleBounds, loadBounds<Simd4f>(mClothData.mPrevBounds));
+ }
+
+ BoundingBox<Simd4f> bounds = intersectBounds(sphereBounds, particleBounds);
+ Simd4f edgeLength = (bounds.mUpper - bounds.mLower) & ~(Simd4f)sMaskW;
+ if(!allGreaterEqual(edgeLength, simd4f(_0)))
+ return false;
+
+ // calculate an expanded bounds to account for numerical inaccuracy
+ const Simd4f expandedLower = bounds.mLower - abs(bounds.mLower) * sGridExpand;
+ const Simd4f expandedUpper = bounds.mUpper + abs(bounds.mUpper) * sGridExpand;
+ const Simd4f expandedEdgeLength = max(expandedUpper - expandedLower, sEpsilon);
+
+ // make grid minimal thickness and strict upper bound of spheres
+ mGridScale = sGridLength * recipT<1>(expandedEdgeLength);
+ mGridBias = -expandedLower * mGridScale;
+ array(mGridBias)[3] = 1.0f; // needed for collideVirtualParticles()
+
+ PX_ASSERT(allTrue(((bounds.mLower * mGridScale + mGridBias) >= simd4f(0.0f)) | sMaskW));
+ PX_ASSERT(allTrue(((bounds.mUpper * mGridScale + mGridBias) < simd4f(8.0f)) | sMaskW));
+
+ memset(mSphereGrid, 0, sizeof(uint32_t) * 6 * (sGridSize));
+ if(mClothData.mEnableContinuousCollision)
+ buildSphereAcceleration(mPrevData.mSpheres);
+ buildSphereAcceleration(mCurData.mSpheres);
+
+ memset(mConeGrid, 0, sizeof(uint32_t) * 6 * (sGridSize));
+ buildConeAcceleration();
+
+ return true;
+}
+
+#ifdef _MSC_VER
+#define FORCE_INLINE __forceinline
+#else
+#define FORCE_INLINE inline __attribute__((always_inline))
+#endif
+
+template <typename Simd4f>
+FORCE_INLINE typename cloth::SwCollision<Simd4f>::ShapeMask& cloth::SwCollision<Simd4f>::ShapeMask::
+operator=(const ShapeMask& right)
+{
+ mCones = right.mCones;
+ mSpheres = right.mSpheres;
+ return *this;
+}
+
+template <typename Simd4f>
+FORCE_INLINE typename cloth::SwCollision<Simd4f>::ShapeMask& cloth::SwCollision<Simd4f>::ShapeMask::
+operator&=(const ShapeMask& right)
+{
+ mCones = mCones & right.mCones;
+ mSpheres = mSpheres & right.mSpheres;
+ return *this;
+}
+
+template <typename Simd4f>
+FORCE_INLINE typename cloth::SwCollision<Simd4f>::ShapeMask
+cloth::SwCollision<Simd4f>::getShapeMask(const Simd4f& position, const Simd4i* __restrict sphereGrid,
+ const Simd4i* __restrict coneGrid)
+{
+ Gather<Simd4i> gather(intFloor(position));
+
+ ShapeMask result;
+ result.mCones = gather(coneGrid);
+ result.mSpheres = gather(sphereGrid);
+ return result;
+}
+
+// lookup acceleration structure and return mask of potential intersectors
+template <typename Simd4f>
+FORCE_INLINE typename cloth::SwCollision<Simd4f>::ShapeMask
+cloth::SwCollision<Simd4f>::getShapeMask(const Simd4f* __restrict positions) const
+{
+ Simd4f posX = positions[0] * splat<0>(mGridScale) + splat<0>(mGridBias);
+ Simd4f posY = positions[1] * splat<1>(mGridScale) + splat<1>(mGridBias);
+ Simd4f posZ = positions[2] * splat<2>(mGridScale) + splat<2>(mGridBias);
+
+ ShapeMask result = getShapeMask(posX, mSphereGrid, mConeGrid);
+ result &= getShapeMask(posY, mSphereGrid + 2, mConeGrid + 2);
+ result &= getShapeMask(posZ, mSphereGrid + 4, mConeGrid + 4);
+
+ return result;
+}
+
+// lookup acceleration structure and return mask of potential intersectors
+template <typename Simd4f>
+FORCE_INLINE typename cloth::SwCollision<Simd4f>::ShapeMask
+cloth::SwCollision<Simd4f>::getShapeMask(const Simd4f* __restrict prevPos, const Simd4f* __restrict curPos) const
+{
+ Simd4f scaleX = splat<0>(mGridScale);
+ Simd4f scaleY = splat<1>(mGridScale);
+ Simd4f scaleZ = splat<2>(mGridScale);
+
+ Simd4f biasX = splat<0>(mGridBias);
+ Simd4f biasY = splat<1>(mGridBias);
+ Simd4f biasZ = splat<2>(mGridBias);
+
+ Simd4f prevX = prevPos[0] * scaleX + biasX;
+ Simd4f prevY = prevPos[1] * scaleY + biasY;
+ Simd4f prevZ = prevPos[2] * scaleZ + biasZ;
+
+ Simd4f curX = curPos[0] * scaleX + biasX;
+ Simd4f curY = curPos[1] * scaleY + biasY;
+ Simd4f curZ = curPos[2] * scaleZ + biasZ;
+
+ Simd4f maxX = min(max(prevX, curX), sGridLength);
+ Simd4f maxY = min(max(prevY, curY), sGridLength);
+ Simd4f maxZ = min(max(prevZ, curZ), sGridLength);
+
+ ShapeMask result = getShapeMask(maxX, mSphereGrid, mConeGrid);
+ result &= getShapeMask(maxY, mSphereGrid + 2, mConeGrid + 2);
+ result &= getShapeMask(maxZ, mSphereGrid + 4, mConeGrid + 4);
+
+ Simd4f zero = simd4f(_0);
+ Simd4f minX = max(min(prevX, curX), zero);
+ Simd4f minY = max(min(prevY, curY), zero);
+ Simd4f minZ = max(min(prevZ, curZ), zero);
+
+ result &= getShapeMask(minX, mSphereGrid + 6, mConeGrid + 6);
+ result &= getShapeMask(minY, mSphereGrid + 8, mConeGrid + 8);
+ result &= getShapeMask(minZ, mSphereGrid + 10, mConeGrid + 10);
+
+ return result;
+}
+
+template <typename Simd4f>
+struct cloth::SwCollision<Simd4f>::ImpulseAccumulator
+{
+ ImpulseAccumulator()
+ : mDeltaX(simd4f(_0))
+ , mDeltaY(mDeltaX)
+ , mDeltaZ(mDeltaX)
+ , mVelX(mDeltaX)
+ , mVelY(mDeltaX)
+ , mVelZ(mDeltaX)
+ , mNumCollisions(sEpsilon)
+ {
+ }
+
+ void add(const Simd4f& x, const Simd4f& y, const Simd4f& z, const Simd4f& scale, const Simd4f& mask)
+ {
+ PX_ASSERT(allTrue((mask & x) == (mask & x)));
+ PX_ASSERT(allTrue((mask & y) == (mask & y)));
+ PX_ASSERT(allTrue((mask & z) == (mask & z)));
+ PX_ASSERT(allTrue((mask & scale) == (mask & scale)));
+
+ Simd4f maskedScale = scale & mask;
+ mDeltaX = mDeltaX + x * maskedScale;
+ mDeltaY = mDeltaY + y * maskedScale;
+ mDeltaZ = mDeltaZ + z * maskedScale;
+ mNumCollisions = mNumCollisions + (simd4f(_1) & mask);
+ }
+
+ void addVelocity(const Simd4f& vx, const Simd4f& vy, const Simd4f& vz, const Simd4f& mask)
+ {
+ PX_ASSERT(allTrue((mask & vx) == (mask & vx)));
+ PX_ASSERT(allTrue((mask & vy) == (mask & vy)));
+ PX_ASSERT(allTrue((mask & vz) == (mask & vz)));
+
+ mVelX = mVelX + (vx & mask);
+ mVelY = mVelY + (vy & mask);
+ mVelZ = mVelZ + (vz & mask);
+ }
+
+ void subtract(const Simd4f& x, const Simd4f& y, const Simd4f& z, const Simd4f& scale, const Simd4f& mask)
+ {
+ PX_ASSERT(allTrue((mask & x) == (mask & x)));
+ PX_ASSERT(allTrue((mask & y) == (mask & y)));
+ PX_ASSERT(allTrue((mask & z) == (mask & z)));
+ PX_ASSERT(allTrue((mask & scale) == (mask & scale)));
+
+ Simd4f maskedScale = scale & mask;
+ mDeltaX = mDeltaX - x * maskedScale;
+ mDeltaY = mDeltaY - y * maskedScale;
+ mDeltaZ = mDeltaZ - z * maskedScale;
+ mNumCollisions = mNumCollisions + (simd4f(_1) & mask);
+ }
+
+ Simd4f mDeltaX, mDeltaY, mDeltaZ;
+ Simd4f mVelX, mVelY, mVelZ;
+ Simd4f mNumCollisions;
+};
+
+template <typename Simd4f>
+FORCE_INLINE void cloth::SwCollision<Simd4f>::collideSpheres(const Simd4i& sphereMask, const Simd4f* positions,
+ ImpulseAccumulator& accum) const
+{
+ const float* __restrict spherePtr = array(mCurData.mSpheres->center);
+
+ bool frictionEnabled = mClothData.mFrictionScale > 0.0f;
+
+ Simd4i mask4 = horizontalOr(sphereMask);
+ uint32_t mask = uint32_t(simdi::array(mask4)[0]);
+ while(mask)
+ {
+ uint32_t test = mask - 1;
+ uint32_t offset = findBitSet(mask & ~test) * sizeof(SphereData);
+ mask = mask & test;
+
+ Simd4f sphere = loadAligned(spherePtr, offset);
+
+ Simd4f deltaX = positions[0] - splat<0>(sphere);
+ Simd4f deltaY = positions[1] - splat<1>(sphere);
+ Simd4f deltaZ = positions[2] - splat<2>(sphere);
+
+ Simd4f sqrDistance = sEpsilon + deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
+ Simd4f negativeScale = simd4f(_1) - rsqrt(sqrDistance) * splat<3>(sphere);
+
+ Simd4f contactMask;
+ if(!anyGreater(simd4f(_0), negativeScale, contactMask))
+ continue;
+
+ accum.subtract(deltaX, deltaY, deltaZ, negativeScale, contactMask);
+
+ if(frictionEnabled)
+ {
+ // load previous sphere pos
+ const float* __restrict prevSpherePtr = array(mPrevData.mSpheres->center);
+
+ Simd4f prevSphere = loadAligned(prevSpherePtr, offset);
+ Simd4f velocity = sphere - prevSphere;
+
+ accum.addVelocity(splat<0>(velocity), splat<1>(velocity), splat<2>(velocity), contactMask);
+ }
+ }
+}
+
+template <typename Simd4f>
+FORCE_INLINE typename cloth::SwCollision<Simd4f>::Simd4i
+cloth::SwCollision<Simd4f>::collideCones(const Simd4f* __restrict positions, ImpulseAccumulator& accum) const
+{
+ const float* __restrict centerPtr = array(mCurData.mCones->center);
+ const float* __restrict axisPtr = array(mCurData.mCones->axis);
+ const float* __restrict auxiliaryPtr = &mCurData.mCones->sqrCosine;
+
+ bool frictionEnabled = mClothData.mFrictionScale > 0.0f;
+
+ ShapeMask shapeMask = getShapeMask(positions);
+ Simd4i mask4 = horizontalOr(shapeMask.mCones);
+ uint32_t mask = uint32_t(simdi::array(mask4)[0]);
+ while(mask)
+ {
+ uint32_t test = mask - 1;
+ uint32_t coneIndex = findBitSet(mask & ~test);
+ uint32_t offset = coneIndex * sizeof(ConeData);
+ mask = mask & test;
+
+ Simd4i test4 = simdi::operator-(mask4, simd4i(_1));
+ Simd4f culled = simd4f(andNotIsZero(shapeMask.mCones, test4));
+ mask4 = mask4 & test4;
+
+ Simd4f center = loadAligned(centerPtr, offset);
+
+ Simd4f deltaX = positions[0] - splat<0>(center);
+ Simd4f deltaY = positions[1] - splat<1>(center);
+ Simd4f deltaZ = positions[2] - splat<2>(center);
+
+ Simd4f axis = loadAligned(axisPtr, offset);
+
+ Simd4f axisX = splat<0>(axis);
+ Simd4f axisY = splat<1>(axis);
+ Simd4f axisZ = splat<2>(axis);
+ Simd4f slope = splat<3>(axis);
+
+ Simd4f dot = deltaX * axisX + deltaY * axisY + deltaZ * axisZ;
+ Simd4f radius = dot * slope + splat<3>(center);
+
+ // set radius to zero if cone is culled
+ radius = max(radius, sZero) & ~culled;
+
+ Simd4f sqrDistance = deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ - dot * dot;
+
+ Simd4i auxiliary = simd4i((Simd4f)loadAligned(auxiliaryPtr, offset));
+ Simd4i bothMask = splat<3>(auxiliary);
+
+ Simd4f contactMask;
+ if(!anyGreater(radius * radius, sqrDistance, contactMask))
+ {
+ // cone only culled when spheres culled, ok to clear those too
+ shapeMask.mSpheres = shapeMask.mSpheres & ~bothMask;
+ continue;
+ }
+
+ // clamp to a small positive epsilon to avoid numerical error
+ // making sqrDistance negative when point lies on the cone axis
+ sqrDistance = max(sqrDistance, sEpsilon);
+
+ Simd4f invDistance = rsqrt(sqrDistance);
+ Simd4f base = dot + slope * sqrDistance * invDistance;
+
+ // force left/rightMask to false if not inside cone
+ base = base & contactMask;
+
+ Simd4f halfLength = splat<1>(simd4f(auxiliary));
+ Simd4i leftMask = simd4i(base < -halfLength);
+ Simd4i rightMask = simd4i(base > halfLength);
+
+ // we use both mask because of the early out above.
+ Simd4i firstMask = splat<2>(auxiliary);
+ Simd4i secondMask = firstMask ^ bothMask;
+ shapeMask.mSpheres = shapeMask.mSpheres & ~(firstMask & ~leftMask);
+ shapeMask.mSpheres = shapeMask.mSpheres & ~(secondMask & ~rightMask);
+
+ deltaX = deltaX - base * axisX;
+ deltaY = deltaY - base * axisY;
+ deltaZ = deltaZ - base * axisZ;
+
+ Simd4f sqrCosine = splat<0>(simd4f(auxiliary));
+ Simd4f scale = radius * invDistance * sqrCosine - sqrCosine;
+
+ contactMask = contactMask & ~simd4f(leftMask | rightMask);
+
+ if(!anyTrue(contactMask))
+ continue;
+
+ accum.add(deltaX, deltaY, deltaZ, scale, contactMask);
+
+ if(frictionEnabled)
+ {
+ uint32_t s0 = mClothData.mCapsuleIndices[coneIndex].first;
+ uint32_t s1 = mClothData.mCapsuleIndices[coneIndex].second;
+
+ float* prevSpheres = reinterpret_cast<float*>(mPrevData.mSpheres);
+ float* curSpheres = reinterpret_cast<float*>(mCurData.mSpheres);
+
+ // todo: could pre-compute sphere velocities or it might be
+ // faster to compute cur/prev sphere positions directly
+ Simd4f s0p0 = loadAligned(prevSpheres, s0 * sizeof(SphereData));
+ Simd4f s0p1 = loadAligned(curSpheres, s0 * sizeof(SphereData));
+
+ Simd4f s1p0 = loadAligned(prevSpheres, s1 * sizeof(SphereData));
+ Simd4f s1p1 = loadAligned(curSpheres, s1 * sizeof(SphereData));
+
+ Simd4f v0 = s0p1 - s0p0;
+ Simd4f v1 = s1p1 - s1p0;
+ Simd4f vd = v1 - v0;
+
+ // dot is in the range -1 to 1, scale and bias to 0 to 1
+ dot = dot * sHalf + sHalf;
+
+ // interpolate velocity at contact points
+ Simd4f vx = splat<0>(v0) + dot * splat<0>(vd);
+ Simd4f vy = splat<1>(v0) + dot * splat<1>(vd);
+ Simd4f vz = splat<2>(v0) + dot * splat<2>(vd);
+
+ accum.addVelocity(vx, vy, vz, contactMask);
+ }
+ }
+
+ return shapeMask.mSpheres;
+}
+
+template <typename Simd4f>
+FORCE_INLINE void cloth::SwCollision<Simd4f>::collideSpheres(const Simd4i& sphereMask, const Simd4f* __restrict prevPos,
+ Simd4f* __restrict curPos, ImpulseAccumulator& accum) const
+{
+ const float* __restrict prevSpheres = array(mPrevData.mSpheres->center);
+ const float* __restrict curSpheres = array(mCurData.mSpheres->center);
+
+ bool frictionEnabled = mClothData.mFrictionScale > 0.0f;
+
+ Simd4i mask4 = horizontalOr(sphereMask);
+ uint32_t mask = uint32_t(simdi::array(mask4)[0]);
+ while(mask)
+ {
+ uint32_t test = mask - 1;
+ uint32_t offset = findBitSet(mask & ~test) * sizeof(SphereData);
+ mask = mask & test;
+
+ Simd4f prevSphere = loadAligned(prevSpheres, offset);
+ Simd4f prevX = prevPos[0] - splat<0>(prevSphere);
+ Simd4f prevY = prevPos[1] - splat<1>(prevSphere);
+ Simd4f prevZ = prevPos[2] - splat<2>(prevSphere);
+ Simd4f prevRadius = splat<3>(prevSphere);
+
+ Simd4f curSphere = loadAligned(curSpheres, offset);
+ Simd4f curX = curPos[0] - splat<0>(curSphere);
+ Simd4f curY = curPos[1] - splat<1>(curSphere);
+ Simd4f curZ = curPos[2] - splat<2>(curSphere);
+ Simd4f curRadius = splat<3>(curSphere);
+
+ Simd4f sqrDistance = sEpsilon + curX * curX + curY * curY + curZ * curZ;
+
+ Simd4f dotPrevPrev = prevX * prevX + prevY * prevY + prevZ * prevZ - prevRadius * prevRadius;
+ Simd4f dotPrevCur = prevX * curX + prevY * curY + prevZ * curZ - prevRadius * curRadius;
+ Simd4f dotCurCur = sqrDistance - curRadius * curRadius;
+
+ Simd4f discriminant = dotPrevCur * dotPrevCur - dotCurCur * dotPrevPrev;
+ Simd4f sqrtD = sqrt(discriminant);
+ Simd4f halfB = dotPrevCur - dotPrevPrev;
+ Simd4f minusA = dotPrevCur - dotCurCur + halfB;
+
+ // time of impact or 0 if prevPos inside sphere
+ Simd4f toi = recip(minusA) * min(simd4f(_0), halfB + sqrtD);
+ Simd4f collisionMask = (toi < simd4f(_1)) & (halfB < sqrtD);
+
+ // skip continuous collision if the (un-clamped) particle
+ // trajectory only touches the outer skin of the cone.
+ Simd4f rMin = prevRadius + halfB * minusA * (curRadius - prevRadius);
+ collisionMask = collisionMask & (discriminant > minusA * rMin * rMin * sSkeletonWidth);
+
+ // a is negative when one sphere is contained in the other,
+ // which is already handled by discrete collision.
+ collisionMask = collisionMask & (minusA < -(Simd4f)sEpsilon);
+
+ if(!allEqual(collisionMask, simd4f(_0)))
+ {
+ Simd4f deltaX = prevX - curX;
+ Simd4f deltaY = prevY - curY;
+ Simd4f deltaZ = prevZ - curZ;
+
+ Simd4f oneMinusToi = (simd4f(_1) - toi) & collisionMask;
+
+ // reduce ccd impulse if (clamped) particle trajectory stays in sphere skin,
+ // i.e. scale by exp2(-k) or 1/(1+k) with k = (tmin - toi) / (1 - toi)
+ Simd4f minusK = sqrtD * recip(minusA * oneMinusToi) & (oneMinusToi > sEpsilon);
+ oneMinusToi = oneMinusToi * recip(sOne - minusK);
+
+ curX = curX + deltaX * oneMinusToi;
+ curY = curY + deltaY * oneMinusToi;
+ curZ = curZ + deltaZ * oneMinusToi;
+
+ curPos[0] = splat<0>(curSphere) + curX;
+ curPos[1] = splat<1>(curSphere) + curY;
+ curPos[2] = splat<2>(curSphere) + curZ;
+
+ sqrDistance = sEpsilon + curX * curX + curY * curY + curZ * curZ;
+ }
+
+ Simd4f negativeScale = simd4f(_1) - rsqrt(sqrDistance) * curRadius;
+
+ Simd4f contactMask;
+ if(!anyGreater(simd4f(_0), negativeScale, contactMask))
+ continue;
+
+ accum.subtract(curX, curY, curZ, negativeScale, contactMask);
+
+ if(frictionEnabled)
+ {
+ Simd4f velocity = curSphere - prevSphere;
+ accum.addVelocity(splat<0>(velocity), splat<1>(velocity), splat<2>(velocity), contactMask);
+ }
+ }
+}
+
+template <typename Simd4f>
+FORCE_INLINE typename cloth::SwCollision<Simd4f>::Simd4i
+cloth::SwCollision<Simd4f>::collideCones(const Simd4f* __restrict prevPos, Simd4f* __restrict curPos,
+ ImpulseAccumulator& accum) const
+{
+ const float* __restrict prevCenterPtr = array(mPrevData.mCones->center);
+ const float* __restrict prevAxisPtr = array(mPrevData.mCones->axis);
+ const float* __restrict prevAuxiliaryPtr = &mPrevData.mCones->sqrCosine;
+
+ const float* __restrict curCenterPtr = array(mCurData.mCones->center);
+ const float* __restrict curAxisPtr = array(mCurData.mCones->axis);
+ const float* __restrict curAuxiliaryPtr = &mCurData.mCones->sqrCosine;
+
+ bool frictionEnabled = mClothData.mFrictionScale > 0.0f;
+
+ ShapeMask shapeMask = getShapeMask(prevPos, curPos);
+ Simd4i mask4 = horizontalOr(shapeMask.mCones);
+ uint32_t mask = uint32_t(simdi::array(mask4)[0]);
+ while(mask)
+ {
+ uint32_t test = mask - 1;
+ uint32_t coneIndex = findBitSet(mask & ~test);
+ uint32_t offset = coneIndex * sizeof(ConeData);
+ mask = mask & test;
+
+ Simd4i test4 = simdi::operator-(mask4, simd4i(_1));
+ Simd4f culled = simd4f(andNotIsZero(shapeMask.mCones, test4));
+ mask4 = mask4 & test4;
+
+ Simd4f prevCenter = loadAligned(prevCenterPtr, offset);
+ Simd4f prevAxis = loadAligned(prevAxisPtr, offset);
+ Simd4f prevAxisX = splat<0>(prevAxis);
+ Simd4f prevAxisY = splat<1>(prevAxis);
+ Simd4f prevAxisZ = splat<2>(prevAxis);
+ Simd4f prevSlope = splat<3>(prevAxis);
+
+ Simd4f prevX = prevPos[0] - splat<0>(prevCenter);
+ Simd4f prevY = prevPos[1] - splat<1>(prevCenter);
+ Simd4f prevZ = prevPos[2] - splat<2>(prevCenter);
+ Simd4f prevT = prevY * prevAxisZ - prevZ * prevAxisY;
+ Simd4f prevU = prevZ * prevAxisX - prevX * prevAxisZ;
+ Simd4f prevV = prevX * prevAxisY - prevY * prevAxisX;
+ Simd4f prevDot = prevX * prevAxisX + prevY * prevAxisY + prevZ * prevAxisZ;
+ Simd4f prevRadius = prevDot * prevSlope + splat<3>(prevCenter);
+
+ Simd4f curCenter = loadAligned(curCenterPtr, offset);
+ Simd4f curAxis = loadAligned(curAxisPtr, offset);
+ Simd4f curAxisX = splat<0>(curAxis);
+ Simd4f curAxisY = splat<1>(curAxis);
+ Simd4f curAxisZ = splat<2>(curAxis);
+ Simd4f curSlope = splat<3>(curAxis);
+ Simd4i curAuxiliary = simd4i((Simd4f)loadAligned(curAuxiliaryPtr, offset));
+
+ Simd4f curX = curPos[0] - splat<0>(curCenter);
+ Simd4f curY = curPos[1] - splat<1>(curCenter);
+ Simd4f curZ = curPos[2] - splat<2>(curCenter);
+ Simd4f curT = curY * curAxisZ - curZ * curAxisY;
+ Simd4f curU = curZ * curAxisX - curX * curAxisZ;
+ Simd4f curV = curX * curAxisY - curY * curAxisX;
+ Simd4f curDot = curX * curAxisX + curY * curAxisY + curZ * curAxisZ;
+ Simd4f curRadius = curDot * curSlope + splat<3>(curCenter);
+
+ Simd4f curSqrDistance = sEpsilon + curT * curT + curU * curU + curV * curV;
+
+ // set radius to zero if cone is culled
+ prevRadius = max(prevRadius, simd4f(_0)) & ~culled;
+ curRadius = max(curRadius, simd4f(_0)) & ~culled;
+
+ Simd4f dotPrevPrev = prevT * prevT + prevU * prevU + prevV * prevV - prevRadius * prevRadius;
+ Simd4f dotPrevCur = prevT * curT + prevU * curU + prevV * curV - prevRadius * curRadius;
+ Simd4f dotCurCur = curSqrDistance - curRadius * curRadius;
+
+ Simd4f discriminant = dotPrevCur * dotPrevCur - dotCurCur * dotPrevPrev;
+ Simd4f sqrtD = sqrt(discriminant);
+ Simd4f halfB = dotPrevCur - dotPrevPrev;
+ Simd4f minusA = dotPrevCur - dotCurCur + halfB;
+
+ // time of impact or 0 if prevPos inside cone
+ Simd4f toi = recip(minusA) * min(simd4f(_0), halfB + sqrtD);
+ Simd4f collisionMask = (toi < simd4f(_1)) & (halfB < sqrtD);
+
+ // skip continuous collision if the (un-clamped) particle
+ // trajectory only touches the outer skin of the cone.
+ Simd4f rMin = prevRadius + halfB * minusA * (curRadius - prevRadius);
+ collisionMask = collisionMask & (discriminant > minusA * rMin * rMin * sSkeletonWidth);
+
+ // a is negative when one cone is contained in the other,
+ // which is already handled by discrete collision.
+ collisionMask = collisionMask & (minusA < -(Simd4f)sEpsilon);
+
+ // test if any particle hits infinite cone (and 0<time of impact<1)
+ if(!allEqual(collisionMask, simd4f(_0)))
+ {
+ Simd4f deltaX = prevX - curX;
+ Simd4f deltaY = prevY - curY;
+ Simd4f deltaZ = prevZ - curZ;
+
+ // interpolate delta at toi
+ Simd4f posX = prevX - deltaX * toi;
+ Simd4f posY = prevY - deltaY * toi;
+ Simd4f posZ = prevZ - deltaZ * toi;
+
+ Simd4f curScaledAxis = curAxis * splat<1>(simd4f(curAuxiliary));
+ Simd4i prevAuxiliary = simd4i((Simd4f)loadAligned(prevAuxiliaryPtr, offset));
+ Simd4f deltaScaledAxis = curScaledAxis - prevAxis * splat<1>(simd4f(prevAuxiliary));
+
+ Simd4f oneMinusToi = simd4f(_1) - toi;
+
+ // interpolate axis at toi
+ Simd4f axisX = splat<0>(curScaledAxis) - splat<0>(deltaScaledAxis) * oneMinusToi;
+ Simd4f axisY = splat<1>(curScaledAxis) - splat<1>(deltaScaledAxis) * oneMinusToi;
+ Simd4f axisZ = splat<2>(curScaledAxis) - splat<2>(deltaScaledAxis) * oneMinusToi;
+ Simd4f slope = (prevSlope * oneMinusToi + curSlope * toi);
+
+ Simd4f sqrHalfLength = axisX * axisX + axisY * axisY + axisZ * axisZ;
+ Simd4f invHalfLength = rsqrt(sqrHalfLength);
+ Simd4f dot = (posX * axisX + posY * axisY + posZ * axisZ) * invHalfLength;
+
+ Simd4f sqrDistance = posX * posX + posY * posY + posZ * posZ - dot * dot;
+ Simd4f invDistance = rsqrt(sqrDistance) & (sqrDistance > simd4f(_0));
+
+ Simd4f base = dot + slope * sqrDistance * invDistance;
+ Simd4f scale = base * invHalfLength & collisionMask;
+
+ Simd4f cullMask = (abs(scale) < simd4f(_1)) & collisionMask;
+
+ // test if any impact position is in cone section
+ if(!allEqual(cullMask, simd4f(_0)))
+ {
+ deltaX = deltaX + splat<0>(deltaScaledAxis) * scale;
+ deltaY = deltaY + splat<1>(deltaScaledAxis) * scale;
+ deltaZ = deltaZ + splat<2>(deltaScaledAxis) * scale;
+
+ oneMinusToi = oneMinusToi & cullMask;
+
+ // reduce ccd impulse if (clamped) particle trajectory stays in cone skin,
+ // i.e. scale by exp2(-k) or 1/(1+k) with k = (tmin - toi) / (1 - toi)
+ // oneMinusToi = oneMinusToi * recip(sOne - sqrtD * recip(minusA * oneMinusToi));
+ Simd4f minusK = sqrtD * recip(minusA * oneMinusToi) & (oneMinusToi > sEpsilon);
+ oneMinusToi = oneMinusToi * recip(sOne - minusK);
+
+ curX = curX + deltaX * oneMinusToi;
+ curY = curY + deltaY * oneMinusToi;
+ curZ = curZ + deltaZ * oneMinusToi;
+
+ curDot = curX * curAxisX + curY * curAxisY + curZ * curAxisZ;
+ curRadius = curDot * curSlope + splat<3>(curCenter);
+ curRadius = max(curRadius, simd4f(_0)) & ~culled;
+ curSqrDistance = curX * curX + curY * curY + curZ * curZ - curDot * curDot;
+
+ curPos[0] = splat<0>(curCenter) + curX;
+ curPos[1] = splat<1>(curCenter) + curY;
+ curPos[2] = splat<2>(curCenter) + curZ;
+ }
+ }
+
+ // curPos inside cone (discrete collision)
+ Simd4f contactMask;
+ int anyContact = anyGreater(curRadius * curRadius, curSqrDistance, contactMask);
+
+ Simd4i bothMask = splat<3>(curAuxiliary);
+
+ // instead of culling continuous collision for ~collisionMask, and discrete
+ // collision for ~contactMask, disable both if ~collisionMask & ~contactMask
+ Simd4i cullMask = bothMask & ~simd4i(collisionMask | contactMask);
+ shapeMask.mSpheres = shapeMask.mSpheres & ~cullMask;
+
+ if(!anyContact)
+ continue;
+
+ Simd4f invDistance = rsqrt(curSqrDistance) & (curSqrDistance > sZero);
+ Simd4f base = curDot + curSlope * curSqrDistance * invDistance;
+
+ Simd4f halfLength = splat<1>(simd4f(curAuxiliary));
+ Simd4i leftMask = simd4i(base < -halfLength);
+ Simd4i rightMask = simd4i(base > halfLength);
+
+ // can only skip continuous sphere collision if post-ccd position
+ // is on code side *and* particle had cone-ccd collision.
+ Simd4i firstMask = splat<2>(curAuxiliary);
+ Simd4i secondMask = firstMask ^ bothMask;
+ cullMask = (firstMask & ~leftMask) | (secondMask & ~rightMask);
+ shapeMask.mSpheres = shapeMask.mSpheres & ~(cullMask & simd4i(collisionMask));
+
+ Simd4f deltaX = curX - base * curAxisX;
+ Simd4f deltaY = curY - base * curAxisY;
+ Simd4f deltaZ = curZ - base * curAxisZ;
+
+ Simd4f sqrCosine = splat<0>(simd4f(curAuxiliary));
+ Simd4f scale = curRadius * invDistance * sqrCosine - sqrCosine;
+
+ contactMask = contactMask & ~simd4f(leftMask | rightMask);
+
+ if(!anyTrue(contactMask))
+ continue;
+
+ accum.add(deltaX, deltaY, deltaZ, scale, contactMask);
+
+ if(frictionEnabled)
+ {
+ uint32_t s0 = mClothData.mCapsuleIndices[coneIndex].first;
+ uint32_t s1 = mClothData.mCapsuleIndices[coneIndex].second;
+
+ float* prevSpheres = reinterpret_cast<float*>(mPrevData.mSpheres);
+ float* curSpheres = reinterpret_cast<float*>(mCurData.mSpheres);
+
+ // todo: could pre-compute sphere velocities or it might be
+ // faster to compute cur/prev sphere positions directly
+ Simd4f s0p0 = loadAligned(prevSpheres, s0 * sizeof(SphereData));
+ Simd4f s0p1 = loadAligned(curSpheres, s0 * sizeof(SphereData));
+
+ Simd4f s1p0 = loadAligned(prevSpheres, s1 * sizeof(SphereData));
+ Simd4f s1p1 = loadAligned(curSpheres, s1 * sizeof(SphereData));
+
+ Simd4f v0 = s0p1 - s0p0;
+ Simd4f v1 = s1p1 - s1p0;
+ Simd4f vd = v1 - v0;
+
+ // dot is in the range -1 to 1, scale and bias to 0 to 1
+ curDot = curDot * sHalf + sHalf;
+
+ // interpolate velocity at contact points
+ Simd4f vx = splat<0>(v0) + curDot * splat<0>(vd);
+ Simd4f vy = splat<1>(v0) + curDot * splat<1>(vd);
+ Simd4f vz = splat<2>(v0) + curDot * splat<2>(vd);
+
+ accum.addVelocity(vx, vy, vz, contactMask);
+ }
+ }
+
+ return shapeMask.mSpheres;
+}
+
+namespace
+{
+
+template <typename Simd4f>
+PX_INLINE void calculateFrictionImpulse(const Simd4f& deltaX, const Simd4f& deltaY, const Simd4f& deltaZ,
+ const Simd4f& velX, const Simd4f& velY, const Simd4f& velZ,
+ const Simd4f* curPos, const Simd4f* prevPos, const Simd4f& scale,
+ const Simd4f& coefficient, const Simd4f& mask, Simd4f* impulse)
+{
+ // calculate collision normal
+ Simd4f deltaSq = deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
+
+ Simd4f rcpDelta = rsqrt(deltaSq + sEpsilon);
+
+ Simd4f nx = deltaX * rcpDelta;
+ Simd4f ny = deltaY * rcpDelta;
+ Simd4f nz = deltaZ * rcpDelta;
+
+ // calculate relative velocity scaled by number of collisions
+ Simd4f rvx = curPos[0] - prevPos[0] - velX * scale;
+ Simd4f rvy = curPos[1] - prevPos[1] - velY * scale;
+ Simd4f rvz = curPos[2] - prevPos[2] - velZ * scale;
+
+ // calculate magnitude of relative normal velocity
+ Simd4f rvn = rvx * nx + rvy * ny + rvz * nz;
+
+ // calculate relative tangential velocity
+ Simd4f rvtx = rvx - rvn * nx;
+ Simd4f rvty = rvy - rvn * ny;
+ Simd4f rvtz = rvz - rvn * nz;
+
+ // calculate magnitude of vt
+ Simd4f rcpVt = rsqrt(rvtx * rvtx + rvty * rvty + rvtz * rvtz + sEpsilon);
+
+ // magnitude of friction impulse (cannot be greater than -vt)
+ Simd4f j = max(-coefficient * deltaSq * rcpDelta * rcpVt, sNegOne) & mask;
+
+ impulse[0] = rvtx * j;
+ impulse[1] = rvty * j;
+ impulse[2] = rvtz * j;
+}
+
+} // anonymous namespace
+
+template <typename Simd4f>
+void cloth::SwCollision<Simd4f>::collideParticles()
+{
+ const bool massScalingEnabled = mClothData.mCollisionMassScale > 0.0f;
+ const Simd4f massScale = simd4f(mClothData.mCollisionMassScale);
+
+ const bool frictionEnabled = mClothData.mFrictionScale > 0.0f;
+ const Simd4f frictionScale = simd4f(mClothData.mFrictionScale);
+
+ Simd4f curPos[4];
+ Simd4f prevPos[4];
+
+ float* __restrict prevIt = mClothData.mPrevParticles;
+ float* __restrict pIt = mClothData.mCurParticles;
+ float* __restrict pEnd = pIt + mClothData.mNumParticles * 4;
+ for(; pIt < pEnd; pIt += 16, prevIt += 16)
+ {
+ curPos[0] = loadAligned(pIt, 0);
+ curPos[1] = loadAligned(pIt, 16);
+ curPos[2] = loadAligned(pIt, 32);
+ curPos[3] = loadAligned(pIt, 48);
+ transpose(curPos[0], curPos[1], curPos[2], curPos[3]);
+
+ ImpulseAccumulator accum;
+ Simd4i sphereMask = collideCones(curPos, accum);
+ collideSpheres(sphereMask, curPos, accum);
+
+ Simd4f mask;
+ if(!anyGreater(accum.mNumCollisions, sEpsilon, mask))
+ continue;
+
+ Simd4f invNumCollisions = recip(accum.mNumCollisions);
+
+ if(frictionEnabled)
+ {
+ prevPos[0] = loadAligned(prevIt, 0);
+ prevPos[1] = loadAligned(prevIt, 16);
+ prevPos[2] = loadAligned(prevIt, 32);
+ prevPos[3] = loadAligned(prevIt, 48);
+ transpose(prevPos[0], prevPos[1], prevPos[2], prevPos[3]);
+
+ Simd4f frictionImpulse[3];
+ calculateFrictionImpulse(accum.mDeltaX, accum.mDeltaY, accum.mDeltaZ, accum.mVelX, accum.mVelY, accum.mVelZ,
+ curPos, prevPos, invNumCollisions, frictionScale, mask, frictionImpulse);
+
+ prevPos[0] = prevPos[0] - frictionImpulse[0];
+ prevPos[1] = prevPos[1] - frictionImpulse[1];
+ prevPos[2] = prevPos[2] - frictionImpulse[2];
+
+ transpose(prevPos[0], prevPos[1], prevPos[2], prevPos[3]);
+ storeAligned(prevIt, 0, prevPos[0]);
+ storeAligned(prevIt, 16, prevPos[1]);
+ storeAligned(prevIt, 32, prevPos[2]);
+ storeAligned(prevIt, 48, prevPos[3]);
+ }
+
+ if(massScalingEnabled)
+ {
+ // calculate the inverse mass scale based on the collision impulse magnitude
+ Simd4f dSq = invNumCollisions * invNumCollisions *
+ (accum.mDeltaX * accum.mDeltaX + accum.mDeltaY * accum.mDeltaY + accum.mDeltaZ * accum.mDeltaZ);
+
+ Simd4f scale = recip(sOne + massScale * dSq);
+
+ // scale invmass
+ curPos[3] = select(mask, curPos[3] * scale, curPos[3]);
+ }
+
+ curPos[0] = curPos[0] + accum.mDeltaX * invNumCollisions;
+ curPos[1] = curPos[1] + accum.mDeltaY * invNumCollisions;
+ curPos[2] = curPos[2] + accum.mDeltaZ * invNumCollisions;
+
+ transpose(curPos[0], curPos[1], curPos[2], curPos[3]);
+ storeAligned(pIt, 0, curPos[0]);
+ storeAligned(pIt, 16, curPos[1]);
+ storeAligned(pIt, 32, curPos[2]);
+ storeAligned(pIt, 48, curPos[3]);
+
+#if PX_PROFILE || PX_DEBUG
+ mNumCollisions += horizontalSum(accum.mNumCollisions);
+#endif
+ }
+}
+
+template <typename Simd4f>
+void cloth::SwCollision<Simd4f>::collideVirtualParticles()
+{
+ const bool massScalingEnabled = mClothData.mCollisionMassScale > 0.0f;
+ const Simd4f massScale = simd4f(mClothData.mCollisionMassScale);
+
+ const bool frictionEnabled = mClothData.mFrictionScale > 0.0f;
+ const Simd4f frictionScale = simd4f(mClothData.mFrictionScale);
+
+ Simd4f curPos[3];
+
+ const float* __restrict weights = mClothData.mVirtualParticleWeights;
+ float* __restrict particles = mClothData.mCurParticles;
+ float* __restrict prevParticles = mClothData.mPrevParticles;
+
+ // move dummy particles outside of collision range
+ Simd4f* __restrict dummy = mClothData.mNumParticles + reinterpret_cast<Simd4f*>(mClothData.mCurParticles);
+ Simd4f invGridScale = recip(mGridScale) & (mGridScale > sEpsilon);
+ dummy[0] = dummy[1] = dummy[2] = invGridScale * mGridBias - invGridScale;
+
+ const uint16_t* __restrict vpIt = mClothData.mVirtualParticlesBegin;
+ const uint16_t* __restrict vpEnd = mClothData.mVirtualParticlesEnd;
+ for(; vpIt != vpEnd; vpIt += 16)
+ {
+ // load 12 particles and 4 weights
+ Simd4f p0v0 = loadAligned(particles, vpIt[0] * sizeof(PxVec4));
+ Simd4f p0v1 = loadAligned(particles, vpIt[1] * sizeof(PxVec4));
+ Simd4f p0v2 = loadAligned(particles, vpIt[2] * sizeof(PxVec4));
+ Simd4f w0 = loadAligned(weights, vpIt[3] * sizeof(PxVec4));
+
+ Simd4f p1v0 = loadAligned(particles, vpIt[4] * sizeof(PxVec4));
+ Simd4f p1v1 = loadAligned(particles, vpIt[5] * sizeof(PxVec4));
+ Simd4f p1v2 = loadAligned(particles, vpIt[6] * sizeof(PxVec4));
+ Simd4f w1 = loadAligned(weights, vpIt[7] * sizeof(PxVec4));
+
+ Simd4f p2v0 = loadAligned(particles, vpIt[8] * sizeof(PxVec4));
+ Simd4f p2v1 = loadAligned(particles, vpIt[9] * sizeof(PxVec4));
+ Simd4f p2v2 = loadAligned(particles, vpIt[10] * sizeof(PxVec4));
+ Simd4f w2 = loadAligned(weights, vpIt[11] * sizeof(PxVec4));
+
+ Simd4f p3v1 = loadAligned(particles, vpIt[13] * sizeof(PxVec4));
+ Simd4f p3v0 = loadAligned(particles, vpIt[12] * sizeof(PxVec4));
+ Simd4f p3v2 = loadAligned(particles, vpIt[14] * sizeof(PxVec4));
+ Simd4f w3 = loadAligned(weights, vpIt[15] * sizeof(PxVec4));
+
+ // interpolate particles and transpose
+ Simd4f px = p0v0 * splat<0>(w0) + p0v1 * splat<1>(w0) + p0v2 * splat<2>(w0);
+ Simd4f py = p1v0 * splat<0>(w1) + p1v1 * splat<1>(w1) + p1v2 * splat<2>(w1);
+ Simd4f pz = p2v0 * splat<0>(w2) + p2v1 * splat<1>(w2) + p2v2 * splat<2>(w2);
+ Simd4f pw = p3v0 * splat<0>(w3) + p3v1 * splat<1>(w3) + p3v2 * splat<2>(w3);
+ transpose(px, py, pz, pw);
+
+ curPos[0] = px;
+ curPos[1] = py;
+ curPos[2] = pz;
+
+ ImpulseAccumulator accum;
+ Simd4i sphereMask = collideCones(curPos, accum);
+ collideSpheres(sphereMask, curPos, accum);
+
+ Simd4f mask;
+ if(!anyGreater(accum.mNumCollisions, sEpsilon, mask))
+ continue;
+
+ Simd4f invNumCollisions = recip(accum.mNumCollisions);
+
+ // displacement and transpose back
+ Simd4f d0 = accum.mDeltaX * invNumCollisions;
+ Simd4f d1 = accum.mDeltaY * invNumCollisions;
+ Simd4f d2 = accum.mDeltaZ * invNumCollisions;
+ Simd4f d3 = sZero;
+ transpose(d0, d1, d2, d3);
+
+ // scale weights by 1/dot(w,w)
+ Simd4f rw0 = w0 * splat<3>(w0);
+ Simd4f rw1 = w1 * splat<3>(w1);
+ Simd4f rw2 = w2 * splat<3>(w2);
+ Simd4f rw3 = w3 * splat<3>(w3);
+
+ if(frictionEnabled)
+ {
+ Simd4f q0v0 = loadAligned(prevParticles, vpIt[0] * sizeof(PxVec4));
+ Simd4f q0v1 = loadAligned(prevParticles, vpIt[1] * sizeof(PxVec4));
+ Simd4f q0v2 = loadAligned(prevParticles, vpIt[2] * sizeof(PxVec4));
+
+ Simd4f q1v0 = loadAligned(prevParticles, vpIt[4] * sizeof(PxVec4));
+ Simd4f q1v1 = loadAligned(prevParticles, vpIt[5] * sizeof(PxVec4));
+ Simd4f q1v2 = loadAligned(prevParticles, vpIt[6] * sizeof(PxVec4));
+
+ Simd4f q2v0 = loadAligned(prevParticles, vpIt[8] * sizeof(PxVec4));
+ Simd4f q2v1 = loadAligned(prevParticles, vpIt[9] * sizeof(PxVec4));
+ Simd4f q2v2 = loadAligned(prevParticles, vpIt[10] * sizeof(PxVec4));
+
+ Simd4f q3v0 = loadAligned(prevParticles, vpIt[12] * sizeof(PxVec4));
+ Simd4f q3v1 = loadAligned(prevParticles, vpIt[13] * sizeof(PxVec4));
+ Simd4f q3v2 = loadAligned(prevParticles, vpIt[14] * sizeof(PxVec4));
+
+ // calculate previous interpolated positions
+ Simd4f qx = q0v0 * splat<0>(w0) + q0v1 * splat<1>(w0) + q0v2 * splat<2>(w0);
+ Simd4f qy = q1v0 * splat<0>(w1) + q1v1 * splat<1>(w1) + q1v2 * splat<2>(w1);
+ Simd4f qz = q2v0 * splat<0>(w2) + q2v1 * splat<1>(w2) + q2v2 * splat<2>(w2);
+ Simd4f qw = q3v0 * splat<0>(w3) + q3v1 * splat<1>(w3) + q3v2 * splat<2>(w3);
+ transpose(qx, qy, qz, qw);
+
+ Simd4f prevPos[3] = { qx, qy, qz };
+ Simd4f frictionImpulse[4];
+ frictionImpulse[3] = sZero;
+
+ calculateFrictionImpulse(accum.mDeltaX, accum.mDeltaY, accum.mDeltaZ, accum.mVelX, accum.mVelY, accum.mVelZ,
+ curPos, prevPos, invNumCollisions, frictionScale, mask, frictionImpulse);
+
+ transpose(frictionImpulse[0], frictionImpulse[1], frictionImpulse[2], frictionImpulse[3]);
+
+ q0v0 = q0v0 - (splat<0>(rw0) * frictionImpulse[0]);
+ q0v1 = q0v1 - (splat<1>(rw0) * frictionImpulse[0]);
+ q0v2 = q0v2 - (splat<2>(rw0) * frictionImpulse[0]);
+
+ q1v0 = q1v0 - (splat<0>(rw1) * frictionImpulse[1]);
+ q1v1 = q1v1 - (splat<1>(rw1) * frictionImpulse[1]);
+ q1v2 = q1v2 - (splat<2>(rw1) * frictionImpulse[1]);
+
+ q2v0 = q2v0 - (splat<0>(rw2) * frictionImpulse[2]);
+ q2v1 = q2v1 - (splat<1>(rw2) * frictionImpulse[2]);
+ q2v2 = q2v2 - (splat<2>(rw2) * frictionImpulse[2]);
+
+ q3v0 = q3v0 - (splat<0>(rw3) * frictionImpulse[3]);
+ q3v1 = q3v1 - (splat<1>(rw3) * frictionImpulse[3]);
+ q3v2 = q3v2 - (splat<2>(rw3) * frictionImpulse[3]);
+
+ // write back prev particles
+ storeAligned(prevParticles, vpIt[0] * sizeof(PxVec4), q0v0);
+ storeAligned(prevParticles, vpIt[1] * sizeof(PxVec4), q0v1);
+ storeAligned(prevParticles, vpIt[2] * sizeof(PxVec4), q0v2);
+
+ storeAligned(prevParticles, vpIt[4] * sizeof(PxVec4), q1v0);
+ storeAligned(prevParticles, vpIt[5] * sizeof(PxVec4), q1v1);
+ storeAligned(prevParticles, vpIt[6] * sizeof(PxVec4), q1v2);
+
+ storeAligned(prevParticles, vpIt[8] * sizeof(PxVec4), q2v0);
+ storeAligned(prevParticles, vpIt[9] * sizeof(PxVec4), q2v1);
+ storeAligned(prevParticles, vpIt[10] * sizeof(PxVec4), q2v2);
+
+ storeAligned(prevParticles, vpIt[12] * sizeof(PxVec4), q3v0);
+ storeAligned(prevParticles, vpIt[13] * sizeof(PxVec4), q3v1);
+ storeAligned(prevParticles, vpIt[14] * sizeof(PxVec4), q3v2);
+ }
+
+ if(massScalingEnabled)
+ {
+ // calculate the inverse mass scale based on the collision impulse
+ Simd4f dSq = invNumCollisions * invNumCollisions *
+ (accum.mDeltaX * accum.mDeltaX + accum.mDeltaY * accum.mDeltaY + accum.mDeltaZ * accum.mDeltaZ);
+
+ Simd4f weightScale = recip(sOne + massScale * dSq);
+
+ weightScale = weightScale - sOne;
+ Simd4f s0 = sOne + splat<0>(weightScale) * (w0 & splat<0>(mask));
+ Simd4f s1 = sOne + splat<1>(weightScale) * (w1 & splat<1>(mask));
+ Simd4f s2 = sOne + splat<2>(weightScale) * (w2 & splat<2>(mask));
+ Simd4f s3 = sOne + splat<3>(weightScale) * (w3 & splat<3>(mask));
+
+ p0v0 = p0v0 * (sOneXYZ | (splat<0>(s0) & sMaskW));
+ p0v1 = p0v1 * (sOneXYZ | (splat<1>(s0) & sMaskW));
+ p0v2 = p0v2 * (sOneXYZ | (splat<2>(s0) & sMaskW));
+
+ p1v0 = p1v0 * (sOneXYZ | (splat<0>(s1) & sMaskW));
+ p1v1 = p1v1 * (sOneXYZ | (splat<1>(s1) & sMaskW));
+ p1v2 = p1v2 * (sOneXYZ | (splat<2>(s1) & sMaskW));
+
+ p2v0 = p2v0 * (sOneXYZ | (splat<0>(s2) & sMaskW));
+ p2v1 = p2v1 * (sOneXYZ | (splat<1>(s2) & sMaskW));
+ p2v2 = p2v2 * (sOneXYZ | (splat<2>(s2) & sMaskW));
+
+ p3v0 = p3v0 * (sOneXYZ | (splat<0>(s3) & sMaskW));
+ p3v1 = p3v1 * (sOneXYZ | (splat<1>(s3) & sMaskW));
+ p3v2 = p3v2 * (sOneXYZ | (splat<2>(s3) & sMaskW));
+ }
+
+ p0v0 = p0v0 + (splat<0>(rw0) * d0);
+ p0v1 = p0v1 + (splat<1>(rw0) * d0);
+ p0v2 = p0v2 + (splat<2>(rw0) * d0);
+
+ p1v0 = p1v0 + (splat<0>(rw1) * d1);
+ p1v1 = p1v1 + (splat<1>(rw1) * d1);
+ p1v2 = p1v2 + (splat<2>(rw1) * d1);
+
+ p2v0 = p2v0 + (splat<0>(rw2) * d2);
+ p2v1 = p2v1 + (splat<1>(rw2) * d2);
+ p2v2 = p2v2 + (splat<2>(rw2) * d2);
+
+ p3v0 = p3v0 + (splat<0>(rw3) * d3);
+ p3v1 = p3v1 + (splat<1>(rw3) * d3);
+ p3v2 = p3v2 + (splat<2>(rw3) * d3);
+
+ // write back particles
+ storeAligned(particles, vpIt[0] * sizeof(PxVec4), p0v0);
+ storeAligned(particles, vpIt[1] * sizeof(PxVec4), p0v1);
+ storeAligned(particles, vpIt[2] * sizeof(PxVec4), p0v2);
+
+ storeAligned(particles, vpIt[4] * sizeof(PxVec4), p1v0);
+ storeAligned(particles, vpIt[5] * sizeof(PxVec4), p1v1);
+ storeAligned(particles, vpIt[6] * sizeof(PxVec4), p1v2);
+
+ storeAligned(particles, vpIt[8] * sizeof(PxVec4), p2v0);
+ storeAligned(particles, vpIt[9] * sizeof(PxVec4), p2v1);
+ storeAligned(particles, vpIt[10] * sizeof(PxVec4), p2v2);
+
+ storeAligned(particles, vpIt[12] * sizeof(PxVec4), p3v0);
+ storeAligned(particles, vpIt[13] * sizeof(PxVec4), p3v1);
+ storeAligned(particles, vpIt[14] * sizeof(PxVec4), p3v2);
+
+#if PX_PROFILE || PX_DEBUG
+ mNumCollisions += horizontalSum(accum.mNumCollisions);
+#endif
+ }
+}
+
+template <typename Simd4f>
+void cloth::SwCollision<Simd4f>::collideContinuousParticles()
+{
+ Simd4f curPos[4];
+ Simd4f prevPos[4];
+
+ const bool massScalingEnabled = mClothData.mCollisionMassScale > 0.0f;
+ const Simd4f massScale = simd4f(mClothData.mCollisionMassScale);
+
+ const bool frictionEnabled = mClothData.mFrictionScale > 0.0f;
+ const Simd4f frictionScale = simd4f(mClothData.mFrictionScale);
+
+ float* __restrict prevIt = mClothData.mPrevParticles;
+ float* __restrict curIt = mClothData.mCurParticles;
+ float* __restrict curEnd = curIt + mClothData.mNumParticles * 4;
+
+ for(; curIt < curEnd; curIt += 16, prevIt += 16)
+ {
+ prevPos[0] = loadAligned(prevIt, 0);
+ prevPos[1] = loadAligned(prevIt, 16);
+ prevPos[2] = loadAligned(prevIt, 32);
+ prevPos[3] = loadAligned(prevIt, 48);
+ transpose(prevPos[0], prevPos[1], prevPos[2], prevPos[3]);
+
+ curPos[0] = loadAligned(curIt, 0);
+ curPos[1] = loadAligned(curIt, 16);
+ curPos[2] = loadAligned(curIt, 32);
+ curPos[3] = loadAligned(curIt, 48);
+ transpose(curPos[0], curPos[1], curPos[2], curPos[3]);
+
+ ImpulseAccumulator accum;
+ Simd4i sphereMask = collideCones(prevPos, curPos, accum);
+ collideSpheres(sphereMask, prevPos, curPos, accum);
+
+ Simd4f mask;
+ if(!anyGreater(accum.mNumCollisions, sEpsilon, mask))
+ continue;
+
+ Simd4f invNumCollisions = recip(accum.mNumCollisions);
+
+ if(frictionEnabled)
+ {
+ Simd4f frictionImpulse[3];
+ calculateFrictionImpulse(accum.mDeltaX, accum.mDeltaY, accum.mDeltaZ, accum.mVelX, accum.mVelY, accum.mVelZ,
+ curPos, prevPos, invNumCollisions, frictionScale, mask, frictionImpulse);
+
+ prevPos[0] = prevPos[0] - frictionImpulse[0];
+ prevPos[1] = prevPos[1] - frictionImpulse[1];
+ prevPos[2] = prevPos[2] - frictionImpulse[2];
+
+ transpose(prevPos[0], prevPos[1], prevPos[2], prevPos[3]);
+ storeAligned(prevIt, 0, prevPos[0]);
+ storeAligned(prevIt, 16, prevPos[1]);
+ storeAligned(prevIt, 32, prevPos[2]);
+ storeAligned(prevIt, 48, prevPos[3]);
+ }
+
+ if(massScalingEnabled)
+ {
+ // calculate the inverse mass scale based on the collision impulse magnitude
+ Simd4f dSq = invNumCollisions * invNumCollisions *
+ (accum.mDeltaX * accum.mDeltaX + accum.mDeltaY * accum.mDeltaY + accum.mDeltaZ * accum.mDeltaZ);
+
+ Simd4f weightScale = recip(sOne + massScale * dSq);
+
+ // scale invmass
+ curPos[3] = select(mask, curPos[3] * weightScale, curPos[3]);
+ }
+
+ curPos[0] = curPos[0] + accum.mDeltaX * invNumCollisions;
+ curPos[1] = curPos[1] + accum.mDeltaY * invNumCollisions;
+ curPos[2] = curPos[2] + accum.mDeltaZ * invNumCollisions;
+
+ transpose(curPos[0], curPos[1], curPos[2], curPos[3]);
+ storeAligned(curIt, 0, curPos[0]);
+ storeAligned(curIt, 16, curPos[1]);
+ storeAligned(curIt, 32, curPos[2]);
+ storeAligned(curIt, 48, curPos[3]);
+
+#if PX_PROFILE || PX_DEBUG
+ mNumCollisions += horizontalSum(accum.mNumCollisions);
+#endif
+ }
+}
+
+template <typename Simd4f>
+void cloth::SwCollision<Simd4f>::collideConvexes(const IterationState<Simd4f>& state)
+{
+ if(!mClothData.mNumConvexes)
+ return;
+
+ // times 2 for plane equation result buffer
+ Simd4f* planes = static_cast<Simd4f*>(mAllocator.allocate(sizeof(Simd4f) * mClothData.mNumPlanes * 2));
+
+ const Simd4f* targetPlanes = reinterpret_cast<const Simd4f*>(mClothData.mTargetCollisionPlanes);
+
+ // generate plane collision data
+ if(state.mRemainingIterations != 1)
+ {
+ // interpolate planes
+ LerpIterator<Simd4f, const Simd4f*> planeIter(reinterpret_cast<const Simd4f*>(mClothData.mStartCollisionPlanes),
+ targetPlanes, state.getCurrentAlpha());
+
+ // todo: normalize plane equations
+ generatePlanes(planes, planeIter, mClothData.mNumPlanes);
+ }
+ else
+ {
+ // otherwise use the target planes directly
+ generatePlanes(planes, targetPlanes, mClothData.mNumPlanes);
+ }
+
+ Simd4f curPos[4], prevPos[4];
+
+ const bool frictionEnabled = mClothData.mFrictionScale > 0.0f;
+ const Simd4f frictionScale = simd4f(mClothData.mFrictionScale);
+
+ float* __restrict curIt = mClothData.mCurParticles;
+ float* __restrict curEnd = curIt + mClothData.mNumParticles * 4;
+ float* __restrict prevIt = mClothData.mPrevParticles;
+ for(; curIt < curEnd; curIt += 16, prevIt += 16)
+ {
+ curPos[0] = loadAligned(curIt, 0);
+ curPos[1] = loadAligned(curIt, 16);
+ curPos[2] = loadAligned(curIt, 32);
+ curPos[3] = loadAligned(curIt, 48);
+ transpose(curPos[0], curPos[1], curPos[2], curPos[3]);
+
+ ImpulseAccumulator accum;
+ collideConvexes(planes, curPos, accum);
+
+ Simd4f mask;
+ if(!anyGreater(accum.mNumCollisions, sEpsilon, mask))
+ continue;
+
+ Simd4f invNumCollisions = recip(accum.mNumCollisions);
+
+ if(frictionEnabled)
+ {
+ prevPos[0] = loadAligned(prevIt, 0);
+ prevPos[1] = loadAligned(prevIt, 16);
+ prevPos[2] = loadAligned(prevIt, 32);
+ prevPos[3] = loadAligned(prevIt, 48);
+ transpose(prevPos[0], prevPos[1], prevPos[2], prevPos[3]);
+
+ Simd4f frictionImpulse[3];
+ calculateFrictionImpulse(accum.mDeltaX, accum.mDeltaY, accum.mDeltaZ, accum.mVelX, accum.mVelY, accum.mVelZ,
+ curPos, prevPos, invNumCollisions, frictionScale, mask, frictionImpulse);
+
+ prevPos[0] = prevPos[0] - frictionImpulse[0];
+ prevPos[1] = prevPos[1] - frictionImpulse[1];
+ prevPos[2] = prevPos[2] - frictionImpulse[2];
+
+ transpose(prevPos[0], prevPos[1], prevPos[2], prevPos[3]);
+ storeAligned(prevIt, 0, prevPos[0]);
+ storeAligned(prevIt, 16, prevPos[1]);
+ storeAligned(prevIt, 32, prevPos[2]);
+ storeAligned(prevIt, 48, prevPos[3]);
+ }
+
+ curPos[0] = curPos[0] + accum.mDeltaX * invNumCollisions;
+ curPos[1] = curPos[1] + accum.mDeltaY * invNumCollisions;
+ curPos[2] = curPos[2] + accum.mDeltaZ * invNumCollisions;
+
+ transpose(curPos[0], curPos[1], curPos[2], curPos[3]);
+ storeAligned(curIt, 0, curPos[0]);
+ storeAligned(curIt, 16, curPos[1]);
+ storeAligned(curIt, 32, curPos[2]);
+ storeAligned(curIt, 48, curPos[3]);
+
+#if PX_PROFILE || PX_DEBUG
+ mNumCollisions += horizontalSum(accum.mNumCollisions);
+#endif
+ }
+
+ mAllocator.deallocate(planes);
+}
+
+template <typename Simd4f>
+void cloth::SwCollision<Simd4f>::collideConvexes(const Simd4f* __restrict planes, Simd4f* __restrict curPos,
+ ImpulseAccumulator& accum)
+{
+ Simd4i result = simd4i(_0);
+ Simd4i mask4 = simd4i(_1);
+
+ const Simd4f* __restrict pIt, *pEnd = planes + mClothData.mNumPlanes;
+ Simd4f* __restrict dIt = const_cast<Simd4f*>(pEnd);
+ for(pIt = planes; pIt != pEnd; ++pIt, ++dIt)
+ {
+ *dIt = splat<3>(*pIt) + curPos[2] * splat<2>(*pIt) + curPos[1] * splat<1>(*pIt) + curPos[0] * splat<0>(*pIt);
+ result = result | (mask4 & simd4i(*dIt < simd4f(_0)));
+ mask4 = mask4 << 1; // todo: shift by Simd4i on consoles
+ }
+
+ if(simdi::allEqual(result, simd4i(_0)))
+ return;
+
+ const uint32_t* __restrict cIt = mClothData.mConvexMasks;
+ const uint32_t* __restrict cEnd = cIt + mClothData.mNumConvexes;
+ for(; cIt != cEnd; ++cIt)
+ {
+ uint32_t mask = *cIt;
+ mask4 = simd4i(int(mask));
+ if(!simdi::anyEqual(mask4 & result, mask4, mask4))
+ continue;
+
+ uint32_t test = mask - 1;
+ uint32_t planeIndex = findBitSet(mask & ~test);
+ Simd4f plane = planes[planeIndex];
+ Simd4f planeX = splat<0>(plane);
+ Simd4f planeY = splat<1>(plane);
+ Simd4f planeZ = splat<2>(plane);
+ Simd4f planeD = pEnd[planeIndex];
+ while(mask &= test)
+ {
+ test = mask - 1;
+ planeIndex = findBitSet(mask & ~test);
+ plane = planes[planeIndex];
+ Simd4f dist = pEnd[planeIndex];
+ Simd4f closer = dist > planeD;
+ planeX = select(closer, splat<0>(plane), planeX);
+ planeY = select(closer, splat<1>(plane), planeY);
+ planeZ = select(closer, splat<2>(plane), planeZ);
+ planeD = max(dist, planeD);
+ }
+
+ accum.subtract(planeX, planeY, planeZ, planeD, simd4f(mask4));
+ }
+}
+
+template <typename Simd4f>
+void cloth::SwCollision<Simd4f>::collideTriangles(const IterationState<Simd4f>& state)
+{
+ if(!mClothData.mNumTriangles)
+ return;
+
+ TriangleData* triangles =
+ static_cast<TriangleData*>(mAllocator.allocate(sizeof(TriangleData) * mClothData.mNumTriangles));
+
+ UnalignedIterator<Simd4f, 3> targetTriangles(mClothData.mTargetCollisionTriangles);
+
+ // generate triangle collision data
+ if(state.mRemainingIterations != 1)
+ {
+ // interpolate triangles
+ LerpIterator<Simd4f, UnalignedIterator<Simd4f, 3> > triangleIter(mClothData.mStartCollisionTriangles,
+ targetTriangles, state.getCurrentAlpha());
+
+ generateTriangles<Simd4f>(triangles, triangleIter, mClothData.mNumTriangles);
+ }
+ else
+ {
+ // otherwise use the target triangles directly
+ generateTriangles<Simd4f>(triangles, targetTriangles, mClothData.mNumTriangles);
+ }
+
+ Simd4f positions[4];
+
+ float* __restrict pIt = mClothData.mCurParticles;
+ float* __restrict pEnd = pIt + mClothData.mNumParticles * 4;
+ for(; pIt < pEnd; pIt += 16)
+ {
+ positions[0] = loadAligned(pIt, 0);
+ positions[1] = loadAligned(pIt, 16);
+ positions[2] = loadAligned(pIt, 32);
+ positions[3] = loadAligned(pIt, 48);
+ transpose(positions[0], positions[1], positions[2], positions[3]);
+
+ ImpulseAccumulator accum;
+ collideTriangles(triangles, positions, accum);
+
+ Simd4f mask;
+ if(!anyGreater(accum.mNumCollisions, sEpsilon, mask))
+ continue;
+
+ Simd4f invNumCollisions = recip(accum.mNumCollisions);
+
+ positions[0] = positions[0] + accum.mDeltaX * invNumCollisions;
+ positions[1] = positions[1] + accum.mDeltaY * invNumCollisions;
+ positions[2] = positions[2] + accum.mDeltaZ * invNumCollisions;
+
+ transpose(positions[0], positions[1], positions[2], positions[3]);
+ storeAligned(pIt, 0, positions[0]);
+ storeAligned(pIt, 16, positions[1]);
+ storeAligned(pIt, 32, positions[2]);
+ storeAligned(pIt, 48, positions[3]);
+
+#if PX_PROFILE || PX_DEBUG
+ mNumCollisions += horizontalSum(accum.mNumCollisions);
+#endif
+ }
+
+ mAllocator.deallocate(triangles);
+}
+
+template <typename Simd4f>
+void cloth::SwCollision<Simd4f>::collideTriangles(const TriangleData* __restrict triangles, Simd4f* __restrict curPos,
+ ImpulseAccumulator& accum)
+{
+ Simd4f normalX, normalY, normalZ, normalD;
+ normalX = normalY = normalZ = normalD = simd4f(_0);
+ Simd4f minSqrLength = sMax;
+
+ const TriangleData* __restrict tIt, *tEnd = triangles + mClothData.mNumTriangles;
+ for(tIt = triangles; tIt != tEnd; ++tIt)
+ {
+ Simd4f base = loadAligned(&tIt->base.x);
+ Simd4f edge0 = loadAligned(&tIt->edge0.x);
+ Simd4f edge1 = loadAligned(&tIt->edge1.x);
+ Simd4f normal = loadAligned(&tIt->normal.x);
+ Simd4f aux = loadAligned(&tIt->det);
+
+ Simd4f dx = curPos[0] - splat<0>(base);
+ Simd4f dy = curPos[1] - splat<1>(base);
+ Simd4f dz = curPos[2] - splat<2>(base);
+
+ Simd4f e0x = splat<0>(edge0);
+ Simd4f e0y = splat<1>(edge0);
+ Simd4f e0z = splat<2>(edge0);
+
+ Simd4f e1x = splat<0>(edge1);
+ Simd4f e1y = splat<1>(edge1);
+ Simd4f e1z = splat<2>(edge1);
+
+ Simd4f nx = splat<0>(normal);
+ Simd4f ny = splat<1>(normal);
+ Simd4f nz = splat<2>(normal);
+
+ Simd4f deltaDotEdge0 = dx * e0x + dy * e0y + dz * e0z;
+ Simd4f deltaDotEdge1 = dx * e1x + dy * e1y + dz * e1z;
+ Simd4f deltaDotNormal = dx * nx + dy * ny + dz * nz;
+
+ Simd4f edge0DotEdge1 = splat<3>(base);
+ Simd4f edge0SqrLength = splat<3>(edge0);
+ Simd4f edge1SqrLength = splat<3>(edge1);
+
+ Simd4f s = edge1SqrLength * deltaDotEdge0 - edge0DotEdge1 * deltaDotEdge1;
+ Simd4f t = edge0SqrLength * deltaDotEdge1 - edge0DotEdge1 * deltaDotEdge0;
+
+ Simd4f sPositive = s > simd4f(_0);
+ Simd4f tPositive = t > simd4f(_0);
+
+ Simd4f det = splat<0>(aux);
+
+ s = select(tPositive, s * det, deltaDotEdge0 * splat<2>(aux));
+ t = select(sPositive, t * det, deltaDotEdge1 * splat<3>(aux));
+
+ Simd4f clamp = simd4f(_1) < s + t;
+ Simd4f numerator = edge1SqrLength - edge0DotEdge1 + deltaDotEdge0 - deltaDotEdge1;
+
+ s = select(clamp, numerator * splat<1>(aux), s);
+
+ s = max(simd4f(_0), min(simd4f(_1), s));
+ t = max(simd4f(_0), min(simd4f(_1) - s, t));
+
+ dx = dx - e0x * s - e1x * t;
+ dy = dy - e0y * s - e1y * t;
+ dz = dz - e0z * s - e1z * t;
+
+ Simd4f sqrLength = dx * dx + dy * dy + dz * dz;
+
+ // slightly increase distance for colliding triangles
+ Simd4f slack = (simd4f(_0) > deltaDotNormal) & simd4f(1e-4f);
+ sqrLength = sqrLength + sqrLength * slack;
+
+ Simd4f mask = sqrLength < minSqrLength;
+
+ normalX = select(mask, nx, normalX);
+ normalY = select(mask, ny, normalY);
+ normalZ = select(mask, nz, normalZ);
+ normalD = select(mask, deltaDotNormal, normalD);
+
+ minSqrLength = min(sqrLength, minSqrLength);
+ }
+
+ Simd4f mask;
+ if(!anyGreater(simd4f(_0), normalD, mask))
+ return;
+
+ accum.subtract(normalX, normalY, normalZ, normalD, mask);
+}
+
+// explicit template instantiation
+#if NVMATH_SIMD
+template class cloth::SwCollision<Simd4f>;
+#endif
+#if NVMATH_SCALAR
+template class cloth::SwCollision<Scalar4f>;
+#endif
+/*
+namespace
+{
+ using namespace cloth;
+
+ int test()
+ {
+ Simd4f vertices[] = {
+ simd4f(0.0f, 0.0f, 0.0f, 0.0f),
+ simd4f(0.1f, 0.0f, 0.0f, 0.0f),
+ simd4f(0.0f, 0.1f, 0.0f, 0.0f)
+ };
+ TriangleData triangle;
+ generateTriangles<Simd4f>(&triangle, &*vertices, 1);
+
+ char buffer[1000];
+ SwKernelAllocator alloc(buffer, 1000);
+
+ SwClothData* cloth = static_cast<SwClothData*>(malloc(sizeof(SwClothData)));
+ memset(cloth, 0, sizeof(SwClothData));
+ cloth->mNumTriangles = 1;
+
+ SwCollision<Simd4f> collision(*cloth, alloc);
+ SwCollision<Simd4f>::ImpulseAccumulator accum;
+
+ Simd4f particles[4] = {};
+ for(float y=-0.1f; y < 0.0f; y += 0.2f)
+ {
+ for(float x=-0.1f; x < 0.0f; x += 0.2f)
+ {
+ particles[0] = simd4f(x);
+ particles[1] = simd4f(y);
+ particles[2] = simd4f(-1.0f);
+
+ collision.collideTriangles(&triangle, particles, accum);
+ }
+ }
+
+ return 0;
+ }
+
+ static int blah = test();
+}
+*/
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwCollision.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwCollision.h
new file mode 100644
index 00000000..bf5f3177
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwCollision.h
@@ -0,0 +1,178 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "Types.h"
+#include "StackAllocator.h"
+#include "Simd4i.h"
+
+#if PX_PROFILE
+#include "PxProfileEventSender.h"
+#include "PxProfileZone.h"
+#else
+namespace physx
+{
+namespace profile
+{
+ class PxProfileZone;
+}
+}
+#endif
+
+namespace nvidia
+{
+namespace cloth
+{
+
+#if PX_PROFILE
+
+struct ProfileZone
+{
+ ProfileZone(const char* name, profile::PxProfileZone* profiler)
+ : mSender(profiler), mEventId(profiler ? profiler->getEventIdForName(name) : uint16_t(-1))
+ {
+ if(mSender)
+ mSender->startEvent(mEventId, (uint64_t)intptr_t(this));
+ }
+
+ ~ProfileZone()
+ {
+ if(mSender)
+ mSender->stopEvent(mEventId, (uint64_t)intptr_t(this));
+ }
+
+ void setValue(int64_t value) const
+ {
+ if(mSender)
+ mSender->eventValue(mEventId, (uint64_t)intptr_t(this), value);
+ }
+
+ profile::PxProfileEventSender* mSender;
+ uint16_t mEventId;
+};
+
+#else // PX_PROFILE
+
+struct ProfileZone
+{
+ ProfileZone(const char*, profile::PxProfileZone*)
+ {
+ }
+ void setValue(int64_t) const
+ {
+ }
+};
+
+#endif // PX_PROFILE
+
+class SwCloth;
+struct SwClothData;
+template <typename>
+struct IterationState;
+struct IndexPair;
+struct SphereData;
+struct ConeData;
+struct TriangleData;
+
+typedef StackAllocator<16> SwKernelAllocator;
+
+/**
+ Collision handler for SwSolver.
+ */
+template <typename Simd4f>
+class SwCollision
+{
+ typedef typename Simd4fToSimd4i<Simd4f>::Type Simd4i;
+
+ public:
+ struct ShapeMask
+ {
+ Simd4i mCones;
+ Simd4i mSpheres;
+
+ ShapeMask& operator=(const ShapeMask&);
+ ShapeMask& operator&=(const ShapeMask&);
+ };
+
+ struct CollisionData
+ {
+ CollisionData();
+ SphereData* mSpheres;
+ ConeData* mCones;
+ };
+
+ struct ImpulseAccumulator;
+
+ public:
+ SwCollision(SwClothData& clothData, SwKernelAllocator& alloc, profile::PxProfileZone* profiler);
+ ~SwCollision();
+
+ void operator()(const IterationState<Simd4f>& state);
+
+ static size_t estimateTemporaryMemory(const SwCloth& cloth);
+ static size_t estimatePersistentMemory(const SwCloth& cloth);
+
+ private:
+ SwCollision& operator=(const SwCollision&); // not implemented
+ void allocate(CollisionData&);
+ void deallocate(const CollisionData&);
+
+ void computeBounds();
+
+ void buildSphereAcceleration(const SphereData*);
+ void buildConeAcceleration();
+ static void mergeAcceleration(uint32_t*);
+ bool buildAcceleration();
+
+ static ShapeMask getShapeMask(const Simd4f&, const Simd4i*, const Simd4i*);
+ ShapeMask getShapeMask(const Simd4f*) const;
+ ShapeMask getShapeMask(const Simd4f*, const Simd4f*) const;
+
+ void collideSpheres(const Simd4i&, const Simd4f*, ImpulseAccumulator&) const;
+ Simd4i collideCones(const Simd4f*, ImpulseAccumulator&) const;
+
+ void collideSpheres(const Simd4i&, const Simd4f*, Simd4f*, ImpulseAccumulator&) const;
+ Simd4i collideCones(const Simd4f*, Simd4f*, ImpulseAccumulator&) const;
+
+ void collideParticles();
+ void collideVirtualParticles();
+ void collideContinuousParticles();
+
+ void collideConvexes(const IterationState<Simd4f>&);
+ void collideConvexes(const Simd4f*, Simd4f*, ImpulseAccumulator&);
+
+ void collideTriangles(const IterationState<Simd4f>&);
+ void collideTriangles(const TriangleData*, Simd4f*, ImpulseAccumulator&);
+
+ public:
+ // acceleration structure
+ static const uint32_t sGridSize = 8;
+ Simd4i mSphereGrid[6 * sGridSize / 4];
+ Simd4i mConeGrid[6 * sGridSize / 4];
+ Simd4f mGridScale, mGridBias;
+
+ CollisionData mPrevData;
+ CollisionData mCurData;
+
+ SwClothData& mClothData;
+ SwKernelAllocator& mAllocator;
+
+ uint32_t mNumCollisions;
+
+ profile::PxProfileZone* mProfiler;
+
+ static const Simd4f sSkeletonWidth;
+};
+}
+}
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwCollisionHelpers.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwCollisionHelpers.h
new file mode 100644
index 00000000..5e098922
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwCollisionHelpers.h
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "Simd4i.h"
+
+// platform specific helpers
+
+namespace nvidia
+{
+namespace cloth
+{
+
+inline uint32_t findBitSet(uint32_t mask);
+
+// intFloor(-1.0f) returns -2 on SSE and NEON!
+inline Simd4i intFloor(const Simd4f& v);
+
+inline Simd4i horizontalOr(Simd4i mask);
+
+template <typename>
+struct Gather;
+
+#if NVMATH_SIMD
+template <>
+struct Gather<Simd4i>
+{
+ inline Gather(const Simd4i& index);
+ inline Simd4i operator()(const Simd4i*) const;
+
+#if NVMATH_SSE2
+ Simd4i mSelectQ, mSelectD, mSelectW;
+ static const Simd4i sIntSignBit;
+ static const Simd4i sSignedMask;
+#elif NVMATH_NEON
+ Simd4i mPermute;
+ static const Simd4i sPack;
+ static const Simd4i sOffset;
+ static const Simd4i sShift;
+ static const Simd4i sMask;
+#endif
+ Simd4i mOutOfRange;
+};
+#endif
+
+} // namespace cloth
+} // namespace nvidia
+
+#if NVMATH_SSE2
+#include "sse2/SwCollisionHelpers.h"
+#elif NVMATH_NEON
+#include "neon/SwCollisionHelpers.h"
+#endif
+
+#if NVMATH_SCALAR
+#include "scalar/SwCollisionHelpers.h"
+#endif
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwFabric.cpp b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwFabric.cpp
new file mode 100644
index 00000000..0d527dbf
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwFabric.cpp
@@ -0,0 +1,150 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "PxAssert.h"
+#include "SwFabric.h"
+#include "SwFactory.h"
+#include "PsSort.h"
+#include "limits.h" // for USHRT_MAX
+
+#include "PsUtilities.h"
+
+using namespace nvidia;
+using namespace physx::shdfnd;
+
+cloth::SwTether::SwTether(uint16_t anchor, float length) : mAnchor(anchor), mLength(length)
+{
+}
+
+cloth::SwFabric::SwFabric(SwFactory& factory, uint32_t numParticles, Range<const uint32_t> phases,
+ Range<const uint32_t> sets, Range<const float> restvalues, Range<const uint32_t> indices,
+ Range<const uint32_t> anchors, Range<const float> tetherLengths, uint32_t id)
+: mFactory(factory), mNumParticles(numParticles), mTetherLengthScale(1.0f), mId(id)
+{
+ // should no longer be prefixed with 0
+ PX_ASSERT(sets.front() != 0);
+
+#if PX_WINDOWS_FAMILY
+ const uint32_t kSimdWidth = 8; // avx
+#else
+ const uint32_t kSimdWidth = 4;
+#endif
+
+ // consistency check
+ PX_ASSERT(sets.back() == restvalues.size());
+ PX_ASSERT(restvalues.size() * 2 == indices.size());
+ PX_ASSERT(mNumParticles > *maxElement(indices.begin(), indices.end()));
+ PX_ASSERT(mNumParticles + kSimdWidth - 1 <= USHRT_MAX);
+
+ mPhases.assign(phases.begin(), phases.end());
+ mSets.reserve(sets.size() + 1);
+ mSets.pushBack(0); // prefix with 0
+
+ mOriginalNumRestvalues = uint32_t(restvalues.size());
+
+ // padd indices for SIMD
+ const uint32_t* iBegin = indices.begin(), *iIt = iBegin;
+ const float* rBegin = restvalues.begin(), *rIt = rBegin;
+ const uint32_t* sIt, *sEnd = sets.end();
+ for(sIt = sets.begin(); sIt != sEnd; ++sIt)
+ {
+ const float* rEnd = rBegin + *sIt;
+ const uint32_t* iEnd = iBegin + *sIt * 2;
+ uint32_t numConstraints = uint32_t(rEnd - rIt);
+
+ for(; rIt != rEnd; ++rIt)
+ mRestvalues.pushBack(*rIt);
+
+ for(; iIt != iEnd; ++iIt)
+ mIndices.pushBack(uint16_t(*iIt));
+
+ // add dummy indices to make multiple of 4
+ for(; numConstraints &= kSimdWidth - 1; ++numConstraints)
+ {
+ mRestvalues.pushBack(-FLT_MAX);
+ uint32_t index = mNumParticles + numConstraints - 1;
+ mIndices.pushBack(uint16_t(index));
+ mIndices.pushBack(uint16_t(index));
+ }
+
+ mSets.pushBack(uint32_t(mRestvalues.size()));
+ }
+
+ // trim overallocations
+ RestvalueContainer(mRestvalues.begin(), mRestvalues.end()).swap(mRestvalues);
+ Vector<uint16_t>::Type(mIndices.begin(), mIndices.end()).swap(mIndices);
+
+ // tethers
+ PX_ASSERT(anchors.size() == tetherLengths.size());
+
+ // pad to allow for direct 16 byte (unaligned) loads
+ mTethers.reserve(anchors.size() + 2);
+ for(; !anchors.empty(); anchors.popFront(), tetherLengths.popFront())
+ mTethers.pushBack(SwTether(uint16_t(anchors.front()), tetherLengths.front()));
+
+ mFactory.mFabrics.pushBack(this);
+}
+
+cloth::SwFabric::~SwFabric()
+{
+ Vector<SwFabric*>::Type::Iterator fIt = mFactory.mFabrics.find(this);
+ PX_ASSERT(fIt != mFactory.mFabrics.end());
+ mFactory.mFabrics.replaceWithLast(fIt);
+}
+
+cloth::Factory& cloth::SwFabric::getFactory() const
+{
+ return mFactory;
+}
+
+uint32_t cloth::SwFabric::getNumPhases() const
+{
+ return uint32_t(mPhases.size());
+}
+
+uint32_t cloth::SwFabric::getNumRestvalues() const
+{
+ return mOriginalNumRestvalues;
+}
+
+uint32_t cloth::SwFabric::getNumSets() const
+{
+ return uint32_t(mSets.size() - 1);
+}
+
+uint32_t cloth::SwFabric::getNumIndices() const
+{
+ return 2 * mOriginalNumRestvalues;
+}
+
+uint32_t cloth::SwFabric::getNumParticles() const
+{
+ return mNumParticles;
+}
+
+uint32_t cloth::SwFabric::getNumTethers() const
+{
+ return uint32_t(mTethers.size());
+}
+
+void cloth::SwFabric::scaleRestvalues(float scale)
+{
+ RestvalueContainer::Iterator rIt, rEnd = mRestvalues.end();
+ for(rIt = mRestvalues.begin(); rIt != rEnd; ++rIt)
+ *rIt *= scale;
+}
+
+void cloth::SwFabric::scaleTetherLengths(float scale)
+{
+ mTetherLengthScale *= scale;
+}
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwFabric.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwFabric.h
new file mode 100644
index 00000000..e2081866
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwFabric.h
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "Allocator.h"
+#include "Fabric.h"
+#include "Types.h"
+#include "Range.h"
+#include "PxVec4.h"
+
+namespace nvidia
+{
+
+namespace cloth
+{
+
+class SwFactory;
+
+struct SwTether
+{
+ SwTether(uint16_t, float);
+ uint16_t mAnchor;
+ float mLength;
+};
+
+class SwFabric : public UserAllocated, public Fabric
+{
+ public:
+#if PX_WINDOWS_FAMILY
+ typedef AlignedVector<float, 32>::Type RestvalueContainer; // avx
+#else
+ typedef AlignedVector<float, 16>::Type RestvalueContainer;
+#endif
+
+ SwFabric(SwFactory& factory, uint32_t numParticles, Range<const uint32_t> phases, Range<const uint32_t> sets,
+ Range<const float> restvalues, Range<const uint32_t> indices, Range<const uint32_t> anchors,
+ Range<const float> tetherLengths, uint32_t id);
+
+ SwFabric& operator=(const SwFabric&);
+
+ virtual ~SwFabric();
+
+ virtual Factory& getFactory() const;
+
+ virtual uint32_t getNumPhases() const;
+ virtual uint32_t getNumRestvalues() const;
+
+ virtual uint32_t getNumSets() const;
+ virtual uint32_t getNumIndices() const;
+
+ virtual uint32_t getNumParticles() const;
+
+ virtual uint32_t getNumTethers() const;
+
+ virtual void scaleRestvalues(float);
+ virtual void scaleTetherLengths(float);
+
+ public:
+ SwFactory& mFactory;
+
+ uint32_t mNumParticles;
+
+ Vector<uint32_t>::Type mPhases; // index of set to use
+ Vector<uint32_t>::Type mSets; // offset of first restvalue, with 0 prefix
+
+ RestvalueContainer mRestvalues; // rest values (edge length)
+ Vector<uint16_t>::Type mIndices; // particle index pairs
+
+ Vector<SwTether>::Type mTethers;
+ float mTetherLengthScale;
+
+ uint32_t mId;
+
+ uint32_t mOriginalNumRestvalues;
+
+} PX_ALIGN_SUFFIX(16);
+}
+}
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwFactory.cpp b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwFactory.cpp
new file mode 100644
index 00000000..9955156d
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwFactory.cpp
@@ -0,0 +1,280 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "SwFactory.h"
+#include "SwFabric.h"
+#include "SwCloth.h"
+#include "SwSolver.h"
+#include "ClothImpl.h"
+#include <string.h> // for memcpy
+#include "PsIntrinsics.h"
+
+using namespace nvidia;
+using namespace nvidia;
+
+namespace nvidia
+{
+namespace cloth
+{
+// defined in Factory.cpp
+uint32_t getNextFabricId();
+}
+}
+
+cloth::SwFactory::SwFactory() : Factory(CPU)
+{
+}
+
+cloth::SwFactory::~SwFactory()
+{
+}
+
+cloth::Fabric* cloth::SwFactory::createFabric(uint32_t numParticles, Range<const uint32_t> phases,
+ Range<const uint32_t> sets, Range<const float> restvalues,
+ Range<const uint32_t> indices, Range<const uint32_t> anchors,
+ Range<const float> tetherLengths)
+{
+ return new SwFabric(*this, numParticles, phases, sets, restvalues, indices, anchors, tetherLengths,
+ getNextFabricId());
+}
+
+cloth::Cloth* cloth::SwFactory::createCloth(Range<const PxVec4> particles, Fabric& fabric)
+{
+ return new SwClothImpl(*this, fabric, particles);
+}
+
+cloth::Solver* cloth::SwFactory::createSolver(profile::PxProfileZone* profiler, PxTaskManager* taskMgr)
+{
+#ifdef PX_PHYSX_GPU_EXPORTS
+ // SwSolver not defined in PhysXGpu project
+ PX_UNUSED(profiler);
+ PX_UNUSED(taskMgr);
+ return 0;
+#else
+ return new SwSolver(profiler, taskMgr);
+#endif
+}
+
+cloth::Cloth* cloth::SwFactory::clone(const Cloth& cloth)
+{
+ if(cloth.getFactory().getPlatform() != Factory::CPU)
+ return cloth.clone(*this); // forward to CuCloth
+
+ // copy construct
+ return new SwClothImpl(*this, static_cast<const SwClothImpl&>(cloth));
+}
+
+void cloth::SwFactory::extractFabricData(const Fabric& fabric, Range<uint32_t> phases, Range<uint32_t> sets,
+ Range<float> restvalues, Range<uint32_t> indices, Range<uint32_t> anchors,
+ Range<float> tetherLengths) const
+{
+ const SwFabric& swFabric = static_cast<const SwFabric&>(fabric);
+
+ PX_ASSERT(phases.empty() || phases.size() == swFabric.getNumPhases());
+ PX_ASSERT(restvalues.empty() || restvalues.size() == swFabric.getNumRestvalues());
+ PX_ASSERT(sets.empty() || sets.size() == swFabric.getNumSets());
+ PX_ASSERT(indices.empty() || indices.size() == swFabric.getNumIndices());
+ PX_ASSERT(anchors.empty() || anchors.size() == swFabric.getNumTethers());
+ PX_ASSERT(tetherLengths.empty() || tetherLengths.size() == swFabric.getNumTethers());
+
+ for(uint32_t i = 0; !phases.empty(); ++i, phases.popFront())
+ phases.front() = swFabric.mPhases[i];
+
+ const uint32_t* sEnd = swFabric.mSets.end(), *sIt;
+ const float* rBegin = swFabric.mRestvalues.begin(), *rIt = rBegin;
+ const uint16_t* iIt = swFabric.mIndices.begin();
+
+ uint32_t* sDst = sets.begin();
+ float* rDst = restvalues.begin();
+ uint32_t* iDst = indices.begin();
+
+ uint32_t numConstraints = 0;
+ for(sIt = swFabric.mSets.begin(); ++sIt != sEnd;)
+ {
+ const float* rEnd = rBegin + *sIt;
+ for(; rIt != rEnd; ++rIt)
+ {
+ uint16_t i0 = *iIt++;
+ uint16_t i1 = *iIt++;
+
+ if(PxMax(i0, i1) >= swFabric.mNumParticles)
+ continue;
+
+ if(!restvalues.empty())
+ *rDst++ = *rIt;
+
+ if(!indices.empty())
+ {
+ *iDst++ = i0;
+ *iDst++ = i1;
+ }
+
+ ++numConstraints;
+ }
+
+ if(!sets.empty())
+ *sDst++ = numConstraints;
+ }
+
+ for(uint32_t i = 0; !anchors.empty(); ++i, anchors.popFront())
+ anchors.front() = swFabric.mTethers[i].mAnchor;
+
+ for(uint32_t i = 0; !tetherLengths.empty(); ++i, tetherLengths.popFront())
+ tetherLengths.front() = swFabric.mTethers[i].mLength * swFabric.mTetherLengthScale;
+}
+
+void cloth::SwFactory::extractCollisionData(const Cloth& cloth, Range<PxVec4> spheres, Range<uint32_t> capsules,
+ Range<PxVec4> planes, Range<uint32_t> convexes, Range<PxVec3> triangles) const
+{
+ PX_ASSERT(&cloth.getFactory() == this);
+
+ const SwCloth& swCloth = static_cast<const SwClothImpl&>(cloth).mCloth;
+
+ PX_ASSERT(spheres.empty() || spheres.size() == swCloth.mStartCollisionSpheres.size());
+ PX_ASSERT(capsules.empty() || capsules.size() == swCloth.mCapsuleIndices.size() * 2);
+ PX_ASSERT(planes.empty() || planes.size() == swCloth.mStartCollisionPlanes.size());
+ PX_ASSERT(convexes.empty() || convexes.size() == swCloth.mConvexMasks.size());
+ PX_ASSERT(triangles.empty() || triangles.size() == swCloth.mStartCollisionTriangles.size());
+
+ if(!swCloth.mStartCollisionSpheres.empty() && !spheres.empty())
+ memcpy(spheres.begin(), &swCloth.mStartCollisionSpheres.front(),
+ swCloth.mStartCollisionSpheres.size() * sizeof(PxVec4));
+
+ if(!swCloth.mCapsuleIndices.empty() && !capsules.empty())
+ memcpy(capsules.begin(), &swCloth.mCapsuleIndices.front(), swCloth.mCapsuleIndices.size() * sizeof(IndexPair));
+
+ if(!swCloth.mStartCollisionPlanes.empty() && !planes.empty())
+ memcpy(planes.begin(), &swCloth.mStartCollisionPlanes.front(),
+ swCloth.mStartCollisionPlanes.size() * sizeof(PxVec4));
+
+ if(!swCloth.mConvexMasks.empty() && !convexes.empty())
+ memcpy(convexes.begin(), &swCloth.mConvexMasks.front(), swCloth.mConvexMasks.size() * sizeof(uint32_t));
+
+ if(!swCloth.mStartCollisionTriangles.empty() && !triangles.empty())
+ memcpy(triangles.begin(), &swCloth.mStartCollisionTriangles.front(),
+ swCloth.mStartCollisionTriangles.size() * sizeof(PxVec3));
+}
+
+void cloth::SwFactory::extractMotionConstraints(const Cloth& cloth, Range<PxVec4> destConstraints) const
+{
+ PX_ASSERT(&cloth.getFactory() == this);
+
+ const SwCloth& swCloth = static_cast<const SwClothImpl&>(cloth).mCloth;
+
+ Vec4fAlignedVector const& srcConstraints = !swCloth.mMotionConstraints.mTarget.empty()
+ ? swCloth.mMotionConstraints.mTarget
+ : swCloth.mMotionConstraints.mStart;
+
+ if(!srcConstraints.empty())
+ {
+ // make sure dest array is big enough
+ PX_ASSERT(destConstraints.size() == srcConstraints.size());
+
+ memcpy(destConstraints.begin(), &srcConstraints.front(), srcConstraints.size() * sizeof(PxVec4));
+ }
+}
+
+void cloth::SwFactory::extractSeparationConstraints(const Cloth& cloth, Range<PxVec4> destConstraints) const
+{
+ PX_ASSERT(&cloth.getFactory() == this);
+
+ const SwCloth& swCloth = static_cast<const SwClothImpl&>(cloth).mCloth;
+
+ Vec4fAlignedVector const& srcConstraints = !swCloth.mSeparationConstraints.mTarget.empty()
+ ? swCloth.mSeparationConstraints.mTarget
+ : swCloth.mSeparationConstraints.mStart;
+
+ if(!srcConstraints.empty())
+ {
+ // make sure dest array is big enough
+ PX_ASSERT(destConstraints.size() == srcConstraints.size());
+
+ memcpy(destConstraints.begin(), &srcConstraints.front(), srcConstraints.size() * sizeof(PxVec4));
+ }
+}
+
+void cloth::SwFactory::extractParticleAccelerations(const Cloth& cloth, Range<PxVec4> destAccelerations) const
+{
+ PX_ASSERT(&cloth.getFactory() == this);
+
+ const SwCloth& swCloth = static_cast<const SwClothImpl&>(cloth).mCloth;
+
+ if(!swCloth.mParticleAccelerations.empty())
+ {
+ // make sure dest array is big enough
+ PX_ASSERT(destAccelerations.size() == swCloth.mParticleAccelerations.size());
+
+ memcpy(destAccelerations.begin(), &swCloth.mParticleAccelerations.front(),
+ swCloth.mParticleAccelerations.size() * sizeof(PxVec4));
+ }
+}
+
+void cloth::SwFactory::extractVirtualParticles(const Cloth& cloth, Range<uint32_t[4]> indices, Range<PxVec3> weights) const
+{
+ PX_ASSERT(this == &cloth.getFactory());
+
+ const SwCloth& swCloth = static_cast<const SwClothImpl&>(cloth).mCloth;
+
+ uint32_t numIndices = cloth.getNumVirtualParticles();
+ uint32_t numWeights = cloth.getNumVirtualParticleWeights();
+
+ PX_ASSERT(indices.size() == numIndices || indices.empty());
+ PX_ASSERT(weights.size() == numWeights || weights.empty());
+
+ if(weights.size() == numWeights)
+ {
+ PxVec3* wDestIt = reinterpret_cast<PxVec3*>(weights.begin());
+
+ // convert weights from vec4 to vec3
+ cloth::Vec4fAlignedVector::ConstIterator wIt = swCloth.mVirtualParticleWeights.begin();
+ cloth::Vec4fAlignedVector::ConstIterator wEnd = wIt + numWeights;
+
+ for(; wIt != wEnd; ++wIt, ++wDestIt)
+ *wDestIt = PxVec3(wIt->x, wIt->y, wIt->z);
+
+ PX_ASSERT(wDestIt == weights.end());
+ }
+ if(indices.size() == numIndices)
+ {
+ // convert indices
+ Vec4u* iDestIt = reinterpret_cast<Vec4u*>(indices.begin());
+ Vector<Vec4us>::Type::ConstIterator iIt = swCloth.mVirtualParticleIndices.begin();
+ Vector<Vec4us>::Type::ConstIterator iEnd = swCloth.mVirtualParticleIndices.end();
+
+ uint32_t numParticles = uint32_t(swCloth.mCurParticles.size());
+
+ for(; iIt != iEnd; ++iIt)
+ {
+ // skip dummy indices
+ if(iIt->x < numParticles)
+ // byte offset to element index
+ *iDestIt++ = Vec4u(*iIt);
+ }
+
+ PX_ASSERT(&array(*iDestIt) == indices.end());
+ }
+}
+
+void cloth::SwFactory::extractSelfCollisionIndices(const Cloth& cloth, Range<uint32_t> destIndices) const
+{
+ const SwCloth& swCloth = static_cast<const SwClothImpl&>(cloth).mCloth;
+ PX_ASSERT(destIndices.size() == swCloth.mSelfCollisionIndices.size());
+ intrinsics::memCopy(destIndices.begin(), swCloth.mSelfCollisionIndices.begin(), destIndices.size() * sizeof(uint32_t));
+}
+
+void cloth::SwFactory::extractRestPositions(const Cloth& cloth, Range<PxVec4> destRestPositions) const
+{
+ const SwCloth& swCloth = static_cast<const SwClothImpl&>(cloth).mCloth;
+ PX_ASSERT(destRestPositions.size() == swCloth.mRestPositions.size());
+ intrinsics::memCopy(destRestPositions.begin(), swCloth.mRestPositions.begin(), destRestPositions.size() * sizeof(PxVec4));
+}
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwFactory.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwFactory.h
new file mode 100644
index 00000000..a078add0
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwFactory.h
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "Factory.h"
+#include "Allocator.h"
+
+namespace nvidia
+{
+
+namespace cloth
+{
+
+class SwFabric;
+class SwCloth;
+template <typename>
+class ClothImpl;
+
+class SwFactory : public UserAllocated, public Factory
+{
+ public:
+ typedef SwFabric FabricType;
+ typedef ClothImpl<SwCloth> ImplType;
+
+ SwFactory();
+ virtual ~SwFactory();
+
+ virtual Fabric* createFabric(uint32_t numParticles, Range<const uint32_t> phases, Range<const uint32_t> sets,
+ Range<const float> restvalues, Range<const uint32_t> indices,
+ Range<const uint32_t> anchors, Range<const float> tetherLengths);
+
+ virtual Cloth* createCloth(Range<const PxVec4> particles, Fabric& fabric);
+
+ virtual Solver* createSolver(profile::PxProfileZone*, PxTaskManager*);
+
+ virtual Cloth* clone(const Cloth& cloth);
+
+ virtual void extractFabricData(const Fabric& fabric, Range<uint32_t> phases, Range<uint32_t> sets,
+ Range<float> restvalues, Range<uint32_t> indices, Range<uint32_t> anchors,
+ Range<float> tetherLengths) const;
+
+ virtual void extractCollisionData(const Cloth& cloth, Range<PxVec4> spheres, Range<uint32_t> capsules,
+ Range<PxVec4> planes, Range<uint32_t> convexes, Range<PxVec3> triangles) const;
+
+ virtual void extractMotionConstraints(const Cloth& cloth, Range<PxVec4> destConstraints) const;
+
+ virtual void extractSeparationConstraints(const Cloth& cloth, Range<PxVec4> destConstraints) const;
+
+ virtual void extractParticleAccelerations(const Cloth& cloth, Range<PxVec4> destAccelerations) const;
+
+ virtual void extractVirtualParticles(const Cloth& cloth, Range<uint32_t[4]> destIndices,
+ Range<PxVec3> destWeights) const;
+
+ virtual void extractSelfCollisionIndices(const Cloth& cloth, Range<uint32_t> destIndices) const;
+
+ virtual void extractRestPositions(const Cloth& cloth, Range<PxVec4> destRestPositions) const;
+
+ public:
+ Vector<SwFabric*>::Type mFabrics;
+};
+}
+}
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwInterCollision.cpp b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwInterCollision.cpp
new file mode 100644
index 00000000..c2c924cf
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwInterCollision.cpp
@@ -0,0 +1,694 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "SwInterCollision.h"
+#include "PsIntrinsics.h"
+#include "SwCollision.h" //temp fix, needed by SwCollisionHelper implementations
+#include "Simd4f.h"
+#include "SwCollisionHelpers.h"
+#include "BoundingBox.h"
+#include "PsSort.h"
+#include "PsIntrinsics.h"
+
+#pragma warning(disable:4127)
+
+using namespace nvidia;
+
+namespace
+{
+typedef Simd4fFactory<detail::FourTuple> Simd4fConstant;
+
+const Simd4fConstant sMaskXYZ = simd4f(simd4i(~0, ~0, ~0, 0));
+const Simd4fConstant sMaskW = simd4f(simd4i(0, 0, 0, ~0));
+const Simd4fConstant sEpsilon = simd4f(FLT_EPSILON);
+const Simd4fConstant sZeroW = simd4f(-FLT_MAX, -FLT_MAX, -FLT_MAX, 0.0f);
+
+// returns sorted indices, output needs to be at least 2*(last-first)+1024
+void radixSort(const uint32_t* first, const uint32_t* last, uint32_t* out)
+{
+ uint32_t n = uint32_t(last - first);
+
+ uint32_t* buffer = out + 2 * n;
+ uint32_t* __restrict histograms[] = { buffer, buffer + 256, buffer + 512, buffer + 768 };
+
+ intrinsics::memZero(buffer, 1024 * sizeof(uint32_t));
+
+ // build 3 histograms in one pass
+ for(const uint32_t* __restrict it = first; it != last; ++it)
+ {
+ uint32_t key = *it;
+ ++histograms[0][0xff & key];
+ ++histograms[1][0xff & (key >> 8)];
+ ++histograms[2][0xff & (key >> 16)];
+ ++histograms[3][key >> 24];
+ }
+
+ // convert histograms to offset tables in-place
+ uint32_t sums[4] = {};
+ for(uint32_t i = 0; i < 256; ++i)
+ {
+ uint32_t temp0 = histograms[0][i] + sums[0];
+ histograms[0][i] = sums[0], sums[0] = temp0;
+
+ uint32_t temp1 = histograms[1][i] + sums[1];
+ histograms[1][i] = sums[1], sums[1] = temp1;
+
+ uint32_t temp2 = histograms[2][i] + sums[2];
+ histograms[2][i] = sums[2], sums[2] = temp2;
+
+ uint32_t temp3 = histograms[3][i] + sums[3];
+ histograms[3][i] = sums[3], sums[3] = temp3;
+ }
+
+ PX_ASSERT(sums[0] == n && sums[1] == n && sums[2] == n && sums[3] == n);
+
+#if PX_DEBUG
+ memset(out, 0xff, 2 * n * sizeof(uint32_t));
+#endif
+
+ // sort 8 bits per pass
+
+ uint32_t* __restrict indices[] = { out, out + n };
+
+ for(uint32_t i = 0; i != n; ++i)
+ indices[1][histograms[0][0xff & first[i]]++] = i;
+
+ for(uint32_t i = 0, index; index = indices[1][i], i != n; ++i)
+ indices[0][histograms[1][0xff & (first[index] >> 8)]++] = index;
+
+ for(uint32_t i = 0, index; index = indices[0][i], i != n; ++i)
+ indices[1][histograms[2][0xff & (first[index] >> 16)]++] = index;
+
+ for(uint32_t i = 0, index; index = indices[1][i], i != n; ++i)
+ indices[0][histograms[3][first[index] >> 24]++] = index;
+}
+
+template <typename Simd4f>
+uint32_t longestAxis(const Simd4f& edgeLength)
+{
+ const float* e = array(edgeLength);
+
+ if(e[0] > e[1])
+ return uint32_t(e[0] > e[2] ? 0 : 2);
+ else
+ return uint32_t(e[1] > e[2] ? 1 : 2);
+}
+}
+
+template <typename Simd4f>
+cloth::SwInterCollision<Simd4f>::SwInterCollision(const cloth::SwInterCollisionData* instances, uint32_t n, float colDist,
+ float stiffness, uint32_t iterations, InterCollisionFilter filter,
+ cloth::SwKernelAllocator& alloc, profile::PxProfileZone* zone)
+: mInstances(instances)
+, mNumInstances(n)
+, mClothIndices(NULL)
+, mParticleIndices(NULL)
+, mNumParticles(0)
+, mTotalParticles(0)
+, mFilter(filter)
+, mAllocator(alloc)
+, mProfiler(zone)
+{
+ PX_ASSERT(mFilter);
+
+ mCollisionDistance = simd4f(colDist, colDist, colDist, 0.0f);
+ mCollisionSquareDistance = mCollisionDistance * mCollisionDistance;
+ mStiffness = simd4f(stiffness);
+ mNumIterations = iterations;
+
+ // calculate particle size
+ for(uint32_t i = 0; i < n; ++i)
+ mTotalParticles += instances[i].mNumParticles;
+}
+
+template <typename Simd4f>
+cloth::SwInterCollision<Simd4f>::~SwInterCollision()
+{
+}
+
+namespace
+{
+// multiple x by m leaving w component of x intact
+template <typename Simd4f>
+PX_INLINE Simd4f transform(const Simd4f m[4], const Simd4f& x)
+{
+ const Simd4f a = m[3] + splat<0>(x) * m[0] + splat<1>(x) * m[1] + splat<2>(x) * m[2];
+ return select(sMaskXYZ, a, x);
+}
+
+// rotate x by m leaving w component intact
+template <typename Simd4f>
+PX_INLINE Simd4f rotate(const Simd4f m[4], const Simd4f& x)
+{
+ const Simd4f a = splat<0>(x) * m[0] + splat<1>(x) * m[1] + splat<2>(x) * m[2];
+ return select(sMaskXYZ, a, x);
+}
+
+template <typename Simd4f>
+struct ClothSorter
+{
+ typedef cloth::BoundingBox<Simd4f> BoundingBox;
+
+ ClothSorter(BoundingBox* bounds, uint32_t n, uint32_t axis) : mBounds(bounds), mNumBounds(n), mAxis(axis)
+ {
+ }
+
+ bool operator()(uint32_t i, uint32_t j) const
+ {
+ PX_ASSERT(i < mNumBounds);
+ PX_ASSERT(j < mNumBounds);
+
+ return array(mBounds[i].mLower)[mAxis] < array(mBounds[j].mLower)[mAxis];
+ }
+
+ BoundingBox* mBounds;
+ uint32_t mNumBounds;
+ uint32_t mAxis;
+};
+
+// for the given cloth array this function calculates the set of particles
+// which potentially interact, the potential colliders are returned with their
+// cloth index and particle index in clothIndices and particleIndices, the
+// function returns the number of potential colliders
+template <typename Simd4f>
+uint32_t calculatePotentialColliders(const cloth::SwInterCollisionData* cBegin, const cloth::SwInterCollisionData* cEnd,
+ Simd4f colDist, uint16_t* clothIndices, uint32_t* particleIndices,
+ cloth::BoundingBox<Simd4f>& bounds, uint32_t* overlapMasks,
+ cloth::InterCollisionFilter filter, cloth::SwKernelAllocator& allocator)
+{
+ using namespace cloth;
+
+ typedef BoundingBox<Simd4f> BoundingBox;
+
+ uint32_t numParticles = 0;
+ const uint32_t numCloths = uint32_t(cEnd - cBegin);
+
+ // bounds of each cloth objects in world space
+ BoundingBox* const clothBounds = (BoundingBox*)(allocator.allocate(numCloths * sizeof(BoundingBox)));
+ BoundingBox* const overlapBounds = (BoundingBox*)(allocator.allocate(numCloths * sizeof(BoundingBox)));
+
+ // union of all cloth world bounds
+ BoundingBox totalClothBounds = emptyBounds<Simd4f>();
+
+ uint32_t* sortedIndices = (uint32_t*)allocator.allocate(numCloths * sizeof(uint32_t));
+
+ for(uint32_t i = 0; i < numCloths; ++i)
+ {
+ const SwInterCollisionData& c = cBegin[i];
+
+ // transform bounds from b local space to local space of a
+ PxBounds3 lcBounds = PxBounds3::centerExtents(c.mBoundsCenter, c.mBoundsHalfExtent + PxVec3(array(colDist)[0]));
+ PX_ASSERT(!lcBounds.isEmpty());
+ PxBounds3 cWorld = PxBounds3::transformFast(c.mGlobalPose, lcBounds);
+
+ BoundingBox cBounds = {(Simd4f)simd4f(cWorld.minimum.x, cWorld.minimum.y, cWorld.minimum.z, 0.0f),
+ (Simd4f)simd4f(cWorld.maximum.x, cWorld.maximum.y, cWorld.maximum.z, 0.0f) };
+
+ sortedIndices[i] = i;
+ clothBounds[i] = cBounds;
+
+ totalClothBounds = expandBounds(totalClothBounds, cBounds);
+ }
+
+ // sort indices by their minimum extent on the longest axis
+ const uint32_t sweepAxis = longestAxis(totalClothBounds.mUpper - totalClothBounds.mLower);
+
+ ClothSorter<Simd4f> predicate(clothBounds, numCloths, sweepAxis);
+ nvidia::sort(sortedIndices, numCloths, predicate);
+
+ for(uint32_t i = 0; i < numCloths; ++i)
+ {
+ PX_ASSERT(sortedIndices[i] < numCloths);
+
+ const SwInterCollisionData& a = cBegin[sortedIndices[i]];
+
+ // local bounds
+ const Simd4f aCenter = load(reinterpret_cast<const float*>(&a.mBoundsCenter));
+ const Simd4f aHalfExtent = load(reinterpret_cast<const float*>(&a.mBoundsHalfExtent)) + colDist;
+ const BoundingBox aBounds = { aCenter - aHalfExtent, aCenter + aHalfExtent };
+
+ const PxMat44 aToWorld(a.mGlobalPose);
+ const PxTransform aToLocal(a.mGlobalPose.getInverse());
+
+ const float axisMin = array(clothBounds[sortedIndices[i]].mLower)[sweepAxis];
+ const float axisMax = array(clothBounds[sortedIndices[i]].mUpper)[sweepAxis];
+
+ uint32_t overlapMask = 0;
+ uint32_t numOverlaps = 0;
+
+ // scan back to find first intersecting bounding box
+ uint32_t startIndex = i;
+ while(startIndex > 0 && array(clothBounds[sortedIndices[startIndex]].mUpper)[sweepAxis] > axisMin)
+ --startIndex;
+
+ // compute all overlapping bounds
+ for(uint32_t j = startIndex; j < numCloths; ++j)
+ {
+ // ignore self-collision
+ if(i == j)
+ continue;
+
+ // early out if no more cloths along axis intersect us
+ if(array(clothBounds[sortedIndices[j]].mLower)[sweepAxis] > axisMax)
+ break;
+
+ const SwInterCollisionData& b = cBegin[sortedIndices[j]];
+
+ // check if collision between these shapes is filtered
+ if(!filter(a.mUserData, b.mUserData))
+ continue;
+
+ // set mask bit for this cloth
+ overlapMask |= 1 << sortedIndices[j];
+
+ // transform bounds from b local space to local space of a
+ PxBounds3 lcBounds =
+ PxBounds3::centerExtents(b.mBoundsCenter, b.mBoundsHalfExtent + PxVec3(array(colDist)[0]));
+ PX_ASSERT(!lcBounds.isEmpty());
+ PxBounds3 bLocal = PxBounds3::transformFast(aToLocal * b.mGlobalPose, lcBounds);
+
+ BoundingBox bBounds = {(Simd4f)simd4f(bLocal.minimum.x, bLocal.minimum.y, bLocal.minimum.z, 0.0f),
+ (Simd4f)simd4f(bLocal.maximum.x, bLocal.maximum.y, bLocal.maximum.z, 0.0f) };
+
+ BoundingBox iBounds = intersectBounds(aBounds, bBounds);
+
+ // setup bounding box w to make point containment test cheaper
+ iBounds.mLower = (iBounds.mLower & sMaskXYZ) | ((Simd4f)sMaskW & simd4f(-FLT_MAX));
+ iBounds.mUpper = (iBounds.mUpper & sMaskXYZ) | ((Simd4f)sMaskW & simd4f(FLT_MAX));
+
+ if(!isEmptyBounds(iBounds))
+ overlapBounds[numOverlaps++] = iBounds;
+ }
+
+ //----------------------------------------------------------------
+ // cull all particles to overlapping bounds and transform particles to world space
+
+ const uint32_t clothIndex = sortedIndices[i];
+ overlapMasks[clothIndex] = overlapMask;
+
+ Simd4f* pBegin = reinterpret_cast<Simd4f*>(a.mParticles);
+ Simd4f* qBegin = reinterpret_cast<Simd4f*>(a.mPrevParticles);
+
+ const Simd4f xform[4] = { load(reinterpret_cast<const float*>(&aToWorld.column0)),
+ load(reinterpret_cast<const float*>(&aToWorld.column1)),
+ load(reinterpret_cast<const float*>(&aToWorld.column2)),
+ load(reinterpret_cast<const float*>(&aToWorld.column3)) };
+
+ Simd4f impulseInvScale = recip(Simd4f(simd4f(cBegin[clothIndex].mImpulseScale)));
+
+ for(uint32_t k = 0; k < a.mNumParticles; ++k)
+ {
+ Simd4f* pIt = a.mIndices ? pBegin + a.mIndices[k] : pBegin + k;
+ Simd4f* qIt = a.mIndices ? qBegin + a.mIndices[k] : qBegin + k;
+
+ const Simd4f p = *pIt;
+
+ for(const BoundingBox* oIt = overlapBounds, *oEnd = overlapBounds + numOverlaps; oIt != oEnd; ++oIt)
+ {
+ // point in box test
+ if(anyGreater(oIt->mLower, p) != 0)
+ continue;
+ if(anyGreater(p, oIt->mUpper) != 0)
+ continue;
+
+ // transform particle to world space in-place
+ // (will be transformed back after collision)
+ *pIt = transform(xform, p);
+
+ Simd4f impulse = (p - *qIt) * impulseInvScale;
+ *qIt = rotate(xform, impulse);
+
+ // update world bounds
+ bounds = expandBounds(bounds, pIt, pIt + 1);
+
+ // add particle to output arrays
+ clothIndices[numParticles] = uint16_t(clothIndex);
+ particleIndices[numParticles] = uint32_t(pIt - pBegin);
+
+ // output each particle only once
+ ++numParticles;
+ break;
+ }
+ }
+ }
+
+ allocator.deallocate(sortedIndices);
+ allocator.deallocate(overlapBounds);
+ allocator.deallocate(clothBounds);
+
+ return numParticles;
+}
+}
+
+template <typename Simd4f>
+PX_INLINE Simd4f& cloth::SwInterCollision<Simd4f>::getParticle(uint32_t index)
+{
+ PX_ASSERT(index < mNumParticles);
+
+ uint16_t clothIndex = mClothIndices[index];
+ uint32_t particleIndex = mParticleIndices[index];
+
+ PX_ASSERT(clothIndex < mNumInstances);
+
+ return reinterpret_cast<Simd4f&>(mInstances[clothIndex].mParticles[particleIndex]);
+}
+
+template <typename Simd4f>
+void cloth::SwInterCollision<Simd4f>::operator()()
+{
+ mNumTests = mNumCollisions = 0;
+
+ mClothIndices = static_cast<uint16_t*>(mAllocator.allocate(sizeof(uint16_t) * mTotalParticles));
+ mParticleIndices = static_cast<uint32_t*>(mAllocator.allocate(sizeof(uint32_t) * mTotalParticles));
+ mOverlapMasks = static_cast<uint32_t*>(mAllocator.allocate(sizeof(uint32_t*) * mNumInstances));
+
+ for(uint32_t k = 0; k < mNumIterations; ++k)
+ {
+ // world bounds of particles
+ BoundingBox<Simd4f> bounds = emptyBounds<Simd4f>();
+
+ // calculate potentially colliding set
+ {
+#if PX_PROFILE
+ ProfileZone zone("cloth::SwInterCollision::BroadPhase", mProfiler);
+#endif
+
+ mNumParticles =
+ calculatePotentialColliders(mInstances, mInstances + mNumInstances, mCollisionDistance, mClothIndices,
+ mParticleIndices, bounds, mOverlapMasks, mFilter, mAllocator);
+ }
+
+ // collide
+ if(mNumParticles)
+ {
+#if PX_PROFILE
+ ProfileZone zone("cloth::SwInterCollision::Collide", mProfiler);
+#endif
+
+ Simd4f lowerBound = bounds.mLower;
+ Simd4f edgeLength = max(bounds.mUpper - lowerBound, sEpsilon);
+
+ // sweep along longest axis
+ uint32_t sweepAxis = longestAxis(edgeLength);
+ uint32_t hashAxis0 = (sweepAxis + 1) % 3;
+ uint32_t hashAxis1 = (sweepAxis + 2) % 3;
+
+ // reserve 0, 127, and 65535 for sentinel
+ Simd4f cellSize = max(mCollisionDistance, simd4f(1.0f / 253) * edgeLength);
+ array(cellSize)[sweepAxis] = array(edgeLength)[sweepAxis] / 65533;
+
+ Simd4f one = simd4f(_1);
+ Simd4f gridSize = simd4f(254.0f);
+ array(gridSize)[sweepAxis] = 65534.0f;
+
+ Simd4f gridScale = recipT<1>(cellSize);
+ Simd4f gridBias = -lowerBound * gridScale + simd4f(_1);
+
+ void* buffer = mAllocator.allocate(getBufferSize(mNumParticles));
+
+ uint32_t* __restrict sortedIndices = reinterpret_cast<uint32_t*>(buffer);
+ uint32_t* __restrict sortedKeys = sortedIndices + mNumParticles;
+ uint32_t* __restrict keys = PxMax(sortedKeys + mNumParticles, sortedIndices + 2 * mNumParticles + 1024);
+
+ typedef typename Simd4fToSimd4i<Simd4f>::Type Simd4i;
+
+ // create keys
+ for(uint32_t i = 0; i < mNumParticles; ++i)
+ {
+ // grid coordinate
+ Simd4f indexf = getParticle(i) * gridScale + gridBias;
+
+ // need to clamp index because shape collision potentially
+ // pushes particles outside of their original bounds
+ Simd4i indexi = intFloor(max(one, min(indexf, gridSize)));
+
+ const int32_t* ptr = simdi::array(indexi);
+ keys[i] = uint32_t(ptr[sweepAxis] | (ptr[hashAxis0] << 16) | (ptr[hashAxis1] << 24));
+ }
+
+ // compute sorted keys indices
+ radixSort(keys, keys + mNumParticles, sortedIndices);
+
+ // snoop histogram: offset of first index with 8 msb > 1 (0 is sentinel)
+ uint32_t firstColumnSize = sortedIndices[2 * mNumParticles + 769];
+
+ // sort keys
+ for(uint32_t i = 0; i < mNumParticles; ++i)
+ sortedKeys[i] = keys[sortedIndices[i]];
+ sortedKeys[mNumParticles] = uint32_t(-1); // sentinel
+
+ // calculate the number of buckets we need to search forward
+ const Simd4i data = intFloor(gridScale * mCollisionDistance);
+ uint32_t collisionDistance = uint32_t(2 + simdi::array(data)[sweepAxis]);
+
+ // collide particles
+ collideParticles(sortedKeys, firstColumnSize, sortedIndices, mNumParticles, collisionDistance);
+
+ mAllocator.deallocate(buffer);
+ }
+
+ /*
+ // verify against brute force (disable collision response when testing)
+ uint32_t numCollisions = mNumCollisions;
+ mNumCollisions = 0;
+
+ for(uint32_t i = 0; i < mNumParticles; ++i)
+ for(uint32_t j = i+1; j < mNumParticles; ++j)
+ if (mOverlapMasks[mClothIndices[i]] & (1 << mClothIndices[j]))
+ collideParticles(getParticle(i), getParticle(j));
+
+ static uint32_t iter = 0; ++iter;
+ if(numCollisions != mNumCollisions)
+ printf("%u: %u != %u\n", iter, numCollisions, mNumCollisions);
+ */
+
+ // transform back to local space
+ {
+#if PX_PROFILE
+ ProfileZone zone("cloth::SwInterCollision::PostTransform", mProfiler);
+#endif
+ Simd4f toLocal[4], impulseScale;
+ uint16_t lastCloth = uint16_t(0xffff);
+
+ for(uint32_t i = 0; i < mNumParticles; ++i)
+ {
+ uint16_t clothIndex = mClothIndices[i];
+ const SwInterCollisionData* instance = mInstances + clothIndex;
+
+ // todo: could pre-compute these inverses
+ if(clothIndex != lastCloth)
+ {
+ const PxMat44 xform(instance->mGlobalPose.getInverse());
+
+ toLocal[0] = load(reinterpret_cast<const float*>(&xform.column0));
+ toLocal[1] = load(reinterpret_cast<const float*>(&xform.column1));
+ toLocal[2] = load(reinterpret_cast<const float*>(&xform.column2));
+ toLocal[3] = load(reinterpret_cast<const float*>(&xform.column3));
+
+ impulseScale = simd4f(instance->mImpulseScale);
+
+ lastCloth = mClothIndices[i];
+ }
+
+ uint32_t particleIndex = mParticleIndices[i];
+ Simd4f& particle = reinterpret_cast<Simd4f&>(instance->mParticles[particleIndex]);
+ Simd4f& impulse = reinterpret_cast<Simd4f&>(instance->mPrevParticles[particleIndex]);
+
+ particle = transform(toLocal, particle);
+ // avoid w becoming negative due to numerical inaccuracies
+ impulse = max(sZeroW, particle - rotate(toLocal, Simd4f(impulse * impulseScale)));
+ }
+ }
+ }
+
+ mAllocator.deallocate(mOverlapMasks);
+ mAllocator.deallocate(mParticleIndices);
+ mAllocator.deallocate(mClothIndices);
+}
+
+template <typename Simd4f>
+size_t cloth::SwInterCollision<Simd4f>::estimateTemporaryMemory(SwInterCollisionData* cloths, uint32_t n)
+{
+ // count total particles
+ uint32_t numParticles = 0;
+ for(uint32_t i = 0; i < n; ++i)
+ numParticles += cloths[i].mNumParticles;
+
+ uint32_t boundsSize = 2 * n * sizeof(BoundingBox<Simd4f>) + n * sizeof(uint32_t);
+ uint32_t clothIndicesSize = numParticles * sizeof(uint16_t);
+ uint32_t particleIndicesSize = numParticles * sizeof(uint32_t);
+ uint32_t masksSize = n * sizeof(uint32_t);
+
+ return boundsSize + clothIndicesSize + particleIndicesSize + masksSize + getBufferSize(numParticles);
+}
+
+template <typename Simd4f>
+size_t cloth::SwInterCollision<Simd4f>::getBufferSize(uint32_t numParticles)
+{
+ uint32_t keysSize = numParticles * sizeof(uint32_t);
+ uint32_t indicesSize = numParticles * sizeof(uint32_t);
+ uint32_t histogramSize = 1024 * sizeof(uint32_t);
+
+ return keysSize + indicesSize + PxMax(indicesSize + histogramSize, keysSize);
+}
+
+template <typename Simd4f>
+void cloth::SwInterCollision<Simd4f>::collideParticle(uint32_t index)
+{
+ uint16_t clothIndex = mClothIndices[index];
+
+ if((1 << clothIndex) & ~mClothMask)
+ return;
+
+ const SwInterCollisionData* instance = mInstances + clothIndex;
+
+ uint32_t particleIndex = mParticleIndices[index];
+ Simd4f& particle = reinterpret_cast<Simd4f&>(instance->mParticles[particleIndex]);
+
+ Simd4f diff = particle - mParticle;
+ Simd4f distSqr = dot3(diff, diff);
+
+#if PX_DEBUG
+ ++mNumTests;
+#endif
+
+ if(allGreater(distSqr, mCollisionSquareDistance))
+ return;
+
+ Simd4f w0 = splat<3>(mParticle);
+ Simd4f w1 = splat<3>(particle);
+
+ Simd4f ratio = mCollisionDistance * rsqrtT<1>(distSqr);
+ Simd4f scale = mStiffness * recipT<1>(sEpsilon + w0 + w1);
+ Simd4f delta = (scale * (diff - diff * ratio)) & sMaskXYZ;
+
+ mParticle = mParticle + delta * w0;
+ particle = particle - delta * w1;
+
+ Simd4f& impulse = reinterpret_cast<Simd4f&>(instance->mPrevParticles[particleIndex]);
+
+ mImpulse = mImpulse + delta * w0;
+ impulse = impulse - delta * w1;
+
+#if PX_DEBUG || PX_PROFILE
+ ++mNumCollisions;
+#endif
+}
+
+template <typename Simd4f>
+void cloth::SwInterCollision<Simd4f>::collideParticles(const uint32_t* keys, uint32_t firstColumnSize,
+ const uint32_t* indices, uint32_t numParticles,
+ uint32_t collisionDistance)
+{
+ const uint32_t bucketMask = uint16_t(-1);
+
+ const uint32_t keyOffsets[] = { 0, 0x00010000, 0x00ff0000, 0x01000000, 0x01010000 };
+
+ const uint32_t* __restrict kFirst[5];
+ const uint32_t* __restrict kLast[5];
+
+ {
+ // optimization: scan forward iterator starting points once instead of 9 times
+ const uint32_t* __restrict kIt = keys;
+
+ uint32_t key = *kIt;
+ uint32_t firstKey = key - PxMin(collisionDistance, key & bucketMask);
+ uint32_t lastKey = PxMin(key + collisionDistance, key | bucketMask);
+
+ kFirst[0] = kIt;
+ while(*kIt < lastKey)
+ ++kIt;
+ kLast[0] = kIt;
+
+ for(uint32_t k = 1; k < 5; ++k)
+ {
+ for(uint32_t n = firstKey + keyOffsets[k]; *kIt < n;)
+ ++kIt;
+ kFirst[k] = kIt;
+
+ for(uint32_t n = lastKey + keyOffsets[k]; *kIt < n;)
+ ++kIt;
+ kLast[k] = kIt;
+
+ // jump forward once to second column
+ kIt = keys + firstColumnSize;
+ firstColumnSize = 0;
+ }
+ }
+
+ const uint32_t* __restrict iIt = indices;
+ const uint32_t* __restrict iEnd = indices + numParticles;
+
+ const uint32_t* __restrict jIt;
+ const uint32_t* __restrict jEnd;
+
+ for(; iIt != iEnd; ++iIt, ++kFirst[0])
+ {
+ // load current particle once outside of inner loop
+ uint32_t index = *iIt;
+ PX_ASSERT(index < mNumParticles);
+ mClothIndex = mClothIndices[index];
+ PX_ASSERT(mClothIndex < mNumInstances);
+ mClothMask = mOverlapMasks[mClothIndex];
+
+ const SwInterCollisionData* instance = mInstances + mClothIndex;
+
+ mParticleIndex = mParticleIndices[index];
+ mParticle = reinterpret_cast<const Simd4f&>(instance->mParticles[mParticleIndex]);
+ mImpulse = reinterpret_cast<const Simd4f&>(instance->mPrevParticles[mParticleIndex]);
+
+ uint32_t key = *kFirst[0];
+
+ // range of keys we need to check against for this particle
+ uint32_t firstKey = key - PxMin(collisionDistance, key & bucketMask);
+ uint32_t lastKey = PxMin(key + collisionDistance, key | bucketMask);
+
+ // scan forward end point
+ while(*kLast[0] < lastKey)
+ ++kLast[0];
+
+ // process potential colliders of same cell
+ jEnd = indices + (kLast[0] - keys);
+ for(jIt = iIt + 1; jIt != jEnd; ++jIt)
+ collideParticle(*jIt);
+
+ // process neighbor cells
+ for(uint32_t k = 1; k < 5; ++k)
+ {
+ // scan forward start point
+ for(uint32_t n = firstKey + keyOffsets[k]; *kFirst[k] < n;)
+ ++kFirst[k];
+
+ // scan forward end point
+ for(uint32_t n = lastKey + keyOffsets[k]; *kLast[k] < n;)
+ ++kLast[k];
+
+ // process potential colliders
+ jEnd = indices + (kLast[k] - keys);
+ for(jIt = indices + (kFirst[k] - keys); jIt != jEnd; ++jIt)
+ collideParticle(*jIt);
+ }
+
+ // write back particle and impulse
+ reinterpret_cast<Simd4f&>(instance->mParticles[mParticleIndex]) = mParticle;
+ reinterpret_cast<Simd4f&>(instance->mPrevParticles[mParticleIndex]) = mImpulse;
+ }
+}
+
+// explicit template instantiation
+#if NVMATH_SIMD
+template class cloth::SwInterCollision<Simd4f>;
+#endif
+#if NVMATH_SCALAR
+template class cloth::SwInterCollision<Scalar4f>;
+#endif
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwInterCollision.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwInterCollision.h
new file mode 100644
index 00000000..ffc62eb1
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwInterCollision.h
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "Types.h"
+
+#include "StackAllocator.h"
+
+#include "Simd4i.h"
+
+#include "PxMat44.h"
+#include "PxTransform.h"
+#include "PxBounds3.h"
+
+namespace physx
+{
+ namespace profile
+ {
+ class PxProfileZone;
+ }
+}
+
+namespace nvidia
+{
+namespace cloth
+{
+
+class SwCloth;
+struct SwClothData;
+
+typedef StackAllocator<16> SwKernelAllocator;
+
+typedef bool (*InterCollisionFilter)(void* cloth0, void* cloth1);
+
+struct SwInterCollisionData
+{
+ SwInterCollisionData()
+ {
+ }
+ SwInterCollisionData(PxVec4* particles, PxVec4* prevParticles, uint32_t numParticles, uint32_t* indices,
+ const PxTransform& globalPose, const PxVec3& boundsCenter, const PxVec3& boundsHalfExtents,
+ float impulseScale, void* userData)
+ : mParticles(particles)
+ , mPrevParticles(prevParticles)
+ , mNumParticles(numParticles)
+ , mIndices(indices)
+ , mGlobalPose(globalPose)
+ , mBoundsCenter(boundsCenter)
+ , mBoundsHalfExtent(boundsHalfExtents)
+ , mImpulseScale(impulseScale)
+ , mUserData(userData)
+ {
+ }
+
+ PxVec4* mParticles;
+ PxVec4* mPrevParticles;
+ uint32_t mNumParticles;
+ uint32_t* mIndices;
+ PxTransform mGlobalPose;
+ PxVec3 mBoundsCenter;
+ PxVec3 mBoundsHalfExtent;
+ float mImpulseScale;
+ void* mUserData;
+};
+
+template <typename Simd4f>
+class SwInterCollision
+{
+
+ public:
+ SwInterCollision(const SwInterCollisionData* cloths, uint32_t n, float colDist, float stiffness, uint32_t iterations,
+ InterCollisionFilter filter, cloth::SwKernelAllocator& alloc, nvidia::profile::PxProfileZone* zone);
+
+ ~SwInterCollision();
+
+ void operator()();
+
+ static size_t estimateTemporaryMemory(SwInterCollisionData* cloths, uint32_t n);
+
+ private:
+ SwInterCollision& operator=(const SwInterCollision&); // not implemented
+
+ static size_t getBufferSize(uint32_t);
+
+ void collideParticles(const uint32_t* keys, uint32_t firstColumnSize, const uint32_t* sortedIndices,
+ uint32_t numParticles, uint32_t collisionDistance);
+
+ Simd4f& getParticle(uint32_t index);
+
+ // better wrap these in a struct
+ void collideParticle(uint32_t index);
+
+ Simd4f mParticle;
+ Simd4f mImpulse;
+
+ Simd4f mCollisionDistance;
+ Simd4f mCollisionSquareDistance;
+ Simd4f mStiffness;
+
+ uint16_t mClothIndex;
+ uint32_t mClothMask;
+ uint32_t mParticleIndex;
+
+ uint32_t mNumIterations;
+
+ const SwInterCollisionData* mInstances;
+ uint32_t mNumInstances;
+
+ uint16_t* mClothIndices;
+ uint32_t* mParticleIndices;
+ uint32_t mNumParticles;
+ uint32_t* mOverlapMasks;
+
+ uint32_t mTotalParticles;
+
+ InterCollisionFilter mFilter;
+
+ SwKernelAllocator& mAllocator;
+
+ profile::PxProfileZone* mProfiler;
+
+ public:
+ mutable uint32_t mNumTests;
+ mutable uint32_t mNumCollisions;
+};
+
+} // namespace cloth
+
+} // namespace nvidia
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwSelfCollision.cpp b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwSelfCollision.cpp
new file mode 100644
index 00000000..939543f4
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwSelfCollision.cpp
@@ -0,0 +1,404 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "SwSelfCollision.h"
+#include "SwCloth.h"
+#include "SwClothData.h"
+#include "PsIntrinsics.h"
+#include "SwCollision.h" //temp fix, needed by SwCollisionHelper implementaitons
+#include "Simd4f.h"
+#include "SwCollisionHelpers.h"
+
+#pragma warning(disable:4127)
+
+using namespace nvidia;
+using namespace nvidia;
+
+namespace
+{
+typedef Simd4fFactory<detail::FourTuple> Simd4fConstant;
+
+const Simd4fConstant sMaskXYZ = simd4f(simd4i(~0, ~0, ~0, 0));
+const Simd4fConstant sEpsilon = simd4f(FLT_EPSILON);
+
+// returns sorted indices, output needs to be at least 2*(last-first)+1024
+void radixSort(const uint32_t* first, const uint32_t* last, uint16_t* out)
+{
+ uint16_t n = uint16_t(last - first);
+
+ uint16_t* buffer = out + 2 * n;
+ uint16_t* __restrict histograms[] = { buffer, buffer + 256, buffer + 512, buffer + 768 };
+
+ intrinsics::memZero(buffer, 1024 * sizeof(uint16_t));
+
+ // build 3 histograms in one pass
+ for(const uint32_t* __restrict it = first; it != last; ++it)
+ {
+ uint32_t key = *it;
+ ++histograms[0][0xff & key];
+ ++histograms[1][0xff & (key >> 8)];
+ ++histograms[2][0xff & (key >> 16)];
+ ++histograms[3][key >> 24];
+ }
+
+ // convert histograms to offset tables in-place
+ uint16_t sums[4] = {};
+ for(uint32_t i = 0; i < 256; ++i)
+ {
+ uint16_t temp0 = uint16_t(histograms[0][i] + sums[0]);
+ histograms[0][i] = sums[0], sums[0] = temp0;
+
+ uint16_t temp1 = uint16_t(histograms[1][i] + sums[1]);
+ histograms[1][i] = sums[1], sums[1] = temp1;
+
+ uint16_t temp2 = uint16_t(histograms[2][i] + sums[2]);
+ histograms[2][i] = sums[2], sums[2] = temp2;
+
+ uint16_t temp3 = uint16_t(histograms[3][i] + sums[3]);
+ histograms[3][i] = sums[3], sums[3] = temp3;
+ }
+
+ PX_ASSERT(sums[0] == n && sums[1] == n && sums[2] == n && sums[3] == n);
+
+#if PX_DEBUG
+ memset(out, 0xff, 2 * n * sizeof(uint16_t));
+#endif
+
+ // sort 8 bits per pass
+
+ uint16_t* __restrict indices[] = { out, out + n };
+
+ for(uint16_t i = 0; i != n; ++i)
+ indices[1][histograms[0][0xff & first[i]]++] = i;
+
+ for(uint16_t i = 0, index; index = indices[1][i], i != n; ++i)
+ indices[0][histograms[1][0xff & (first[index] >> 8)]++] = index;
+
+ for(uint16_t i = 0, index; index = indices[0][i], i != n; ++i)
+ indices[1][histograms[2][0xff & (first[index] >> 16)]++] = index;
+
+ for(uint16_t i = 0, index; index = indices[1][i], i != n; ++i)
+ indices[0][histograms[3][first[index] >> 24]++] = index;
+}
+
+template <typename Simd4f>
+uint32_t longestAxis(const Simd4f& edgeLength)
+{
+ const float* e = array(edgeLength);
+
+ if(e[0] > e[1])
+ return uint32_t(e[0] > e[2] ? 0 : 2);
+ else
+ return uint32_t(e[1] > e[2] ? 1 : 2);
+}
+
+bool isSelfCollisionEnabled(const cloth::SwClothData& cloth)
+{
+ return PxMin(cloth.mSelfCollisionDistance, cloth.mSelfCollisionStiffness) > 0.0f;
+}
+
+bool isSelfCollisionEnabled(const cloth::SwCloth& cloth)
+{
+ return PxMin(cloth.mSelfCollisionDistance, -cloth.mSelfCollisionLogStiffness) > 0.0f;
+}
+
+inline uint32_t align2(uint32_t x)
+{
+ return (x + 1) & ~1;
+}
+
+} // anonymous namespace
+
+template <typename Simd4f>
+cloth::SwSelfCollision<Simd4f>::SwSelfCollision(cloth::SwClothData& clothData, cloth::SwKernelAllocator& alloc)
+: mClothData(clothData), mAllocator(alloc)
+{
+ mCollisionDistance = simd4f(mClothData.mSelfCollisionDistance);
+ mCollisionSquareDistance = mCollisionDistance * mCollisionDistance;
+ mStiffness = (Simd4f)sMaskXYZ & simd4f(mClothData.mSelfCollisionStiffness);
+}
+
+template <typename Simd4f>
+cloth::SwSelfCollision<Simd4f>::~SwSelfCollision()
+{
+}
+
+template <typename Simd4f>
+void cloth::SwSelfCollision<Simd4f>::operator()()
+{
+ mNumTests = mNumCollisions = 0;
+
+ if(!isSelfCollisionEnabled(mClothData))
+ return;
+
+ Simd4f lowerBound = load(mClothData.mCurBounds);
+ Simd4f edgeLength = max(load(mClothData.mCurBounds + 3) - lowerBound, sEpsilon);
+
+ // sweep along longest axis
+ uint32_t sweepAxis = longestAxis(edgeLength);
+ uint32_t hashAxis0 = (sweepAxis + 1) % 3;
+ uint32_t hashAxis1 = (sweepAxis + 2) % 3;
+
+ // reserve 0, 127, and 65535 for sentinel
+ Simd4f cellSize = max(mCollisionDistance, simd4f(1.0f / 253) * edgeLength);
+ array(cellSize)[sweepAxis] = array(edgeLength)[sweepAxis] / 65533;
+
+ Simd4f one = simd4f(_1);
+ Simd4f gridSize = simd4f(254.0f);
+ array(gridSize)[sweepAxis] = 65534.0f;
+
+ Simd4f gridScale = recipT<1>(cellSize);
+ Simd4f gridBias = -lowerBound * gridScale + simd4f(_1);
+
+ uint32_t numIndices = mClothData.mNumSelfCollisionIndices;
+ void* buffer = mAllocator.allocate(getBufferSize(numIndices));
+
+ const uint32_t* __restrict indices = mClothData.mSelfCollisionIndices;
+ uint32_t* __restrict keys = reinterpret_cast<uint32_t*>(buffer);
+ uint16_t* __restrict sortedIndices = reinterpret_cast<uint16_t*>(keys + numIndices);
+ uint32_t* __restrict sortedKeys = reinterpret_cast<uint32_t*>(sortedIndices + align2(numIndices));
+
+ const Simd4f* particles = reinterpret_cast<const Simd4f*>(mClothData.mCurParticles);
+
+ // create keys
+ for(uint32_t i = 0; i < numIndices; ++i)
+ {
+ uint32_t index = indices ? indices[i] : i;
+
+ // grid coordinate
+ Simd4f keyf = particles[index] * gridScale + gridBias;
+
+ // need to clamp index because shape collision potentially
+ // pushes particles outside of their original bounds
+ Simd4i keyi = intFloor(max(one, min(keyf, gridSize)));
+
+ const int32_t* ptr = simdi::array(keyi);
+ keys[i] = uint32_t(ptr[sweepAxis] | (ptr[hashAxis0] << 16) | (ptr[hashAxis1] << 24));
+ }
+
+ // compute sorted keys indices
+ radixSort(keys, keys + numIndices, sortedIndices);
+
+ // snoop histogram: offset of first index with 8 msb > 1 (0 is sentinel)
+ uint16_t firstColumnSize = sortedIndices[2 * numIndices + 769];
+
+ // sort keys
+ for(uint32_t i = 0; i < numIndices; ++i)
+ sortedKeys[i] = keys[sortedIndices[i]];
+ sortedKeys[numIndices] = uint32_t(-1); // sentinel
+
+ if(indices)
+ {
+ // sort indices (into no-longer-needed keys array)
+ const uint16_t* __restrict permutation = sortedIndices;
+ sortedIndices = reinterpret_cast<uint16_t*>(keys);
+ for(uint32_t i = 0; i < numIndices; ++i)
+ sortedIndices[i] = uint16_t(indices[permutation[i]]);
+ }
+
+ // calculate the number of buckets we need to search forward
+ const Simd4i data = intFloor(gridScale * mCollisionDistance);
+ uint32_t collisionDistance = 2 + (uint32_t)simdi::array(data)[sweepAxis];
+
+ // collide particles
+ if(mClothData.mRestPositions)
+ collideParticles<true>(sortedKeys, firstColumnSize, sortedIndices, collisionDistance);
+ else
+ collideParticles<false>(sortedKeys, firstColumnSize, sortedIndices, collisionDistance);
+
+ mAllocator.deallocate(buffer);
+
+ // verify against brute force (disable collision response when testing)
+ /*
+ uint32_t numCollisions = mNumCollisions;
+ mNumCollisions = 0;
+
+ Simd4f* qarticles = reinterpret_cast<
+ Simd4f*>(mClothData.mCurParticles);
+ for(uint32_t i = 0; i < numIndices; ++i)
+ {
+ uint32_t indexI = indices ? indices[i] : i;
+ for(uint32_t j = i+1; j < numIndices; ++j)
+ {
+ uint32_t indexJ = indices ? indices[j] : j;
+ collideParticles(qarticles[indexI], qarticles[indexJ]);
+ }
+ }
+
+ static uint32_t iter = 0; ++iter;
+ if(numCollisions != mNumCollisions)
+ printf("%u: %u != %u\n", iter, numCollisions, mNumCollisions);
+ */
+}
+
+template <typename Simd4f>
+size_t cloth::SwSelfCollision<Simd4f>::estimateTemporaryMemory(const SwCloth& cloth)
+{
+ uint32_t numIndices =
+ cloth.mSelfCollisionIndices.empty() ? cloth.mCurParticles.size() : cloth.mSelfCollisionIndices.size();
+ return isSelfCollisionEnabled(cloth) ? getBufferSize(numIndices) : 0;
+}
+
+template <typename Simd4f>
+size_t cloth::SwSelfCollision<Simd4f>::getBufferSize(uint32_t numIndices)
+{
+ uint32_t keysSize = numIndices * sizeof(uint32_t);
+ uint32_t indicesSize = align2(numIndices) * sizeof(uint16_t);
+ uint32_t radixSize = (numIndices + 1024) * sizeof(uint16_t);
+ return keysSize + indicesSize + PxMax(radixSize, keysSize + uint32_t(sizeof(uint32_t)));
+}
+
+template <typename Simd4f>
+template <bool useRestParticles>
+void cloth::SwSelfCollision<Simd4f>::collideParticles(Simd4f& pos0, Simd4f& pos1, const Simd4f& pos0rest,
+ const Simd4f& pos1rest)
+{
+ Simd4f diff = pos1 - pos0;
+ Simd4f distSqr = dot3(diff, diff);
+
+#if PX_DEBUG
+ ++mNumTests;
+#endif
+
+ if(allGreater(distSqr, mCollisionSquareDistance))
+ return;
+
+ if(useRestParticles)
+ {
+ // calculate distance in rest configuration, if less than collision
+ // distance then ignore collision between particles in deformed config
+ Simd4f restDiff = pos1rest - pos0rest;
+ Simd4f restDistSqr = dot3(restDiff, restDiff);
+
+ if(allGreater(mCollisionSquareDistance, restDistSqr))
+ return;
+ }
+
+ Simd4f w0 = splat<3>(pos0);
+ Simd4f w1 = splat<3>(pos1);
+
+ Simd4f ratio = mCollisionDistance * rsqrt(distSqr);
+ Simd4f scale = mStiffness * recip(sEpsilon + w0 + w1);
+ Simd4f delta = (scale * (diff - diff * ratio)) & sMaskXYZ;
+
+ pos0 = pos0 + delta * w0;
+ pos1 = pos1 - delta * w1;
+
+#if PX_DEBUG || PX_PROFILE
+ ++mNumCollisions;
+#endif
+}
+
+template <typename Simd4f>
+template <bool useRestParticles>
+void cloth::SwSelfCollision<Simd4f>::collideParticles(const uint32_t* keys, uint16_t firstColumnSize,
+ const uint16_t* indices, uint32_t collisionDistance)
+{
+ Simd4f* __restrict particles = reinterpret_cast<Simd4f*>(mClothData.mCurParticles);
+ Simd4f* __restrict restParticles =
+ useRestParticles ? reinterpret_cast<Simd4f*>(mClothData.mRestPositions) : particles;
+
+ const uint32_t bucketMask = uint16_t(-1);
+
+ const uint32_t keyOffsets[] = { 0, 0x00010000, 0x00ff0000, 0x01000000, 0x01010000 };
+
+ const uint32_t* __restrict kFirst[5];
+ const uint32_t* __restrict kLast[5];
+
+ {
+ // optimization: scan forward iterator starting points once instead of 9 times
+ const uint32_t* __restrict kIt = keys;
+
+ uint32_t key = *kIt;
+ uint32_t firstKey = key - PxMin(collisionDistance, key & bucketMask);
+ uint32_t lastKey = PxMin(key + collisionDistance, key | bucketMask);
+
+ kFirst[0] = kIt;
+ while(*kIt < lastKey)
+ ++kIt;
+ kLast[0] = kIt;
+
+ for(uint32_t k = 1; k < 5; ++k)
+ {
+ for(uint32_t n = firstKey + keyOffsets[k]; *kIt < n;)
+ ++kIt;
+ kFirst[k] = kIt;
+
+ for(uint32_t n = lastKey + keyOffsets[k]; *kIt < n;)
+ ++kIt;
+ kLast[k] = kIt;
+
+ // jump forward once to second column
+ kIt = keys + firstColumnSize;
+ firstColumnSize = 0;
+ }
+ }
+
+ const uint16_t* __restrict iIt = indices;
+ const uint16_t* __restrict iEnd = indices + mClothData.mNumSelfCollisionIndices;
+
+ const uint16_t* __restrict jIt;
+ const uint16_t* __restrict jEnd;
+
+ for(; iIt != iEnd; ++iIt, ++kFirst[0])
+ {
+ PX_ASSERT(*iIt < mClothData.mNumParticles);
+
+ // load current particle once outside of inner loop
+ Simd4f particle = particles[*iIt];
+ Simd4f restParticle = restParticles[*iIt];
+
+ uint32_t key = *kFirst[0];
+
+ // range of keys we need to check against for this particle
+ uint32_t firstKey = key - PxMin(collisionDistance, key & bucketMask);
+ uint32_t lastKey = PxMin(key + collisionDistance, key | bucketMask);
+
+ // scan forward end point
+ while(*kLast[0] < lastKey)
+ ++kLast[0];
+
+ // process potential colliders of same cell
+ jEnd = indices + (kLast[0] - keys);
+ for(jIt = iIt + 1; jIt != jEnd; ++jIt)
+ collideParticles<useRestParticles>(particle, particles[*jIt], restParticle, restParticles[*jIt]);
+
+ // process neighbor cells
+ for(uint32_t k = 1; k < 5; ++k)
+ {
+ // scan forward start point
+ for(uint32_t n = firstKey + keyOffsets[k]; *kFirst[k] < n;)
+ ++kFirst[k];
+
+ // scan forward end point
+ for(uint32_t n = lastKey + keyOffsets[k]; *kLast[k] < n;)
+ ++kLast[k];
+
+ // process potential colliders
+ jEnd = indices + (kLast[k] - keys);
+ for(jIt = indices + (kFirst[k] - keys); jIt != jEnd; ++jIt)
+ collideParticles<useRestParticles>(particle, particles[*jIt], restParticle, restParticles[*jIt]);
+ }
+
+ // store current particle
+ particles[*iIt] = particle;
+ }
+}
+
+// explicit template instantiation
+#if NVMATH_SIMD
+template class cloth::SwSelfCollision<Simd4f>;
+#endif
+#if NVMATH_SCALAR
+template class cloth::SwSelfCollision<Scalar4f>;
+#endif
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwSelfCollision.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwSelfCollision.h
new file mode 100644
index 00000000..fa023e56
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwSelfCollision.h
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "Types.h"
+#include "StackAllocator.h"
+#include "Simd4i.h"
+
+namespace nvidia
+{
+
+namespace cloth
+{
+
+class SwCloth;
+struct SwClothData;
+
+typedef StackAllocator<16> SwKernelAllocator;
+
+template <typename Simd4f>
+class SwSelfCollision
+{
+ typedef typename Simd4fToSimd4i<Simd4f>::Type Simd4i;
+
+ public:
+ SwSelfCollision(SwClothData& clothData, SwKernelAllocator& alloc);
+ ~SwSelfCollision();
+
+ void operator()();
+
+ static size_t estimateTemporaryMemory(const SwCloth&);
+
+ private:
+ SwSelfCollision& operator=(const SwSelfCollision&); // not implemented
+ static size_t getBufferSize(uint32_t);
+
+ template <bool useRestParticles>
+ void collideParticles(Simd4f&, Simd4f&, const Simd4f&, const Simd4f&);
+
+ template <bool useRestParticles>
+ void collideParticles(const uint32_t*, uint16_t, const uint16_t*, uint32_t);
+
+ Simd4f mCollisionDistance;
+ Simd4f mCollisionSquareDistance;
+ Simd4f mStiffness;
+
+ SwClothData& mClothData;
+ SwKernelAllocator& mAllocator;
+
+ public:
+ mutable uint32_t mNumTests;
+ mutable uint32_t mNumCollisions;
+};
+
+} // namespace cloth
+
+} // namespace nvidia
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwSolver.cpp b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwSolver.cpp
new file mode 100644
index 00000000..35cb1bde
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwSolver.cpp
@@ -0,0 +1,398 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "SwSolver.h"
+#include "SwCloth.h"
+#include "ClothImpl.h"
+#include "SwFabric.h"
+#include "SwFactory.h"
+#include "SwClothData.h"
+#include "SwSolverKernel.h"
+#include "SwInterCollision.h"
+#include "IterationState.h"
+#include "PxCpuDispatcher.h"
+#include "PxProfileZone.h"
+#include "PsFPU.h"
+#include "PsSort.h"
+
+namespace nvidia
+{
+namespace cloth
+{
+bool neonSolverKernel(SwCloth const&, SwClothData&, SwKernelAllocator&, IterationStateFactory&, profile::PxProfileZone*);
+}
+}
+
+#if NVMATH_SIMD
+typedef Simd4f Simd4fType;
+#else
+typedef Scalar4f Simd4fType;
+#endif
+
+using namespace nvidia;
+
+cloth::SwSolver::SwSolver(nvidia::profile::PxProfileZone* profiler, PxTaskManager* taskMgr)
+: mProfiler(profiler)
+, mSimulateEventId(mProfiler ? mProfiler->getEventIdForName("cloth::SwSolver::simulate") : uint16_t(-1))
+#if APEX_UE4
+, mDt(0.0f)
+#endif
+, mInterCollisionDistance(0.0f)
+, mInterCollisionStiffness(1.0f)
+, mInterCollisionIterations(1)
+, mInterCollisionScratchMem(NULL)
+, mInterCollisionScratchMemSize(0)
+{
+ mStartSimulationTask.mSolver = this;
+ mEndSimulationTask.mSolver = this;
+
+ PX_UNUSED(taskMgr);
+}
+
+cloth::SwSolver::~SwSolver()
+{
+ if(mInterCollisionScratchMem)
+ PX_FREE(mInterCollisionScratchMem);
+
+ PX_ASSERT(mCpuClothSimulationTasks.empty());
+}
+
+namespace
+{
+template <typename T>
+bool clothSizeGreater(const T& t0, const T& t1)
+{
+#if APEX_UE4
+ return t0->mCloth->mCurParticles.size() > t1->mCloth->mCurParticles.size();
+#else
+ return t0.mCloth->mCurParticles.size() > t1.mCloth->mCurParticles.size();
+#endif
+}
+
+template <typename T>
+void sortTasks(nvidia::Array<T, nvidia::NonTrackingAllocator>& tasks)
+{
+ nvidia::sort(tasks.begin(), tasks.size(), &clothSizeGreater<T>);
+}
+}
+
+void cloth::SwSolver::addCloth(Cloth* cloth)
+{
+ SwCloth& swCloth = static_cast<SwClothImpl&>(*cloth).mCloth;
+
+#if APEX_UE4
+ mCpuClothSimulationTasks.pushBack(new CpuClothSimulationTask(swCloth, *this));
+#else
+ mCpuClothSimulationTasks.pushBack(CpuClothSimulationTask(swCloth, mEndSimulationTask));
+#endif
+
+ sortTasks(mCpuClothSimulationTasks);
+}
+
+void cloth::SwSolver::removeCloth(Cloth* cloth)
+{
+ SwCloth& swCloth = static_cast<SwClothImpl&>(*cloth).mCloth;
+
+ CpuClothSimulationTaskVector::Iterator tIt = mCpuClothSimulationTasks.begin();
+ CpuClothSimulationTaskVector::Iterator tEnd = mCpuClothSimulationTasks.end();
+
+ while (tIt != tEnd &&
+#if APEX_UE4
+ (*tIt)->mCloth != &swCloth
+#else
+ tIt->mCloth != &swCloth
+#endif
+ )
+ ++tIt;
+
+ if(tIt != tEnd)
+ {
+#if APEX_UE4
+ delete *tIt;
+#else
+ deallocate(tIt->mScratchMemory);
+#endif
+ mCpuClothSimulationTasks.replaceWithLast(tIt);
+ sortTasks(mCpuClothSimulationTasks);
+ }
+}
+
+PxBaseTask& cloth::SwSolver::simulate(float dt, PxBaseTask& continuation)
+{
+ if (mCpuClothSimulationTasks.empty()
+#if APEX_UE4
+ || dt == 0.0f
+#endif
+ )
+ {
+ continuation.addReference();
+ return continuation;
+ }
+
+ mEndSimulationTask.setContinuation(&continuation);
+#if APEX_UE4
+ mDt = dt;
+#else
+ mEndSimulationTask.mDt = dt;
+#endif
+
+ mStartSimulationTask.setContinuation(&mEndSimulationTask);
+
+ mEndSimulationTask.removeReference();
+
+ return mStartSimulationTask;
+}
+
+void cloth::SwSolver::interCollision()
+{
+ if(!mInterCollisionIterations || mInterCollisionDistance == 0.0f)
+ return;
+
+ float elasticity = 1.0f;
+
+ // rebuild cloth instance array
+ mInterCollisionInstances.resize(0);
+ for(uint32_t i = 0; i < mCpuClothSimulationTasks.size(); ++i)
+ {
+#if APEX_UE4
+ SwCloth* c = mCpuClothSimulationTasks[i]->mCloth;
+ float invNumIterations = mCpuClothSimulationTasks[i]->mInvNumIterations;
+#else
+ SwCloth* c = mCpuClothSimulationTasks[i].mCloth;
+ float invNumIterations = mCpuClothSimulationTasks[i].mInvNumIterations;
+#endif
+
+ mInterCollisionInstances.pushBack(SwInterCollisionData(
+ c->mCurParticles.begin(), c->mPrevParticles.begin(),
+ c->mSelfCollisionIndices.empty() ? c->mCurParticles.size() : c->mSelfCollisionIndices.size(),
+ c->mSelfCollisionIndices.empty() ? NULL : &c->mSelfCollisionIndices[0], c->mTargetMotion,
+ c->mParticleBoundsCenter, c->mParticleBoundsHalfExtent, elasticity * invNumIterations, c->mUserData));
+ }
+
+ const uint32_t requiredTempMemorySize = uint32_t(SwInterCollision<Simd4fType>::estimateTemporaryMemory(
+ &mInterCollisionInstances[0], mInterCollisionInstances.size()));
+
+ // realloc temp memory if necessary
+ if(mInterCollisionScratchMemSize < requiredTempMemorySize)
+ {
+ if(mInterCollisionScratchMem)
+ PX_FREE(mInterCollisionScratchMem);
+
+ mInterCollisionScratchMem = PX_ALLOC(requiredTempMemorySize, "cloth::SwSolver::mInterCollisionScratchMem");
+ mInterCollisionScratchMemSize = requiredTempMemorySize;
+ }
+
+ SwKernelAllocator allocator(mInterCollisionScratchMem, mInterCollisionScratchMemSize);
+
+ // run inter-collision
+ SwInterCollision<Simd4fType> collider(mInterCollisionInstances.begin(), mInterCollisionInstances.size(),
+ mInterCollisionDistance, mInterCollisionStiffness, mInterCollisionIterations,
+ mInterCollisionFilter, allocator, mProfiler);
+
+ collider();
+}
+
+void cloth::SwSolver::beginFrame() const
+{
+ if(mProfiler)
+ mProfiler->startEvent(mSimulateEventId, uint64_t(intptr_t(this)), uint32_t(intptr_t(this)));
+}
+
+void cloth::SwSolver::endFrame() const
+{
+ if(mProfiler)
+ mProfiler->stopEvent(mSimulateEventId, uint64_t(intptr_t(this)), uint32_t(intptr_t(this)));
+}
+
+#if APEX_UE4
+void cloth::SwSolver::simulate(void* task, float dt)
+{
+ if (task)
+ static_cast<cloth::SwSolver::CpuClothSimulationTask*>(task)->simulate(dt);
+}
+#endif
+
+void cloth::SwSolver::StartSimulationTask::runInternal()
+{
+ mSolver->beginFrame();
+
+ CpuClothSimulationTaskVector::Iterator tIt = mSolver->mCpuClothSimulationTasks.begin();
+ CpuClothSimulationTaskVector::Iterator tEnd = mSolver->mCpuClothSimulationTasks.end();
+
+ for(; tIt != tEnd; ++tIt)
+ {
+#if APEX_UE4
+ if (!(*tIt)->mCloth->isSleeping())
+ {
+ (*tIt)->setContinuation(mCont);
+ (*tIt)->removeReference();
+ }
+#else
+ if(!tIt->mCloth->isSleeping())
+ {
+ tIt->setContinuation(mCont);
+ tIt->removeReference();
+ }
+#endif
+ }
+}
+
+const char* cloth::SwSolver::StartSimulationTask::getName() const
+{
+ return "cloth.SwSolver.startSimulation";
+}
+
+void cloth::SwSolver::EndSimulationTask::runInternal()
+{
+ mSolver->interCollision();
+ mSolver->endFrame();
+}
+
+const char* cloth::SwSolver::EndSimulationTask::getName() const
+{
+ return "cloth.SwSolver.endSimulation";
+}
+
+#if !APEX_UE4
+cloth::SwSolver::CpuClothSimulationTask::CpuClothSimulationTask(SwCloth& cloth, EndSimulationTask& continuation)
+: mCloth(&cloth), mContinuation(&continuation), mScratchMemorySize(0), mScratchMemory(0), mInvNumIterations(0.0f)
+{
+}
+#endif
+
+#if APEX_UE4
+cloth::SwSolver::CpuClothSimulationTask::CpuClothSimulationTask(SwCloth& cloth, SwSolver& solver)
+ : mCloth(&cloth), mSolver(&solver), mScratchMemorySize(0), mScratchMemory(0), mInvNumIterations(0.0f)
+{
+ mCloth->mSimulationTask = this;
+}
+
+cloth::SwSolver::CpuClothSimulationTask::~CpuClothSimulationTask()
+{
+ deallocate(mScratchMemory);
+ mCloth->mSimulationTask = NULL;
+}
+
+void cloth::SwSolver::CpuClothSimulationTask::runInternal()
+{
+ simulate(mSolver->mDt);
+}
+
+
+void cloth::SwSolver::CpuClothSimulationTask::simulate(float dt)
+{
+ // check if we need to reallocate the temp memory buffer
+ // (number of shapes may have changed)
+ uint32_t requiredTempMemorySize = uint32_t(SwSolverKernel<Simd4fType>::estimateTemporaryMemory(*mCloth));
+
+ if (mScratchMemorySize < requiredTempMemorySize)
+ {
+ deallocate(mScratchMemory);
+
+ mScratchMemory = allocate(requiredTempMemorySize);
+ mScratchMemorySize = requiredTempMemorySize;
+ }
+
+ IterationStateFactory factory(*mCloth, dt);
+ mInvNumIterations = factory.mInvNumIterations;
+
+ nvidia::SIMDGuard simdGuard;
+
+ SwClothData data(*mCloth, mCloth->mFabric);
+ SwKernelAllocator allocator(mScratchMemory, uint32_t(mScratchMemorySize));
+ nvidia::profile::PxProfileZone* profileZone = mSolver->mProfiler;
+
+ // construct kernel functor and execute
+#if PX_ANDROID
+ // if(!neonSolverKernel(cloth, data, allocator, factory, profileZone))
+#endif
+ SwSolverKernel<Simd4fType>(*mCloth, data, allocator, factory, profileZone)();
+
+ data.reconcile(*mCloth); // update cloth
+
+ release();
+}
+
+#else
+
+void cloth::SwSolver::CpuClothSimulationTask::runInternal()
+{
+ // check if we need to reallocate the temp memory buffer
+ // (number of shapes may have changed)
+ uint32_t requiredTempMemorySize = uint32_t(SwSolverKernel<Simd4fType>::estimateTemporaryMemory(*mCloth));
+
+ if(mScratchMemorySize < requiredTempMemorySize)
+ {
+ deallocate(mScratchMemory);
+
+ mScratchMemory = allocate(requiredTempMemorySize);
+ mScratchMemorySize = requiredTempMemorySize;
+ }
+
+ if(mContinuation->mDt == 0.0f)
+ return;
+
+ IterationStateFactory factory(*mCloth, mContinuation->mDt);
+ mInvNumIterations = factory.mInvNumIterations;
+
+ nvidia::SIMDGuard simdGuard;
+
+ SwClothData data(*mCloth, mCloth->mFabric);
+ SwKernelAllocator allocator(mScratchMemory, uint32_t(mScratchMemorySize));
+ nvidia::profile::PxProfileZone* profileZone = mContinuation->mSolver->mProfiler;
+
+ // construct kernel functor and execute
+#if PX_ANDROID
+ // if(!neonSolverKernel(cloth, data, allocator, factory, profileZone))
+#endif
+ SwSolverKernel<Simd4fType>(*mCloth, data, allocator, factory, profileZone)();
+
+ data.reconcile(*mCloth); // update cloth
+}
+#endif
+
+const char* cloth::SwSolver::CpuClothSimulationTask::getName() const
+{
+ return "cloth.SwSolver.cpuClothSimulation";
+}
+
+void cloth::SwSolver::CpuClothSimulationTask::release()
+{
+ mCloth->mMotionConstraints.pop();
+ mCloth->mSeparationConstraints.pop();
+
+ if (!mCloth->mTargetCollisionSpheres.empty())
+ {
+ swap(mCloth->mStartCollisionSpheres, mCloth->mTargetCollisionSpheres);
+ mCloth->mTargetCollisionSpheres.resize(0);
+ }
+
+ if (!mCloth->mTargetCollisionPlanes.empty())
+ {
+ swap(mCloth->mStartCollisionPlanes, mCloth->mTargetCollisionPlanes);
+ mCloth->mTargetCollisionPlanes.resize(0);
+ }
+
+ if (!mCloth->mTargetCollisionTriangles.empty())
+ {
+ swap(mCloth->mStartCollisionTriangles, mCloth->mTargetCollisionTriangles);
+ mCloth->mTargetCollisionTriangles.resize(0);
+ }
+#if !APEX_UE4
+ mContinuation->removeReference();
+#endif
+}
+
+#if APEX_UE4
+void(*const cloth::SwCloth::sSimulationFunction)(void*, float) = &cloth::SwSolver::simulate;
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwSolver.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwSolver.h
new file mode 100644
index 00000000..472a5dba
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwSolver.h
@@ -0,0 +1,173 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "Solver.h"
+#include "Allocator.h"
+#include "SwInterCollision.h"
+#include "CmTask.h"
+
+namespace nvidia
+{
+namespace cloth
+{
+
+class SwCloth;
+class SwFactory;
+
+/// CPU/SSE based cloth solver
+class SwSolver : public UserAllocated, public Solver
+{
+ struct StartSimulationTask : public Cm::Task
+ {
+ using PxLightCpuTask::mRefCount;
+ using PxLightCpuTask::mTm;
+
+ virtual void runInternal();
+ virtual const char* getName() const;
+
+ SwSolver* mSolver;
+ };
+
+ struct EndSimulationTask : public Cm::Task
+ {
+ using PxLightCpuTask::mRefCount;
+
+ virtual void runInternal();
+ virtual const char* getName() const;
+
+ SwSolver* mSolver;
+#if !APEX_UE4
+ float mDt;
+#endif
+ };
+
+ struct CpuClothSimulationTask : public Cm::Task
+ {
+#if APEX_UE4
+ void* operator new(size_t n){ return allocate(n); }
+ void operator delete(void* ptr) { return deallocate(ptr); }
+
+ CpuClothSimulationTask(SwCloth&, SwSolver&);
+ ~CpuClothSimulationTask();
+
+ void simulate(float dt);
+
+ SwSolver* mSolver;
+#else
+ CpuClothSimulationTask(SwCloth&, EndSimulationTask&);
+
+ EndSimulationTask* mContinuation;
+#endif
+ virtual void runInternal();
+ virtual const char* getName() const;
+ virtual void release();
+
+ SwCloth* mCloth;
+
+ uint32_t mScratchMemorySize;
+ void* mScratchMemory;
+ float mInvNumIterations;
+ };
+
+ public:
+ SwSolver(nvidia::profile::PxProfileZone*, PxTaskManager*);
+ virtual ~SwSolver();
+
+ virtual void addCloth(Cloth*);
+ virtual void removeCloth(Cloth*);
+
+ virtual PxBaseTask& simulate(float dt, PxBaseTask&);
+
+ virtual void setInterCollisionDistance(float distance)
+ {
+ mInterCollisionDistance = distance;
+ }
+ virtual float getInterCollisionDistance() const
+ {
+ return mInterCollisionDistance;
+ }
+
+ virtual void setInterCollisionStiffness(float stiffness)
+ {
+ mInterCollisionStiffness = stiffness;
+ }
+ virtual float getInterCollisionStiffness() const
+ {
+ return mInterCollisionStiffness;
+ }
+
+ virtual void setInterCollisionNbIterations(uint32_t nbIterations)
+ {
+ mInterCollisionIterations = nbIterations;
+ }
+ virtual uint32_t getInterCollisionNbIterations() const
+ {
+ return mInterCollisionIterations;
+ }
+
+ virtual void setInterCollisionFilter(InterCollisionFilter filter)
+ {
+ mInterCollisionFilter = filter;
+ }
+
+ virtual uint32_t getNumSharedPositions( const Cloth* ) const
+ {
+ return uint32_t(-1);
+ }
+
+ virtual bool hasError() const
+ {
+ return false;
+ }
+
+#if APEX_UE4
+ static void simulate(void*, float);
+#endif
+
+ private:
+ void beginFrame() const;
+ void endFrame() const;
+
+ void interCollision();
+
+ private:
+ StartSimulationTask mStartSimulationTask;
+
+#if APEX_UE4
+ typedef Vector<CpuClothSimulationTask*>::Type CpuClothSimulationTaskVector;
+ float mDt;
+#else
+ typedef Vector<CpuClothSimulationTask>::Type CpuClothSimulationTaskVector;
+#endif
+
+ CpuClothSimulationTaskVector mCpuClothSimulationTasks;
+
+ EndSimulationTask mEndSimulationTask;
+
+ profile::PxProfileZone* mProfiler;
+ uint16_t mSimulateEventId;
+
+ float mInterCollisionDistance;
+ float mInterCollisionStiffness;
+ uint32_t mInterCollisionIterations;
+ InterCollisionFilter mInterCollisionFilter;
+
+ void* mInterCollisionScratchMem;
+ uint32_t mInterCollisionScratchMemSize;
+ nvidia::Array<SwInterCollisionData> mInterCollisionInstances;
+
+};
+}
+}
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwSolverKernel.cpp b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwSolverKernel.cpp
new file mode 100644
index 00000000..29f3fdc3
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwSolverKernel.cpp
@@ -0,0 +1,695 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "SwSolverKernel.h"
+#include "SwCloth.h"
+#include "SwClothData.h"
+#include "SwFabric.h"
+#include "SwFactory.h"
+#include "PointInterpolator.h"
+#include "BoundingBox.h"
+#include "Simd4i.h"
+
+#if defined(_MSC_VER) && _MSC_VER >= 1600 && PX_WINDOWS_FAMILY
+#define PX_AVX 1
+
+namespace avx
+{
+// defined in SwSolveConstraints.cpp
+
+void initialize();
+
+template <bool, uint32_t>
+void solveConstraints(float* __restrict, const float* __restrict, const float* __restrict, const uint16_t* __restrict,
+ const __m128&);
+}
+
+namespace
+{
+uint32_t getAvxSupport()
+{
+// Checking for AVX requires 3 things:
+// 1) CPUID indicates that the OS uses XSAVE and XRSTORE
+// 2) CPUID indicates support for AVX
+// 3) XGETBV indicates registers are saved and restored on context switch
+
+#if _MSC_FULL_VER < 160040219 || !defined(_XCR_XFEATURE_ENABLED_MASK)
+ // need at least VC10 SP1 and compile on at least Win7 SP1
+ return 0;
+#else
+ int cpuInfo[4];
+ __cpuid(cpuInfo, 1);
+ int avxFlags = 3 << 27; // checking 1) and 2) above
+ if((cpuInfo[2] & avxFlags) != avxFlags)
+ return 0; // xgetbv not enabled or no AVX support
+
+ if((_xgetbv(_XCR_XFEATURE_ENABLED_MASK) & 0x6) != 0x6)
+ return 0; // OS does not save YMM registers
+
+ avx::initialize();
+
+#if _MSC_VER < 1700
+ return 1;
+#else
+ int fmaFlags = 1 << 12;
+ if((cpuInfo[2] & fmaFlags) != fmaFlags)
+ return 1; // no FMA3 support
+
+ /* only using fma at the moment, don't lock out AMD's piledriver by requiring avx2
+ __cpuid(cpuInfo, 7);
+ int avx2Flags = 1 << 5;
+ if((cpuInfo[1] & avx2Flags) != avx2Flags)
+ return 1; // no AVX2 support
+ */
+
+ return 2;
+#endif // _MSC_VER
+#endif // _MSC_FULL_VER
+}
+
+const uint32_t sAvxSupport = getAvxSupport(); // 0: no AVX, 1: AVX, 2: AVX+FMA
+}
+#endif
+
+using namespace nvidia;
+
+namespace
+{
+/* simd constants */
+
+typedef Simd4fFactory<detail::FourTuple> Simd4fConstant;
+
+const Simd4fConstant sMaskW = simd4f(simd4i(0, 0, 0, ~0));
+const Simd4fConstant sMaskXY = simd4f(simd4i(~0, ~0, 0, 0));
+const Simd4fConstant sMaskXYZ = simd4f(simd4i(~0, ~0, ~0, 0));
+const Simd4fConstant sMaskYZW = simd4f(simd4i(0, ~0, ~0, ~0));
+const Simd4fConstant sEpsilon = simd4f(FLT_EPSILON);
+const Simd4fConstant sMinusOneXYZOneW = simd4f(-1.0f, -1.0f, -1.0f, 1.0f);
+const Simd4fConstant sFloatMaxW = simd4f(0.0f, 0.0f, 0.0f, FLT_MAX);
+const Simd4fConstant sMinusFloatMaxXYZ = simd4f(-FLT_MAX, -FLT_MAX, -FLT_MAX, 0.0f);
+
+/* static worker functions */
+
+/**
+ This function performs explicit Euler integration based on position, where
+ x_next = x_cur + (x_cur - x_prev) * dt_cur/dt_prev * damping + g * dt * dt
+ The g * dt * dt term is folded into accelIt.
+ */
+
+template <typename Simd4f, typename AccelerationIterator>
+void integrateParticles(Simd4f* __restrict curIt, Simd4f* __restrict curEnd, Simd4f* __restrict prevIt, Simd4f scale,
+ const AccelerationIterator& aIt, const Simd4f& prevBias)
+{
+ // local copy to avoid LHS
+ AccelerationIterator accelIt(aIt);
+
+ for(; curIt != curEnd; ++curIt, ++prevIt, ++accelIt)
+ {
+ Simd4f current = *curIt;
+ Simd4f previous = *prevIt;
+ // if(current.w == 0) current.w = previous.w
+ current = select(current > sMinusFloatMaxXYZ, current, previous);
+ Simd4f finiteMass = splat<3>(previous) > sFloatMaxW;
+ Simd4f delta = (current - previous) * scale + *accelIt;
+ *curIt = current + (delta & finiteMass);
+ *prevIt = select(sMaskW, previous, current) + (prevBias & finiteMass);
+ }
+}
+
+template <typename Simd4f, typename AccelerationIterator>
+void integrateParticles(Simd4f* __restrict curIt, Simd4f* __restrict curEnd, Simd4f* __restrict prevIt,
+ const Simd4f (&prevMatrix)[3], const Simd4f (&curMatrix)[3], const AccelerationIterator& aIt,
+ const Simd4f& prevBias)
+{
+ // local copy to avoid LHS
+ AccelerationIterator accelIt(aIt);
+
+ for(; curIt != curEnd; ++curIt, ++prevIt, ++accelIt)
+ {
+ Simd4f current = *curIt;
+ Simd4f previous = *prevIt;
+ // if(current.w == 0) current.w = previous.w
+ current = select(current > sMinusFloatMaxXYZ, current, previous);
+ Simd4f finiteMass = splat<3>(previous) > sFloatMaxW;
+ // curMatrix*current + prevMatrix*previous + accel
+ Simd4f delta = cloth::transform(curMatrix, cloth::transform(prevMatrix, *accelIt, previous), current);
+ *curIt = current + (delta & finiteMass);
+ *prevIt = select(sMaskW, previous, current) + (prevBias & finiteMass);
+ }
+}
+
+template <typename Simd4f, typename ConstraintIterator>
+void constrainMotion(Simd4f* __restrict curIt, const Simd4f* __restrict curEnd, const ConstraintIterator& spheres,
+ Simd4f scaleBiasStiffness)
+{
+ Simd4f scale = splat<0>(scaleBiasStiffness);
+ Simd4f bias = splat<1>(scaleBiasStiffness);
+ Simd4f stiffness = splat<3>(scaleBiasStiffness);
+
+ // local copy of iterator to maintain alignment
+ ConstraintIterator sphIt = spheres;
+
+ for(; curIt < curEnd; curIt += 4)
+ {
+ // todo: use msub where available
+ Simd4f curPos0 = curIt[0];
+ Simd4f curPos1 = curIt[1];
+ Simd4f curPos2 = curIt[2];
+ Simd4f curPos3 = curIt[3];
+
+ Simd4f delta0 = *sphIt - (sMaskXYZ & curPos0);
+ ++sphIt;
+ Simd4f delta1 = *sphIt - (sMaskXYZ & curPos1);
+ ++sphIt;
+ Simd4f delta2 = *sphIt - (sMaskXYZ & curPos2);
+ ++sphIt;
+ Simd4f delta3 = *sphIt - (sMaskXYZ & curPos3);
+ ++sphIt;
+
+ Simd4f deltaX = delta0, deltaY = delta1, deltaZ = delta2, deltaW = delta3;
+ transpose(deltaX, deltaY, deltaZ, deltaW);
+
+ Simd4f sqrLength = sEpsilon + deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
+ Simd4f radius = max(simd4f(_0), deltaW * scale + bias);
+
+ Simd4f slack = simd4f(_1) - radius * rsqrt(sqrLength);
+
+ // if slack <= 0.0f then we don't want to affect particle
+ // and can skip if all particles are unaffected
+ Simd4f isPositive;
+ if(anyGreater(slack, simd4f(_0), isPositive))
+ {
+ // set invMass to zero if radius is zero
+ curPos0 = curPos0 & (splat<0>(radius) > sMinusFloatMaxXYZ);
+ curPos1 = curPos1 & (splat<1>(radius) > sMinusFloatMaxXYZ);
+ curPos2 = curPos2 & (splat<2>(radius) > sMinusFloatMaxXYZ);
+ curPos3 = curPos3 & ((radius) > sMinusFloatMaxXYZ);
+
+ slack = slack * stiffness & isPositive;
+
+ curIt[0] = curPos0 + (delta0 & sMaskXYZ) * splat<0>(slack);
+ curIt[1] = curPos1 + (delta1 & sMaskXYZ) * splat<1>(slack);
+ curIt[2] = curPos2 + (delta2 & sMaskXYZ) * splat<2>(slack);
+ curIt[3] = curPos3 + (delta3 & sMaskXYZ) * splat<3>(slack);
+ }
+ }
+}
+
+template <typename Simd4f, typename ConstraintIterator>
+void constrainSeparation(Simd4f* __restrict curIt, const Simd4f* __restrict curEnd, const ConstraintIterator& spheres)
+{
+ // local copy of iterator to maintain alignment
+ ConstraintIterator sphIt = spheres;
+
+ for(; curIt < curEnd; curIt += 4)
+ {
+ // todo: use msub where available
+ Simd4f curPos0 = curIt[0];
+ Simd4f curPos1 = curIt[1];
+ Simd4f curPos2 = curIt[2];
+ Simd4f curPos3 = curIt[3];
+
+ Simd4f delta0 = *sphIt - (sMaskXYZ & curPos0);
+ ++sphIt;
+ Simd4f delta1 = *sphIt - (sMaskXYZ & curPos1);
+ ++sphIt;
+ Simd4f delta2 = *sphIt - (sMaskXYZ & curPos2);
+ ++sphIt;
+ Simd4f delta3 = *sphIt - (sMaskXYZ & curPos3);
+ ++sphIt;
+
+ Simd4f deltaX = delta0, deltaY = delta1, deltaZ = delta2, deltaW = delta3;
+ transpose(deltaX, deltaY, deltaZ, deltaW);
+
+ Simd4f sqrLength = sEpsilon + deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
+
+ Simd4f slack = simd4f(_1) - deltaW * rsqrtT<1>(sqrLength);
+
+ // if slack >= 0.0f then we don't want to affect particle
+ // and can skip if all particles are unaffected
+ Simd4f isNegative;
+ if(anyGreater(simd4f(_0), slack, isNegative))
+ {
+ slack = slack & isNegative;
+
+ curIt[0] = curPos0 + (delta0 & sMaskXYZ) * splat<0>(slack);
+ curIt[1] = curPos1 + (delta1 & sMaskXYZ) * splat<1>(slack);
+ curIt[2] = curPos2 + (delta2 & sMaskXYZ) * splat<2>(slack);
+ curIt[3] = curPos3 + (delta3 & sMaskXYZ) * splat<3>(slack);
+ }
+ }
+}
+
+/**
+ traditional gauss-seidel internal constraint solver
+ */
+template <bool useMultiplier, typename Simd4f>
+void solveConstraints(float* __restrict posIt, const float* __restrict rIt, const float* __restrict rEnd,
+ const uint16_t* __restrict iIt, Simd4f stiffness)
+{
+ Simd4f stretchLimit, compressionLimit, multiplier;
+ if(useMultiplier)
+ {
+ stretchLimit = splat<3>(stiffness);
+ compressionLimit = splat<2>(stiffness);
+ multiplier = splat<1>(stiffness);
+ }
+ stiffness = splat<0>(stiffness);
+
+ for(; rIt != rEnd; rIt += 4, iIt += 8)
+ {
+ uint32_t p0i = iIt[0] * sizeof(PxVec4);
+ uint32_t p0j = iIt[1] * sizeof(PxVec4);
+ uint32_t p1i = iIt[2] * sizeof(PxVec4);
+ uint32_t p1j = iIt[3] * sizeof(PxVec4);
+ uint32_t p2i = iIt[4] * sizeof(PxVec4);
+ uint32_t p2j = iIt[5] * sizeof(PxVec4);
+ uint32_t p3i = iIt[6] * sizeof(PxVec4);
+ uint32_t p3j = iIt[7] * sizeof(PxVec4);
+
+ Simd4f v0i = loadAligned(posIt, p0i);
+ Simd4f v0j = loadAligned(posIt, p0j);
+ Simd4f v1i = loadAligned(posIt, p1i);
+ Simd4f v1j = loadAligned(posIt, p1j);
+ Simd4f v2i = loadAligned(posIt, p2i);
+ Simd4f v2j = loadAligned(posIt, p2j);
+ Simd4f v3i = loadAligned(posIt, p3i);
+ Simd4f v3j = loadAligned(posIt, p3j);
+
+ Simd4f h0ij = v0j + v0i * sMinusOneXYZOneW;
+ Simd4f h1ij = v1j + v1i * sMinusOneXYZOneW;
+ Simd4f h2ij = v2j + v2i * sMinusOneXYZOneW;
+ Simd4f h3ij = v3j + v3i * sMinusOneXYZOneW;
+
+ Simd4f hxij = h0ij, hyij = h1ij, hzij = h2ij, vwij = h3ij;
+ transpose(hxij, hyij, hzij, vwij);
+
+ Simd4f rij = loadAligned(rIt);
+ Simd4f e2ij = sEpsilon + hxij * hxij + hyij * hyij + hzij * hzij;
+ Simd4f erij = (simd4f(_1) - rij * rsqrt(e2ij)) & (rij > sEpsilon); // add parentheses for wiiu
+
+ if(useMultiplier)
+ {
+ erij = erij - multiplier * max(compressionLimit, min(erij, stretchLimit));
+ }
+ Simd4f exij = erij * stiffness * recip(sEpsilon + vwij);
+
+ h0ij = h0ij * splat<0>(exij) & sMaskXYZ;
+ h1ij = h1ij * splat<1>(exij) & sMaskXYZ;
+ h2ij = h2ij * splat<2>(exij) & sMaskXYZ;
+ h3ij = h3ij * splat<3>(exij) & sMaskXYZ;
+
+ storeAligned(posIt, p0i, v0i + h0ij * splat<3>(v0i));
+ storeAligned(posIt, p0j, v0j - h0ij * splat<3>(v0j));
+ storeAligned(posIt, p1i, v1i + h1ij * splat<3>(v1i));
+ storeAligned(posIt, p1j, v1j - h1ij * splat<3>(v1j));
+ storeAligned(posIt, p2i, v2i + h2ij * splat<3>(v2i));
+ storeAligned(posIt, p2j, v2j - h2ij * splat<3>(v2j));
+ storeAligned(posIt, p3i, v3i + h3ij * splat<3>(v3i));
+ storeAligned(posIt, p3j, v3j - h3ij * splat<3>(v3j));
+ }
+}
+
+#if PX_WINDOWS_FAMILY
+#include "sse2/SwSolveConstraints.h"
+#endif
+
+// calculates upper bound of all position deltas
+template <typename Simd4f>
+Simd4f calculateMaxDelta(const Simd4f* prevIt, const Simd4f* curIt, const Simd4f* curEnd)
+{
+ Simd4f maxDelta(simd4f(_0));
+ for(; curIt < curEnd; ++curIt, ++prevIt)
+ maxDelta = max(maxDelta, abs(*curIt - *prevIt));
+
+ return maxDelta & sMaskXYZ;
+}
+
+} // anonymous namespace
+
+template <typename Simd4f>
+cloth::SwSolverKernel<Simd4f>::SwSolverKernel(SwCloth const& cloth, SwClothData& clothData, SwKernelAllocator& allocator,
+ IterationStateFactory& factory, profile::PxProfileZone* profiler)
+: mCloth(cloth)
+, mClothData(clothData)
+, mAllocator(allocator)
+, mCollision(clothData, allocator, profiler)
+, mSelfCollision(clothData, allocator)
+, mState(factory.create<Simd4f>(cloth))
+, mProfiler(profiler)
+{
+ mClothData.verify();
+}
+
+template <typename Simd4f>
+void cloth::SwSolverKernel<Simd4f>::operator()()
+{
+ simulateCloth();
+}
+
+template <typename Simd4f>
+size_t cloth::SwSolverKernel<Simd4f>::estimateTemporaryMemory(const SwCloth& cloth)
+{
+ size_t collisionTempMemory = SwCollision<Simd4f>::estimateTemporaryMemory(cloth);
+ size_t selfCollisionTempMemory = SwSelfCollision<Simd4f>::estimateTemporaryMemory(cloth);
+
+ size_t tempMemory = PxMax(collisionTempMemory, selfCollisionTempMemory);
+ size_t persistentMemory = SwCollision<Simd4f>::estimatePersistentMemory(cloth);
+
+ // account for any allocator overhead (this could be exposed in the allocator)
+ size_t maxAllocs = 32;
+ size_t maxPerAllocationOverhead = 32;
+ size_t maxAllocatorOverhead = maxAllocs * maxPerAllocationOverhead;
+
+ return maxAllocatorOverhead + persistentMemory + tempMemory;
+}
+
+template <typename Simd4f>
+template <typename AccelerationIterator>
+void cloth::SwSolverKernel<Simd4f>::integrateParticles(AccelerationIterator& accelIt, const Simd4f& prevBias)
+{
+ Simd4f* curIt = reinterpret_cast<Simd4f*>(mClothData.mCurParticles);
+ Simd4f* curEnd = curIt + mClothData.mNumParticles;
+ Simd4f* prevIt = reinterpret_cast<Simd4f*>(mClothData.mPrevParticles);
+
+ if(!mState.mIsTurning)
+ ::integrateParticles(curIt, curEnd, prevIt, mState.mPrevMatrix[0], accelIt, prevBias);
+ else
+ ::integrateParticles(curIt, curEnd, prevIt, mState.mPrevMatrix, mState.mCurMatrix, accelIt, prevBias);
+}
+
+template <typename Simd4f>
+void cloth::SwSolverKernel<Simd4f>::integrateParticles()
+{
+ ProfileZone zone("cloth::SwSolverKernel::integrateParticles", mProfiler);
+
+ const Simd4f* startAccelIt = reinterpret_cast<const Simd4f*>(mClothData.mParticleAccelerations);
+
+ // dt^2 (todo: should this be the smoothed dt used for gravity?)
+ const Simd4f sqrIterDt = simd4f(sqr(mState.mIterDt)) & (Simd4f)sMaskXYZ;
+
+ if(!startAccelIt)
+ {
+ // no per-particle accelerations, use a constant
+ ConstantIterator<Simd4f> accelIt(mState.mCurBias);
+ integrateParticles(accelIt, mState.mPrevBias);
+ }
+ else
+ {
+ // iterator implicitly scales by dt^2 and adds gravity
+ ScaleBiasIterator<Simd4f, const Simd4f*> accelIt(startAccelIt, sqrIterDt, mState.mCurBias);
+ integrateParticles(accelIt, mState.mPrevBias);
+ }
+
+ zone.setValue(mState.mIsTurning);
+}
+
+template <typename Simd4f>
+void cloth::SwSolverKernel<Simd4f>::constrainTether()
+{
+ if(0.0f == mClothData.mTetherConstraintStiffness || !mClothData.mNumTethers)
+ return;
+
+#if PX_PROFILE
+ ProfileZone zone("cloth::SwSolverKernel::solveTethers", mProfiler);
+#endif
+
+ uint32_t numParticles = mClothData.mNumParticles;
+ uint32_t numTethers = mClothData.mNumTethers;
+ PX_ASSERT(0 == numTethers % numParticles);
+
+ float* __restrict curIt = mClothData.mCurParticles;
+ const float* __restrict curFirst = curIt;
+ const float* __restrict curEnd = curIt + 4 * numParticles;
+
+ typedef const SwTether* __restrict TetherIter;
+ TetherIter tFirst = mClothData.mTethers;
+ TetherIter tEnd = tFirst + numTethers;
+
+ Simd4f stiffness = (Simd4f)sMaskXYZ & simd4f(numParticles * mClothData.mTetherConstraintStiffness / numTethers);
+ Simd4f scale = simd4f(mClothData.mTetherConstraintScale);
+
+ for(; curIt != curEnd; curIt += 4, ++tFirst)
+ {
+ Simd4f position = loadAligned(curIt);
+ Simd4f offset = simd4f(_0);
+
+ for(TetherIter tIt = tFirst; tIt < tEnd; tIt += numParticles)
+ {
+ PX_ASSERT(tIt->mAnchor < numParticles);
+ Simd4f anchor = loadAligned(curFirst, tIt->mAnchor * sizeof(PxVec4));
+ Simd4f delta = anchor - position;
+ Simd4f sqrLength = sEpsilon + dot3(delta, delta);
+
+ Simd4f tetherLength = load(&tIt->mLength);
+ tetherLength = splat<0>(tetherLength);
+
+ Simd4f radius = tetherLength * scale;
+ Simd4f slack = simd4f(_1) - radius * rsqrt(sqrLength);
+
+ offset = offset + delta * max(slack, simd4f(_0));
+ }
+
+ storeAligned(curIt, position + offset * stiffness);
+ }
+}
+
+template <typename Simd4f>
+void cloth::SwSolverKernel<Simd4f>::solveFabric()
+{
+ ProfileZone zone("cloth::SwSolverKernel::solveFabric", mProfiler);
+
+ float* pIt = mClothData.mCurParticles;
+
+ const PhaseConfig* cIt = mClothData.mConfigBegin;
+ const PhaseConfig* cEnd = mClothData.mConfigEnd;
+
+ const uint32_t* pBegin = mClothData.mPhases;
+ const float* rBegin = mClothData.mRestvalues;
+
+ const uint32_t* sBegin = mClothData.mSets;
+ const uint16_t* iBegin = mClothData.mIndices;
+
+ uint32_t totalConstraints = 0;
+
+ Simd4f stiffnessExponent = simd4f(mCloth.mStiffnessFrequency * mState.mIterDt);
+
+ for(; cIt != cEnd; ++cIt)
+ {
+ const uint32_t* sIt = sBegin + pBegin[cIt->mPhaseIndex];
+ const float* rIt = rBegin + sIt[0];
+ const float* rEnd = rBegin + sIt[1];
+ const uint16_t* iIt = iBegin + sIt[0] * 2;
+
+ totalConstraints += uint32_t(rEnd - rIt);
+
+ // (stiffness, multiplier, compressionLimit, stretchLimit)
+ Simd4f config = load(&cIt->mStiffness);
+ // stiffness specified as fraction of constraint error per-millisecond
+ Simd4f scaledConfig = simd4f(_1) - simdf::exp2(config * stiffnessExponent);
+ Simd4f stiffness = select(sMaskXY, scaledConfig, config);
+
+ int neutralMultiplier = allEqual(sMaskYZW & stiffness, simd4f(_0));
+
+#if PX_AVX
+ switch(sAvxSupport)
+ {
+ case 2:
+#if _MSC_VER >= 1700
+ neutralMultiplier ? avx::solveConstraints<false, 2>(pIt, rIt, rEnd, iIt, stiffness)
+ : avx::solveConstraints<true, 2>(pIt, rIt, rEnd, iIt, stiffness);
+ break;
+#endif
+ case 1:
+ neutralMultiplier ? avx::solveConstraints<false, 1>(pIt, rIt, rEnd, iIt, stiffness)
+ : avx::solveConstraints<true, 1>(pIt, rIt, rEnd, iIt, stiffness);
+ break;
+ default:
+#endif
+ neutralMultiplier ? solveConstraints<false>(pIt, rIt, rEnd, iIt, stiffness)
+ : solveConstraints<true>(pIt, rIt, rEnd, iIt, stiffness);
+#if PX_AVX
+ break;
+ }
+#endif
+ }
+
+ zone.setValue(totalConstraints);
+}
+
+template <typename Simd4f>
+void cloth::SwSolverKernel<Simd4f>::constrainMotion()
+{
+ if(!mClothData.mStartMotionConstraints)
+ return;
+
+#if PX_PROFILE
+ ProfileZone zone("cloth::SwSolverKernel::constrainMotion", mProfiler);
+#endif
+
+ Simd4f* curIt = reinterpret_cast<Simd4f*>(mClothData.mCurParticles);
+ Simd4f* curEnd = curIt + mClothData.mNumParticles;
+
+ const Simd4f* startIt = reinterpret_cast<const Simd4f*>(mClothData.mStartMotionConstraints);
+ const Simd4f* targetIt = reinterpret_cast<const Simd4f*>(mClothData.mTargetMotionConstraints);
+
+ Simd4f scaleBias = load(&mCloth.mMotionConstraintScale);
+ Simd4f stiffness = simd4f(mClothData.mMotionConstraintStiffness);
+ Simd4f scaleBiasStiffness = select(sMaskXYZ, scaleBias, stiffness);
+
+ if(!mClothData.mTargetMotionConstraints)
+ // no interpolation, use the start positions
+ return ::constrainMotion(curIt, curEnd, startIt, scaleBiasStiffness);
+
+ if(mState.mRemainingIterations == 1)
+ // use the target positions on last iteration
+ return ::constrainMotion(curIt, curEnd, targetIt, scaleBiasStiffness);
+
+ // otherwise use an interpolating iterator
+ LerpIterator<Simd4f, const Simd4f*> interpolator(startIt, targetIt, mState.getCurrentAlpha());
+ ::constrainMotion(curIt, curEnd, interpolator, scaleBiasStiffness);
+}
+
+template <typename Simd4f>
+void cloth::SwSolverKernel<Simd4f>::constrainSeparation()
+{
+ if(!mClothData.mStartSeparationConstraints)
+ return;
+
+#if PX_PROFILE
+ ProfileZone zone("cloth::SwSolverKernel::constrainSeparation", mProfiler);
+#endif
+
+ Simd4f* curIt = reinterpret_cast<Simd4f*>(mClothData.mCurParticles);
+ Simd4f* curEnd = curIt + mClothData.mNumParticles;
+
+ const Simd4f* startIt = reinterpret_cast<const Simd4f*>(mClothData.mStartSeparationConstraints);
+ const Simd4f* targetIt = reinterpret_cast<const Simd4f*>(mClothData.mTargetSeparationConstraints);
+
+ if(!mClothData.mTargetSeparationConstraints)
+ // no interpolation, use the start positions
+ return ::constrainSeparation(curIt, curEnd, startIt);
+
+ if(mState.mRemainingIterations == 1)
+ // use the target positions on last iteration
+ return ::constrainSeparation(curIt, curEnd, targetIt);
+
+ // otherwise use an interpolating iterator
+ LerpIterator<Simd4f, const Simd4f*> interpolator(startIt, targetIt, mState.getCurrentAlpha());
+ ::constrainSeparation(curIt, curEnd, interpolator);
+}
+
+template <typename Simd4f>
+void cloth::SwSolverKernel<Simd4f>::collideParticles()
+{
+ ProfileZone zone("cloth::SwSolverKernel::collideParticles", mProfiler);
+
+ mCollision(mState);
+
+ zone.setValue(mCollision.mNumCollisions);
+}
+
+template <typename Simd4f>
+void cloth::SwSolverKernel<Simd4f>::selfCollideParticles()
+{
+ ProfileZone zone("cloth::SwSolverKernel::selfCollideParticles", mProfiler);
+
+ mSelfCollision();
+
+ zone.setValue(mSelfCollision.mNumCollisions);
+}
+
+template <typename Simd4f>
+void cloth::SwSolverKernel<Simd4f>::updateSleepState()
+{
+ ProfileZone zone("cloth::SwSolverKernel::updateSleepState", mProfiler);
+
+ mClothData.mSleepTestCounter += PxMax(1u, uint32_t(mState.mIterDt * 1000));
+ if(mClothData.mSleepTestCounter >= mCloth.mSleepTestInterval)
+ {
+ const Simd4f* prevIt = reinterpret_cast<Simd4f*>(mClothData.mPrevParticles);
+ const Simd4f* curIt = reinterpret_cast<Simd4f*>(mClothData.mCurParticles);
+ const Simd4f* curEnd = curIt + mClothData.mNumParticles;
+
+ // calculate max particle delta since last iteration
+ Simd4f maxDelta = calculateMaxDelta(prevIt, curIt, curEnd);
+
+ ++mClothData.mSleepPassCounter;
+ Simd4f threshold = simd4f(mCloth.mSleepThreshold * mState.mIterDt);
+ if(anyGreaterEqual(maxDelta, threshold))
+ mClothData.mSleepPassCounter = 0;
+
+ mClothData.mSleepTestCounter -= mCloth.mSleepTestInterval;
+ }
+
+ zone.setValue(mClothData.mSleepPassCounter);
+}
+
+template <typename Simd4f>
+void cloth::SwSolverKernel<Simd4f>::iterateCloth()
+{
+ // note on invMass (stored in current/previous positions.w):
+ // integrateParticles()
+ // - if(current.w == 0) current.w = previous.w
+ // constraintMotion()
+ // - if(constraint.radius <= 0) current.w = 0
+ // computeBounds()
+ // - if(current.w > 0) current.w = previous.w
+ // collideParticles()
+ // - if(collides) current.w *= 1/massScale
+ // after simulate()
+ // - previous.w: original invMass as set by user
+ // - current.w: zeroed by motion constraints and mass-scaled by collision
+
+ // integrate positions
+ integrateParticles();
+
+ // motion constraints
+ constrainMotion();
+
+ // solve tether constraints
+ constrainTether();
+
+ // solve edge constraints
+ solveFabric();
+
+ // separation constraints
+ constrainSeparation();
+
+ // perform character collision
+ collideParticles();
+
+ // perform self collision
+ selfCollideParticles();
+
+ // test wake / sleep conditions
+ updateSleepState();
+}
+
+template <typename Simd4f>
+void cloth::SwSolverKernel<Simd4f>::simulateCloth()
+{
+ while(mState.mRemainingIterations)
+ {
+ iterateCloth();
+ mState.update();
+ }
+}
+
+// explicit template instantiation
+#if NVMATH_SIMD
+template class cloth::SwSolverKernel<Simd4f>;
+#endif
+#if NVMATH_SCALAR
+template class cloth::SwSolverKernel<Scalar4f>;
+#endif
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwSolverKernel.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwSolverKernel.h
new file mode 100644
index 00000000..26b45a88
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/SwSolverKernel.h
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "IterationState.h"
+#include "SwCollision.h"
+#include "SwSelfCollision.h"
+
+namespace nvidia
+{
+namespace cloth
+{
+
+class SwCloth;
+struct SwClothData;
+
+template <typename Simd4f>
+class SwSolverKernel
+{
+ public:
+ SwSolverKernel(SwCloth const&, SwClothData&, SwKernelAllocator&, IterationStateFactory&, nvidia::profile::PxProfileZone*);
+
+ void operator()();
+
+ // returns a conservative estimate of the
+ // total memory requirements during a solve
+ static size_t estimateTemporaryMemory(const SwCloth& c);
+
+ private:
+ void integrateParticles();
+ void constrainTether();
+ void solveFabric();
+ void constrainMotion();
+ void constrainSeparation();
+ void collideParticles();
+ void selfCollideParticles();
+ void updateSleepState();
+
+ void iterateCloth();
+ void simulateCloth();
+
+ SwCloth const& mCloth;
+ SwClothData& mClothData;
+ SwKernelAllocator& mAllocator;
+
+ SwCollision<Simd4f> mCollision;
+ SwSelfCollision<Simd4f> mSelfCollision;
+ IterationState<Simd4f> mState;
+
+ profile::PxProfileZone* mProfiler;
+
+ private:
+ SwSolverKernel<Simd4f>& operator=(const SwSolverKernel<Simd4f>&);
+ template <typename AccelerationIterator>
+ void integrateParticles(AccelerationIterator& accelIt, const Simd4f&);
+};
+}
+}
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/TripletScheduler.cpp b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/TripletScheduler.cpp
new file mode 100644
index 00000000..d077624e
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/TripletScheduler.cpp
@@ -0,0 +1,229 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "TripletScheduler.h"
+#include "PxMath.h"
+#include "PsFPU.h"
+#include "PxMat33.h"
+#include "PsVecMath.h"
+#include "PsUtilities.h"
+
+using namespace nvidia;
+using namespace physx::shdfnd::aos;
+
+cloth::TripletScheduler::TripletScheduler(Range<const uint32_t[4]> triplets)
+: mTriplets(reinterpret_cast<const Vec4u*>(triplets.begin()), reinterpret_cast<const Vec4u*>(triplets.end()))
+{
+}
+
+// SSE version
+void cloth::TripletScheduler::simd(uint32_t numParticles, uint32_t simdWidth)
+{
+ if(mTriplets.empty())
+ return;
+
+ Vector<uint32_t>::Type mark(numParticles, uint32_t(-1));
+
+ uint32_t setIndex = 0, setSize = 0;
+ for(TripletIter tIt = mTriplets.begin(), tEnd = mTriplets.end(); tIt != tEnd; ++setIndex)
+ {
+ TripletIter tLast = tIt + PxMin(simdWidth, uint32_t(tEnd - tIt));
+ TripletIter tSwap = tEnd;
+
+ for(; tIt != tLast && tIt != tSwap; ++tIt, ++setSize)
+ {
+ // swap from tail until independent triplet found
+ while((mark[tIt->x] == setIndex || mark[tIt->y] == setIndex || mark[tIt->z] == setIndex) && tIt != --tSwap)
+ swap(*tIt, *tSwap);
+
+ if(tIt == tSwap)
+ break; // no independent triplet found
+
+ // mark vertices to be used in simdIndex
+ mark[tIt->x] = setIndex;
+ mark[tIt->y] = setIndex;
+ mark[tIt->z] = setIndex;
+ }
+
+ if(tIt == tSwap) // remaining triplets depend on current set
+ {
+ if(setSize > simdWidth) // trim set to multiple of simdWidth
+ {
+ uint32_t overflow = setSize % simdWidth;
+ setSize -= overflow;
+ tIt -= overflow;
+ }
+ mSetSizes.pushBack(setSize);
+ setSize = 0;
+ }
+ }
+}
+
+namespace
+{
+struct TripletSet
+{
+ TripletSet() : mMark(0xFFFFFFFF)
+ {
+ mNumReplays[0] = mNumReplays[1] = mNumReplays[2] = 1;
+ memset(mNumConflicts[0], 0, 32);
+ memset(mNumConflicts[1], 0, 32);
+ memset(mNumConflicts[2], 0, 32);
+ }
+
+ uint32_t mMark; // triplet index
+ uint8_t mNumReplays[3];
+ uint8_t mNumConflicts[3][32];
+};
+
+/*
+struct GreaterSum
+{
+ typedef cloth::Vector<uint32_t>::Type Container;
+
+ GreaterSum(const Container& cont)
+ : mContainer(cont)
+ {}
+
+ bool operator()(const cloth::Vec4u& a, const cloth::Vec4u& b) const
+ {
+ return mContainer[a.x] + mContainer[a.y] + mContainer[a.z]
+ > mContainer[b.x] + mContainer[b.y] + mContainer[b.z];
+ }
+
+ const Container& mContainer;
+};
+*/
+
+// calculate the inclusive prefix sum, equivalent of std::partial_sum
+template <typename T>
+void prefixSum(const T* first, const T* last, T* dest)
+{
+ if(first == last)
+ return;
+ else
+ {
+ *(dest++) = *(first++);
+
+ for(; first != last; ++first, ++dest)
+ *dest = *(dest - 1) + *first;
+ }
+}
+}
+
+// CUDA version
+void cloth::TripletScheduler::warp(uint32_t numParticles, uint32_t warpWidth)
+{
+ // PX_ASSERT(warpWidth == 32 || warpWidth == 16);
+
+ if(mTriplets.empty())
+ return;
+
+ TripletIter tIt, tEnd = mTriplets.end();
+ uint32_t tripletIndex;
+
+ // count number of triplets per particle
+ Vector<uint32_t>::Type adjacentCount(numParticles + 1, uint32_t(0));
+ for(tIt = mTriplets.begin(); tIt != tEnd; ++tIt)
+ for(int i = 0; i < 3; ++i)
+ ++adjacentCount[(*tIt)[i]];
+
+ /* neither of those were really improving number of batches:
+ // run simd version to pre-sort particles
+ simd(numParticles, blockWidth); mSetSizes.resize(0);
+ // sort according to triplet degree (estimated by sum of adjacentCount)
+ std::sort(mTriplets.begin(), tEnd, GreaterSum(adjacentCount));
+ */
+
+ uint32_t maxTripletCount = *maxElement(adjacentCount.begin(), adjacentCount.end());
+
+ // compute in place prefix sum (inclusive)
+ prefixSum(adjacentCount.begin(), adjacentCount.end(), adjacentCount.begin());
+
+ // initialize adjacencies (for each particle, collect touching triplets)
+ // also converts partial sum in adjacentCount from inclusive to exclusive
+ Vector<uint32_t>::Type adjacencies(adjacentCount.back());
+ for(tIt = mTriplets.begin(), tripletIndex = 0; tIt != tEnd; ++tIt, ++tripletIndex)
+ for(int i = 0; i < 3; ++i)
+ adjacencies[--adjacentCount[(*tIt)[i]]] = tripletIndex;
+
+ uint32_t warpMask = warpWidth - 1;
+
+ uint32_t numSets = maxTripletCount; // start with minimum number of sets
+ Vector<TripletSet>::Type sets(numSets);
+ Vector<uint32_t>::Type setIndices(mTriplets.size(), uint32_t(-1));
+ mSetSizes.resize(numSets);
+
+ // color triplets (assign to sets)
+ Vector<uint32_t>::Type::ConstIterator aBegin = adjacencies.begin(), aIt, aEnd;
+ for(tIt = mTriplets.begin(), tripletIndex = 0; tIt != tEnd; ++tIt, ++tripletIndex)
+ {
+ // mark sets of adjacent triplets
+ for(int i = 0; i < 3; ++i)
+ {
+ uint32_t particleIndex = (*tIt)[i];
+ aIt = aBegin + adjacentCount[particleIndex];
+ aEnd = aBegin + adjacentCount[particleIndex + 1];
+ for(uint32_t setIndex; aIt != aEnd; ++aIt)
+ if(numSets > (setIndex = setIndices[*aIt]))
+ sets[setIndex].mMark = tripletIndex;
+ }
+
+ // find valid set with smallest number of bank conflicts
+ uint32_t bestIndex = numSets;
+ uint32_t minReplays = 4;
+ for(uint32_t setIndex = 0; setIndex < numSets && minReplays; ++setIndex)
+ {
+ const TripletSet& set = sets[setIndex];
+
+ if(set.mMark == tripletIndex)
+ continue; // triplet collision
+
+ uint32_t numReplays = 0;
+ for(uint32_t i = 0; i < 3; ++i)
+ numReplays += set.mNumReplays[i] == set.mNumConflicts[i][warpMask & (*tIt)[i]];
+
+ if(minReplays > numReplays)
+ minReplays = numReplays, bestIndex = setIndex;
+ }
+
+ // add new set if none found
+ if(bestIndex == numSets)
+ {
+ sets.pushBack(TripletSet());
+ mSetSizes.pushBack(0);
+ ++numSets;
+ }
+
+ // increment bank conflicts or reset if warp filled
+ TripletSet& set = sets[bestIndex];
+ if(++mSetSizes[bestIndex] & warpMask)
+ for(uint32_t i = 0; i < 3; ++i)
+ set.mNumReplays[i] = PxMax(set.mNumReplays[i], ++set.mNumConflicts[i][warpMask & (*tIt)[i]]);
+ else
+ set = TripletSet();
+
+ setIndices[tripletIndex] = bestIndex;
+ }
+
+ // reorder triplets
+ Vector<uint32_t>::Type setOffsets(mSetSizes.size());
+ prefixSum(mSetSizes.begin(), mSetSizes.end(), setOffsets.begin());
+
+ Vector<Vec4u>::Type triplets(mTriplets.size());
+ Vector<uint32_t>::Type::ConstIterator iIt = setIndices.begin();
+ for(tIt = mTriplets.begin(), tripletIndex = 0; tIt != tEnd; ++tIt, ++iIt)
+ triplets[--setOffsets[*iIt]] = *tIt;
+
+ mTriplets.swap(triplets);
+}
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/TripletScheduler.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/TripletScheduler.h
new file mode 100644
index 00000000..836c9784
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/TripletScheduler.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "Types.h"
+#include "Range.h"
+#include "Allocator.h"
+#include "Vec4T.h"
+
+namespace nvidia
+{
+
+namespace cloth
+{
+
+struct TripletScheduler
+{
+ typedef Vector<Vec4u>::Type::ConstIterator ConstTripletIter;
+ typedef Vector<Vec4u>::Type::Iterator TripletIter;
+
+ TripletScheduler(Range<const uint32_t[4]>);
+ void simd(uint32_t numParticles, uint32_t simdWidth);
+ void warp(uint32_t numParticles, uint32_t warpWidth);
+
+ Vector<Vec4u>::Type mTriplets;
+ Vector<uint32_t>::Type mSetSizes;
+};
+}
+}
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/Vec4T.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/Vec4T.h
new file mode 100644
index 00000000..c82b9629
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/Vec4T.h
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "Types.h"
+
+namespace nvidia
+{
+
+namespace cloth
+{
+
+template <typename T>
+struct Vec4T
+{
+ Vec4T()
+ {
+ }
+
+ Vec4T(T a, T b, T c, T d) : x(a), y(b), z(c), w(d)
+ {
+ }
+
+ template <typename S>
+ Vec4T(const Vec4T<S>& other)
+ {
+ x = T(other.x);
+ y = T(other.y);
+ z = T(other.z);
+ w = T(other.w);
+ }
+
+ template <typename Index>
+ T& operator[](Index i)
+ {
+ return reinterpret_cast<T*>(this)[i];
+ }
+
+ template <typename Index>
+ const T& operator[](Index i) const
+ {
+ return reinterpret_cast<const T*>(this)[i];
+ }
+
+ T x, y, z, w;
+};
+
+template <typename T>
+Vec4T<T> operator*(const Vec4T<T>& vec, T scalar)
+{
+ return Vec4T<T>(vec.x * scalar, vec.y * scalar, vec.z * scalar, vec.w * scalar);
+}
+
+template <typename T>
+Vec4T<T> operator/(const Vec4T<T>& vec, T scalar)
+{
+ return Vec4T<T>(vec.x / scalar, vec.y / scalar, vec.z / scalar, vec.w / scalar);
+}
+
+template <typename T>
+T (&array(Vec4T<T>& vec))[4]
+{
+ return reinterpret_cast<T(&)[4]>(vec);
+}
+
+template <typename T>
+const T (&array(const Vec4T<T>& vec))[4]
+{
+ return reinterpret_cast<const T(&)[4]>(vec);
+}
+
+typedef Vec4T<uint32_t> Vec4u;
+typedef Vec4T<uint16_t> Vec4us;
+
+} // namespace cloth
+
+} // namespace nvidia
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/avx/SwSolveConstraints.cpp b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/avx/SwSolveConstraints.cpp
new file mode 100644
index 00000000..b9a6ab35
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/avx/SwSolveConstraints.cpp
@@ -0,0 +1,916 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma warning(push)
+#pragma warning(disable : 4668) //'symbol' is not defined as a preprocessor macro, replacing with '0' for 'directives'
+#pragma warning(disable : 4987) // nonstandard extension used: 'throw (...)'
+#include <intrin.h>
+#pragma warning(pop)
+
+#pragma warning(disable : 4127) // conditional expression is constant
+
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int32 uint32_t;
+
+namespace avx
+{
+__m128 sMaskYZW;
+__m256 sOne, sEpsilon, sMinusOneXYZOneW, sMaskXY;
+
+void initialize()
+{
+ sMaskYZW = _mm_castsi128_ps(_mm_setr_epi32(0, ~0, ~0, ~0));
+ sOne = _mm256_set1_ps(1.0f);
+ sEpsilon = _mm256_set1_ps(1.192092896e-07f);
+ sMinusOneXYZOneW = _mm256_setr_ps(-1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f);
+ sMaskXY = _mm256_castsi256_ps(_mm256_setr_epi32(~0, ~0, 0, 0, ~0, ~0, 0, 0));
+}
+
+template <uint32_t>
+__m256 fmadd_ps(__m256 a, __m256 b, __m256 c)
+{
+ return _mm256_add_ps(_mm256_mul_ps(a, b), c);
+}
+template <uint32_t>
+__m256 fnmadd_ps(__m256 a, __m256 b, __m256 c)
+{
+ return _mm256_sub_ps(c, _mm256_mul_ps(a, b));
+}
+#if _MSC_VER >= 1700
+template <>
+__m256 fmadd_ps<2>(__m256 a, __m256 b, __m256 c)
+{
+ return _mm256_fmadd_ps(a, b, c);
+}
+template <>
+__m256 fnmadd_ps<2>(__m256 a, __m256 b, __m256 c)
+{
+ return _mm256_fnmadd_ps(a, b, c);
+}
+#endif
+
+// roughly same perf as SSE2 intrinsics, the asm version below is about 10% faster
+template <bool useMultiplier, uint32_t avx>
+void solveConstraints(float* __restrict posIt, const float* __restrict rIt, const float* __restrict rEnd,
+ const uint16_t* __restrict iIt, const __m128& stiffnessRef)
+{
+ __m256 stiffness, stretchLimit, compressionLimit, multiplier;
+
+ if(useMultiplier)
+ {
+ stiffness = _mm256_broadcast_ps(&stiffnessRef);
+ stretchLimit = _mm256_permute_ps(stiffness, 0xff);
+ compressionLimit = _mm256_permute_ps(stiffness, 0xaa);
+ multiplier = _mm256_permute_ps(stiffness, 0x55);
+ stiffness = _mm256_permute_ps(stiffness, 0x00);
+ }
+ else
+ {
+ stiffness = _mm256_broadcast_ss((const float*)&stiffnessRef);
+ }
+
+ for(; rIt < rEnd; rIt += 8, iIt += 16)
+ {
+ float* p0i = posIt + iIt[0] * 4;
+ float* p4i = posIt + iIt[8] * 4;
+ float* p0j = posIt + iIt[1] * 4;
+ float* p4j = posIt + iIt[9] * 4;
+ float* p1i = posIt + iIt[2] * 4;
+ float* p5i = posIt + iIt[10] * 4;
+ float* p1j = posIt + iIt[3] * 4;
+ float* p5j = posIt + iIt[11] * 4;
+
+ __m128 v0i = _mm_load_ps(p0i);
+ __m128 v4i = _mm_load_ps(p4i);
+ __m128 v0j = _mm_load_ps(p0j);
+ __m128 v4j = _mm_load_ps(p4j);
+ __m128 v1i = _mm_load_ps(p1i);
+ __m128 v5i = _mm_load_ps(p5i);
+ __m128 v1j = _mm_load_ps(p1j);
+ __m128 v5j = _mm_load_ps(p5j);
+
+ __m256 v04i = _mm256_insertf128_ps(_mm256_castps128_ps256(v0i), v4i, 1);
+ __m256 v04j = _mm256_insertf128_ps(_mm256_castps128_ps256(v0j), v4j, 1);
+ __m256 v15i = _mm256_insertf128_ps(_mm256_castps128_ps256(v1i), v5i, 1);
+ __m256 v15j = _mm256_insertf128_ps(_mm256_castps128_ps256(v1j), v5j, 1);
+
+ __m256 h04ij = fmadd_ps<avx>(sMinusOneXYZOneW, v04i, v04j);
+ __m256 h15ij = fmadd_ps<avx>(sMinusOneXYZOneW, v15i, v15j);
+
+ float* p2i = posIt + iIt[4] * 4;
+ float* p6i = posIt + iIt[12] * 4;
+ float* p2j = posIt + iIt[5] * 4;
+ float* p6j = posIt + iIt[13] * 4;
+ float* p3i = posIt + iIt[6] * 4;
+ float* p7i = posIt + iIt[14] * 4;
+ float* p3j = posIt + iIt[7] * 4;
+ float* p7j = posIt + iIt[15] * 4;
+
+ __m128 v2i = _mm_load_ps(p2i);
+ __m128 v6i = _mm_load_ps(p6i);
+ __m128 v2j = _mm_load_ps(p2j);
+ __m128 v6j = _mm_load_ps(p6j);
+ __m128 v3i = _mm_load_ps(p3i);
+ __m128 v7i = _mm_load_ps(p7i);
+ __m128 v3j = _mm_load_ps(p3j);
+ __m128 v7j = _mm_load_ps(p7j);
+
+ __m256 v26i = _mm256_insertf128_ps(_mm256_castps128_ps256(v2i), v6i, 1);
+ __m256 v26j = _mm256_insertf128_ps(_mm256_castps128_ps256(v2j), v6j, 1);
+ __m256 v37i = _mm256_insertf128_ps(_mm256_castps128_ps256(v3i), v7i, 1);
+ __m256 v37j = _mm256_insertf128_ps(_mm256_castps128_ps256(v3j), v7j, 1);
+
+ __m256 h26ij = fmadd_ps<avx>(sMinusOneXYZOneW, v26i, v26j);
+ __m256 h37ij = fmadd_ps<avx>(sMinusOneXYZOneW, v37i, v37j);
+
+ __m256 a = _mm256_unpacklo_ps(h04ij, h26ij);
+ __m256 b = _mm256_unpackhi_ps(h04ij, h26ij);
+ __m256 c = _mm256_unpacklo_ps(h15ij, h37ij);
+ __m256 d = _mm256_unpackhi_ps(h15ij, h37ij);
+
+ __m256 hxij = _mm256_unpacklo_ps(a, c);
+ __m256 hyij = _mm256_unpackhi_ps(a, c);
+ __m256 hzij = _mm256_unpacklo_ps(b, d);
+ __m256 vwij = _mm256_unpackhi_ps(b, d);
+
+ __m256 e2ij = fmadd_ps<avx>(hxij, hxij, fmadd_ps<avx>(hyij, hyij, fmadd_ps<avx>(hzij, hzij, sEpsilon)));
+
+ __m256 rij = _mm256_load_ps(rIt);
+ __m256 mask = _mm256_cmp_ps(rij, sEpsilon, _CMP_GT_OQ);
+ __m256 erij = _mm256_and_ps(fnmadd_ps<avx>(rij, _mm256_rsqrt_ps(e2ij), sOne), mask);
+
+ if(useMultiplier)
+ {
+ erij = fnmadd_ps<avx>(multiplier, _mm256_max_ps(compressionLimit, _mm256_min_ps(erij, stretchLimit)), erij);
+ }
+
+ __m256 exij = _mm256_mul_ps(erij, _mm256_mul_ps(stiffness, _mm256_rcp_ps(_mm256_add_ps(sEpsilon, vwij))));
+
+ // replace these two instructions with _mm_maskstore_ps below?
+ __m256 exlo = _mm256_and_ps(sMaskXY, exij);
+ __m256 exhi = _mm256_andnot_ps(sMaskXY, exij);
+
+ __m256 f04ij = _mm256_mul_ps(h04ij, _mm256_permute_ps(exlo, 0xc0));
+ __m256 u04i = fmadd_ps<avx>(f04ij, _mm256_permute_ps(v04i, 0xff), v04i);
+ __m256 u04j = fnmadd_ps<avx>(f04ij, _mm256_permute_ps(v04j, 0xff), v04j);
+
+ _mm_store_ps(p0i, _mm256_extractf128_ps(u04i, 0));
+ _mm_store_ps(p0j, _mm256_extractf128_ps(u04j, 0));
+ _mm_store_ps(p4i, _mm256_extractf128_ps(u04i, 1));
+ _mm_store_ps(p4j, _mm256_extractf128_ps(u04j, 1));
+
+ __m256 f15ij = _mm256_mul_ps(h15ij, _mm256_permute_ps(exlo, 0xd5));
+ __m256 u15i = fmadd_ps<avx>(f15ij, _mm256_permute_ps(v15i, 0xff), v15i);
+ __m256 u15j = fnmadd_ps<avx>(f15ij, _mm256_permute_ps(v15j, 0xff), v15j);
+
+ _mm_store_ps(p1i, _mm256_extractf128_ps(u15i, 0));
+ _mm_store_ps(p1j, _mm256_extractf128_ps(u15j, 0));
+ _mm_store_ps(p5i, _mm256_extractf128_ps(u15i, 1));
+ _mm_store_ps(p5j, _mm256_extractf128_ps(u15j, 1));
+
+ __m256 f26ij = _mm256_mul_ps(h26ij, _mm256_permute_ps(exhi, 0x2a));
+ __m256 u26i = fmadd_ps<avx>(f26ij, _mm256_permute_ps(v26i, 0xff), v26i);
+ __m256 u26j = fnmadd_ps<avx>(f26ij, _mm256_permute_ps(v26j, 0xff), v26j);
+
+ _mm_store_ps(p2i, _mm256_extractf128_ps(u26i, 0));
+ _mm_store_ps(p2j, _mm256_extractf128_ps(u26j, 0));
+ _mm_store_ps(p6i, _mm256_extractf128_ps(u26i, 1));
+ _mm_store_ps(p6j, _mm256_extractf128_ps(u26j, 1));
+
+ __m256 f37ij = _mm256_mul_ps(h37ij, _mm256_permute_ps(exhi, 0x3f));
+ __m256 u37i = fmadd_ps<avx>(f37ij, _mm256_permute_ps(v37i, 0xff), v37i);
+ __m256 u37j = fnmadd_ps<avx>(f37ij, _mm256_permute_ps(v37j, 0xff), v37j);
+
+ _mm_store_ps(p3i, _mm256_extractf128_ps(u37i, 0));
+ _mm_store_ps(p3j, _mm256_extractf128_ps(u37j, 0));
+ _mm_store_ps(p7i, _mm256_extractf128_ps(u37i, 1));
+ _mm_store_ps(p7j, _mm256_extractf128_ps(u37j, 1));
+ }
+
+ _mm256_zeroupper();
+}
+
+#ifdef _M_IX86
+
+// clang-format:disable
+
+/* full template specializations of above functions in assembler */
+
+// AVX without useMultiplier
+template <>
+void solveConstraints<false, 1>(float* __restrict posIt, const float* __restrict rIt,
+ const float* __restrict rEnd, const uint16_t* __restrict iIt, const __m128& stiffnessRef)
+{
+ __m256 stiffness = _mm256_broadcast_ss((const float*)&stiffnessRef);
+
+ __m256 vtmp[8], htmp[4];
+ float* ptmp[16];
+
+ __asm
+ {
+ mov edx, rIt
+ mov esi, rEnd
+
+ cmp edx, esi
+ jae forEnd
+
+ mov eax, iIt
+ mov ecx, posIt
+
+forBegin:
+ movzx edi, WORD PTR [eax ] __asm shl edi, 4 __asm mov [ptmp ], edi __asm vmovaps xmm0, XMMWORD PTR [edi + ecx] // v0i
+ movzx edi, WORD PTR [eax+16] __asm shl edi, 4 __asm mov [ptmp+ 4], edi __asm vmovaps xmm1, XMMWORD PTR [edi + ecx] // v4i
+ movzx edi, WORD PTR [eax+ 2] __asm shl edi, 4 __asm mov [ptmp+ 8], edi __asm vmovaps xmm2, XMMWORD PTR [edi + ecx] // v0j
+ movzx edi, WORD PTR [eax+18] __asm shl edi, 4 __asm mov [ptmp+12], edi __asm vmovaps xmm3, XMMWORD PTR [edi + ecx] // v4j
+ movzx edi, WORD PTR [eax+ 4] __asm shl edi, 4 __asm mov [ptmp+16], edi __asm vmovaps xmm4, XMMWORD PTR [edi + ecx] // v1i
+ movzx edi, WORD PTR [eax+20] __asm shl edi, 4 __asm mov [ptmp+20], edi __asm vmovaps xmm5, XMMWORD PTR [edi + ecx] // v5i
+ movzx edi, WORD PTR [eax+ 6] __asm shl edi, 4 __asm mov [ptmp+24], edi __asm vmovaps xmm6, XMMWORD PTR [edi + ecx] // v1j
+ movzx edi, WORD PTR [eax+22] __asm shl edi, 4 __asm mov [ptmp+28], edi __asm vmovaps xmm7, XMMWORD PTR [edi + ecx] // v5j
+
+ vinsertf128 ymm0, ymm0, xmm1, 1 __asm vmovaps YMMWORD PTR [vtmp ], ymm0 // v04i
+ vinsertf128 ymm2, ymm2, xmm3, 1 __asm vmovaps YMMWORD PTR [vtmp+ 32], ymm2 // v04j
+ vinsertf128 ymm4, ymm4, xmm5, 1 __asm vmovaps YMMWORD PTR [vtmp+ 64], ymm4 // v15i
+ vinsertf128 ymm6, ymm6, xmm7, 1 __asm vmovaps YMMWORD PTR [vtmp+ 96], ymm6 // v15j
+
+ vmovaps ymm7, sMinusOneXYZOneW
+ vmulps ymm2, ymm2, ymm7 __asm vaddps ymm0, ymm0, ymm2 __asm vmovaps YMMWORD PTR [htmp ], ymm0 // h04ij
+ vmulps ymm6, ymm6, ymm7 __asm vaddps ymm4, ymm4, ymm6 __asm vmovaps YMMWORD PTR [htmp+32], ymm4 // h15ij
+
+ movzx edi, WORD PTR [eax+ 8] __asm shl edi, 4 __asm mov [ptmp+32], edi __asm vmovaps xmm0, XMMWORD PTR [edi + ecx] // v2i
+ movzx edi, WORD PTR [eax+24] __asm shl edi, 4 __asm mov [ptmp+36], edi __asm vmovaps xmm1, XMMWORD PTR [edi + ecx] // v6i
+ movzx edi, WORD PTR [eax+10] __asm shl edi, 4 __asm mov [ptmp+40], edi __asm vmovaps xmm2, XMMWORD PTR [edi + ecx] // v2j
+ movzx edi, WORD PTR [eax+26] __asm shl edi, 4 __asm mov [ptmp+44], edi __asm vmovaps xmm3, XMMWORD PTR [edi + ecx] // v6j
+ movzx edi, WORD PTR [eax+12] __asm shl edi, 4 __asm mov [ptmp+48], edi __asm vmovaps xmm4, XMMWORD PTR [edi + ecx] // v3i
+ movzx edi, WORD PTR [eax+28] __asm shl edi, 4 __asm mov [ptmp+52], edi __asm vmovaps xmm5, XMMWORD PTR [edi + ecx] // v7i
+ movzx edi, WORD PTR [eax+14] __asm shl edi, 4 __asm mov [ptmp+56], edi __asm vmovaps xmm6, XMMWORD PTR [edi + ecx] // v3j
+ movzx edi, WORD PTR [eax+30] __asm shl edi, 4 __asm mov [ptmp+60], edi __asm vmovaps xmm7, XMMWORD PTR [edi + ecx] // v7j
+
+ vinsertf128 ymm0, ymm0, xmm1, 1 __asm vmovaps YMMWORD PTR [vtmp+128], ymm0 // v26i
+ vinsertf128 ymm2, ymm2, xmm3, 1 __asm vmovaps YMMWORD PTR [vtmp+160], ymm2 // v26j
+ vinsertf128 ymm4, ymm4, xmm5, 1 __asm vmovaps YMMWORD PTR [vtmp+192], ymm4 // v37i
+ vinsertf128 ymm6, ymm6, xmm7, 1 __asm vmovaps YMMWORD PTR [vtmp+224], ymm6 // v37j
+
+ vmovaps ymm7, sMinusOneXYZOneW
+ vmulps ymm2, ymm2, ymm7 __asm vaddps ymm2, ymm0, ymm2 __asm vmovaps YMMWORD PTR [htmp+64], ymm2 // h26ij
+ vmulps ymm6, ymm6, ymm7 __asm vaddps ymm6, ymm4, ymm6 __asm vmovaps YMMWORD PTR [htmp+96], ymm6 // h37ij
+
+ vmovaps ymm0, YMMWORD PTR [htmp ] // h04ij
+ vmovaps ymm4, YMMWORD PTR [htmp+32] // h15ij
+
+ vunpcklps ymm1, ymm0, ymm2 // a
+ vunpckhps ymm3, ymm0, ymm2 // b
+ vunpcklps ymm5, ymm4, ymm6 // c
+ vunpckhps ymm7, ymm4, ymm6 // d
+
+ vunpcklps ymm0, ymm1, ymm5 // hxij
+ vunpckhps ymm2, ymm1, ymm5 // hyij
+ vunpcklps ymm4, ymm3, ymm7 // hzij
+ vunpckhps ymm6, ymm3, ymm7 // vwij
+
+ vmovaps ymm7, sEpsilon
+ vmovaps ymm5, sOne
+ vmovaps ymm3, stiffness
+ vmovaps ymm1, YMMWORD PTR [edx] // rij
+
+ vmulps ymm0, ymm0, ymm0 __asm vaddps ymm0, ymm0, ymm7 // e2ij
+ vmulps ymm2, ymm2, ymm2 __asm vaddps ymm0, ymm0, ymm2
+ vmulps ymm4, ymm4, ymm4 __asm vaddps ymm0, ymm0, ymm4
+
+ vcmpgt_oqps ymm2, ymm1, ymm7 // mask
+ vrsqrtps ymm0, ymm0 __asm vmulps ymm0, ymm0, ymm1 // erij
+ vsubps ymm5, ymm5, ymm0 __asm vandps ymm5, ymm5, ymm2
+ vaddps ymm6, ymm6, ymm7 __asm vrcpps ymm6, ymm6
+
+ vmulps ymm6, ymm6, ymm3 __asm vmulps ymm6, ymm6, ymm5 // exij
+
+ vmovaps ymm7, sMaskXY
+ vandps ymm7, ymm7, ymm6 // exlo
+ vxorps ymm6, ymm6, ymm7 // exhi
+
+ vmovaps ymm4, YMMWORD PTR [htmp ] // h04ij
+ vmovaps ymm0, YMMWORD PTR [vtmp ] // v04i
+ vmovaps ymm1, YMMWORD PTR [vtmp+ 32] // v04j
+
+ vpermilps ymm5, ymm7, 0xc0 __asm vmulps ymm4, ymm4, ymm5 // f04ij
+ vpermilps ymm2, ymm0, 0xff __asm vmulps ymm2, ymm2, ymm4 __asm vsubps ymm0, ymm0, ymm2 // u04i
+ vpermilps ymm3, ymm1, 0xff __asm vmulps ymm3, ymm3, ymm4 __asm vaddps ymm1, ymm1, ymm3 // u04j
+
+ vextractf128 xmm2, ymm0, 1
+ vextractf128 xmm3, ymm1, 1
+
+ mov edi, [ptmp ] __asm vmovaps XMMWORD PTR [edi + ecx], xmm0 // v0i
+ mov edi, [ptmp+ 8] __asm vmovaps XMMWORD PTR [edi + ecx], xmm1 // v0j
+ mov edi, [ptmp+ 4] __asm vmovaps XMMWORD PTR [edi + ecx], xmm2 // v4i
+ mov edi, [ptmp+12] __asm vmovaps XMMWORD PTR [edi + ecx], xmm3 // v4j
+
+ vmovaps ymm4, YMMWORD PTR [htmp+ 32] // h15ij
+ vmovaps ymm0, YMMWORD PTR [vtmp+ 64] // v15i
+ vmovaps ymm1, YMMWORD PTR [vtmp+ 96] // v15j
+
+ vpermilps ymm5, ymm7, 0xd5 __asm vmulps ymm4, ymm4, ymm5 // f15ij
+ vpermilps ymm2, ymm0, 0xff __asm vmulps ymm2, ymm2, ymm4 __asm vsubps ymm0, ymm0, ymm2 // u15i
+ vpermilps ymm3, ymm1, 0xff __asm vmulps ymm3, ymm3, ymm4 __asm vaddps ymm1, ymm1, ymm3 // u15j
+
+ vextractf128 xmm2, ymm0, 1
+ vextractf128 xmm3, ymm1, 1
+
+ mov edi, [ptmp+16] __asm vmovaps XMMWORD PTR [edi + ecx], xmm0 // v1i
+ mov edi, [ptmp+24] __asm vmovaps XMMWORD PTR [edi + ecx], xmm1 // v1j
+ mov edi, [ptmp+20] __asm vmovaps XMMWORD PTR [edi + ecx], xmm2 // v5i
+ mov edi, [ptmp+28] __asm vmovaps XMMWORD PTR [edi + ecx], xmm3 // v5j
+
+ vmovaps ymm4, YMMWORD PTR [htmp+ 64] // h26ij
+ vmovaps ymm0, YMMWORD PTR [vtmp+128] // v26i
+ vmovaps ymm1, YMMWORD PTR [vtmp+160] // v26j
+
+ vpermilps ymm5, ymm6, 0x2a __asm vmulps ymm4, ymm4, ymm5 // f26ij
+ vpermilps ymm2, ymm0, 0xff __asm vmulps ymm2, ymm2, ymm4 __asm vsubps ymm0, ymm0, ymm2 // u26i
+ vpermilps ymm3, ymm1, 0xff __asm vmulps ymm3, ymm3, ymm4 __asm vaddps ymm1, ymm1, ymm3 // u26j
+
+ vextractf128 xmm2, ymm0, 1
+ vextractf128 xmm3, ymm1, 1
+
+ mov edi, [ptmp+32] __asm vmovaps XMMWORD PTR [edi + ecx], xmm0 // v2i
+ mov edi, [ptmp+40] __asm vmovaps XMMWORD PTR [edi + ecx], xmm1 // v2j
+ mov edi, [ptmp+36] __asm vmovaps XMMWORD PTR [edi + ecx], xmm2 // v6i
+ mov edi, [ptmp+44] __asm vmovaps XMMWORD PTR [edi + ecx], xmm3 // v6j
+
+ vmovaps ymm4, YMMWORD PTR [htmp+ 96] // h37ij
+ vmovaps ymm0, YMMWORD PTR [vtmp+192] // v37i
+ vmovaps ymm1, YMMWORD PTR [vtmp+224] // v37j
+
+ vpermilps ymm5, ymm6, 0x3f __asm vmulps ymm4, ymm4, ymm5 // f37ij
+ vpermilps ymm2, ymm0, 0xff __asm vmulps ymm2, ymm2, ymm4 __asm vsubps ymm0, ymm0, ymm2 // u37i
+ vpermilps ymm3, ymm1, 0xff __asm vmulps ymm3, ymm3, ymm4 __asm vaddps ymm1, ymm1, ymm3 // u37j
+
+ vextractf128 xmm2, ymm0, 1
+ vextractf128 xmm3, ymm1, 1
+
+ mov edi, [ptmp+48] __asm vmovaps XMMWORD PTR [edi + ecx], xmm0 // v3i
+ mov edi, [ptmp+56] __asm vmovaps XMMWORD PTR [edi + ecx], xmm1 // v3j
+ mov edi, [ptmp+52] __asm vmovaps XMMWORD PTR [edi + ecx], xmm2 // v7i
+ mov edi, [ptmp+60] __asm vmovaps XMMWORD PTR [edi + ecx], xmm3 // v7j
+
+ add eax, 32
+ add edx, 32
+
+ cmp edx, esi
+ jb forBegin
+forEnd:
+ }
+
+ _mm256_zeroupper();
+}
+
+// AVX with useMultiplier
+template <>
+void solveConstraints<true, 1>(float* __restrict posIt, const float* __restrict rIt,
+ const float* __restrict rEnd, const uint16_t* __restrict iIt, const __m128& stiffnessRef)
+{
+ __m256 stiffness = _mm256_broadcast_ps(&stiffnessRef);
+ __m256 stretchLimit = _mm256_permute_ps(stiffness, 0xff);
+ __m256 compressionLimit = _mm256_permute_ps(stiffness, 0xaa);
+ __m256 multiplier = _mm256_permute_ps(stiffness, 0x55);
+ stiffness = _mm256_permute_ps(stiffness, 0x00);
+
+ __m256 vtmp[8], htmp[4];
+ float* ptmp[16];
+
+ __asm
+ {
+ mov edx, rIt
+ mov esi, rEnd
+
+ cmp edx, esi
+ jae forEnd
+
+ mov eax, iIt
+ mov ecx, posIt
+
+forBegin:
+ movzx edi, WORD PTR [eax ] __asm shl edi, 4 __asm mov [ptmp ], edi __asm vmovaps xmm0, XMMWORD PTR [edi + ecx] // v0i
+ movzx edi, WORD PTR [eax+16] __asm shl edi, 4 __asm mov [ptmp+ 4], edi __asm vmovaps xmm1, XMMWORD PTR [edi + ecx] // v4i
+ movzx edi, WORD PTR [eax+ 2] __asm shl edi, 4 __asm mov [ptmp+ 8], edi __asm vmovaps xmm2, XMMWORD PTR [edi + ecx] // v0j
+ movzx edi, WORD PTR [eax+18] __asm shl edi, 4 __asm mov [ptmp+12], edi __asm vmovaps xmm3, XMMWORD PTR [edi + ecx] // v4j
+ movzx edi, WORD PTR [eax+ 4] __asm shl edi, 4 __asm mov [ptmp+16], edi __asm vmovaps xmm4, XMMWORD PTR [edi + ecx] // v1i
+ movzx edi, WORD PTR [eax+20] __asm shl edi, 4 __asm mov [ptmp+20], edi __asm vmovaps xmm5, XMMWORD PTR [edi + ecx] // v5i
+ movzx edi, WORD PTR [eax+ 6] __asm shl edi, 4 __asm mov [ptmp+24], edi __asm vmovaps xmm6, XMMWORD PTR [edi + ecx] // v1j
+ movzx edi, WORD PTR [eax+22] __asm shl edi, 4 __asm mov [ptmp+28], edi __asm vmovaps xmm7, XMMWORD PTR [edi + ecx] // v5j
+
+ vinsertf128 ymm0, ymm0, xmm1, 1 __asm vmovaps YMMWORD PTR [vtmp ], ymm0 // v04i
+ vinsertf128 ymm2, ymm2, xmm3, 1 __asm vmovaps YMMWORD PTR [vtmp+ 32], ymm2 // v04j
+ vinsertf128 ymm4, ymm4, xmm5, 1 __asm vmovaps YMMWORD PTR [vtmp+ 64], ymm4 // v15i
+ vinsertf128 ymm6, ymm6, xmm7, 1 __asm vmovaps YMMWORD PTR [vtmp+ 96], ymm6 // v15j
+
+ vmovaps ymm7, sMinusOneXYZOneW
+ vmulps ymm2, ymm2, ymm7 __asm vaddps ymm0, ymm0, ymm2 __asm vmovaps YMMWORD PTR [htmp ], ymm0 // h04ij
+ vmulps ymm6, ymm6, ymm7 __asm vaddps ymm4, ymm4, ymm6 __asm vmovaps YMMWORD PTR [htmp+32], ymm4 // h15ij
+
+ movzx edi, WORD PTR [eax+ 8] __asm shl edi, 4 __asm mov [ptmp+32], edi __asm vmovaps xmm0, XMMWORD PTR [edi + ecx] // v2i
+ movzx edi, WORD PTR [eax+24] __asm shl edi, 4 __asm mov [ptmp+36], edi __asm vmovaps xmm1, XMMWORD PTR [edi + ecx] // v6i
+ movzx edi, WORD PTR [eax+10] __asm shl edi, 4 __asm mov [ptmp+40], edi __asm vmovaps xmm2, XMMWORD PTR [edi + ecx] // v2j
+ movzx edi, WORD PTR [eax+26] __asm shl edi, 4 __asm mov [ptmp+44], edi __asm vmovaps xmm3, XMMWORD PTR [edi + ecx] // v6j
+ movzx edi, WORD PTR [eax+12] __asm shl edi, 4 __asm mov [ptmp+48], edi __asm vmovaps xmm4, XMMWORD PTR [edi + ecx] // v3i
+ movzx edi, WORD PTR [eax+28] __asm shl edi, 4 __asm mov [ptmp+52], edi __asm vmovaps xmm5, XMMWORD PTR [edi + ecx] // v7i
+ movzx edi, WORD PTR [eax+14] __asm shl edi, 4 __asm mov [ptmp+56], edi __asm vmovaps xmm6, XMMWORD PTR [edi + ecx] // v3j
+ movzx edi, WORD PTR [eax+30] __asm shl edi, 4 __asm mov [ptmp+60], edi __asm vmovaps xmm7, XMMWORD PTR [edi + ecx] // v7j
+
+ vinsertf128 ymm0, ymm0, xmm1, 1 __asm vmovaps YMMWORD PTR [vtmp+128], ymm0 // v26i
+ vinsertf128 ymm2, ymm2, xmm3, 1 __asm vmovaps YMMWORD PTR [vtmp+160], ymm2 // v26j
+ vinsertf128 ymm4, ymm4, xmm5, 1 __asm vmovaps YMMWORD PTR [vtmp+192], ymm4 // v37i
+ vinsertf128 ymm6, ymm6, xmm7, 1 __asm vmovaps YMMWORD PTR [vtmp+224], ymm6 // v37j
+
+ vmovaps ymm7, sMinusOneXYZOneW
+ vmulps ymm2, ymm2, ymm7 __asm vaddps ymm2, ymm0, ymm2 __asm vmovaps YMMWORD PTR [htmp+64], ymm2 // h26ij
+ vmulps ymm6, ymm6, ymm7 __asm vaddps ymm6, ymm4, ymm6 __asm vmovaps YMMWORD PTR [htmp+96], ymm6 // h37ij
+
+ vmovaps ymm0, YMMWORD PTR [htmp ] // h04ij
+ vmovaps ymm4, YMMWORD PTR [htmp+32] // h15ij
+
+ vunpcklps ymm1, ymm0, ymm2 // a
+ vunpckhps ymm3, ymm0, ymm2 // b
+ vunpcklps ymm5, ymm4, ymm6 // c
+ vunpckhps ymm7, ymm4, ymm6 // d
+
+ vunpcklps ymm0, ymm1, ymm5 // hxij
+ vunpckhps ymm2, ymm1, ymm5 // hyij
+ vunpcklps ymm4, ymm3, ymm7 // hzij
+ vunpckhps ymm6, ymm3, ymm7 // vwij
+
+ vmovaps ymm7, sEpsilon
+ vmovaps ymm5, sOne
+ vmovaps ymm3, stiffness
+ vmovaps ymm1, YMMWORD PTR [edx] // rij
+
+ vmulps ymm0, ymm0, ymm0 __asm vaddps ymm0, ymm0, ymm7 // e2ij
+ vmulps ymm2, ymm2, ymm2 __asm vaddps ymm0, ymm0, ymm2
+ vmulps ymm4, ymm4, ymm4 __asm vaddps ymm0, ymm0, ymm4
+
+ vcmpgt_oqps ymm2, ymm1, ymm7 // mask
+ vrsqrtps ymm0, ymm0 __asm vmulps ymm0, ymm0, ymm1 // erij
+ vsubps ymm5, ymm5, ymm0 __asm vandps ymm5, ymm5, ymm2
+ vaddps ymm6, ymm6, ymm7 __asm vrcpps ymm6, ymm6
+
+ vmovaps ymm0, stretchLimit // multiplier block
+ vmovaps ymm1, compressionLimit
+ vmovaps ymm2, multiplier
+ vminps ymm0, ymm0, ymm5
+ vmaxps ymm1, ymm1, ymm0
+ vmulps ymm2, ymm2, ymm1
+ vsubps ymm5, ymm5, ymm2
+
+ vmulps ymm6, ymm6, ymm3 __asm vmulps ymm6, ymm6, ymm5 // exij
+
+ vmovaps ymm7, sMaskXY
+ vandps ymm7, ymm7, ymm6 // exlo
+ vxorps ymm6, ymm6, ymm7 // exhi
+
+ vmovaps ymm4, YMMWORD PTR [htmp ] // h04ij
+ vmovaps ymm0, YMMWORD PTR [vtmp ] // v04i
+ vmovaps ymm1, YMMWORD PTR [vtmp+ 32] // v04j
+
+ vpermilps ymm5, ymm7, 0xc0 __asm vmulps ymm4, ymm4, ymm5 // f04ij
+ vpermilps ymm2, ymm0, 0xff __asm vmulps ymm2, ymm2, ymm4 __asm vsubps ymm0, ymm0, ymm2 // u04i
+ vpermilps ymm3, ymm1, 0xff __asm vmulps ymm3, ymm3, ymm4 __asm vaddps ymm1, ymm1, ymm3 // u04j
+
+ vextractf128 xmm2, ymm0, 1
+ vextractf128 xmm3, ymm1, 1
+
+ mov edi, [ptmp ] __asm vmovaps XMMWORD PTR [edi + ecx], xmm0 // v0i
+ mov edi, [ptmp+ 8] __asm vmovaps XMMWORD PTR [edi + ecx], xmm1 // v0j
+ mov edi, [ptmp+ 4] __asm vmovaps XMMWORD PTR [edi + ecx], xmm2 // v4i
+ mov edi, [ptmp+12] __asm vmovaps XMMWORD PTR [edi + ecx], xmm3 // v4j
+
+ vmovaps ymm4, YMMWORD PTR [htmp+ 32] // h15ij
+ vmovaps ymm0, YMMWORD PTR [vtmp+ 64] // v15i
+ vmovaps ymm1, YMMWORD PTR [vtmp+ 96] // v15j
+
+ vpermilps ymm5, ymm7, 0xd5 __asm vmulps ymm4, ymm4, ymm5 // f15ij
+ vpermilps ymm2, ymm0, 0xff __asm vmulps ymm2, ymm2, ymm4 __asm vsubps ymm0, ymm0, ymm2 // u15i
+ vpermilps ymm3, ymm1, 0xff __asm vmulps ymm3, ymm3, ymm4 __asm vaddps ymm1, ymm1, ymm3 // u15j
+
+ vextractf128 xmm2, ymm0, 1
+ vextractf128 xmm3, ymm1, 1
+
+ mov edi, [ptmp+16] __asm vmovaps XMMWORD PTR [edi + ecx], xmm0 // v1i
+ mov edi, [ptmp+24] __asm vmovaps XMMWORD PTR [edi + ecx], xmm1 // v1j
+ mov edi, [ptmp+20] __asm vmovaps XMMWORD PTR [edi + ecx], xmm2 // v5i
+ mov edi, [ptmp+28] __asm vmovaps XMMWORD PTR [edi + ecx], xmm3 // v5j
+
+ vmovaps ymm4, YMMWORD PTR [htmp+ 64] // h26ij
+ vmovaps ymm0, YMMWORD PTR [vtmp+128] // v26i
+ vmovaps ymm1, YMMWORD PTR [vtmp+160] // v26j
+
+ vpermilps ymm5, ymm6, 0x2a __asm vmulps ymm4, ymm4, ymm5 // f26ij
+ vpermilps ymm2, ymm0, 0xff __asm vmulps ymm2, ymm2, ymm4 __asm vsubps ymm0, ymm0, ymm2 // u26i
+ vpermilps ymm3, ymm1, 0xff __asm vmulps ymm3, ymm3, ymm4 __asm vaddps ymm1, ymm1, ymm3 // u26j
+
+ vextractf128 xmm2, ymm0, 1
+ vextractf128 xmm3, ymm1, 1
+
+ mov edi, [ptmp+32] __asm vmovaps XMMWORD PTR [edi + ecx], xmm0 // v2i
+ mov edi, [ptmp+40] __asm vmovaps XMMWORD PTR [edi + ecx], xmm1 // v2j
+ mov edi, [ptmp+36] __asm vmovaps XMMWORD PTR [edi + ecx], xmm2 // v6i
+ mov edi, [ptmp+44] __asm vmovaps XMMWORD PTR [edi + ecx], xmm3 // v6j
+
+ vmovaps ymm4, YMMWORD PTR [htmp+ 96] // h37ij
+ vmovaps ymm0, YMMWORD PTR [vtmp+192] // v37i
+ vmovaps ymm1, YMMWORD PTR [vtmp+224] // v37j
+
+ vpermilps ymm5, ymm6, 0x3f __asm vmulps ymm4, ymm4, ymm5 // f37ij
+ vpermilps ymm2, ymm0, 0xff __asm vmulps ymm2, ymm2, ymm4 __asm vsubps ymm0, ymm0, ymm2 // u37i
+ vpermilps ymm3, ymm1, 0xff __asm vmulps ymm3, ymm3, ymm4 __asm vaddps ymm1, ymm1, ymm3 // u37j
+
+ vextractf128 xmm2, ymm0, 1
+ vextractf128 xmm3, ymm1, 1
+
+ mov edi, [ptmp+48] __asm vmovaps XMMWORD PTR [edi + ecx], xmm0 // v3i
+ mov edi, [ptmp+56] __asm vmovaps XMMWORD PTR [edi + ecx], xmm1 // v3j
+ mov edi, [ptmp+52] __asm vmovaps XMMWORD PTR [edi + ecx], xmm2 // v7i
+ mov edi, [ptmp+60] __asm vmovaps XMMWORD PTR [edi + ecx], xmm3 // v7j
+
+ add eax, 32
+ add edx, 32
+
+ cmp edx, esi
+ jb forBegin
+forEnd:
+ }
+
+ _mm256_zeroupper();
+}
+
+#if _MSC_VER >= 1700
+// AVX2 without useMultiplier
+template <>
+void solveConstraints<false, 2>(float* __restrict posIt, const float* __restrict rIt,
+ const float* __restrict rEnd, const uint16_t* __restrict iIt, const __m128& stiffnessRef)
+{
+ __m256 stiffness = _mm256_broadcast_ss((const float*)&stiffnessRef);
+
+ __m256 vtmp[8], htmp[4];
+ float* ptmp[16];
+
+ __asm
+ {
+ mov edx, rIt
+ mov esi, rEnd
+
+ cmp edx, esi
+ jae forEnd
+
+ mov eax, iIt
+ mov ecx, posIt
+
+forBegin:
+ movzx edi, WORD PTR [eax ] __asm shl edi, 4 __asm mov [ptmp ], edi __asm vmovaps xmm0, XMMWORD PTR [edi + ecx] // v0i
+ movzx edi, WORD PTR [eax+16] __asm shl edi, 4 __asm mov [ptmp+ 4], edi __asm vmovaps xmm1, XMMWORD PTR [edi + ecx] // v4i
+ movzx edi, WORD PTR [eax+ 2] __asm shl edi, 4 __asm mov [ptmp+ 8], edi __asm vmovaps xmm2, XMMWORD PTR [edi + ecx] // v0j
+ movzx edi, WORD PTR [eax+18] __asm shl edi, 4 __asm mov [ptmp+12], edi __asm vmovaps xmm3, XMMWORD PTR [edi + ecx] // v4j
+ movzx edi, WORD PTR [eax+ 4] __asm shl edi, 4 __asm mov [ptmp+16], edi __asm vmovaps xmm4, XMMWORD PTR [edi + ecx] // v1i
+ movzx edi, WORD PTR [eax+20] __asm shl edi, 4 __asm mov [ptmp+20], edi __asm vmovaps xmm5, XMMWORD PTR [edi + ecx] // v5i
+ movzx edi, WORD PTR [eax+ 6] __asm shl edi, 4 __asm mov [ptmp+24], edi __asm vmovaps xmm6, XMMWORD PTR [edi + ecx] // v1j
+ movzx edi, WORD PTR [eax+22] __asm shl edi, 4 __asm mov [ptmp+28], edi __asm vmovaps xmm7, XMMWORD PTR [edi + ecx] // v5j
+
+ vinsertf128 ymm0, ymm0, xmm1, 1 __asm vmovaps YMMWORD PTR [vtmp ], ymm0 // v04i
+ vinsertf128 ymm2, ymm2, xmm3, 1 __asm vmovaps YMMWORD PTR [vtmp+ 32], ymm2 // v04j
+ vinsertf128 ymm4, ymm4, xmm5, 1 __asm vmovaps YMMWORD PTR [vtmp+ 64], ymm4 // v15i
+ vinsertf128 ymm6, ymm6, xmm7, 1 __asm vmovaps YMMWORD PTR [vtmp+ 96], ymm6 // v15j
+
+ vmovaps ymm7, sMinusOneXYZOneW
+ vfmadd213ps ymm2, ymm7, ymm0 __asm vmovaps YMMWORD PTR [htmp ], ymm2 // h04ij
+ vfmadd213ps ymm6, ymm7, ymm4 __asm vmovaps YMMWORD PTR [htmp+32], ymm6 // h15ij
+
+ movzx edi, WORD PTR [eax+ 8] __asm shl edi, 4 __asm mov [ptmp+32], edi __asm vmovaps xmm0, XMMWORD PTR [edi + ecx] // v2i
+ movzx edi, WORD PTR [eax+24] __asm shl edi, 4 __asm mov [ptmp+36], edi __asm vmovaps xmm1, XMMWORD PTR [edi + ecx] // v6i
+ movzx edi, WORD PTR [eax+10] __asm shl edi, 4 __asm mov [ptmp+40], edi __asm vmovaps xmm2, XMMWORD PTR [edi + ecx] // v2j
+ movzx edi, WORD PTR [eax+26] __asm shl edi, 4 __asm mov [ptmp+44], edi __asm vmovaps xmm3, XMMWORD PTR [edi + ecx] // v6j
+ movzx edi, WORD PTR [eax+12] __asm shl edi, 4 __asm mov [ptmp+48], edi __asm vmovaps xmm4, XMMWORD PTR [edi + ecx] // v3i
+ movzx edi, WORD PTR [eax+28] __asm shl edi, 4 __asm mov [ptmp+52], edi __asm vmovaps xmm5, XMMWORD PTR [edi + ecx] // v7i
+ movzx edi, WORD PTR [eax+14] __asm shl edi, 4 __asm mov [ptmp+56], edi __asm vmovaps xmm6, XMMWORD PTR [edi + ecx] // v3j
+ movzx edi, WORD PTR [eax+30] __asm shl edi, 4 __asm mov [ptmp+60], edi __asm vmovaps xmm7, XMMWORD PTR [edi + ecx] // v7j
+
+ vinsertf128 ymm0, ymm0, xmm1, 1 __asm vmovaps YMMWORD PTR [vtmp+128], ymm0 // v26i
+ vinsertf128 ymm2, ymm2, xmm3, 1 __asm vmovaps YMMWORD PTR [vtmp+160], ymm2 // v26j
+ vinsertf128 ymm4, ymm4, xmm5, 1 __asm vmovaps YMMWORD PTR [vtmp+192], ymm4 // v37i
+ vinsertf128 ymm6, ymm6, xmm7, 1 __asm vmovaps YMMWORD PTR [vtmp+224], ymm6 // v37j
+
+ vmovaps ymm7, sMinusOneXYZOneW
+ vfmadd213ps ymm2, ymm7, ymm0 __asm vmovaps YMMWORD PTR [htmp+64], ymm2 // h26ij
+ vfmadd213ps ymm6, ymm7, ymm4 __asm vmovaps YMMWORD PTR [htmp+96], ymm6 // h37ij
+
+ vmovaps ymm0, YMMWORD PTR [htmp ] // h04ij
+ vmovaps ymm4, YMMWORD PTR [htmp+32] // h15ij
+
+ vunpcklps ymm1, ymm0, ymm2 // a
+ vunpckhps ymm3, ymm0, ymm2 // b
+ vunpcklps ymm5, ymm4, ymm6 // c
+ vunpckhps ymm7, ymm4, ymm6 // d
+
+ vunpcklps ymm0, ymm1, ymm5 // hxij
+ vunpckhps ymm2, ymm1, ymm5 // hyij
+ vunpcklps ymm4, ymm3, ymm7 // hzij
+ vunpckhps ymm6, ymm3, ymm7 // vwij
+
+ vmovaps ymm7, sEpsilon
+ vmovaps ymm5, sOne
+ vmovaps ymm3, stiffness
+ vmovaps ymm1, YMMWORD PTR [edx] // rij
+
+ vfmadd213ps ymm4, ymm4, ymm7 // e2ij
+ vfmadd213ps ymm2, ymm2, ymm4
+ vfmadd213ps ymm0, ymm0, ymm2
+
+ vcmpgt_oqps ymm2, ymm1, ymm7 // mask
+ vrsqrtps ymm0, ymm0 __asm vfnmadd231ps ymm5, ymm0, ymm1 // erij
+ vandps ymm5, ymm5, ymm2
+ vaddps ymm6, ymm6, ymm7 __asm vrcpps ymm6, ymm6
+
+ vmulps ymm6, ymm6, ymm3 __asm vmulps ymm6, ymm6, ymm5 // exij
+
+ vmovaps ymm7, sMaskXY
+ vandps ymm7, ymm7, ymm6 // exlo
+ vxorps ymm6, ymm6, ymm7 // exhi
+
+ vmovaps ymm4, YMMWORD PTR [htmp ] // h04ij
+ vmovaps ymm0, YMMWORD PTR [vtmp ] // v04i
+ vmovaps ymm1, YMMWORD PTR [vtmp+ 32] // v04j
+
+ vpermilps ymm5, ymm7, 0xc0 __asm vmulps ymm4, ymm4, ymm5 // f04ij
+ vpermilps ymm2, ymm0, 0xff __asm vfnmadd231ps ymm0, ymm2, ymm4 // u04i
+ vpermilps ymm3, ymm1, 0xff __asm vfmadd231ps ymm1, ymm3, ymm4 // u04j
+
+ vextractf128 xmm2, ymm0, 1
+ vextractf128 xmm3, ymm1, 1
+
+ mov edi, [ptmp ] __asm vmovaps XMMWORD PTR [edi + ecx], xmm0 // v0i
+ mov edi, [ptmp+ 8] __asm vmovaps XMMWORD PTR [edi + ecx], xmm1 // v0j
+ mov edi, [ptmp+ 4] __asm vmovaps XMMWORD PTR [edi + ecx], xmm2 // v4i
+ mov edi, [ptmp+12] __asm vmovaps XMMWORD PTR [edi + ecx], xmm3 // v4j
+
+ vmovaps ymm4, YMMWORD PTR [htmp+ 32] // h15ij
+ vmovaps ymm0, YMMWORD PTR [vtmp+ 64] // v15i
+ vmovaps ymm1, YMMWORD PTR [vtmp+ 96] // v15j
+
+ vpermilps ymm5, ymm7, 0xd5 __asm vmulps ymm4, ymm4, ymm5 // f15ij
+ vpermilps ymm2, ymm0, 0xff __asm vfnmadd231ps ymm0, ymm2, ymm4 // u15i
+ vpermilps ymm3, ymm1, 0xff __asm vfmadd231ps ymm1, ymm3, ymm4 // u15j
+
+ vextractf128 xmm2, ymm0, 1
+ vextractf128 xmm3, ymm1, 1
+
+ mov edi, [ptmp+16] __asm vmovaps XMMWORD PTR [edi + ecx], xmm0 // v1i
+ mov edi, [ptmp+24] __asm vmovaps XMMWORD PTR [edi + ecx], xmm1 // v1j
+ mov edi, [ptmp+20] __asm vmovaps XMMWORD PTR [edi + ecx], xmm2 // v5i
+ mov edi, [ptmp+28] __asm vmovaps XMMWORD PTR [edi + ecx], xmm3 // v5j
+
+ vmovaps ymm4, YMMWORD PTR [htmp+ 64] // h26ij
+ vmovaps ymm0, YMMWORD PTR [vtmp+128] // v26i
+ vmovaps ymm1, YMMWORD PTR [vtmp+160] // v26j
+
+ vpermilps ymm5, ymm6, 0x2a __asm vmulps ymm4, ymm4, ymm5 // f26ij
+ vpermilps ymm2, ymm0, 0xff __asm vfnmadd231ps ymm0, ymm2, ymm4 // u26i
+ vpermilps ymm3, ymm1, 0xff __asm vfmadd231ps ymm1, ymm3, ymm4 // u26j
+
+ vextractf128 xmm2, ymm0, 1
+ vextractf128 xmm3, ymm1, 1
+
+ mov edi, [ptmp+32] __asm vmovaps XMMWORD PTR [edi + ecx], xmm0 // v2i
+ mov edi, [ptmp+40] __asm vmovaps XMMWORD PTR [edi + ecx], xmm1 // v2j
+ mov edi, [ptmp+36] __asm vmovaps XMMWORD PTR [edi + ecx], xmm2 // v6i
+ mov edi, [ptmp+44] __asm vmovaps XMMWORD PTR [edi + ecx], xmm3 // v6j
+
+ vmovaps ymm4, YMMWORD PTR [htmp+ 96] // h37ij
+ vmovaps ymm0, YMMWORD PTR [vtmp+192] // v37i
+ vmovaps ymm1, YMMWORD PTR [vtmp+224] // v37j
+
+ vpermilps ymm5, ymm6, 0x3f __asm vmulps ymm4, ymm4, ymm5 // f37ij
+ vpermilps ymm2, ymm0, 0xff __asm vfnmadd231ps ymm0, ymm2, ymm4 // u37i
+ vpermilps ymm3, ymm1, 0xff __asm vfmadd231ps ymm1, ymm3, ymm4 // u37j
+
+ vextractf128 xmm2, ymm0, 1
+ vextractf128 xmm3, ymm1, 1
+
+ mov edi, [ptmp+48] __asm vmovaps XMMWORD PTR [edi + ecx], xmm0 // v3i
+ mov edi, [ptmp+56] __asm vmovaps XMMWORD PTR [edi + ecx], xmm1 // v3j
+ mov edi, [ptmp+52] __asm vmovaps XMMWORD PTR [edi + ecx], xmm2 // v7i
+ mov edi, [ptmp+60] __asm vmovaps XMMWORD PTR [edi + ecx], xmm3 // v7j
+
+ add eax, 32
+ add edx, 32
+
+ cmp edx, esi
+ jb forBegin
+forEnd:
+ }
+
+ _mm256_zeroupper();
+}
+
+// AVX2 with useMultiplier
+template <>
+void solveConstraints<true, 2>(float* __restrict posIt, const float* __restrict rIt,
+ const float* __restrict rEnd, const uint16_t* __restrict iIt, const __m128& stiffnessRef)
+{
+ __m256 stiffness = _mm256_broadcast_ps(&stiffnessRef);
+ __m256 stretchLimit = _mm256_permute_ps(stiffness, 0xff);
+ __m256 compressionLimit = _mm256_permute_ps(stiffness, 0xaa);
+ __m256 multiplier = _mm256_permute_ps(stiffness, 0x55);
+ stiffness = _mm256_permute_ps(stiffness, 0x00);
+
+ __m256 vtmp[8], htmp[4];
+ float* ptmp[16];
+
+ __asm
+ {
+ mov edx, rIt
+ mov esi, rEnd
+
+ cmp edx, esi
+ jae forEnd
+
+ mov eax, iIt
+ mov ecx, posIt
+
+forBegin:
+ movzx edi, WORD PTR [eax ] __asm shl edi, 4 __asm mov [ptmp ], edi __asm vmovaps xmm0, XMMWORD PTR [edi + ecx] // v0i
+ movzx edi, WORD PTR [eax+16] __asm shl edi, 4 __asm mov [ptmp+ 4], edi __asm vmovaps xmm1, XMMWORD PTR [edi + ecx] // v4i
+ movzx edi, WORD PTR [eax+ 2] __asm shl edi, 4 __asm mov [ptmp+ 8], edi __asm vmovaps xmm2, XMMWORD PTR [edi + ecx] // v0j
+ movzx edi, WORD PTR [eax+18] __asm shl edi, 4 __asm mov [ptmp+12], edi __asm vmovaps xmm3, XMMWORD PTR [edi + ecx] // v4j
+ movzx edi, WORD PTR [eax+ 4] __asm shl edi, 4 __asm mov [ptmp+16], edi __asm vmovaps xmm4, XMMWORD PTR [edi + ecx] // v1i
+ movzx edi, WORD PTR [eax+20] __asm shl edi, 4 __asm mov [ptmp+20], edi __asm vmovaps xmm5, XMMWORD PTR [edi + ecx] // v5i
+ movzx edi, WORD PTR [eax+ 6] __asm shl edi, 4 __asm mov [ptmp+24], edi __asm vmovaps xmm6, XMMWORD PTR [edi + ecx] // v1j
+ movzx edi, WORD PTR [eax+22] __asm shl edi, 4 __asm mov [ptmp+28], edi __asm vmovaps xmm7, XMMWORD PTR [edi + ecx] // v5j
+
+ vinsertf128 ymm0, ymm0, xmm1, 1 __asm vmovaps YMMWORD PTR [vtmp ], ymm0 // v04i
+ vinsertf128 ymm2, ymm2, xmm3, 1 __asm vmovaps YMMWORD PTR [vtmp+ 32], ymm2 // v04j
+ vinsertf128 ymm4, ymm4, xmm5, 1 __asm vmovaps YMMWORD PTR [vtmp+ 64], ymm4 // v15i
+ vinsertf128 ymm6, ymm6, xmm7, 1 __asm vmovaps YMMWORD PTR [vtmp+ 96], ymm6 // v15j
+
+ vmovaps ymm7, sMinusOneXYZOneW
+ vfmadd213ps ymm2, ymm7, ymm0 __asm vmovaps YMMWORD PTR [htmp ], ymm2 // h04ij
+ vfmadd213ps ymm6, ymm7, ymm4 __asm vmovaps YMMWORD PTR [htmp+32], ymm6 // h15ij
+
+ movzx edi, WORD PTR [eax+ 8] __asm shl edi, 4 __asm mov [ptmp+32], edi __asm vmovaps xmm0, XMMWORD PTR [edi + ecx] // v2i
+ movzx edi, WORD PTR [eax+24] __asm shl edi, 4 __asm mov [ptmp+36], edi __asm vmovaps xmm1, XMMWORD PTR [edi + ecx] // v6i
+ movzx edi, WORD PTR [eax+10] __asm shl edi, 4 __asm mov [ptmp+40], edi __asm vmovaps xmm2, XMMWORD PTR [edi + ecx] // v2j
+ movzx edi, WORD PTR [eax+26] __asm shl edi, 4 __asm mov [ptmp+44], edi __asm vmovaps xmm3, XMMWORD PTR [edi + ecx] // v6j
+ movzx edi, WORD PTR [eax+12] __asm shl edi, 4 __asm mov [ptmp+48], edi __asm vmovaps xmm4, XMMWORD PTR [edi + ecx] // v3i
+ movzx edi, WORD PTR [eax+28] __asm shl edi, 4 __asm mov [ptmp+52], edi __asm vmovaps xmm5, XMMWORD PTR [edi + ecx] // v7i
+ movzx edi, WORD PTR [eax+14] __asm shl edi, 4 __asm mov [ptmp+56], edi __asm vmovaps xmm6, XMMWORD PTR [edi + ecx] // v3j
+ movzx edi, WORD PTR [eax+30] __asm shl edi, 4 __asm mov [ptmp+60], edi __asm vmovaps xmm7, XMMWORD PTR [edi + ecx] // v7j
+
+ vinsertf128 ymm0, ymm0, xmm1, 1 __asm vmovaps YMMWORD PTR [vtmp+128], ymm0 // v26i
+ vinsertf128 ymm2, ymm2, xmm3, 1 __asm vmovaps YMMWORD PTR [vtmp+160], ymm2 // v26j
+ vinsertf128 ymm4, ymm4, xmm5, 1 __asm vmovaps YMMWORD PTR [vtmp+192], ymm4 // v37i
+ vinsertf128 ymm6, ymm6, xmm7, 1 __asm vmovaps YMMWORD PTR [vtmp+224], ymm6 // v37j
+
+ vmovaps ymm7, sMinusOneXYZOneW
+ vfmadd213ps ymm2, ymm7, ymm0 __asm vmovaps YMMWORD PTR [htmp+64], ymm2 // h26ij
+ vfmadd213ps ymm6, ymm7, ymm4 __asm vmovaps YMMWORD PTR [htmp+96], ymm6 // h37ij
+
+ vmovaps ymm0, YMMWORD PTR [htmp ] // h04ij
+ vmovaps ymm4, YMMWORD PTR [htmp+32] // h15ij
+
+ vunpcklps ymm1, ymm0, ymm2 // a
+ vunpckhps ymm3, ymm0, ymm2 // b
+ vunpcklps ymm5, ymm4, ymm6 // c
+ vunpckhps ymm7, ymm4, ymm6 // d
+
+ vunpcklps ymm0, ymm1, ymm5 // hxij
+ vunpckhps ymm2, ymm1, ymm5 // hyij
+ vunpcklps ymm4, ymm3, ymm7 // hzij
+ vunpckhps ymm6, ymm3, ymm7 // vwij
+
+ vmovaps ymm7, sEpsilon
+ vmovaps ymm5, sOne
+ vmovaps ymm3, stiffness
+ vmovaps ymm1, YMMWORD PTR [edx] // rij
+
+ vfmadd213ps ymm4, ymm4, ymm7 // e2ij
+ vfmadd213ps ymm2, ymm2, ymm4
+ vfmadd213ps ymm0, ymm0, ymm2
+
+ vcmpgt_oqps ymm2, ymm1, ymm7 // mask
+ vrsqrtps ymm0, ymm0 __asm vfnmadd231ps ymm5, ymm0, ymm1 // erij
+ vandps ymm5, ymm5, ymm2
+ vaddps ymm6, ymm6, ymm7 __asm vrcpps ymm6, ymm6
+
+ vmovaps ymm0, stretchLimit // multiplier block
+ vmovaps ymm1, compressionLimit
+ vmovaps ymm2, multiplier
+ vminps ymm0, ymm0, ymm5
+ vmaxps ymm1, ymm1, ymm0
+ vfnmadd231ps ymm5, ymm1, ymm2
+
+ vmulps ymm6, ymm6, ymm3 __asm vmulps ymm6, ymm6, ymm5 // exij
+
+ vmovaps ymm7, sMaskXY
+ vandps ymm7, ymm7, ymm6 // exlo
+ vxorps ymm6, ymm6, ymm7 // exhi
+
+ vmovaps ymm4, YMMWORD PTR [htmp ] // h04ij
+ vmovaps ymm0, YMMWORD PTR [vtmp ] // v04i
+ vmovaps ymm1, YMMWORD PTR [vtmp+ 32] // v04j
+
+ vpermilps ymm5, ymm7, 0xc0 __asm vmulps ymm4, ymm4, ymm5 // f04ij
+ vpermilps ymm2, ymm0, 0xff __asm vfnmadd231ps ymm0, ymm2, ymm4 // u04i
+ vpermilps ymm3, ymm1, 0xff __asm vfmadd231ps ymm1, ymm3, ymm4 // u04j
+
+ vextractf128 xmm2, ymm0, 1
+ vextractf128 xmm3, ymm1, 1
+
+ mov edi, [ptmp ] __asm vmovaps XMMWORD PTR [edi + ecx], xmm0 // v0i
+ mov edi, [ptmp+ 8] __asm vmovaps XMMWORD PTR [edi + ecx], xmm1 // v0j
+ mov edi, [ptmp+ 4] __asm vmovaps XMMWORD PTR [edi + ecx], xmm2 // v4i
+ mov edi, [ptmp+12] __asm vmovaps XMMWORD PTR [edi + ecx], xmm3 // v4j
+
+ vmovaps ymm4, YMMWORD PTR [htmp+ 32] // h15ij
+ vmovaps ymm0, YMMWORD PTR [vtmp+ 64] // v15i
+ vmovaps ymm1, YMMWORD PTR [vtmp+ 96] // v15j
+
+ vpermilps ymm5, ymm7, 0xd5 __asm vmulps ymm4, ymm4, ymm5 // f15ij
+ vpermilps ymm2, ymm0, 0xff __asm vfnmadd231ps ymm0, ymm2, ymm4 // u15i
+ vpermilps ymm3, ymm1, 0xff __asm vfmadd231ps ymm1, ymm3, ymm4 // u15j
+
+ vextractf128 xmm2, ymm0, 1
+ vextractf128 xmm3, ymm1, 1
+
+ mov edi, [ptmp+16] __asm vmovaps XMMWORD PTR [edi + ecx], xmm0 // v1i
+ mov edi, [ptmp+24] __asm vmovaps XMMWORD PTR [edi + ecx], xmm1 // v1j
+ mov edi, [ptmp+20] __asm vmovaps XMMWORD PTR [edi + ecx], xmm2 // v5i
+ mov edi, [ptmp+28] __asm vmovaps XMMWORD PTR [edi + ecx], xmm3 // v5j
+
+ vmovaps ymm4, YMMWORD PTR [htmp+ 64] // h26ij
+ vmovaps ymm0, YMMWORD PTR [vtmp+128] // v26i
+ vmovaps ymm1, YMMWORD PTR [vtmp+160] // v26j
+
+ vpermilps ymm5, ymm6, 0x2a __asm vmulps ymm4, ymm4, ymm5 // f26ij
+ vpermilps ymm2, ymm0, 0xff __asm vfnmadd231ps ymm0, ymm2, ymm4 // u26i
+ vpermilps ymm3, ymm1, 0xff __asm vfmadd231ps ymm1, ymm3, ymm4 // u26j
+
+ vextractf128 xmm2, ymm0, 1
+ vextractf128 xmm3, ymm1, 1
+
+ mov edi, [ptmp+32] __asm vmovaps XMMWORD PTR [edi + ecx], xmm0 // v2i
+ mov edi, [ptmp+40] __asm vmovaps XMMWORD PTR [edi + ecx], xmm1 // v2j
+ mov edi, [ptmp+36] __asm vmovaps XMMWORD PTR [edi + ecx], xmm2 // v6i
+ mov edi, [ptmp+44] __asm vmovaps XMMWORD PTR [edi + ecx], xmm3 // v6j
+
+ vmovaps ymm4, YMMWORD PTR [htmp+ 96] // h37ij
+ vmovaps ymm0, YMMWORD PTR [vtmp+192] // v37i
+ vmovaps ymm1, YMMWORD PTR [vtmp+224] // v37j
+
+ vpermilps ymm5, ymm6, 0x3f __asm vmulps ymm4, ymm4, ymm5 // f37ij
+ vpermilps ymm2, ymm0, 0xff __asm vfnmadd231ps ymm0, ymm2, ymm4 // u37i
+ vpermilps ymm3, ymm1, 0xff __asm vfmadd231ps ymm1, ymm3, ymm4 // u37j
+
+ vextractf128 xmm2, ymm0, 1
+ vextractf128 xmm3, ymm1, 1
+
+ mov edi, [ptmp+48] __asm vmovaps XMMWORD PTR [edi + ecx], xmm0 // v3i
+ mov edi, [ptmp+56] __asm vmovaps XMMWORD PTR [edi + ecx], xmm1 // v3j
+ mov edi, [ptmp+52] __asm vmovaps XMMWORD PTR [edi + ecx], xmm2 // v7i
+ mov edi, [ptmp+60] __asm vmovaps XMMWORD PTR [edi + ecx], xmm3 // v7j
+
+ add eax, 32
+ add edx, 32
+
+ cmp edx, esi
+ jb forBegin
+forEnd:
+ }
+
+ _mm256_zeroupper();
+}
+#endif // _MSC_VER >= 1700
+
+// clang-format:enable
+
+#else // _M_IX86
+
+template void solveConstraints<false, 1>(float* __restrict, const float* __restrict, const float* __restrict,
+ const uint16_t* __restrict, const __m128&);
+
+template void solveConstraints<true, 1>(float* __restrict, const float* __restrict, const float* __restrict,
+ const uint16_t* __restrict, const __m128&);
+
+template void solveConstraints<false, 2>(float* __restrict, const float* __restrict, const float* __restrict,
+ const uint16_t* __restrict, const __m128&);
+
+template void solveConstraints<true, 2>(float* __restrict, const float* __restrict, const float* __restrict,
+ const uint16_t* __restrict, const __m128&);
+
+#endif // _M_IX86
+
+} // namespace avx
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/neon/NeonCollision.cpp b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/neon/NeonCollision.cpp
new file mode 100644
index 00000000..01f1fb50
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/neon/NeonCollision.cpp
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef __ARM_NEON__
+#error This file needs to be compiled with NEON support!
+#endif
+
+#include "SwCollision.cpp"
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/neon/NeonSelfCollision.cpp b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/neon/NeonSelfCollision.cpp
new file mode 100644
index 00000000..d272bb6d
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/neon/NeonSelfCollision.cpp
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef __ARM_NEON__
+#error This file needs to be compiled with NEON support!
+#endif
+
+#include "SwSelfCollision.cpp"
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/neon/NeonSolverKernel.cpp b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/neon/NeonSolverKernel.cpp
new file mode 100644
index 00000000..068c900a
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/neon/NeonSolverKernel.cpp
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef __ARM_NEON__
+#error This file needs to be compiled with NEON support!
+#endif
+
+#include "SwSolverKernel.cpp"
+
+#include <cpu-features.h>
+
+namespace nvidia
+{
+namespace cloth
+{
+bool neonSolverKernel(SwCloth const& cloth, SwClothData& data, SwKernelAllocator& allocator,
+ IterationStateFactory& factory, PxProfileZone* profileZone)
+{
+ return ANDROID_CPU_ARM_FEATURE_NEON & android_getCpuFeatures() &&
+ (SwSolverKernel<Simd4f>(cloth, data, allocator, factory, profileZone)(), true);
+}
+}
+}
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/neon/Simd4f.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/neon/Simd4f.h
new file mode 100644
index 00000000..0c0b884c
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/neon/Simd4f.h
@@ -0,0 +1,500 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// factory implementation
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+template <>
+inline Simd4fFactory<const float&>::operator Simd4f() const
+{
+ return vdupq_n_f32(reinterpret_cast<const float32_t&>(v));
+}
+
+inline Simd4fFactory<detail::FourTuple>::operator Simd4f() const
+{
+ return reinterpret_cast<const Simd4f&>(v);
+}
+
+template <int i>
+inline Simd4fFactory<detail::IntType<i> >::operator Simd4f() const
+{
+ return vdupq_n_u32(i);
+}
+
+template <>
+inline Simd4fFactory<detail::IntType<1> >::operator Simd4f() const
+{
+ return vdupq_n_f32(1.0f);
+}
+
+template <>
+inline Simd4fFactory<const float*>::operator Simd4f() const
+{
+ return vld1q_f32((const float32_t*)v);
+}
+
+template <>
+inline Simd4fFactory<detail::AlignedPointer<float> >::operator Simd4f() const
+{
+ return vld1q_f32((const float32_t*)v.ptr);
+}
+
+template <>
+inline Simd4fFactory<detail::OffsetPointer<float> >::operator Simd4f() const
+{
+ return vld1q_f32(reinterpret_cast<const float32_t*>(reinterpret_cast<const char*>(v.ptr) + v.offset));
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// expression templates
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+template <>
+inline ComplementExpr<Simd4f>::operator Simd4f() const
+{
+ return vbicq_u32(vdupq_n_u32(0xffffffff), v.u4);
+}
+
+Simd4f operator&(const ComplementExpr<Simd4f>& complement, const Simd4f& v)
+{
+ return vbicq_u32(v.u4, complement.v.u4);
+}
+
+Simd4f operator&(const Simd4f& v, const ComplementExpr<Simd4f>& complement)
+{
+ return vbicq_u32(v.u4, complement.v.u4);
+}
+
+ProductExpr::operator Simd4f() const
+{
+ return vmulq_f32(v0.f4, v1.f4);
+}
+
+Simd4f operator+(const ProductExpr& p, const Simd4f& v)
+{
+ return vmlaq_f32(v.f4, p.v0.f4, p.v1.f4);
+}
+
+Simd4f operator+(const Simd4f& v, const ProductExpr& p)
+{
+ return vmlaq_f32(v.f4, p.v0.f4, p.v1.f4);
+}
+
+Simd4f operator+(const ProductExpr& p0, const ProductExpr& p1)
+{
+ // cast calls operator Simd4f() which evaluates the other ProductExpr
+ return vmlaq_f32(static_cast<Simd4f>(p0).f4, p1.v0.f4, p1.v1.f4);
+}
+
+Simd4f operator-(const Simd4f& v, const ProductExpr& p)
+{
+ return vmlsq_f32(v.f4, p.v0.f4, p.v1.f4);
+}
+
+Simd4f operator-(const ProductExpr& p0, const ProductExpr& p1)
+{
+ // cast calls operator Simd4f() which evaluates the other ProductExpr
+ return vmlsq_f32(static_cast<Simd4f>(p0).f4, p1.v0.f4, p1.v1.f4);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// operator implementations
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+Simd4f operator==(const Simd4f& v0, const Simd4f& v1)
+{
+ return vceqq_f32(v0.f4, v1.f4);
+}
+
+Simd4f operator<(const Simd4f& v0, const Simd4f& v1)
+{
+ return vcltq_f32(v0.f4, v1.f4);
+}
+
+Simd4f operator<=(const Simd4f& v0, const Simd4f& v1)
+{
+ return vcleq_f32(v0.f4, v1.f4);
+}
+
+Simd4f operator>(const Simd4f& v0, const Simd4f& v1)
+{
+ return vcgtq_f32(v0.f4, v1.f4);
+}
+
+Simd4f operator>=(const Simd4f& v0, const Simd4f& v1)
+{
+ return vcgeq_f32(v0.f4, v1.f4);
+}
+
+ComplementExpr<Simd4f> operator~(const Simd4f& v)
+{
+ return ComplementExpr<Simd4f>(v);
+}
+
+Simd4f operator&(const Simd4f& v0, const Simd4f& v1)
+{
+ return vandq_u32(v0.u4, v1.u4);
+}
+
+Simd4f operator|(const Simd4f& v0, const Simd4f& v1)
+{
+ return vorrq_u32(v0.u4, v1.u4);
+}
+
+Simd4f operator^(const Simd4f& v0, const Simd4f& v1)
+{
+ return veorq_u32(v0.u4, v1.u4);
+}
+
+Simd4f operator<<(const Simd4f& v, int shift)
+{
+ return vshlq_u32(v.u4, vdupq_n_s32(shift));
+}
+
+Simd4f operator>>(const Simd4f& v, int shift)
+{
+ return vshlq_u32(v.u4, vdupq_n_s32(-shift));
+}
+
+Simd4f operator<<(const Simd4f& v, const Simd4f& shift)
+{
+ return vshlq_u32(v.u4, shift.i4);
+}
+
+Simd4f operator>>(const Simd4f& v, const Simd4f& shift)
+{
+ return vshlq_u32(v.u4, vnegq_s32(shift.i4));
+}
+
+Simd4f operator+(const Simd4f& v)
+{
+ return v;
+}
+
+Simd4f operator+(const Simd4f& v0, const Simd4f& v1)
+{
+ return vaddq_f32(v0.f4, v1.f4);
+}
+
+Simd4f operator-(const Simd4f& v)
+{
+ return vnegq_f32(v.f4);
+}
+
+Simd4f operator-(const Simd4f& v0, const Simd4f& v1)
+{
+ return vsubq_f32(v0.f4, v1.f4);
+}
+
+ProductExpr operator*(const Simd4f& v0, const Simd4f& v1)
+{
+ return ProductExpr(v0, v1);
+}
+
+Simd4f operator/(const Simd4f& v0, const Simd4f& v1)
+{
+ return v0 * vrecpeq_f32(v1.f4); // reciprocal estimate
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// function implementations
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+Simd4f simd4f(const Simd4i& v)
+{
+ return v.u4;
+}
+
+float (&array(Simd4f& v))[4]
+{
+ return (float(&)[4])v;
+}
+
+const float (&array(const Simd4f& v))[4]
+{
+ return (const float(&)[4])v;
+}
+
+void store(float* ptr, Simd4f const& v)
+{
+ return vst1q_f32((float32_t*)ptr, v.f4);
+}
+
+void storeAligned(float* ptr, Simd4f const& v)
+{
+ return vst1q_f32((float32_t*)ptr, v.f4);
+}
+
+void storeAligned(float* ptr, unsigned int offset, Simd4f const& v)
+{
+ return storeAligned(reinterpret_cast<float*>(reinterpret_cast<char*>(ptr) + offset), v);
+}
+
+template <size_t i>
+Simd4f splat(Simd4f const& v)
+{
+ return vdupq_n_f32(array(v)[i]);
+}
+
+Simd4f select(Simd4f const& mask, Simd4f const& v0, Simd4f const& v1)
+{
+ return vbslq_f32(mask.u4, v0.f4, v1.f4);
+}
+
+Simd4f abs(const Simd4f& v)
+{
+ return vabsq_f32(v.f4);
+}
+
+Simd4f floor(const Simd4f& v)
+{
+ int32x4_t neg = vreinterpretq_s32_u32(vshrq_n_u32(v.u4, 31));
+ return vcvtq_f32_s32(vsubq_s32(vcvtq_s32_f32(v.f4), neg));
+}
+
+Simd4f max(const Simd4f& v0, const Simd4f& v1)
+{
+ return vmaxq_f32(v0.f4, v1.f4);
+}
+
+Simd4f min(const Simd4f& v0, const Simd4f& v1)
+{
+ return vminq_f32(v0.f4, v1.f4);
+}
+
+Simd4f recip(const Simd4f& v)
+{
+ return recipT<0>(v);
+}
+
+template <int n>
+Simd4f recipT(const Simd4f& v)
+{
+ Simd4f recipV = vrecpeq_f32(v.f4);
+ // n+1 newton iterations because initial approximation is crude
+ for(int i = 0; i <= n; ++i)
+ recipV = vrecpsq_f32(v.f4, recipV.f4) * recipV;
+ return recipV;
+}
+
+Simd4f sqrt(const Simd4f& v)
+{
+ return v * rsqrt(v);
+}
+
+Simd4f rsqrt(const Simd4f& v)
+{
+ return rsqrtT<0>(v);
+}
+
+template <int n>
+Simd4f rsqrtT(const Simd4f& v)
+{
+ Simd4f rsqrtV = vrsqrteq_f32(v.f4);
+ // n+1 newton iterations because initial approximation is crude
+ for(int i = 0; i <= n; ++i)
+ rsqrtV = vrsqrtsq_f32(vmulq_f32(v.f4, rsqrtV.f4), rsqrtV.f4) * rsqrtV;
+ return rsqrtV;
+}
+
+Simd4f exp2(const Simd4f& v)
+{
+ // http://www.netlib.org/cephes/
+
+ Simd4f limit = simd4f(127.4999f);
+ Simd4f x = min(max(-limit, v), limit);
+
+ // separate into integer and fractional part
+
+ Simd4f fx = x + simd4f(0.5f);
+ Simd4i ix = vsubq_s32(vcvtq_s32_f32(fx.f4), vreinterpretq_s32_u32(vshrq_n_u32(fx.u4, 31)));
+ fx = x - vcvtq_f32_s32(ix.i4);
+
+ // exp2(fx) ~ 1 + 2*P(fx) / (Q(fx) - P(fx))
+
+ Simd4f fx2 = fx * fx;
+
+ Simd4f px = fx * (simd4f(1.51390680115615096133e+3f) +
+ fx2 * (simd4f(2.02020656693165307700e+1f) + fx2 * simd4f(2.30933477057345225087e-2f)));
+ Simd4f qx = simd4f(4.36821166879210612817e+3f) + fx2 * (simd4f(2.33184211722314911771e+2f) + fx2);
+
+ Simd4f exp2fx = px * recip(qx - px);
+ exp2fx = simd4f(_1) + exp2fx + exp2fx;
+
+ // exp2(ix)
+
+ Simd4f exp2ix = vreinterpretq_f32_s32(vshlq_n_s32(vaddq_s32(ix.i4, vdupq_n_s32(0x7f)), 23));
+
+ return exp2fx * exp2ix;
+}
+
+Simd4f log2(const Simd4f& v)
+{
+ Simd4f scale = simd4f(1.44269504088896341f); // 1/ln(2)
+ const float* ptr = array(v);
+ return simd4f(::logf(ptr[0]), ::logf(ptr[1]), ::logf(ptr[2]), ::logf(ptr[3])) * scale;
+}
+
+Simd4f dot3(const Simd4f& v0, const Simd4f& v1)
+{
+ Simd4f tmp = v0 * v1;
+ return splat<0>(tmp) + splat<1>(tmp) + splat<2>(tmp);
+}
+
+Simd4f cross3(const Simd4f& v0, const Simd4f& v1)
+{
+ float32x2_t x0_y0 = vget_low_f32(v0.f4);
+ float32x2_t z0_w0 = vget_high_f32(v0.f4);
+ float32x2_t x1_y1 = vget_low_f32(v1.f4);
+ float32x2_t z1_w1 = vget_high_f32(v1.f4);
+
+ float32x2_t y1_z1 = vext_f32(x1_y1, z1_w1, 1);
+ float32x2_t y0_z0 = vext_f32(x0_y0, z0_w0, 1);
+
+ float32x2_t z0x1_w0y1 = vmul_f32(z0_w0, x1_y1);
+ float32x2_t x0y1_y0z1 = vmul_f32(x0_y0, y1_z1);
+
+ float32x2_t y2_w2 = vmls_f32(z0x1_w0y1, x0_y0, z1_w1);
+ float32x2_t z2_x2 = vmls_f32(x0y1_y0z1, y0_z0, x1_y1);
+ float32x2_t x2_y2 = vext_f32(z2_x2, y2_w2, 1);
+
+ return vcombine_f32(x2_y2, z2_x2);
+}
+
+void transpose(Simd4f& x, Simd4f& y, Simd4f& z, Simd4f& w)
+{
+#if NVMATH_INLINE_ASSEMBLER
+ asm volatile("vzip.f32 %q0, %q2 \n\t"
+ "vzip.f32 %q1, %q3 \n\t"
+ "vzip.f32 %q0, %q1 \n\t"
+ "vzip.f32 %q2, %q3 \n\t"
+ : "+w"(x.f4), "+w"(y.f4), "+w"(z.f4), "+w"(w.f4));
+#else
+ float32x4x2_t v0v1 = vzipq_f32(x.f4, z.f4);
+ float32x4x2_t v2v3 = vzipq_f32(y.f4, w.f4);
+ float32x4x2_t zip0 = vzipq_f32(v0v1.val[0], v2v3.val[0]);
+ float32x4x2_t zip1 = vzipq_f32(v0v1.val[1], v2v3.val[1]);
+
+ x = zip0.val[0];
+ y = zip0.val[1];
+ z = zip1.val[0];
+ w = zip1.val[1];
+#endif
+}
+
+int allEqual(const Simd4f& v0, const Simd4f& v1)
+{
+ return allTrue(v0 == v1);
+}
+
+int allEqual(const Simd4f& v0, const Simd4f& v1, Simd4f& outMask)
+{
+ return allTrue(outMask = v0 == v1);
+}
+
+int anyEqual(const Simd4f& v0, const Simd4f& v1)
+{
+ return anyTrue(v0 == v1);
+}
+
+int anyEqual(const Simd4f& v0, const Simd4f& v1, Simd4f& outMask)
+{
+ return anyTrue(outMask = v0 == v1);
+}
+
+int allGreater(const Simd4f& v0, const Simd4f& v1)
+{
+ return allTrue(v0 > v1);
+}
+
+int allGreater(const Simd4f& v0, const Simd4f& v1, Simd4f& outMask)
+{
+ return allTrue(outMask = v0 > v1);
+}
+
+int anyGreater(const Simd4f& v0, const Simd4f& v1)
+{
+ return anyTrue(v0 > v1);
+}
+
+int anyGreater(const Simd4f& v0, const Simd4f& v1, Simd4f& outMask)
+{
+ return anyTrue(outMask = v0 > v1);
+}
+
+int allGreaterEqual(const Simd4f& v0, const Simd4f& v1)
+{
+ return allTrue(v0 >= v1);
+}
+
+int allGreaterEqual(const Simd4f& v0, const Simd4f& v1, Simd4f& outMask)
+{
+ return allTrue(outMask = v0 >= v1);
+}
+
+int anyGreaterEqual(const Simd4f& v0, const Simd4f& v1)
+{
+ return anyTrue(v0 >= v1);
+}
+
+int anyGreaterEqual(const Simd4f& v0, const Simd4f& v1, Simd4f& outMask)
+{
+ return anyTrue(outMask = v0 >= v1);
+}
+
+int allTrue(const Simd4f& v)
+{
+#if NVMATH_INLINE_ASSEMBLER
+ int result;
+ asm volatile("vmovq q0, %q1 \n\t"
+ "vand.u32 d0, d0, d1 \n\t"
+ "vpmin.u32 d0, d0, d0 \n\t"
+ "vcmp.f32 s0, #0 \n\t"
+ "fmrx %0, fpscr"
+ : "=r"(result)
+ : "w"(v.f4)
+ : "q0");
+ return result >> 28 & 0x1;
+#else
+ uint16x4_t hi = vget_high_u16(vreinterpretq_u16_u32(v.u4));
+ uint16x4_t lo = vmovn_u32(v.u4);
+ uint16x8_t combined = vcombine_u16(lo, hi);
+ uint32x2_t reduced = vreinterpret_u32_u8(vmovn_u16(combined));
+ return vget_lane_u32(reduced, 0) == 0xffffffff;
+#endif
+}
+
+int anyTrue(const Simd4f& v)
+{
+#if NVMATH_INLINE_ASSEMBLER
+ int result;
+ asm volatile("vmovq q0, %q1 \n\t"
+ "vorr.u32 d0, d0, d1 \n\t"
+ "vpmax.u32 d0, d0, d0 \n\t"
+ "vcmp.f32 s0, #0 \n\t"
+ "fmrx %0, fpscr"
+ : "=r"(result)
+ : "w"(v.f4)
+ : "q0");
+ return result >> 28 & 0x1;
+#else
+ uint16x4_t hi = vget_high_u16(vreinterpretq_u16_u32(v.u4));
+ uint16x4_t lo = vmovn_u32(v.u4);
+ uint16x8_t combined = vcombine_u16(lo, hi);
+ uint32x2_t reduced = vreinterpret_u32_u8(vmovn_u16(combined));
+ return vget_lane_u32(reduced, 0) != 0x0;
+#endif
+}
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/neon/Simd4i.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/neon/Simd4i.h
new file mode 100644
index 00000000..7a566256
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/neon/Simd4i.h
@@ -0,0 +1,276 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// factory implementation
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+template <>
+inline Simd4iFactory<const int&>::operator Simd4i() const
+{
+ return vdupq_n_s32(v);
+}
+
+inline Simd4iFactory<detail::FourTuple>::operator Simd4i() const
+{
+ return reinterpret_cast<const Simd4i&>(v);
+}
+
+template <int i>
+inline Simd4iFactory<detail::IntType<i> >::operator Simd4i() const
+{
+ return vdupq_n_u32(i);
+}
+
+template <>
+inline Simd4iFactory<const int*>::operator Simd4i() const
+{
+ return vld1q_s32(v);
+}
+
+template <>
+inline Simd4iFactory<detail::AlignedPointer<int> >::operator Simd4i() const
+{
+ return vld1q_s32(v.ptr);
+}
+
+template <>
+inline Simd4iFactory<detail::OffsetPointer<int> >::operator Simd4i() const
+{
+ return vld1q_s32(reinterpret_cast<const int*>(reinterpret_cast<const char*>(v.ptr) + v.offset));
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// expression template
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+template <>
+inline ComplementExpr<Simd4i>::operator Simd4i() const
+{
+ return vbicq_u32(vdupq_n_u32(0xffffffff), v.u4);
+}
+
+Simd4i operator&(const ComplementExpr<Simd4i>& complement, const Simd4i& v)
+{
+ return vbicq_u32(v.u4, complement.v.u4);
+}
+
+Simd4i operator&(const Simd4i& v, const ComplementExpr<Simd4i>& complement)
+{
+ return vbicq_u32(v.u4, complement.v.u4);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// operator implementations
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+Simd4i simdi::operator==(const Simd4i& v0, const Simd4i& v1)
+{
+ return vceqq_u32(v0.u4, v1.u4);
+}
+
+Simd4i simdi::operator<(const Simd4i& v0, const Simd4i& v1)
+{
+ return vcltq_s32(v0.i4, v1.i4);
+}
+
+Simd4i simdi::operator>(const Simd4i& v0, const Simd4i& v1)
+{
+ return vcgtq_s32(v0.i4, v1.i4);
+}
+
+ComplementExpr<Simd4i> operator~(const Simd4i& v)
+{
+ return ComplementExpr<Simd4i>(v);
+}
+
+Simd4i operator&(const Simd4i& v0, const Simd4i& v1)
+{
+ return vandq_u32(v0.u4, v1.u4);
+}
+
+Simd4i operator|(const Simd4i& v0, const Simd4i& v1)
+{
+ return vorrq_u32(v0.u4, v1.u4);
+}
+
+Simd4i operator^(const Simd4i& v0, const Simd4i& v1)
+{
+ return veorq_u32(v0.u4, v1.u4);
+}
+
+Simd4i operator<<(const Simd4i& v, int shift)
+{
+ return vshlq_u32(v.u4, vdupq_n_s32(shift));
+}
+
+Simd4i operator>>(const Simd4i& v, int shift)
+{
+ return vshlq_u32(v.u4, vdupq_n_s32(-shift));
+}
+
+Simd4i operator<<(const Simd4i& v, const Simd4i& shift)
+{
+ return vshlq_u32(v.u4, shift.i4);
+}
+
+Simd4i operator>>(const Simd4i& v, const Simd4i& shift)
+{
+ return vshlq_u32(v.u4, vnegq_s32(shift.i4));
+}
+
+Simd4i simdi::operator+(const Simd4i& v0, const Simd4i& v1)
+{
+ return vaddq_u32(v0.u4, v1.u4);
+}
+
+Simd4i simdi::operator-(const Simd4i& v)
+{
+ return vnegq_s32(v.i4);
+}
+
+Simd4i simdi::operator-(const Simd4i& v0, const Simd4i& v1)
+{
+ return vsubq_u32(v0.u4, v1.u4);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// function implementations
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+Simd4i simd4i(const Simd4f& v)
+{
+ return v.u4;
+}
+
+int (&simdi::array(Simd4i& v))[4]
+{
+ return (int(&)[4])v;
+}
+
+const int (&simdi::array(const Simd4i& v))[4]
+{
+ return (const int(&)[4])v;
+}
+
+void store(int* ptr, const Simd4i& v)
+{
+ return vst1q_s32(ptr, v.i4);
+}
+
+void storeAligned(int* ptr, const Simd4i& v)
+{
+ vst1q_s32(ptr, v.i4);
+}
+
+void storeAligned(int* ptr, unsigned int offset, const Simd4i& v)
+{
+ return storeAligned(reinterpret_cast<int*>(reinterpret_cast<char*>(ptr) + offset), v);
+}
+
+template <size_t i>
+Simd4i splat(Simd4i const& v)
+{
+ return vdupq_n_s32(simdi::array(v)[i]);
+}
+
+Simd4i select(Simd4i const& mask, Simd4i const& v0, Simd4i const& v1)
+{
+ return vbslq_u32(mask.u4, v0.u4, v1.u4);
+}
+
+int simdi::allEqual(const Simd4i& v0, const Simd4i& v1)
+{
+ return allTrue(simdi::operator==(v0, v1));
+}
+
+int simdi::allEqual(const Simd4i& v0, const Simd4i& v1, Simd4i& outMask)
+{
+ return allTrue(outMask = simdi::operator==(v0, v1));
+}
+
+int simdi::anyEqual(const Simd4i& v0, const Simd4i& v1)
+{
+ return anyTrue(simdi::operator==(v0, v1));
+}
+
+int simdi::anyEqual(const Simd4i& v0, const Simd4i& v1, Simd4i& outMask)
+{
+ return anyTrue(outMask = simdi::operator==(v0, v1));
+}
+
+int simdi::allGreater(const Simd4i& v0, const Simd4i& v1)
+{
+ return allTrue(simdi::operator>(v0, v1));
+}
+
+int simdi::allGreater(const Simd4i& v0, const Simd4i& v1, Simd4i& outMask)
+{
+ return allTrue(outMask = simdi::operator>(v0, v1));
+}
+
+int simdi::anyGreater(const Simd4i& v0, const Simd4i& v1)
+{
+ return anyTrue(simdi::operator>(v0, v1));
+}
+
+int simdi::anyGreater(const Simd4i& v0, const Simd4i& v1, Simd4i& outMask)
+{
+ return anyTrue(outMask = simdi::operator>(v0, v1));
+}
+
+int allTrue(const Simd4i& v)
+{
+#if NVMATH_INLINE_ASSEMBLER
+ int result;
+ asm volatile("vmovq q0, %q1 \n\t"
+ "vand.u32 d0, d0, d1 \n\t"
+ "vpmin.u32 d0, d0, d0 \n\t"
+ "vcmp.f32 s0, #0 \n\t"
+ "fmrx %0, fpscr"
+ : "=r"(result)
+ : "w"(v.u4)
+ : "q0");
+ return result >> 28 & 0x1;
+#else
+ uint16x4_t hi = vget_high_u16(vreinterpretq_u16_u32(v.u4));
+ uint16x4_t lo = vmovn_u32(v.u4);
+ uint16x8_t combined = vcombine_u16(lo, hi);
+ uint32x2_t reduced = vreinterpret_u32_u8(vmovn_u16(combined));
+ return vget_lane_u32(reduced, 0) == 0xffffffff;
+#endif
+}
+
+int anyTrue(const Simd4i& v)
+{
+#if NVMATH_INLINE_ASSEMBLER
+ int result;
+ asm volatile("vmovq q0, %q1 \n\t"
+ "vorr.u32 d0, d0, d1 \n\t"
+ "vpmax.u32 d0, d0, d0 \n\t"
+ "vcmp.f32 s0, #0 \n\t"
+ "fmrx %0, fpscr"
+ : "=r"(result)
+ : "w"(v.u4)
+ : "q0");
+ return result >> 28 & 0x1;
+#else
+ uint16x4_t hi = vget_high_u16(vreinterpretq_u16_u32(v.u4));
+ uint16x4_t lo = vmovn_u32(v.u4);
+ uint16x8_t combined = vcombine_u16(lo, hi);
+ uint32x2_t reduced = vreinterpret_u32_u8(vmovn_u16(combined));
+ return vget_lane_u32(reduced, 0) != 0x0;
+#endif
+}
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/neon/SimdTypes.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/neon/SimdTypes.h
new file mode 100644
index 00000000..542fac08
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/neon/SimdTypes.h
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include <arm_neon.h>
+
+union Simd4f
+{
+ Simd4f()
+ {
+ }
+ Simd4f(const float32x4_t& v) : f4(v)
+ {
+ }
+#ifndef _M_ARM // all *32x4_t map to the same type
+ Simd4f(const uint32x4_t& v) : u4(v)
+ {
+ }
+#endif
+ float32x4_t f4;
+ uint32x4_t u4;
+ int32x4_t i4;
+};
+
+union Simd4i
+{
+ Simd4i()
+ {
+ }
+ Simd4i(const uint32x4_t& v) : u4(v)
+ {
+ }
+#ifndef _M_ARM // all *32x4_t map to the same type
+ Simd4i(const int32x4_t& v) : i4(v)
+ {
+ }
+#endif
+ uint32x4_t u4;
+ int32x4_t i4;
+};
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/neon/SwCollisionHelpers.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/neon/SwCollisionHelpers.h
new file mode 100644
index 00000000..b67f96aa
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/neon/SwCollisionHelpers.h
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#ifdef _M_ARM
+#include <arm_neon.h>
+#endif
+
+namespace nvidia
+{
+namespace cloth
+{
+
+uint32_t findBitSet(uint32_t mask)
+{
+#ifdef _M_ARM
+ __n64 t = { mask };
+ return 31 - (vclz_u32(t)).n64_u32[0];
+#else
+ return 31 - __builtin_clz(mask);
+#endif
+}
+
+Simd4i intFloor(const Simd4f& v)
+{
+ int32x4_t neg = vreinterpretq_s32_u32(vshrq_n_u32(v.u4, 31));
+ return vsubq_s32(vcvtq_s32_f32(v.f4), neg);
+}
+
+Simd4i horizontalOr(Simd4i mask)
+{
+ using namespace simdi;
+ uint32x2_t hi = vget_high_u32(mask.u4);
+ uint32x2_t lo = vget_low_u32(mask.u4);
+ uint32x2_t tmp = vorr_u32(lo, hi);
+ uint32x2_t rev = vrev64_u32(tmp);
+ uint32x2_t res = vorr_u32(tmp, rev);
+ return vcombine_u32(res, res);
+}
+
+Gather<Simd4i>::Gather(const Simd4i& index)
+{
+#ifdef __arm64__
+ using namespace simdi;
+ PX_ALIGN(16, uint8x8x2_t) byteIndex = reinterpret_cast<const uint8x8x2_t&>(sPack);
+ uint8x16_t lohiIndex = reinterpret_cast<const uint8x16_t&>(index);
+ byteIndex.val[0] = vtbl1q_u8(lohiIndex, byteIndex.val[0]);
+ byteIndex.val[1] = vtbl1q_u8(lohiIndex, byteIndex.val[1]);
+ mPermute = vshlq_n_u32(reinterpret_cast<const uint32x4_t&>(byteIndex), 2);
+ mPermute = mPermute | sOffset | vcgtq_u32(index.u4, sMask.u4);
+#else
+ using namespace simdi;
+ PX_ALIGN(16, uint8x8x2_t) byteIndex = reinterpret_cast<const uint8x8x2_t&>(sPack);
+ uint8x8x2_t lohiIndex = reinterpret_cast<const uint8x8x2_t&>(index);
+ byteIndex.val[0] = vtbl2_u8(lohiIndex, byteIndex.val[0]);
+ byteIndex.val[1] = vtbl2_u8(lohiIndex, byteIndex.val[1]);
+ mPermute = vshlq_n_u32(reinterpret_cast<const uint32x4_t&>(byteIndex), 2);
+ mPermute = mPermute | sOffset | vcgtq_u32(index.u4, sMask.u4);
+#endif
+}
+
+Simd4i Gather<Simd4i>::operator()(const Simd4i* ptr) const
+{
+#ifdef __arm64__
+ PX_ALIGN(16, uint8x8x2_t) result = reinterpret_cast<const uint8x8x2_t&>(mPermute);
+ const uint8x16x2_t* table = reinterpret_cast<const uint8x16x2_t*>(ptr);
+ result.val[0] = vtbl2q_u8(*table, result.val[0]);
+ result.val[1] = vtbl2q_u8(*table, result.val[1]);
+ return reinterpret_cast<const Simd4i&>(result);
+#else
+ PX_ALIGN(16, uint8x8x2_t) result = reinterpret_cast<const uint8x8x2_t&>(mPermute);
+ const uint8x8x4_t* table = reinterpret_cast<const uint8x8x4_t*>(ptr);
+ result.val[0] = vtbl4_u8(*table, result.val[0]);
+ result.val[1] = vtbl4_u8(*table, result.val[1]);
+ return reinterpret_cast<const Simd4i&>(result);
+#endif
+}
+
+} // namespace cloth
+} // namespace physx
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/scalar/Simd4f.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/scalar/Simd4f.h
new file mode 100644
index 00000000..d02d5066
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/scalar/Simd4f.h
@@ -0,0 +1,410 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// factory implementation
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+template <>
+inline Simd4fFactory<const float&>::operator Scalar4f() const
+{
+ return Scalar4f(v, v, v, v);
+}
+
+inline Simd4fFactory<detail::FourTuple>::operator Scalar4f() const
+{
+ return reinterpret_cast<const Scalar4f&>(v);
+}
+
+template <int i>
+inline Simd4fFactory<detail::IntType<i> >::operator Scalar4f() const
+{
+ float s = i;
+ return Scalar4f(s, s, s, s);
+}
+
+template <>
+inline Simd4fFactory<detail::IntType<0x80000000u> >::operator Scalar4f() const
+{
+ int32_t i = 0x80000000u;
+ return Scalar4f(i, i, i, i);
+}
+
+template <>
+inline Simd4fFactory<detail::IntType<0xffffffff> >::operator Scalar4f() const
+{
+ int32_t i = 0xffffffff;
+ return Scalar4f(i, i, i, i);
+}
+
+template <>
+inline Simd4fFactory<const float*>::operator Scalar4f() const
+{
+ return Scalar4f(v[0], v[1], v[2], v[3]);
+}
+
+template <>
+inline Simd4fFactory<detail::AlignedPointer<float> >::operator Scalar4f() const
+{
+ return Scalar4f(v.ptr[0], v.ptr[1], v.ptr[2], v.ptr[3]);
+}
+
+template <>
+inline Simd4fFactory<detail::OffsetPointer<float> >::operator Scalar4f() const
+{
+ const float* ptr = reinterpret_cast<const float*>(reinterpret_cast<const char*>(v.ptr) + v.offset);
+ return Scalar4f(ptr[0], ptr[1], ptr[2], ptr[3]);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// expression template
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+template <>
+inline ComplementExpr<Scalar4f>::operator Scalar4f() const
+{
+ return Scalar4f(~v.u4[0], ~v.u4[1], ~v.u4[2], ~v.u4[3]);
+}
+
+inline Scalar4f operator&(const ComplementExpr<Scalar4f>& complement, const Scalar4f& v)
+{
+ return Scalar4f(v.u4[0] & ~complement.v.u4[0], v.u4[1] & ~complement.v.u4[1], v.u4[2] & ~complement.v.u4[2],
+ v.u4[3] & ~complement.v.u4[3]);
+}
+
+inline Scalar4f operator&(const Scalar4f& v, const ComplementExpr<Scalar4f>& complement)
+{
+ return Scalar4f(v.u4[0] & ~complement.v.u4[0], v.u4[1] & ~complement.v.u4[1], v.u4[2] & ~complement.v.u4[2],
+ v.u4[3] & ~complement.v.u4[3]);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// operator implementations
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+inline Scalar4f operator==(const Scalar4f& v0, const Scalar4f& v1)
+{
+ return Scalar4f(v0.f4[0] == v1.f4[0], v0.f4[1] == v1.f4[1], v0.f4[2] == v1.f4[2], v0.f4[3] == v1.f4[3]);
+}
+
+inline Scalar4f operator<(const Scalar4f& v0, const Scalar4f& v1)
+{
+ return Scalar4f(v0.f4[0] < v1.f4[0], v0.f4[1] < v1.f4[1], v0.f4[2] < v1.f4[2], v0.f4[3] < v1.f4[3]);
+}
+
+inline Scalar4f operator<=(const Scalar4f& v0, const Scalar4f& v1)
+{
+ return Scalar4f(v0.f4[0] <= v1.f4[0], v0.f4[1] <= v1.f4[1], v0.f4[2] <= v1.f4[2], v0.f4[3] <= v1.f4[3]);
+}
+
+inline Scalar4f operator>(const Scalar4f& v0, const Scalar4f& v1)
+{
+ return Scalar4f(v0.f4[0] > v1.f4[0], v0.f4[1] > v1.f4[1], v0.f4[2] > v1.f4[2], v0.f4[3] > v1.f4[3]);
+}
+
+inline Scalar4f operator>=(const Scalar4f& v0, const Scalar4f& v1)
+{
+ return Scalar4f(v0.f4[0] >= v1.f4[0], v0.f4[1] >= v1.f4[1], v0.f4[2] >= v1.f4[2], v0.f4[3] >= v1.f4[3]);
+}
+
+inline ComplementExpr<Scalar4f> operator~(const Scalar4f& v)
+{
+ return ComplementExpr<Scalar4f>(v);
+}
+
+inline Scalar4f operator&(const Scalar4f& v0, const Scalar4f& v1)
+{
+ return Scalar4f(v0.u4[0] & v1.u4[0], v0.u4[1] & v1.u4[1], v0.u4[2] & v1.u4[2], v0.u4[3] & v1.u4[3]);
+}
+
+inline Scalar4f operator|(const Scalar4f& v0, const Scalar4f& v1)
+{
+ return Scalar4f(v0.u4[0] | v1.u4[0], v0.u4[1] | v1.u4[1], v0.u4[2] | v1.u4[2], v0.u4[3] | v1.u4[3]);
+}
+
+inline Scalar4f operator^(const Scalar4f& v0, const Scalar4f& v1)
+{
+ return Scalar4f(v0.u4[0] ^ v1.u4[0], v0.u4[1] ^ v1.u4[1], v0.u4[2] ^ v1.u4[2], v0.u4[3] ^ v1.u4[3]);
+}
+
+inline Scalar4f operator<<(const Scalar4f& v, int shift)
+{
+ return Scalar4f(v.u4[0] << shift, v.u4[1] << shift, v.u4[2] << shift, v.u4[3] << shift);
+}
+
+inline Scalar4f operator>>(const Scalar4f& v, int shift)
+{
+ return Scalar4f(v.u4[0] >> shift, v.u4[1] >> shift, v.u4[2] >> shift, v.u4[3] >> shift);
+}
+
+inline Scalar4f operator+(const Scalar4f& v)
+{
+ return v;
+}
+
+inline Scalar4f operator+(const Scalar4f& v0, const Scalar4f& v1)
+{
+ return Scalar4f(v0.f4[0] + v1.f4[0], v0.f4[1] + v1.f4[1], v0.f4[2] + v1.f4[2], v0.f4[3] + v1.f4[3]);
+}
+
+inline Scalar4f operator-(const Scalar4f& v)
+{
+ return Scalar4f(-v.f4[0], -v.f4[1], -v.f4[2], -v.f4[3]);
+}
+
+inline Scalar4f operator-(const Scalar4f& v0, const Scalar4f& v1)
+{
+ return Scalar4f(v0.f4[0] - v1.f4[0], v0.f4[1] - v1.f4[1], v0.f4[2] - v1.f4[2], v0.f4[3] - v1.f4[3]);
+}
+
+inline Scalar4f operator*(const Scalar4f& v0, const Scalar4f& v1)
+{
+ return Scalar4f(v0.f4[0] * v1.f4[0], v0.f4[1] * v1.f4[1], v0.f4[2] * v1.f4[2], v0.f4[3] * v1.f4[3]);
+}
+
+inline Scalar4f operator/(const Scalar4f& v0, const Scalar4f& v1)
+{
+ return Scalar4f(v0.f4[0] / v1.f4[0], v0.f4[1] / v1.f4[1], v0.f4[2] / v1.f4[2], v0.f4[3] / v1.f4[3]);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// function implementations
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+inline Scalar4f simd4f(const Scalar4i& v)
+{
+ return v;
+}
+
+inline float (&array(Scalar4f& v))[4]
+{
+ return v.f4;
+}
+
+inline const float (&array(const Scalar4f& v))[4]
+{
+ return v.f4;
+}
+
+inline void store(float* ptr, const Scalar4f& v)
+{
+ ptr[0] = v.f4[0];
+ ptr[1] = v.f4[1];
+ ptr[2] = v.f4[2];
+ ptr[3] = v.f4[3];
+}
+
+inline void storeAligned(float* ptr, const Scalar4f& v)
+{
+ store(ptr, v);
+}
+
+inline void storeAligned(float* ptr, unsigned int offset, const Scalar4f& v)
+{
+ storeAligned(reinterpret_cast<float*>(reinterpret_cast<char*>(ptr) + offset), v);
+}
+
+template <size_t i>
+inline Scalar4f splat(const Scalar4f& v)
+{
+ return Scalar4f(v.f4[i], v.f4[i], v.f4[i], v.f4[i]);
+}
+
+inline Scalar4f select(const Scalar4f& mask, const Scalar4f& v0, const Scalar4f& v1)
+{
+ return ((v0 ^ v1) & mask) ^ v1;
+}
+
+inline Scalar4f abs(const Scalar4f& v)
+{
+ return Scalar4f(::fabsf(v.f4[0]), ::fabsf(v.f4[1]), ::fabsf(v.f4[2]), ::fabsf(v.f4[3]));
+}
+
+inline Scalar4f floor(const Scalar4f& v)
+{
+ return Scalar4f(::floorf(v.f4[0]), ::floorf(v.f4[1]), ::floorf(v.f4[2]), ::floorf(v.f4[3]));
+}
+
+inline Scalar4f max(const Scalar4f& v0, const Scalar4f& v1)
+{
+ return Scalar4f(std::max(v0.f4[0], v1.f4[0]), std::max(v0.f4[1], v1.f4[1]), std::max(v0.f4[2], v1.f4[2]),
+ std::max(v0.f4[3], v1.f4[3]));
+}
+
+inline Scalar4f min(const Scalar4f& v0, const Scalar4f& v1)
+{
+ return Scalar4f(std::min(v0.f4[0], v1.f4[0]), std::min(v0.f4[1], v1.f4[1]), std::min(v0.f4[2], v1.f4[2]),
+ std::min(v0.f4[3], v1.f4[3]));
+}
+
+inline Scalar4f recip(const Scalar4f& v)
+{
+ return Scalar4f(1 / v.f4[0], 1 / v.f4[1], 1 / v.f4[2], 1 / v.f4[3]);
+}
+
+template <int n>
+inline Scalar4f recipT(const Scalar4f& v)
+{
+ return recip(v);
+}
+
+inline Scalar4f sqrt(const Scalar4f& v)
+{
+ return Scalar4f(::sqrtf(v.f4[0]), ::sqrtf(v.f4[1]), ::sqrtf(v.f4[2]), ::sqrtf(v.f4[3]));
+}
+
+inline Scalar4f rsqrt(const Scalar4f& v)
+{
+ return recip(sqrt(v));
+}
+
+template <int n>
+inline Scalar4f rsqrtT(const Scalar4f& v)
+{
+ return rsqrt(v);
+}
+
+inline Scalar4f exp2(const Scalar4f& v)
+{
+ float scale = 0.69314718055994531f; // ::logf(2.0f);
+ return Scalar4f(::expf(v.f4[0] * scale), ::expf(v.f4[1] * scale), ::expf(v.f4[2] * scale), ::expf(v.f4[3] * scale));
+}
+
+namespace simdf
+{
+// PSP2 is confused resolving about exp2, forwarding works
+inline Scalar4f exp2(const Scalar4f& v)
+{
+ return ::exp2(v);
+}
+}
+
+inline Scalar4f log2(const Scalar4f& v)
+{
+ float scale = 1.44269504088896341f; // 1/ln(2)
+ return Scalar4f(::logf(v.f4[0]) * scale, ::logf(v.f4[1]) * scale, ::logf(v.f4[2]) * scale, ::logf(v.f4[3]) * scale);
+}
+
+inline Scalar4f dot3(const Scalar4f& v0, const Scalar4f& v1)
+{
+ return simd4f(v0.f4[0] * v1.f4[0] + v0.f4[1] * v1.f4[1] + v0.f4[2] * v1.f4[2]);
+}
+
+inline Scalar4f cross3(const Scalar4f& v0, const Scalar4f& v1)
+{
+ return simd4f(v0.f4[1] * v1.f4[2] - v0.f4[2] * v1.f4[1], v0.f4[2] * v1.f4[0] - v0.f4[0] * v1.f4[2],
+ v0.f4[0] * v1.f4[1] - v0.f4[1] * v1.f4[0], 0.0f);
+}
+
+inline void transpose(Scalar4f& x, Scalar4f& y, Scalar4f& z, Scalar4f& w)
+{
+ float x1 = x.f4[1], x2 = x.f4[2], x3 = x.f4[3];
+ float y2 = y.f4[2], y3 = y.f4[3], z3 = z.f4[3];
+
+ x.f4[1] = y.f4[0];
+ x.f4[2] = z.f4[0];
+ x.f4[3] = w.f4[0];
+ y.f4[0] = x1;
+ y.f4[2] = z.f4[1];
+ y.f4[3] = w.f4[1];
+ z.f4[0] = x2;
+ z.f4[1] = y2;
+ z.f4[3] = w.f4[2];
+ w.f4[0] = x3;
+ w.f4[1] = y3;
+ w.f4[2] = z3;
+}
+
+inline int allEqual(const Scalar4f& v0, const Scalar4f& v1)
+{
+ return v0.f4[0] == v1.f4[0] && v0.f4[1] == v1.f4[1] && v0.f4[2] == v1.f4[2] && v0.f4[3] == v1.f4[3];
+}
+
+inline int allEqual(const Scalar4f& v0, const Scalar4f& v1, Scalar4f& outMask)
+{
+ bool b0 = v0.f4[0] == v1.f4[0], b1 = v0.f4[1] == v1.f4[1], b2 = v0.f4[2] == v1.f4[2], b3 = v0.f4[3] == v1.f4[3];
+ outMask = Scalar4f(b0, b1, b2, b3);
+ return b0 && b1 && b2 && b3;
+}
+
+inline int anyEqual(const Scalar4f& v0, const Scalar4f& v1)
+{
+ return v0.f4[0] == v1.f4[0] || v0.f4[1] == v1.f4[1] || v0.f4[2] == v1.f4[2] || v0.f4[3] == v1.f4[3];
+}
+
+inline int anyEqual(const Scalar4f& v0, const Scalar4f& v1, Scalar4f& outMask)
+{
+ bool b0 = v0.f4[0] == v1.f4[0], b1 = v0.f4[1] == v1.f4[1], b2 = v0.f4[2] == v1.f4[2], b3 = v0.f4[3] == v1.f4[3];
+ outMask = Scalar4f(b0, b1, b2, b3);
+ return b0 || b1 || b2 || b3;
+}
+
+inline int allGreater(const Scalar4f& v0, const Scalar4f& v1)
+{
+ return v0.f4[0] > v1.f4[0] && v0.f4[1] > v1.f4[1] && v0.f4[2] > v1.f4[2] && v0.f4[3] > v1.f4[3];
+}
+
+inline int allGreater(const Scalar4f& v0, const Scalar4f& v1, Scalar4f& outMask)
+{
+ bool b0 = v0.f4[0] > v1.f4[0], b1 = v0.f4[1] > v1.f4[1], b2 = v0.f4[2] > v1.f4[2], b3 = v0.f4[3] > v1.f4[3];
+ outMask = Scalar4f(b0, b1, b2, b3);
+ return b0 && b1 && b2 && b3;
+}
+
+inline int anyGreater(const Scalar4f& v0, const Scalar4f& v1)
+{
+ return v0.f4[0] > v1.f4[0] || v0.f4[1] > v1.f4[1] || v0.f4[2] > v1.f4[2] || v0.f4[3] > v1.f4[3];
+}
+
+inline int anyGreater(const Scalar4f& v0, const Scalar4f& v1, Scalar4f& outMask)
+{
+ bool b0 = v0.f4[0] > v1.f4[0], b1 = v0.f4[1] > v1.f4[1], b2 = v0.f4[2] > v1.f4[2], b3 = v0.f4[3] > v1.f4[3];
+ outMask = Scalar4f(b0, b1, b2, b3);
+ return b0 || b1 || b2 || b3;
+}
+
+inline int allGreaterEqual(const Scalar4f& v0, const Scalar4f& v1)
+{
+ return v0.f4[0] >= v1.f4[0] && v0.f4[1] >= v1.f4[1] && v0.f4[2] >= v1.f4[2] && v0.f4[3] >= v1.f4[3];
+}
+
+inline int allGreaterEqual(const Scalar4f& v0, const Scalar4f& v1, Scalar4f& outMask)
+{
+ bool b0 = v0.f4[0] >= v1.f4[0], b1 = v0.f4[1] >= v1.f4[1], b2 = v0.f4[2] >= v1.f4[2], b3 = v0.f4[3] >= v1.f4[3];
+ outMask = Scalar4f(b0, b1, b2, b3);
+ return b0 && b1 && b2 && b3;
+}
+
+inline int anyGreaterEqual(const Scalar4f& v0, const Scalar4f& v1)
+{
+ return v0.f4[0] >= v1.f4[0] || v0.f4[1] >= v1.f4[1] || v0.f4[2] >= v1.f4[2] || v0.f4[3] >= v1.f4[3];
+}
+
+inline int anyGreaterEqual(const Scalar4f& v0, const Scalar4f& v1, Scalar4f& outMask)
+{
+ bool b0 = v0.f4[0] >= v1.f4[0], b1 = v0.f4[1] >= v1.f4[1], b2 = v0.f4[2] >= v1.f4[2], b3 = v0.f4[3] >= v1.f4[3];
+ outMask = Scalar4f(b0, b1, b2, b3);
+ return b0 || b1 || b2 || b3;
+}
+
+inline int allTrue(const Scalar4f& v)
+{
+ return v.u4[0] & v.u4[1] & v.u4[2] & v.u4[3];
+}
+
+inline int anyTrue(const Scalar4f& v)
+{
+ return v.u4[0] | v.u4[1] | v.u4[2] | v.u4[3];
+}
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/scalar/Simd4i.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/scalar/Simd4i.h
new file mode 100644
index 00000000..80ac2abd
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/scalar/Simd4i.h
@@ -0,0 +1,188 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// factory implementation
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+template <>
+inline Simd4iFactory<const int&>::operator Scalar4i() const
+{
+ return Scalar4i(v, v, v, v);
+}
+
+inline Simd4iFactory<detail::FourTuple>::operator Scalar4i() const
+{
+ return reinterpret_cast<const Scalar4i&>(v);
+}
+
+template <int i>
+inline Simd4iFactory<detail::IntType<i> >::operator Scalar4i() const
+{
+ return Scalar4i(i, i, i, i);
+}
+
+template <>
+inline Simd4iFactory<const int*>::operator Scalar4i() const
+{
+ return Scalar4i(v[0], v[1], v[2], v[3]);
+}
+
+template <>
+inline Simd4iFactory<detail::AlignedPointer<int> >::operator Scalar4i() const
+{
+ return Scalar4i(v.ptr[0], v.ptr[1], v.ptr[2], v.ptr[3]);
+}
+
+template <>
+inline Simd4iFactory<detail::OffsetPointer<int> >::operator Scalar4i() const
+{
+ const int* ptr = reinterpret_cast<const int*>(reinterpret_cast<const char*>(v.ptr) + v.offset);
+ return Scalar4i(ptr[0], ptr[1], ptr[2], ptr[3]);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// operator implementations
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+namespace simdi
+{
+
+inline Scalar4i operator==(const Scalar4i& v0, const Scalar4i& v1)
+{
+ return Scalar4i(v0.i4[0] == v1.i4[0], v0.i4[1] == v1.i4[1], v0.i4[2] == v1.i4[2], v0.i4[3] == v1.i4[3]);
+}
+
+inline Scalar4i operator<(const Scalar4i& v0, const Scalar4i& v1)
+{
+ return Scalar4i(v0.i4[0] < v1.i4[0], v0.i4[1] < v1.i4[1], v0.i4[2] < v1.i4[2], v0.i4[3] < v1.i4[3]);
+}
+
+inline Scalar4i operator>(const Scalar4i& v0, const Scalar4i& v1)
+{
+ return Scalar4i(v0.i4[0] > v1.i4[0], v0.i4[1] > v1.i4[1], v0.i4[2] > v1.i4[2], v0.i4[3] > v1.i4[3]);
+}
+
+inline Scalar4i operator+(const Scalar4i& v0, const Scalar4i& v1)
+{
+ return Scalar4i(v0.i4[0] + v1.i4[0], v0.i4[1] + v1.i4[1], v0.i4[2] + v1.i4[2], v0.i4[3] + v1.i4[3]);
+}
+
+inline Scalar4i operator-(const Scalar4i& v)
+{
+ return Scalar4i(-v.i4[0], -v.i4[1], -v.i4[2], -v.i4[3]);
+}
+
+inline Scalar4i operator-(const Scalar4i& v0, const Scalar4i& v1)
+{
+ return Scalar4i(v0.i4[0] - v1.i4[0], v0.i4[1] - v1.i4[1], v0.i4[2] - v1.i4[2], v0.i4[3] - v1.i4[3]);
+}
+
+} // namespace simd
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// function implementations
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+inline Scalar4i simd4i(const Scalar4f& v)
+{
+ return v;
+}
+
+namespace simdi
+{
+
+inline int (&array(Scalar4i& v))[4]
+{
+ return v.i4;
+}
+
+inline const int (&array(const Scalar4i& v))[4]
+{
+ return v.i4;
+}
+
+} // namespace simdi
+
+inline void store(int* ptr, const Scalar4i& v)
+{
+ ptr[0] = v.i4[0];
+ ptr[1] = v.i4[1];
+ ptr[2] = v.i4[2];
+ ptr[3] = v.i4[3];
+}
+
+inline void storeAligned(int* ptr, const Scalar4i& v)
+{
+ store(ptr, v);
+}
+
+inline void storeAligned(int* ptr, unsigned int offset, const Scalar4i& v)
+{
+ store(reinterpret_cast<int*>(reinterpret_cast<char*>(ptr) + offset), v);
+}
+
+namespace simdi
+{
+
+inline int allEqual(const Scalar4i& v0, const Scalar4i& v1)
+{
+ return v0.i4[0] == v1.i4[0] && v0.i4[1] == v1.i4[1] && v0.i4[2] == v1.i4[2] && v0.i4[3] == v1.i4[3];
+}
+
+inline int allEqual(const Scalar4i& v0, const Scalar4i& v1, Scalar4i& outMask)
+{
+ bool b0 = v0.i4[0] == v1.i4[0], b1 = v0.i4[1] == v1.i4[1], b2 = v0.i4[2] == v1.i4[2], b3 = v0.i4[3] == v1.i4[3];
+ outMask = Scalar4f(b0, b1, b2, b3);
+ return b0 && b1 && b2 && b3;
+}
+
+inline int anyEqual(const Scalar4i& v0, const Scalar4i& v1)
+{
+ return v0.i4[0] == v1.i4[0] || v0.i4[1] == v1.i4[1] || v0.i4[2] == v1.i4[2] || v0.i4[3] == v1.i4[3];
+}
+
+inline int anyEqual(const Scalar4i& v0, const Scalar4i& v1, Scalar4i& outMask)
+{
+ bool b0 = v0.i4[0] == v1.i4[0], b1 = v0.i4[1] == v1.i4[1], b2 = v0.i4[2] == v1.i4[2], b3 = v0.i4[3] == v1.i4[3];
+ outMask = Scalar4f(b0, b1, b2, b3);
+ return b0 || b1 || b2 || b3;
+}
+
+inline int allGreater(const Scalar4i& v0, const Scalar4i& v1)
+{
+ return v0.i4[0] > v1.i4[0] && v0.i4[1] > v1.i4[1] && v0.i4[2] > v1.i4[2] && v0.i4[3] > v1.i4[3];
+}
+
+inline int allGreater(const Scalar4i& v0, const Scalar4i& v1, Scalar4i& outMask)
+{
+ bool b0 = v0.i4[0] > v1.i4[0], b1 = v0.i4[1] > v1.i4[1], b2 = v0.i4[2] > v1.i4[2], b3 = v0.i4[3] > v1.i4[3];
+ outMask = Scalar4f(b0, b1, b2, b3);
+ return b0 && b1 && b2 && b3;
+}
+
+inline int anyGreater(const Scalar4i& v0, const Scalar4i& v1)
+{
+ return v0.i4[0] > v1.i4[0] || v0.i4[1] > v1.i4[1] || v0.i4[2] > v1.i4[2] || v0.i4[3] > v1.i4[3];
+}
+
+inline int anyGreater(const Scalar4i& v0, const Scalar4i& v1, Scalar4i& outMask)
+{
+ bool b0 = v0.i4[0] > v1.i4[0], b1 = v0.i4[1] > v1.i4[1], b2 = v0.i4[2] > v1.i4[2], b3 = v0.i4[3] > v1.i4[3];
+ outMask = Scalar4f(b0, b1, b2, b3);
+ return b0 || b1 || b2 || b3;
+}
+
+} // namespace simd
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/scalar/SimdTypes.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/scalar/SimdTypes.h
new file mode 100644
index 00000000..a287766c
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/scalar/SimdTypes.h
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#ifdef PX_WIIU
+#pragma ghs nowarning 193 // warning #193-D: zero used for undefined preprocessing identifier
+#endif
+
+#include <algorithm>
+
+#ifdef PX_WIIU
+#pragma ghs endnowarning
+#endif
+
+union Scalar4f
+{
+ Scalar4f()
+ {
+ }
+
+ Scalar4f(float x, float y, float z, float w)
+ {
+ f4[0] = x;
+ f4[1] = y;
+ f4[2] = z;
+ f4[3] = w;
+ }
+
+ Scalar4f(int32_t x, int32_t y, int32_t z, int32_t w)
+ {
+ i4[0] = x;
+ i4[1] = y;
+ i4[2] = z;
+ i4[3] = w;
+ }
+
+ Scalar4f(uint32_t x, uint32_t y, uint32_t z, uint32_t w)
+ {
+ u4[0] = x;
+ u4[1] = y;
+ u4[2] = z;
+ u4[3] = w;
+ }
+
+ Scalar4f(bool x, bool y, bool z, bool w)
+ {
+ u4[0] = ~(uint32_t(x) - 1);
+ u4[1] = ~(uint32_t(y) - 1);
+ u4[2] = ~(uint32_t(z) - 1);
+ u4[3] = ~(uint32_t(w) - 1);
+ }
+
+ Scalar4f(const Scalar4f& other)
+ {
+ u4[0] = other.u4[0];
+ u4[1] = other.u4[1];
+ u4[2] = other.u4[2];
+ u4[3] = other.u4[3];
+ }
+
+ Scalar4f& operator=(const Scalar4f& other)
+ {
+ u4[0] = other.u4[0];
+ u4[1] = other.u4[1];
+ u4[2] = other.u4[2];
+ u4[3] = other.u4[3];
+ return *this;
+ }
+
+ float f4[4];
+ int32_t i4[4];
+ uint32_t u4[4];
+};
+
+typedef Scalar4f Scalar4i;
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/scalar/SwCollisionHelpers.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/scalar/SwCollisionHelpers.h
new file mode 100644
index 00000000..33b35f72
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/scalar/SwCollisionHelpers.h
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+namespace nvidia
+{
+namespace cloth
+{
+
+#if !NVMATH_SIMD
+uint32_t findBitSet(uint32_t mask)
+{
+ uint32_t result = 0;
+ while(mask >>= 1)
+ ++result;
+ return result;
+}
+#endif
+
+inline Scalar4i intFloor(const Scalar4f& v)
+{
+ return Scalar4i(int(floor(v.f4[0])), int(floor(v.f4[1])), int(floor(v.f4[2])), int(floor(v.f4[3])));
+}
+
+inline Scalar4i horizontalOr(Scalar4i mask)
+{
+ return simd4i(mask.i4[0] | mask.i4[1] | mask.i4[2] | mask.i4[3]);
+}
+
+template <>
+struct Gather<Scalar4i>
+{
+ inline Gather(const Scalar4i& index);
+ inline Scalar4i operator()(const Scalar4i*) const;
+
+ Scalar4i mIndex;
+ Scalar4i mOutOfRange;
+};
+
+Gather<Scalar4i>::Gather(const Scalar4i& index)
+{
+ uint32_t mask = physx::cloth::SwCollision<Scalar4i>::sGridSize - 1;
+
+ mIndex.u4[0] = index.u4[0] & mask;
+ mIndex.u4[1] = index.u4[1] & mask;
+ mIndex.u4[2] = index.u4[2] & mask;
+ mIndex.u4[3] = index.u4[3] & mask;
+
+ mOutOfRange.u4[0] = index.u4[0] & ~mask ? 0 : -1;
+ mOutOfRange.u4[1] = index.u4[1] & ~mask ? 0 : -1;
+ mOutOfRange.u4[2] = index.u4[2] & ~mask ? 0 : -1;
+ mOutOfRange.u4[3] = index.u4[3] & ~mask ? 0 : -1;
+}
+
+Scalar4i Gather<Scalar4i>::operator()(const Scalar4i* ptr) const
+{
+ const int32_t* base = ptr->i4;
+ const int32_t* index = mIndex.i4;
+ const int32_t* mask = mOutOfRange.i4;
+ return Scalar4i(base[index[0]] & mask[0], base[index[1]] & mask[1], base[index[2]] & mask[2],
+ base[index[3]] & mask[3]);
+}
+
+} // namespace cloth
+} // namespace physx
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/sse2/Simd4f.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/sse2/Simd4f.h
new file mode 100644
index 00000000..3f04750f
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/sse2/Simd4f.h
@@ -0,0 +1,411 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// factory implementation
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+template <>
+inline Simd4fFactory<const float&>::operator Simd4f() const
+{
+ return _mm_set1_ps(v);
+}
+
+inline Simd4fFactory<detail::FourTuple>::operator Simd4f() const
+{
+ return reinterpret_cast<const Simd4f&>(v);
+}
+
+template <>
+inline Simd4fFactory<detail::IntType<0> >::operator Simd4f() const
+{
+ return _mm_setzero_ps();
+}
+
+template <>
+inline Simd4fFactory<detail::IntType<1> >::operator Simd4f() const
+{
+ return _mm_set1_ps(1.0f);
+}
+
+template <>
+inline Simd4fFactory<detail::IntType<int(0x80000000)> >::operator Simd4f() const
+{
+ return _mm_castsi128_ps(_mm_set1_epi32(0x80000000));
+}
+
+template <>
+inline Simd4fFactory<detail::IntType<int(0xffffffff)> >::operator Simd4f() const
+{
+ return _mm_castsi128_ps(_mm_set1_epi32(-1));
+}
+
+template <>
+inline Simd4fFactory<const float*>::operator Simd4f() const
+{
+ return _mm_loadu_ps(v);
+}
+
+template <>
+inline Simd4fFactory<detail::AlignedPointer<float> >::operator Simd4f() const
+{
+ return _mm_load_ps(v.ptr);
+}
+
+template <>
+inline Simd4fFactory<detail::OffsetPointer<float> >::operator Simd4f() const
+{
+ return _mm_load_ps(reinterpret_cast<const float*>(reinterpret_cast<const char*>(v.ptr) + v.offset));
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// expression template
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+template <>
+inline ComplementExpr<Simd4f>::operator Simd4f() const
+{
+ return _mm_andnot_ps(v, _mm_castsi128_ps(_mm_set1_epi32(-1)));
+}
+
+Simd4f operator&(const ComplementExpr<Simd4f>& complement, const Simd4f& v)
+{
+ return _mm_andnot_ps(complement.v, v);
+}
+
+Simd4f operator&(const Simd4f& v, const ComplementExpr<Simd4f>& complement)
+{
+ return _mm_andnot_ps(complement.v, v);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// operator implementations
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+Simd4f operator==(const Simd4f& v0, const Simd4f& v1)
+{
+ return _mm_cmpeq_ps(v0, v1);
+}
+
+Simd4f operator<(const Simd4f& v0, const Simd4f& v1)
+{
+ return _mm_cmplt_ps(v0, v1);
+}
+
+Simd4f operator<=(const Simd4f& v0, const Simd4f& v1)
+{
+ return _mm_cmple_ps(v0, v1);
+}
+
+Simd4f operator>(const Simd4f& v0, const Simd4f& v1)
+{
+ return _mm_cmpgt_ps(v0, v1);
+}
+
+Simd4f operator>=(const Simd4f& v0, const Simd4f& v1)
+{
+ return _mm_cmpge_ps(v0, v1);
+}
+
+ComplementExpr<Simd4f> operator~(const Simd4f& v)
+{
+ return ComplementExpr<Simd4f>(v);
+}
+
+Simd4f operator&(const Simd4f& v0, const Simd4f& v1)
+{
+ return _mm_and_ps(v0, v1);
+}
+
+Simd4f operator|(const Simd4f& v0, const Simd4f& v1)
+{
+ return _mm_or_ps(v0, v1);
+}
+
+Simd4f operator^(const Simd4f& v0, const Simd4f& v1)
+{
+ return _mm_xor_ps(v0, v1);
+}
+
+Simd4f operator<<(const Simd4f& v, int shift)
+{
+ return _mm_castsi128_ps(_mm_slli_epi32(_mm_castps_si128(v), shift));
+}
+
+Simd4f operator>>(const Simd4f& v, int shift)
+{
+ return _mm_castsi128_ps(_mm_srli_epi32(_mm_castps_si128(v), shift));
+}
+
+Simd4f operator+(const Simd4f& v)
+{
+ return v;
+}
+
+Simd4f operator+(const Simd4f& v0, const Simd4f& v1)
+{
+ return _mm_add_ps(v0, v1);
+}
+
+Simd4f operator-(const Simd4f& v)
+{
+ return _mm_sub_ps(_mm_setzero_ps(), v);
+}
+
+Simd4f operator-(const Simd4f& v0, const Simd4f& v1)
+{
+ return _mm_sub_ps(v0, v1);
+}
+
+Simd4f operator*(const Simd4f& v0, const Simd4f& v1)
+{
+ return _mm_mul_ps(v0, v1);
+}
+
+Simd4f operator/(const Simd4f& v0, const Simd4f& v1)
+{
+ return _mm_div_ps(v0, v1);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// function implementations
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+Simd4f simd4f(const Simd4i& v)
+{
+ return _mm_castsi128_ps(v);
+}
+
+float (&array(Simd4f& v))[4]
+{
+ return reinterpret_cast<float(&)[4]>(v);
+}
+
+const float (&array(const Simd4f& v))[4]
+{
+ return reinterpret_cast<const float(&)[4]>(v);
+}
+
+void store(float* ptr, Simd4f const& v)
+{
+ _mm_storeu_ps(ptr, v);
+}
+
+void storeAligned(float* ptr, Simd4f const& v)
+{
+ _mm_store_ps(ptr, v);
+}
+
+void storeAligned(float* ptr, unsigned int offset, Simd4f const& v)
+{
+ _mm_store_ps(reinterpret_cast<float*>(reinterpret_cast<char*>(ptr) + offset), v);
+}
+
+template <size_t i>
+Simd4f splat(Simd4f const& v)
+{
+ return _mm_shuffle_ps(v, v, _MM_SHUFFLE(i, i, i, i));
+}
+
+Simd4f select(Simd4f const& mask, Simd4f const& v0, Simd4f const& v1)
+{
+ return _mm_xor_ps(v1, _mm_and_ps(mask, _mm_xor_ps(v1, v0)));
+}
+
+Simd4f abs(const Simd4f& v)
+{
+ return _mm_andnot_ps(_mm_castsi128_ps(_mm_set1_epi32(0x80000000)), v);
+}
+
+Simd4f floor(const Simd4f& v)
+{
+ // SSE 4.1: return _mm_floor_ps(v);
+ Simd4i i = _mm_cvttps_epi32(v);
+ return _mm_cvtepi32_ps(_mm_sub_epi32(i, _mm_srli_epi32(i, 31)));
+}
+
+Simd4f max(const Simd4f& v0, const Simd4f& v1)
+{
+ return _mm_max_ps(v0, v1);
+}
+
+Simd4f min(const Simd4f& v0, const Simd4f& v1)
+{
+ return _mm_min_ps(v0, v1);
+}
+
+Simd4f recip(const Simd4f& v)
+{
+ return _mm_rcp_ps(v);
+}
+
+template <int n>
+Simd4f recipT(const Simd4f& v)
+{
+ Simd4f two = simd4f(2.0f);
+ Simd4f recipV = recip(v);
+ for(int i = 0; i < n; ++i)
+ recipV = recipV * (two - v * recipV);
+ return recipV;
+}
+
+Simd4f sqrt(const Simd4f& v)
+{
+ return _mm_sqrt_ps(v);
+}
+
+Simd4f rsqrt(const Simd4f& v)
+{
+ return _mm_rsqrt_ps(v);
+}
+
+template <int n>
+Simd4f rsqrtT(const Simd4f& v)
+{
+ Simd4f halfV = v * simd4f(0.5f);
+ Simd4f threeHalf = simd4f(1.5f);
+ Simd4f rsqrtV = rsqrt(v);
+ for(int i = 0; i < n; ++i)
+ rsqrtV = rsqrtV * (threeHalf - halfV * rsqrtV * rsqrtV);
+ return rsqrtV;
+}
+
+Simd4f exp2(const Simd4f& v)
+{
+ // http://www.netlib.org/cephes/
+
+ Simd4f limit = simd4f(127.4999f);
+ Simd4f x = min(max(-limit, v), limit);
+
+ // separate into integer and fractional part
+
+ Simd4f fx = x + simd4f(0.5f);
+ Simd4i ix = _mm_sub_epi32(_mm_cvttps_epi32(fx), _mm_srli_epi32(_mm_castps_si128(fx), 31));
+ fx = x - Simd4f(_mm_cvtepi32_ps(ix));
+
+ // exp2(fx) ~ 1 + 2*P(fx) / (Q(fx) - P(fx))
+
+ Simd4f fx2 = fx * fx;
+
+ Simd4f px = fx * (simd4f(1.51390680115615096133e+3f) +
+ fx2 * (simd4f(2.02020656693165307700e+1f) + fx2 * simd4f(2.30933477057345225087e-2f)));
+ Simd4f qx = simd4f(4.36821166879210612817e+3f) + fx2 * (simd4f(2.33184211722314911771e+2f) + fx2);
+
+ Simd4f exp2fx = px * recip(qx - px);
+ exp2fx = simd4f(_1) + exp2fx + exp2fx;
+
+ // exp2(ix)
+
+ Simd4f exp2ix = _mm_castsi128_ps(_mm_slli_epi32(_mm_add_epi32(ix, _mm_set1_epi32(0x7f)), 23));
+
+ return exp2fx * exp2ix;
+}
+
+Simd4f log2(const Simd4f& v)
+{
+ // todo: fast approximate implementation like exp2
+ Simd4f scale = simd4f(1.44269504088896341f); // 1/ln(2)
+ const float* ptr = array(v);
+ return simd4f(::logf(ptr[0]), ::logf(ptr[1]), ::logf(ptr[2]), ::logf(ptr[3])) * scale;
+}
+
+Simd4f dot3(const Simd4f& v0, const Simd4f& v1)
+{
+ Simd4f tmp = v0 * v1;
+ return splat<0>(tmp) + splat<1>(tmp) + splat<2>(tmp);
+}
+
+Simd4f cross3(const Simd4f& v0, const Simd4f& v1)
+{
+ Simd4f t0 = _mm_shuffle_ps(v0, v0, 0xc9); // w z y x -> w x z y
+ Simd4f t1 = _mm_shuffle_ps(v1, v1, 0xc9);
+ Simd4f tmp = v0 * t1 - t0 * v1;
+ return _mm_shuffle_ps(tmp, tmp, 0xc9);
+}
+
+void transpose(Simd4f& x, Simd4f& y, Simd4f& z, Simd4f& w)
+{
+ _MM_TRANSPOSE4_PS(x, y, z, w);
+}
+
+int allEqual(const Simd4f& v0, const Simd4f& v1)
+{
+ return allTrue(v0 == v1);
+}
+
+int allEqual(const Simd4f& v0, const Simd4f& v1, Simd4f& outMask)
+{
+ return allTrue(outMask = v0 == v1);
+}
+
+int anyEqual(const Simd4f& v0, const Simd4f& v1)
+{
+ return anyTrue(v0 == v1);
+}
+
+int anyEqual(const Simd4f& v0, const Simd4f& v1, Simd4f& outMask)
+{
+ return anyTrue(outMask = v0 == v1);
+}
+
+int allGreater(const Simd4f& v0, const Simd4f& v1)
+{
+ return allTrue(v0 > v1);
+}
+
+int allGreater(const Simd4f& v0, const Simd4f& v1, Simd4f& outMask)
+{
+ return allTrue(outMask = v0 > v1);
+}
+
+int anyGreater(const Simd4f& v0, const Simd4f& v1)
+{
+ return anyTrue(v0 > v1);
+}
+
+int anyGreater(const Simd4f& v0, const Simd4f& v1, Simd4f& outMask)
+{
+ return anyTrue(outMask = v0 > v1);
+}
+
+int allGreaterEqual(const Simd4f& v0, const Simd4f& v1)
+{
+ return allTrue(v0 >= v1);
+}
+
+int allGreaterEqual(const Simd4f& v0, const Simd4f& v1, Simd4f& outMask)
+{
+ return allTrue(outMask = v0 >= v1);
+}
+
+int anyGreaterEqual(const Simd4f& v0, const Simd4f& v1)
+{
+ return anyTrue(v0 >= v1);
+}
+
+int anyGreaterEqual(const Simd4f& v0, const Simd4f& v1, Simd4f& outMask)
+{
+ return anyTrue(outMask = v0 >= v1);
+}
+
+int allTrue(const Simd4f& v)
+{
+ return _mm_movemask_ps(v) == 0xf;
+}
+
+int anyTrue(const Simd4f& v)
+{
+ return _mm_movemask_ps(v);
+}
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/sse2/Simd4i.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/sse2/Simd4i.h
new file mode 100644
index 00000000..d4a70a02
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/sse2/Simd4i.h
@@ -0,0 +1,238 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// factory implementation
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+template <>
+inline Simd4iFactory<const int&>::operator Simd4i() const
+{
+ return _mm_set1_epi32(v);
+}
+
+inline Simd4iFactory<detail::FourTuple>::operator Simd4i() const
+{
+ return reinterpret_cast<const Simd4i&>(v);
+}
+
+template <int i>
+inline Simd4iFactory<detail::IntType<i> >::operator Simd4i() const
+{
+ return _mm_set1_epi32(i);
+}
+
+template <>
+inline Simd4iFactory<detail::IntType<0> >::operator Simd4i() const
+{
+ return _mm_setzero_si128();
+}
+
+template <>
+inline Simd4iFactory<const int*>::operator Simd4i() const
+{
+ return _mm_loadu_si128(reinterpret_cast<const __m128i*>(v));
+}
+
+template <>
+inline Simd4iFactory<detail::AlignedPointer<int> >::operator Simd4i() const
+{
+ return _mm_load_si128(reinterpret_cast<const __m128i*>(v.ptr));
+}
+
+template <>
+inline Simd4iFactory<detail::OffsetPointer<int> >::operator Simd4i() const
+{
+ return _mm_load_si128(reinterpret_cast<const __m128i*>(reinterpret_cast<const char*>(v.ptr) + v.offset));
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// expression template
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+template <>
+inline ComplementExpr<Simd4i>::operator Simd4i() const
+{
+ return _mm_andnot_si128(v, _mm_set1_epi32(0xffffffff));
+}
+
+Simd4i operator&(const ComplementExpr<Simd4i>& complement, const Simd4i& v)
+{
+ return _mm_andnot_si128(complement.v, v);
+}
+
+Simd4i operator&(const Simd4i& v, const ComplementExpr<Simd4i>& complement)
+{
+ return _mm_andnot_si128(complement.v, v);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// operator implementations
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+Simd4i simdi::operator==(const Simd4i& v0, const Simd4i& v1)
+{
+ return _mm_cmpeq_epi32(v0, v1);
+}
+
+Simd4i simdi::operator<(const Simd4i& v0, const Simd4i& v1)
+{
+ return _mm_cmplt_epi32(v0, v1);
+}
+
+Simd4i simdi::operator>(const Simd4i& v0, const Simd4i& v1)
+{
+ return _mm_cmpgt_epi32(v0, v1);
+}
+
+ComplementExpr<Simd4i> operator~(const Simd4i& v)
+{
+ return ComplementExpr<Simd4i>(v);
+}
+
+Simd4i operator&(const Simd4i& v0, const Simd4i& v1)
+{
+ return _mm_and_si128(v0, v1);
+}
+
+Simd4i operator|(const Simd4i& v0, const Simd4i& v1)
+{
+ return _mm_or_si128(v0, v1);
+}
+
+Simd4i operator^(const Simd4i& v0, const Simd4i& v1)
+{
+ return _mm_xor_si128(v0, v1);
+}
+
+Simd4i operator<<(const Simd4i& v, int shift)
+{
+ return _mm_slli_epi32(v, shift);
+}
+
+Simd4i operator>>(const Simd4i& v, int shift)
+{
+ return _mm_srli_epi32(v, shift);
+}
+
+Simd4i simdi::operator+(const Simd4i& v0, const Simd4i& v1)
+{
+ return _mm_add_epi32(v0, v1);
+}
+
+Simd4i simdi::operator-(const Simd4i& v)
+{
+ return _mm_sub_epi32(_mm_setzero_si128(), v);
+}
+
+Simd4i simdi::operator-(const Simd4i& v0, const Simd4i& v1)
+{
+ return _mm_sub_epi32(v0, v1);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// function implementations
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+Simd4i simd4i(const Simd4f& v)
+{
+ return _mm_castps_si128(v);
+}
+
+int (&simdi::array(Simd4i& v))[4]
+{
+ return reinterpret_cast<int(&)[4]>(v);
+}
+
+const int (&simdi::array(const Simd4i& v))[4]
+{
+ return reinterpret_cast<const int(&)[4]>(v);
+}
+
+void store(int* ptr, const Simd4i& v)
+{
+ _mm_storeu_si128(reinterpret_cast<__m128i*>(ptr), v);
+}
+
+void storeAligned(int* ptr, const Simd4i& v)
+{
+ _mm_store_si128(reinterpret_cast<__m128i*>(ptr), v);
+}
+
+void storeAligned(int* ptr, unsigned int offset, const Simd4i& v)
+{
+ _mm_store_si128(reinterpret_cast<__m128i*>(reinterpret_cast<char*>(ptr) + offset), v);
+}
+
+template <size_t i>
+Simd4i splat(const Simd4i& v)
+{
+ return _mm_shuffle_epi32(v, _MM_SHUFFLE(i, i, i, i));
+}
+
+Simd4i select(const Simd4i& mask, const Simd4i& v0, const Simd4i& v1)
+{
+ return _mm_xor_si128(v1, _mm_and_si128(mask, _mm_xor_si128(v1, v0)));
+}
+
+int simdi::allEqual(const Simd4i& v0, const Simd4i& v1)
+{
+ return allTrue(simdi::operator==(v0, v1));
+}
+
+int simdi::allEqual(const Simd4i& v0, const Simd4i& v1, Simd4i& outMask)
+{
+ return allTrue(outMask = simdi::operator==(v0, v1));
+}
+
+int simdi::anyEqual(const Simd4i& v0, const Simd4i& v1)
+{
+ return anyTrue(simdi::operator==(v0, v1));
+}
+
+int simdi::anyEqual(const Simd4i& v0, const Simd4i& v1, Simd4i& outMask)
+{
+ return anyTrue(outMask = simdi::operator==(v0, v1));
+}
+
+int simdi::allGreater(const Simd4i& v0, const Simd4i& v1)
+{
+ return allTrue(simdi::operator>(v0, v1));
+}
+
+int simdi::allGreater(const Simd4i& v0, const Simd4i& v1, Simd4i& outMask)
+{
+ return allTrue(outMask = simdi::operator>(v0, v1));
+}
+
+int simdi::anyGreater(const Simd4i& v0, const Simd4i& v1)
+{
+ return anyTrue(simdi::operator>(v0, v1));
+}
+
+int simdi::anyGreater(const Simd4i& v0, const Simd4i& v1, Simd4i& outMask)
+{
+ return anyTrue(outMask = simdi::operator>(v0, v1));
+}
+
+int allTrue(const Simd4i& v)
+{
+ return _mm_movemask_ps(_mm_castsi128_ps(v)) == 0xf;
+}
+
+int anyTrue(const Simd4i& v)
+{
+ return _mm_movemask_ps(_mm_castsi128_ps(v));
+}
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/sse2/SimdTypes.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/sse2/SimdTypes.h
new file mode 100644
index 00000000..e54edde7
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/sse2/SimdTypes.h
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+// SSE + SSE2 (don't include intrin.h!)
+#include <emmintrin.h>
+
+#if defined(_MSC_VER)
+
+typedef __m128 Simd4f;
+typedef __m128i Simd4i;
+
+#else
+
+struct Simd4f
+{
+ Simd4f()
+ {
+ }
+ Simd4f(__m128 x) : m128(x)
+ {
+ }
+
+ operator __m128&()
+ {
+ return m128;
+ }
+ operator const __m128&() const
+ {
+ return m128;
+ }
+
+ private:
+ __m128 m128;
+};
+
+struct Simd4i
+{
+ Simd4i()
+ {
+ }
+ Simd4i(__m128i x) : m128i(x)
+ {
+ }
+
+ operator __m128i&()
+ {
+ return m128i;
+ }
+ operator const __m128i&() const
+ {
+ return m128i;
+ }
+
+ private:
+ __m128i m128i;
+};
+
+#endif
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/sse2/SwCollisionHelpers.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/sse2/SwCollisionHelpers.h
new file mode 100644
index 00000000..0750fcf5
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/sse2/SwCollisionHelpers.h
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#ifdef PX_GCC_FAMILY
+#include <xmmintrin.h> // _BitScanForward
+#else
+#pragma warning(push)
+#pragma warning(disable : 4668) //'symbol' is not defined as a preprocessor macro, replacing with '0' for 'directives'
+#pragma warning(disable : 4987) // nonstandard extension used: 'throw (...)'
+#include <intrin.h> // _BitScanForward
+#pragma warning(pop)
+#endif
+
+namespace nvidia
+{
+namespace cloth
+{
+
+uint32_t findBitSet(uint32_t mask)
+{
+#if defined(_MSC_VER)
+ unsigned long result;
+ _BitScanForward(&result, unsigned long(mask));
+ return result;
+#else
+ return __builtin_ffs(mask) - 1;
+#endif
+}
+
+Simd4i intFloor(const Simd4f& v)
+{
+ Simd4i i = _mm_cvttps_epi32(v);
+ return simdi::operator-(i, _mm_srli_epi32(simd4i(v), 31));
+}
+
+Simd4i horizontalOr(Simd4i mask)
+{
+ Simd4i tmp = mask | _mm_shuffle_epi32(mask, 0xb1); // w z y x -> z w x y
+ return tmp | _mm_shuffle_epi32(tmp, 0x4e); // w z y x -> y x w z
+}
+
+Gather<Simd4i>::Gather(const Simd4i& index)
+{
+ mSelectQ = _mm_srai_epi32(index << 29, 31);
+ mSelectD = _mm_srai_epi32(index << 30, 31);
+ mSelectW = _mm_srai_epi32(index << 31, 31);
+ mOutOfRange = simdi::operator>(index ^ sIntSignBit, sSignedMask);
+}
+
+Simd4i Gather<Simd4i>::operator()(const Simd4i* ptr) const
+{
+ // more efficient with _mm_shuffle_epi8 (SSSE3)
+ Simd4i lo = ptr[0], hi = ptr[1];
+ Simd4i m01 = select(mSelectW, splat<1>(lo), splat<0>(lo));
+ Simd4i m23 = select(mSelectW, splat<3>(lo), splat<2>(lo));
+ Simd4i m45 = select(mSelectW, splat<1>(hi), splat<0>(hi));
+ Simd4i m67 = select(mSelectW, splat<3>(hi), splat<2>(hi));
+ Simd4i m0123 = select(mSelectD, m23, m01);
+ Simd4i m4567 = select(mSelectD, m67, m45);
+ return select(mSelectQ, m4567, m0123) & ~mOutOfRange;
+}
+
+} // namespace cloth
+} // namespace nvidia
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/sse2/SwSolveConstraints.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/sse2/SwSolveConstraints.h
new file mode 100644
index 00000000..382812bb
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/sse2/SwSolveConstraints.h
@@ -0,0 +1,379 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma warning(push)
+#pragma warning(disable:4127) // Disable the nag warning 'conditional expression is constant'
+
+template <bool useMultiplier>
+void solveConstraints(float* __restrict posIt, const float* __restrict rIt, const float* __restrict rEnd,
+ const uint16_t* __restrict iIt, __m128 stiffness)
+{
+ __m128 sOne = _mm_set1_ps(1.0f);
+
+ __m128 stretchLimit, compressionLimit, multiplier;
+ if(useMultiplier)
+ {
+ stretchLimit = _mm_shuffle_ps(stiffness, stiffness, 0xff);
+ compressionLimit = _mm_shuffle_ps(stiffness, stiffness, 0xaa);
+ multiplier = _mm_shuffle_ps(stiffness, stiffness, 0x55);
+ }
+ stiffness = _mm_shuffle_ps(stiffness, stiffness, 0x00);
+
+ for(; rIt != rEnd; rIt += 4, iIt += 8)
+ {
+ float* p0i = posIt + iIt[0] * 4;
+ float* p0j = posIt + iIt[1] * 4;
+ float* p1i = posIt + iIt[2] * 4;
+ float* p1j = posIt + iIt[3] * 4;
+ float* p2i = posIt + iIt[4] * 4;
+ float* p2j = posIt + iIt[5] * 4;
+ float* p3i = posIt + iIt[6] * 4;
+ float* p3j = posIt + iIt[7] * 4;
+
+ __m128 v0i = _mm_load_ps(p0i);
+ __m128 v0j = _mm_load_ps(p0j);
+ __m128 v1i = _mm_load_ps(p1i);
+ __m128 v1j = _mm_load_ps(p1j);
+ __m128 v2i = _mm_load_ps(p2i);
+ __m128 v2j = _mm_load_ps(p2j);
+ __m128 v3i = _mm_load_ps(p3i);
+ __m128 v3j = _mm_load_ps(p3j);
+
+ __m128 h0ij = _mm_add_ps(v0j, _mm_mul_ps(v0i, sMinusOneXYZOneW));
+ __m128 h1ij = _mm_add_ps(v1j, _mm_mul_ps(v1i, sMinusOneXYZOneW));
+ __m128 h2ij = _mm_add_ps(v2j, _mm_mul_ps(v2i, sMinusOneXYZOneW));
+ __m128 h3ij = _mm_add_ps(v3j, _mm_mul_ps(v3i, sMinusOneXYZOneW));
+
+ __m128 a = _mm_unpacklo_ps(h0ij, h2ij);
+ __m128 b = _mm_unpackhi_ps(h0ij, h2ij);
+ __m128 c = _mm_unpacklo_ps(h1ij, h3ij);
+ __m128 d = _mm_unpackhi_ps(h1ij, h3ij);
+
+ __m128 hxij = _mm_unpacklo_ps(a, c);
+ __m128 hyij = _mm_unpackhi_ps(a, c);
+ __m128 hzij = _mm_unpacklo_ps(b, d);
+ __m128 vwij = _mm_unpackhi_ps(b, d);
+
+ __m128 rij = _mm_load_ps(rIt);
+ __m128 e2ij = _mm_add_ps(
+ sEpsilon, _mm_add_ps(_mm_mul_ps(hxij, hxij), _mm_add_ps(_mm_mul_ps(hyij, hyij), _mm_mul_ps(hzij, hzij))));
+ __m128 mask = _mm_cmpnle_ps(rij, sEpsilon);
+ __m128 erij = _mm_and_ps(_mm_sub_ps(sOne, _mm_mul_ps(rij, _mm_rsqrt_ps(e2ij))), mask);
+
+ if(useMultiplier)
+ {
+ erij = _mm_sub_ps(erij, _mm_mul_ps(multiplier, _mm_max_ps(compressionLimit, _mm_min_ps(erij, stretchLimit))));
+ }
+ __m128 exij = _mm_mul_ps(erij, _mm_mul_ps(stiffness, _mm_rcp_ps(_mm_add_ps(sEpsilon, vwij))));
+
+ __m128 exlo = _mm_and_ps(sMaskXY, exij);
+ __m128 exhi = _mm_andnot_ps(sMaskXY, exij);
+
+ __m128 f0ij = _mm_mul_ps(h0ij, _mm_shuffle_ps(exlo, exlo, 0xc0));
+ __m128 f1ij = _mm_mul_ps(h1ij, _mm_shuffle_ps(exlo, exlo, 0xd5));
+ __m128 f2ij = _mm_mul_ps(h2ij, _mm_shuffle_ps(exhi, exhi, 0x2a));
+ __m128 f3ij = _mm_mul_ps(h3ij, _mm_shuffle_ps(exhi, exhi, 0x3f));
+
+ __m128 u0i = _mm_add_ps(v0i, _mm_mul_ps(f0ij, _mm_shuffle_ps(v0i, v0i, 0xff)));
+ __m128 u0j = _mm_sub_ps(v0j, _mm_mul_ps(f0ij, _mm_shuffle_ps(v0j, v0j, 0xff)));
+ __m128 u1i = _mm_add_ps(v1i, _mm_mul_ps(f1ij, _mm_shuffle_ps(v1i, v1i, 0xff)));
+ __m128 u1j = _mm_sub_ps(v1j, _mm_mul_ps(f1ij, _mm_shuffle_ps(v1j, v1j, 0xff)));
+ __m128 u2i = _mm_add_ps(v2i, _mm_mul_ps(f2ij, _mm_shuffle_ps(v2i, v2i, 0xff)));
+ __m128 u2j = _mm_sub_ps(v2j, _mm_mul_ps(f2ij, _mm_shuffle_ps(v2j, v2j, 0xff)));
+ __m128 u3i = _mm_add_ps(v3i, _mm_mul_ps(f3ij, _mm_shuffle_ps(v3i, v3i, 0xff)));
+ __m128 u3j = _mm_sub_ps(v3j, _mm_mul_ps(f3ij, _mm_shuffle_ps(v3j, v3j, 0xff)));
+
+ _mm_store_ps(p0i, u0i);
+ _mm_store_ps(p0j, u0j);
+ _mm_store_ps(p1i, u1i);
+ _mm_store_ps(p1j, u1j);
+ _mm_store_ps(p2i, u2i);
+ _mm_store_ps(p2j, u2j);
+ _mm_store_ps(p3i, u3i);
+ _mm_store_ps(p3j, u3j);
+ }
+}
+
+#if PX_X86
+
+// clang-format:disable
+
+// asm blocks in static condition blocks don't get removed, specialize
+template <>
+void solveConstraints<false>(float* __restrict posIt, const float* __restrict rIt, const float* __restrict rEnd,
+ const uint16_t* __restrict iIt, __m128 stiffness)
+{
+ __m128 sOne = _mm_set1_ps(1.0f);
+ stiffness = _mm_shuffle_ps(stiffness, stiffness, 0x00);
+
+ __m128 htmp[4];
+ float* ptmp[8];
+
+ __asm
+ {
+ mov edx, rIt
+ mov esi, rEnd
+
+ cmp edx, esi
+ jae forEnd
+
+ mov eax, iIt
+ mov ecx, posIt
+
+forBegin:
+ movzx edi, WORD PTR [eax ] __asm shl edi, 4 __asm mov [ptmp ], edi __asm movaps xmm0, XMMWORD PTR [edi + ecx] /* v0i */
+ movzx edi, WORD PTR [eax+ 2] __asm shl edi, 4 __asm mov [ptmp+ 4], edi __asm movaps xmm2, XMMWORD PTR [edi + ecx] /* v0j */
+ movzx edi, WORD PTR [eax+ 4] __asm shl edi, 4 __asm mov [ptmp+ 8], edi __asm movaps xmm1, XMMWORD PTR [edi + ecx] /* v1i */
+ movzx edi, WORD PTR [eax+ 6] __asm shl edi, 4 __asm mov [ptmp+12], edi __asm movaps xmm3, XMMWORD PTR [edi + ecx] /* v1j */
+
+ movaps xmm7, sMinusOneXYZOneW
+ mulps xmm2, xmm7 __asm addps xmm0, xmm2 __asm movaps XMMWORD PTR [htmp ], xmm0 /* h0ij */
+ mulps xmm3, xmm7 __asm addps xmm1, xmm3 __asm movaps XMMWORD PTR [htmp+16], xmm1 /* h1ij */
+
+ movzx edi, WORD PTR [eax+ 8] __asm shl edi, 4 __asm mov [ptmp+16], edi __asm movaps xmm4, XMMWORD PTR [edi + ecx] /* v2i */
+ movzx edi, WORD PTR [eax+10] __asm shl edi, 4 __asm mov [ptmp+20], edi __asm movaps xmm2, XMMWORD PTR [edi + ecx] /* v2j */
+ movzx edi, WORD PTR [eax+12] __asm shl edi, 4 __asm mov [ptmp+24], edi __asm movaps xmm5, XMMWORD PTR [edi + ecx] /* v3i */
+ movzx edi, WORD PTR [eax+14] __asm shl edi, 4 __asm mov [ptmp+28], edi __asm movaps xmm3, XMMWORD PTR [edi + ecx] /* v3j */
+
+ mulps xmm2, xmm7 __asm addps xmm2, xmm4 __asm movaps XMMWORD PTR [htmp+32], xmm2 /* h2ij */
+ mulps xmm3, xmm7 __asm addps xmm3, xmm5 __asm movaps XMMWORD PTR [htmp+48], xmm3 /* h3ij */
+
+ movaps xmm4, xmm0
+ movaps xmm5, xmm1
+
+ unpcklps xmm0, xmm2 /* a */
+ unpckhps xmm4, xmm2 /* b */
+ unpcklps xmm1, xmm3 /* c */
+ unpckhps xmm5, xmm3 /* d */
+
+ movaps xmm2, xmm0
+ movaps xmm6, xmm4
+
+ unpcklps xmm0, xmm1 /* hxij */
+ unpckhps xmm2, xmm1 /* hyij */
+ unpcklps xmm4, xmm5 /* hzij */
+ unpckhps xmm6, xmm5 /* vwij */
+
+ movaps xmm7, sEpsilon
+ movaps xmm5, sOne
+ movaps xmm3, stiffness
+ movaps xmm1, XMMWORD PTR [edx] /* rij */
+
+ mulps xmm0, xmm0 __asm addps xmm0, xmm7 /* e2ij */
+ mulps xmm2, xmm2 __asm addps xmm0, xmm2
+ mulps xmm4, xmm4 __asm addps xmm0, xmm4
+
+ rsqrtps xmm0, xmm0 __asm mulps xmm0, xmm1 /* erij */
+ cmpnleps xmm1, xmm7 /* mask */
+ subps xmm5, xmm0 __asm andps xmm5, xmm1
+ addps xmm6, xmm7 __asm rcpps xmm6, xmm6
+
+ mulps xmm6, xmm3 __asm mulps xmm6, xmm5 /* exij */
+
+ movaps xmm7, sMaskXY
+ andps xmm7, xmm6 /* exlo */
+ xorps xmm6, xmm7 /* exhi */
+
+ movaps xmm0, XMMWORD PTR [htmp ] /* h0ij */
+ movaps xmm1, XMMWORD PTR [htmp+16] /* h1ij */
+ movaps xmm2, XMMWORD PTR [htmp+32] /* h2ij */
+ movaps xmm3, XMMWORD PTR [htmp+48] /* h3ij */
+
+ pshufd xmm5, xmm7, 0xc0 __asm mulps xmm0, xmm5 /* f0ij */
+ pshufd xmm7, xmm7, 0xd5 __asm mulps xmm1, xmm7 /* f1ij */
+ pshufd xmm4, xmm6, 0x2a __asm mulps xmm2, xmm4 /* f2ij */
+ pshufd xmm6, xmm6, 0x3f __asm mulps xmm3, xmm6 /* f3ij */
+
+ mov edi, [ptmp ] __asm movaps xmm4, XMMWORD PTR [edi + ecx] /* v0i */
+ pshufd xmm5, xmm4, 0xff __asm mulps xmm5, xmm0 __asm subps xmm4, xmm5 /* u0i */
+ movaps XMMWORD PTR [edi + ecx], xmm4
+
+ mov edi, [ptmp+ 4] __asm movaps xmm6, XMMWORD PTR [edi + ecx] /* v0j */
+ pshufd xmm7, xmm6, 0xff __asm mulps xmm7, xmm0 __asm addps xmm6, xmm7 /* u0j */
+ movaps XMMWORD PTR [edi + ecx], xmm6
+
+ mov edi, [ptmp+ 8] __asm movaps xmm4, XMMWORD PTR [edi + ecx] /* v1i */
+ pshufd xmm5, xmm4, 0xff __asm mulps xmm5, xmm1 __asm subps xmm4, xmm5 /* u1i */
+ movaps XMMWORD PTR [edi + ecx], xmm4
+
+ mov edi, [ptmp+12] __asm movaps xmm6, XMMWORD PTR [edi + ecx] /* v1j */
+ pshufd xmm7, xmm6, 0xff __asm mulps xmm7, xmm1 __asm addps xmm6, xmm7 /* u1j */
+ movaps XMMWORD PTR [edi + ecx], xmm6
+
+ mov edi, [ptmp+16] __asm movaps xmm4, XMMWORD PTR [edi + ecx] /* v2i */
+ pshufd xmm5, xmm4, 0xff __asm mulps xmm5, xmm2 __asm subps xmm4, xmm5 /* u2i */
+ movaps XMMWORD PTR [edi + ecx], xmm4
+
+ mov edi, [ptmp+20] __asm movaps xmm6, XMMWORD PTR [edi + ecx] /* v2j */
+ pshufd xmm7, xmm6, 0xff __asm mulps xmm7, xmm2 __asm addps xmm6, xmm7 /* u2j */
+ movaps XMMWORD PTR [edi + ecx], xmm6
+
+ mov edi, [ptmp+24] __asm movaps xmm4, XMMWORD PTR [edi + ecx] /* v3i */
+ pshufd xmm5, xmm4, 0xff __asm mulps xmm5, xmm3 __asm subps xmm4, xmm5 /* u3i */
+ movaps XMMWORD PTR [edi + ecx], xmm4
+
+ mov edi, [ptmp+28] __asm movaps xmm6, XMMWORD PTR [edi + ecx] /* v3j */
+ pshufd xmm7, xmm6, 0xff __asm mulps xmm7, xmm3 __asm addps xmm6, xmm7 /* u3j */
+ movaps XMMWORD PTR [edi + ecx], xmm6
+
+ add eax, 16
+ add edx, 16
+
+ cmp edx, esi
+ jb forBegin
+forEnd:
+ }
+}
+
+template <>
+void solveConstraints<true>(float* __restrict posIt, const float* __restrict rIt, const float* __restrict rEnd,
+ const uint16_t* __restrict iIt, __m128 stiffness)
+{
+ __m128 sOne = _mm_set1_ps(1.0f);
+ __m128 stretchLimit = _mm_shuffle_ps(stiffness, stiffness, 0xff);
+ __m128 compressionLimit = _mm_shuffle_ps(stiffness, stiffness, 0xaa);
+ __m128 multiplier = _mm_shuffle_ps(stiffness, stiffness, 0x55);
+ stiffness = _mm_shuffle_ps(stiffness, stiffness, 0x00);
+
+ __m128 htmp[4];
+ float* ptmp[8];
+
+ __asm
+ {
+ mov edx, rIt
+ mov esi, rEnd
+
+ cmp edx, esi
+ jae forEnd
+
+ mov eax, iIt
+ mov ecx, posIt
+
+forBegin:
+ movzx edi, WORD PTR [eax ] __asm shl edi, 4 __asm mov [ptmp ], edi __asm movaps xmm0, XMMWORD PTR [edi + ecx] /* v0i */
+ movzx edi, WORD PTR [eax+ 2] __asm shl edi, 4 __asm mov [ptmp+ 4], edi __asm movaps xmm2, XMMWORD PTR [edi + ecx] /* v0j */
+ movzx edi, WORD PTR [eax+ 4] __asm shl edi, 4 __asm mov [ptmp+ 8], edi __asm movaps xmm1, XMMWORD PTR [edi + ecx] /* v1i */
+ movzx edi, WORD PTR [eax+ 6] __asm shl edi, 4 __asm mov [ptmp+12], edi __asm movaps xmm3, XMMWORD PTR [edi + ecx] /* v1j */
+
+ movaps xmm7, sMinusOneXYZOneW
+ mulps xmm2, xmm7 __asm addps xmm0, xmm2 __asm movaps XMMWORD PTR [htmp ], xmm0 /* h0ij */
+ mulps xmm3, xmm7 __asm addps xmm1, xmm3 __asm movaps XMMWORD PTR [htmp+16], xmm1 /* h1ij */
+
+ movzx edi, WORD PTR [eax+ 8] __asm shl edi, 4 __asm mov [ptmp+16], edi __asm movaps xmm4, XMMWORD PTR [edi + ecx] /* v2i */
+ movzx edi, WORD PTR [eax+10] __asm shl edi, 4 __asm mov [ptmp+20], edi __asm movaps xmm2, XMMWORD PTR [edi + ecx] /* v2j */
+ movzx edi, WORD PTR [eax+12] __asm shl edi, 4 __asm mov [ptmp+24], edi __asm movaps xmm5, XMMWORD PTR [edi + ecx] /* v3i */
+ movzx edi, WORD PTR [eax+14] __asm shl edi, 4 __asm mov [ptmp+28], edi __asm movaps xmm3, XMMWORD PTR [edi + ecx] /* v3j */
+
+ mulps xmm2, xmm7 __asm addps xmm2, xmm4 __asm movaps XMMWORD PTR [htmp+32], xmm2 /* h2ij */
+ mulps xmm3, xmm7 __asm addps xmm3, xmm5 __asm movaps XMMWORD PTR [htmp+48], xmm3 /* h3ij */
+
+ movaps xmm4, xmm0
+ movaps xmm5, xmm1
+
+ unpcklps xmm0, xmm2 /* a */
+ unpckhps xmm4, xmm2 /* b */
+ unpcklps xmm1, xmm3 /* c */
+ unpckhps xmm5, xmm3 /* d */
+
+ movaps xmm2, xmm0
+ movaps xmm6, xmm4
+
+ unpcklps xmm0, xmm1 /* hxij */
+ unpckhps xmm2, xmm1 /* hyij */
+ unpcklps xmm4, xmm5 /* hzij */
+ unpckhps xmm6, xmm5 /* vwij */
+
+ movaps xmm7, sEpsilon
+ movaps xmm5, sOne
+ movaps xmm3, stiffness
+ movaps xmm1, XMMWORD PTR [edx] /* rij */
+
+ mulps xmm0, xmm0 __asm addps xmm0, xmm7 /* e2ij */
+ mulps xmm2, xmm2 __asm addps xmm0, xmm2
+ mulps xmm4, xmm4 __asm addps xmm0, xmm4
+
+ rsqrtps xmm0, xmm0 __asm mulps xmm0, xmm1 /* erij */
+ cmpnleps xmm1, xmm7 /* mask */
+ subps xmm5, xmm0 __asm andps xmm5, xmm1
+ addps xmm6, xmm7 __asm rcpps xmm6, xmm6
+
+ movaps xmm0, stretchLimit /* multiplier block */
+ movaps xmm1, compressionLimit
+ movaps xmm2, multiplier
+ minps xmm0, xmm5
+ maxps xmm1, xmm0
+ mulps xmm2, xmm1
+ subps xmm5, xmm2
+
+ mulps xmm6, xmm3 __asm mulps xmm6, xmm5 /* exij */
+
+ movaps xmm7, sMaskXY
+ andps xmm7, xmm6 /* exlo */
+ xorps xmm6, xmm7 /* exhi */
+
+ movaps xmm0, XMMWORD PTR [htmp ] /* h0ij */
+ movaps xmm1, XMMWORD PTR [htmp+16] /* h1ij */
+ movaps xmm2, XMMWORD PTR [htmp+32] /* h2ij */
+ movaps xmm3, XMMWORD PTR [htmp+48] /* h3ij */
+
+ pshufd xmm5, xmm7, 0xc0 __asm mulps xmm0, xmm5 /* f0ij */
+ pshufd xmm7, xmm7, 0xd5 __asm mulps xmm1, xmm7 /* f1ij */
+ pshufd xmm4, xmm6, 0x2a __asm mulps xmm2, xmm4 /* f2ij */
+ pshufd xmm6, xmm6, 0x3f __asm mulps xmm3, xmm6 /* f3ij */
+
+ mov edi, [ptmp ] __asm movaps xmm4, XMMWORD PTR [edi + ecx] /* v0i */
+ pshufd xmm5, xmm4, 0xff __asm mulps xmm5, xmm0 __asm subps xmm4, xmm5 /* u0i */
+ movaps XMMWORD PTR [edi + ecx], xmm4
+
+ mov edi, [ptmp+ 4] __asm movaps xmm6, XMMWORD PTR [edi + ecx] /* v0j */
+ pshufd xmm7, xmm6, 0xff __asm mulps xmm7, xmm0 __asm addps xmm6, xmm7 /* u0j */
+ movaps XMMWORD PTR [edi + ecx], xmm6
+
+ mov edi, [ptmp+ 8] __asm movaps xmm4, XMMWORD PTR [edi + ecx] /* v1i */
+ pshufd xmm5, xmm4, 0xff __asm mulps xmm5, xmm1 __asm subps xmm4, xmm5 /* u1i */
+ movaps XMMWORD PTR [edi + ecx], xmm4
+
+ mov edi, [ptmp+12] __asm movaps xmm6, XMMWORD PTR [edi + ecx] /* v1j */
+ pshufd xmm7, xmm6, 0xff __asm mulps xmm7, xmm1 __asm addps xmm6, xmm7 /* u1j */
+ movaps XMMWORD PTR [edi + ecx], xmm6
+
+ mov edi, [ptmp+16] __asm movaps xmm4, XMMWORD PTR [edi + ecx] /* v2i */
+ pshufd xmm5, xmm4, 0xff __asm mulps xmm5, xmm2 __asm subps xmm4, xmm5 /* u2i */
+ movaps XMMWORD PTR [edi + ecx], xmm4
+
+ mov edi, [ptmp+20] __asm movaps xmm6, XMMWORD PTR [edi + ecx] /* v2j */
+ pshufd xmm7, xmm6, 0xff __asm mulps xmm7, xmm2 __asm addps xmm6, xmm7 /* u2j */
+ movaps XMMWORD PTR [edi + ecx], xmm6
+
+ mov edi, [ptmp+24] __asm movaps xmm4, XMMWORD PTR [edi + ecx] /* v3i */
+ pshufd xmm5, xmm4, 0xff __asm mulps xmm5, xmm3 __asm subps xmm4, xmm5 /* u3i */
+ movaps XMMWORD PTR [edi + ecx], xmm4
+
+ mov edi, [ptmp+28] __asm movaps xmm6, XMMWORD PTR [edi + ecx] /* v3j */
+ pshufd xmm7, xmm6, 0xff __asm mulps xmm7, xmm3 __asm addps xmm6, xmm7 /* u3j */
+ movaps XMMWORD PTR [edi + ecx], xmm6
+
+ add eax, 16
+ add edx, 16
+
+ cmp edx, esi
+ jb forBegin
+forEnd:
+ }
+}
+
+// clang-format:enable
+
+#endif
+
+#pragma warning(pop)
diff --git a/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/windows/CuFactory.h b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/windows/CuFactory.h
new file mode 100644
index 00000000..59cec2d9
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/LowLevelCloth/src/windows/CuFactory.h
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#pragma once
+
+#include "Factory.h"
+#include "Allocator.h"
+
+namespace physx
+{
+ class PxCudaContextManager;
+}
+
+namespace nvidia
+{
+namespace cloth
+{
+
+class CuFabric;
+class CuCloth;
+template <typename>
+class ClothImpl;
+
+class CuFactory : public UserAllocated, public Factory
+{
+ protected:
+ CuFactory& operator=(const CuFactory&);
+
+ public:
+ typedef CuFabric FabricType;
+ typedef ClothImpl<CuCloth> ImplType;
+
+ CuFactory(PxCudaContextManager*);
+ virtual ~CuFactory();
+
+ virtual Fabric* createFabric(uint32_t numParticles, Range<const uint32_t> phases, Range<const uint32_t> sets,
+ Range<const float> restvalues, Range<const uint32_t> indices,
+ Range<const uint32_t> anchors, Range<const float> tetherLengths);
+
+ virtual Cloth* createCloth(Range<const PxVec4> particles, Fabric& fabric);
+
+ virtual Solver* createSolver(profile::PxProfileZone* profiler, PxTaskManager* taskMgr);
+
+ virtual Cloth* clone(const Cloth& cloth);
+
+ virtual void extractFabricData(const Fabric& fabric, Range<uint32_t> phases, Range<uint32_t> sets,
+ Range<float> restvalues, Range<uint32_t> indices, Range<uint32_t> anchors,
+ Range<float> tetherLengths) const;
+
+ virtual void extractCollisionData(const Cloth& cloth, Range<PxVec4> spheres, Range<uint32_t> capsules,
+ Range<PxVec4> planes, Range<uint32_t> convexes, Range<PxVec3> triangles) const;
+
+ virtual void extractMotionConstraints(const Cloth& cloth, Range<PxVec4> destConstraints) const;
+
+ virtual void extractSeparationConstraints(const Cloth& cloth, Range<PxVec4> destConstraints) const;
+
+ virtual void extractParticleAccelerations(const Cloth& cloth, Range<PxVec4> destAccelerations) const;
+
+ virtual void extractVirtualParticles(const Cloth& cloth, Range<uint32_t[4]> destIndices,
+ Range<PxVec3> destWeights) const;
+
+ virtual void extractSelfCollisionIndices(const Cloth& cloth, Range<uint32_t> destIndices) const;
+
+ virtual void extractRestPositions(const Cloth& cloth, Range<PxVec4> destRestPositions) const;
+
+ public:
+ void copyToHost(const void* srcIt, const void* srcEnd, void* dstIt) const;
+
+ public:
+ Vector<CuFabric*>::Type mFabrics;
+
+ PxCudaContextManager* mContextManager;
+
+ uint32_t mNumThreadsPerBlock;
+
+ const uint32_t mMaxThreadsPerBlock;
+};
+}
+}
diff --git a/APEX_1.4/module/clothing/embedded/PxClothFabric.h b/APEX_1.4/module/clothing/embedded/PxClothFabric.h
new file mode 100644
index 00000000..78d41228
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/PxClothFabric.h
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PX_PHYSICS_NX_CLOTH_FABRIC
+#define PX_PHYSICS_NX_CLOTH_FABRIC
+/** \addtogroup cloth
+ @{
+*/
+
+
+#if PX_DOXYGEN == 0
+namespace nvidia
+{
+#endif
+
+/**
+\brief Describe type of phase in cloth fabric.
+\see PxClothFabric for an explanation of concepts on phase and set.
+*/
+struct PxClothFabricPhaseType
+{
+ enum Enum
+ {
+ eINVALID, //!< invalid type
+ eVERTICAL, //!< resists stretching or compression, usually along the gravity
+ eHORIZONTAL, //!< resists stretching or compression, perpendicular to the gravity
+ eBENDING, //!< resists out-of-plane bending in angle-based formulation
+ eSHEARING, //!< resists in-plane shearing along (typically) diagonal edges,
+ eCOUNT // internal use only
+ };
+};
+
+/**
+\brief References a set of constraints that can be solved in parallel.
+\see PxClothFabric for an explanation of the concepts on phase and set.
+*/
+struct PxClothFabricPhase
+{
+ PxClothFabricPhase(PxClothFabricPhaseType::Enum type =
+ PxClothFabricPhaseType::eINVALID, uint32_t index = 0);
+
+ /**
+ \brief Type of constraints to solve.
+ */
+ PxClothFabricPhaseType::Enum phaseType;
+
+ /**
+ \brief Index of the set that contains the particle indices.
+ */
+ uint32_t setIndex;
+};
+
+PX_INLINE PxClothFabricPhase::PxClothFabricPhase(
+ PxClothFabricPhaseType::Enum type, uint32_t index)
+ : phaseType(type)
+ , setIndex(index)
+{}
+
+/**
+\brief References all the data required to create a fabric.
+\see PxPhysics.createClothFabric(), PxClothFabricCooker.getDescriptor()
+*/
+class PxClothFabricDesc
+{
+public:
+ /** \brief The number of particles needed when creating a PxCloth instance from the fabric. */
+ uint32_t nbParticles;
+
+ /** \brief The number of solver phases. */
+ uint32_t nbPhases;
+ /** \brief Array defining which constraints to solve each phase. See #PxClothFabric.getPhases(). */
+ const PxClothFabricPhase* phases;
+
+ /** \brief The number of sets in the fabric. */
+ uint32_t nbSets;
+ /** \brief Array with an index per set which points one entry beyond the last constraint of the set. See #PxClothFabric.getSets(). */
+ const uint32_t* sets;
+
+ /** \brief Array of particle indices which specifies the pair of constrained vertices. See #PxClothFabric.getParticleIndices(). */
+ const uint32_t* indices;
+ /** \brief Array of rest values for each constraint. See #PxClothFabric.getRestvalues(). */
+ const float* restvalues;
+
+ /** \brief Size of tetherAnchors and tetherLengths arrays, needs to be multiple of nbParticles. */
+ uint32_t nbTethers;
+ /** \brief Array of particle indices specifying the tether anchors. See #PxClothFabric.getTetherAnchors(). */
+ const uint32_t* tetherAnchors;
+ /** \brief Array of rest distance between tethered particle pairs. See #PxClothFabric.getTetherLengths(). */
+ const float* tetherLengths;
+
+ /**
+ \brief constructor sets to default.
+ */
+ PX_INLINE PxClothFabricDesc();
+
+ /**
+ \brief (re)sets the structure to the default.
+ */
+ PX_INLINE void setToDefault();
+
+ /**
+ \brief Returns true if the descriptor is valid.
+ \return True if the current settings are valid
+ */
+ PX_INLINE bool isValid() const;
+};
+
+PX_INLINE PxClothFabricDesc::PxClothFabricDesc()
+{
+ setToDefault();
+}
+
+PX_INLINE void PxClothFabricDesc::setToDefault()
+{
+ memset(this, 0, sizeof(PxClothFabricDesc));
+}
+
+PX_INLINE bool PxClothFabricDesc::isValid() const
+{
+ return (nbParticles && nbPhases && phases && restvalues && nbSets
+ && sets && indices && (!nbTethers || (tetherAnchors && tetherLengths)));
+}
+
+
+#if PX_DOXYGEN == 0
+} // namespace nvidia
+#endif
+
+/** @} */
+#endif
diff --git a/APEX_1.4/module/clothing/embedded/PxClothMeshDesc.h b/APEX_1.4/module/clothing/embedded/PxClothMeshDesc.h
new file mode 100644
index 00000000..c60aef5b
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/PxClothMeshDesc.h
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PX_PHYSICS_NX_CLOTHMESHDESC
+#define PX_PHYSICS_NX_CLOTHMESHDESC
+/** \addtogroup cooking
+@{
+*/
+
+#include "ExtClothCoreUtilityTypes.h"
+#include "PxVec3.h"
+
+#if PX_DOXYGEN == 0
+namespace nvidia
+{
+#endif
+
+/**
+\brief Descriptor class for a cloth mesh.
+
+@see PxCooking.cookClothMesh()
+
+*/
+class PxClothMeshDesc
+{
+public:
+
+ /**
+ \brief Pointer to first vertex point.
+ */
+ PxBoundedData points;
+
+ /**
+ \brief Determines whether particle is simulated or static.
+ A positive value denotes that the particle is being simulated, zero denotes a static particle.
+ This data is used to generate tether and zero stretch constraints.
+ If invMasses.data is null, all particles are assumed to be simulated
+ and no tether and zero stretch constraints are being generated.
+ */
+ PxBoundedData invMasses;
+
+ /**
+ \brief Pointer to the first triangle.
+
+ These are triplets of 0 based indices:
+ vert0 vert1 vert2
+ vert0 vert1 vert2
+ vert0 vert1 vert2
+ ...
+
+ where vert* is either a 32 or 16 bit unsigned integer. There are a total of 3*count indices.
+ The stride determines the byte offset to the next index triple.
+
+ This is declared as a void pointer because it is actually either an uint16_t or a uint32_t pointer.
+ */
+ PxBoundedData triangles;
+
+ /**
+ \brief Pointer to the first quad.
+
+ These are quadruples of 0 based indices:
+ vert0 vert1 vert2 vert3
+ vert0 vert1 vert2 vert3
+ vert0 vert1 vert2 vert3
+ ...
+
+ where vert* is either a 32 or 16 bit unsigned integer. There are a total of 4*count indices.
+ The stride determines the byte offset to the next index quadruple.
+
+ This is declared as a void pointer because it is actually either an uint16_t or a uint32_t pointer.
+ */
+ PxBoundedData quads;
+
+ /**
+ \brief Flags bits, combined from values of the enum ::PxMeshFlag
+ */
+ PxMeshFlags flags;
+
+ /**
+ \brief constructor sets to default.
+ */
+ PX_INLINE PxClothMeshDesc();
+ /**
+ \brief (re)sets the structure to the default.
+ */
+ PX_INLINE void setToDefault();
+ /**
+ \brief Returns true if the descriptor is valid.
+ \return True if the current settings are valid
+ */
+ PX_INLINE bool isValid() const;
+};
+
+PX_INLINE PxClothMeshDesc::PxClothMeshDesc() //constructor sets to default
+{
+}
+
+PX_INLINE void PxClothMeshDesc::setToDefault()
+{
+ *this = PxClothMeshDesc();
+}
+
+PX_INLINE bool PxClothMeshDesc::isValid() const
+{
+ if(points.count < 3) //at least 1 trig's worth of points
+ return false;
+ if(points.count > 0xffff && flags & PxMeshFlag::e16_BIT_INDICES)
+ return false;
+ if(!points.data)
+ return false;
+ if(points.stride < sizeof(physx::PxVec3)) //should be at least one point's worth of data
+ return false;
+
+ if(invMasses.data && invMasses.stride < sizeof(float))
+ return false;
+ if(invMasses.data && invMasses.count != points.count)
+ return false;
+
+ if (!triangles.count && !quads.count) // no support for non-indexed mesh
+ return false;
+ if (triangles.count && !triangles.data)
+ return false;
+ if (quads.count && !quads.data)
+ return false;
+
+ uint32_t indexSize = (flags & PxMeshFlag::e16_BIT_INDICES) ? sizeof(uint16_t) : sizeof(uint32_t);
+ if(triangles.count && triangles.stride < indexSize*3)
+ return false;
+ if(quads.count && quads.stride < indexSize*4)
+ return false;
+
+ return true;
+}
+
+#if PX_DOXYGEN == 0
+} // namespace nvidia
+#endif
+
+/** @} */
+#endif
diff --git a/APEX_1.4/module/clothing/embedded/PxClothTypes.h b/APEX_1.4/module/clothing/embedded/PxClothTypes.h
new file mode 100644
index 00000000..a210d6cc
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/PxClothTypes.h
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PX_PHYSICS_NX_CLOTH_TYPES
+#define PX_PHYSICS_NX_CLOTH_TYPES
+/** \addtogroup cloth
+ @{
+*/
+
+#include "PxPhysXConfig.h"
+#include "PxFlags.h"
+
+#include "PxVec3.h"
+
+#if PX_DOXYGEN == 0
+namespace nvidia
+{
+#endif
+
+/**
+ \brief flag for behaviors of the cloth solver
+ \details Defines flags to turn on/off features of the cloth solver.
+ The flag can be set during the cloth object construction (\see PxPhysics.createCloth() ),
+ or individually after the cloth has been created (\see PxCloth.setClothFlag() ).
+ */
+struct PxClothFlag
+{
+ enum Enum
+ {
+ eGPU = (1<<0), //!< turn on/off gpu based solver
+ eSWEPT_CONTACT = (1<<1), //!< use swept contact (continuous collision)
+ eSCENE_COLLISION = (1<<2), //!< collide against rigid body shapes in scene
+ eCOUNT = 3 // internal use only
+ };
+};
+
+typedef PxFlags<PxClothFlag::Enum,uint16_t> PxClothFlags;
+PX_FLAGS_OPERATORS(PxClothFlag::Enum, uint16_t)
+
+/**
+ \brief Per particle data for cloth.
+ \details Defines position of the cloth particle as well as inverse mass.
+ When inverse mass is set to 0, the particle gets fully constrained
+ to the position during simulation.
+ \see PxPhysics.createCloth()
+ \see PxCloth.setParticles()
+*/
+struct PxClothParticle
+{
+ PxVec3 pos; //!< position of the particle (in cloth local space)
+ float invWeight; //!< inverse mass of the particle. If set to 0, the particle is fully constrained.
+
+ /**
+ \brief Default constructor, performs no initialization.
+ */
+ PxClothParticle() {}
+ PxClothParticle(const PxVec3& pos_, float invWeight_)
+ : pos(pos_), invWeight(invWeight_){}
+};
+
+/**
+\brief Constraints for cloth particle motion.
+\details Defines a spherical volume to which the motion of a particle should be constrained.
+@see PxCloth.setMotionConstraints()
+*/
+struct PxClothParticleMotionConstraint
+{
+ PxVec3 pos; //!< Center of the motion constraint sphere (in cloth local space)
+ float radius; //!< Maximum distance the particle can move away from the sphere center.
+
+ /**
+ \brief Default constructor, performs no initialization.
+ */
+ PxClothParticleMotionConstraint() {}
+ PxClothParticleMotionConstraint(const PxVec3& p, float r)
+ : pos(p), radius(r){}
+};
+
+/**
+\brief Separation constraints for cloth particle movement
+\details Defines a spherical volume such that corresponding particles should stay outside.
+@see PxCloth.setSeparationConstraints()
+*/
+struct PxClothParticleSeparationConstraint
+{
+ PxVec3 pos; //!< Center of the constraint sphere (in cloth local space)
+ float radius; //!< Radius of the constraint sphere such that the particle stay outside of this sphere.
+
+ /**
+ \brief Default constructor, performs no initialization.
+ */
+ PxClothParticleSeparationConstraint() {}
+ PxClothParticleSeparationConstraint(const PxVec3& p, float r)
+ : pos(p), radius(r){}
+};
+
+#if PX_DOXYGEN == 0
+} // namespace nvidia
+#endif
+
+/** @} */
+#endif
diff --git a/APEX_1.4/module/clothing/embedded/Simulation.cpp b/APEX_1.4/module/clothing/embedded/Simulation.cpp
new file mode 100644
index 00000000..3705a156
--- /dev/null
+++ b/APEX_1.4/module/clothing/embedded/Simulation.cpp
@@ -0,0 +1,2488 @@
+/*
+ * 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 "Simulation.h"
+
+#include "ModuleClothingImpl.h"
+#include "ClothingScene.h"
+#include "ClothingCookedPhysX3Param.h"
+
+#include "DebugRenderParams.h"
+#include "ClothingDebugRenderParams.h"
+//#include "RenderDebugInterface.h"
+#include "RenderDebugInterface.h"
+
+#include "ModuleClothingHelpers.h"
+#include "ClothStructs.h"
+
+// only for the phase flags
+#include "ExtClothFabricCooker.h"
+
+// from LowLevelCloth
+#include "Cloth.h"
+#include "Fabric.h"
+#include "Factory.h"
+#include "Range.h"
+#include "Solver.h"
+
+#include "ApexSDKIntl.h"
+#include "SceneIntl.h"
+#include "PxCudaContextManager.h"
+#include "PxGpuDispatcher.h"
+
+#include "PsIntrinsics.h"
+#include "ProfilerCallback.h"
+
+#include <ApexCollision.h>
+#include "ApexMath.h"
+
+#include "Lock.h"
+
+#include "ClothingCollisionImpl.h"
+
+// visualize convexes
+#include "ApexSharedUtils.h"
+
+// pvd
+#include "ApexPvdClient.h"
+
+#include "PxPvdDataStream.h"
+#include "PxPvdUserRenderer.h"
+
+#if PX_PHYSICS_VERSION_MAJOR == 3
+#include "ScopedPhysXLock.h"
+#endif
+
+namespace nvidia
+{
+namespace clothing
+{
+
+using namespace physx;
+
+Simulation::Simulation(ClothingScene* clothingScene, bool useCuda) : SimulationAbstract(clothingScene),
+ mCookedData(NULL),
+ mIndices(NULL),
+ mRestPositions(NULL),
+ mConstrainCoeffs(NULL),
+ mCloth(NULL),
+ mNumAssetSpheres(0),
+ mNumAssetCapsules(0),
+ mNumAssetCapsulesInvalid(0),
+ mNumAssetConvexes(0),
+ mConstrainConstantsDirty(false),
+ mMotionConstrainScale(1.0f),
+ mMotionConstrainBias(0.0f),
+ mNumBackstopConstraints(-1),
+ mScaledGravity(0.0f),
+ mLastTimestep(0.0f),
+ mLocalSpaceSim(false),
+ mGlobalPose(PxMat44(PxIdentity)),
+ mGlobalPosePrevious(PxMat44(PxIdentity)),
+ mGlobalPoseNormalized(PxMat44(PxIdentity)),
+ mGlobalPoseNormalizedInv(PxMat44(PxIdentity)),
+ mActorScale(0.0f),
+ mTetherLimit(0.0f),
+ mTeleported(false),
+ mIsStatic(false)
+{
+ PX_ASSERT(clothingScene != NULL);
+ PX_UNUSED(useCuda);
+
+#if PX_WINDOWS_FAMILY
+ mUseCuda = useCuda;
+#else
+ mUseCuda = false; // disabled on consoles
+#endif
+}
+
+
+
+Simulation::~Simulation()
+{
+ if (mCloth != NULL)
+ {
+ mClothingScene->lockScene();
+ mClothingScene->getClothSolver(mUseCuda)->removeCloth(mCloth);
+ delete mCloth;
+ mClothingScene->unlockScene();
+ mCloth = NULL;
+ }
+}
+
+
+
+bool Simulation::needsExpensiveCreation()
+{
+ // disable caching of unused objects!
+ return false;
+}
+
+
+
+bool Simulation::needsAdaptiveTargetFrequency()
+{
+ // this is handled by the cloth solver directly
+ return false;
+}
+
+
+
+bool Simulation::needsManualSubstepping()
+{
+ // the solver will interpolate the skinned positions itself
+ return false;
+}
+
+
+
+bool Simulation::needsLocalSpaceGravity()
+{
+ return false;
+}
+
+
+
+uint32_t Simulation::getNumSolverIterations() const
+{
+ uint32_t numSolverIterations = 0;
+ if (mCloth != NULL)
+ {
+ numSolverIterations = (uint32_t)PxMax(1, int(mLastTimestep * mCloth->getSolverFrequency() + 0.5f));
+ }
+ return numSolverIterations;
+}
+
+
+
+bool Simulation::setCookedData(NvParameterized::Interface* cookedData, float actorScale)
+{
+ PX_ASSERT(cookedData != NULL);
+
+ mActorScale = actorScale;
+ PX_ASSERT(mActorScale > 0.0f);
+
+ if (::strcmp(cookedData->className(), ClothingCookedPhysX3Param::staticClassName()) != 0)
+ {
+ PX_ALWAYS_ASSERT();
+ return false;
+ }
+
+ mCookedData = static_cast<ClothingCookedPhysX3Param*>(cookedData);
+
+ return true;
+}
+
+
+bool Simulation::initPhysics(uint32_t _physicalMeshId, uint32_t* indices, PxVec3* restPositions, tMaterial* material, const PxMat44& /*globalPose*/, const PxVec3& scaledGravity, bool /*localSpaceSim*/)
+{
+ PX_ASSERT(mCookedData != NULL);
+
+ while (mCookedData->physicalMeshId != _physicalMeshId)
+ {
+ mCookedData = static_cast<ClothingCookedPhysX3Param*>(mCookedData->nextCookedData);
+ }
+
+ PX_ASSERT(mCookedData != NULL);
+ PX_ASSERT(mCookedData->physicalMeshId == _physicalMeshId);
+
+ mIndices = indices;
+ mRestPositions = restPositions;
+
+ if (mCookedData != NULL)
+ {
+#if PX_PHYSICS_VERSION_MAJOR == 3
+ SCOPED_PHYSX_LOCK_WRITE(mClothingScene->getApexScene());
+#else
+ WRITE_LOCK(*mClothingScene->getApexScene());
+#endif
+ // PH: mUseCuda is passed by reference. If for whatever reason a FactoryGPU could not be created, a FactoryCPU is returned and mUseCuda will be false
+ ClothFactory factory = mClothingScene->getClothFactory(mUseCuda);
+ nvidia::Mutex::ScopedLock _wlockFactory(*factory.mutex);
+
+
+ // find if there's a shared fabric
+ cloth::Fabric* fabric = NULL;
+ if (factory.factory->getPlatform() == cloth::Factory::CPU)
+ {
+ fabric = (cloth::Fabric*)mCookedData->fabricCPU;
+ }
+ else
+ {
+ for (int32_t i = 0; i < mCookedData->fabricGPU.arraySizes[0]; ++i)
+ {
+ if (mCookedData->fabricGPU.buf[i].factory == factory.factory)
+ {
+ fabric = (cloth::Fabric*)mCookedData->fabricGPU.buf[i].fabricGPU;
+ break;
+ }
+ }
+ }
+
+ if (fabric == NULL)
+ {
+ nvidia::Array<uint32_t> phases((uint32_t)mCookedData->deformablePhaseDescs.arraySizes[0]);
+ for (uint32_t i = 0; i < phases.size(); i++)
+ phases[i] = mCookedData->deformablePhaseDescs.buf[i].setIndex;
+ nvidia::Array<uint32_t> sets((uint32_t)mCookedData->deformableSets.arraySizes[0]);
+ for (uint32_t i = 0; i < sets.size(); i++)
+ {
+ sets[i] = mCookedData->deformableSets.buf[i].fiberEnd;
+ }
+ cloth::Range<uint32_t> indices(mCookedData->deformableIndices.buf, mCookedData->deformableIndices.buf + mCookedData->deformableIndices.arraySizes[0]);
+ cloth::Range<float> restLengths(mCookedData->deformableRestLengths.buf, mCookedData->deformableRestLengths.buf + mCookedData->deformableRestLengths.arraySizes[0]);
+ cloth::Range<uint32_t> tetherAnchors(mCookedData->tetherAnchors.buf, mCookedData->tetherAnchors.buf + mCookedData->tetherAnchors.arraySizes[0]);
+ cloth::Range<float> tetherLengths(mCookedData->tetherLengths.buf, mCookedData->tetherLengths.buf + mCookedData->tetherLengths.arraySizes[0]);
+
+ PX_PROFILE_ZONE("ClothingActorImpl::createClothFabric", GetInternalApexSDK()->getContextId());
+
+ // TODO use PhysX interface to scale tethers when available
+ for (int i = 0; i < mCookedData->tetherLengths.arraySizes[0]; ++i)
+ {
+ mCookedData->tetherLengths.buf[i] *= simulation.restLengthScale;
+ }
+
+ fabric = factory.factory->createFabric(
+ mCookedData->numVertices,
+ cloth::Range<uint32_t>(phases.begin(), phases.end()),
+ cloth::Range<uint32_t>(sets.begin(), sets.end()),
+ restLengths,
+ indices,
+ tetherAnchors,
+ tetherLengths
+ );
+
+
+ // store new fabric pointer so it can be shared
+ if (factory.factory->getPlatform() == cloth::Factory::CPU)
+ {
+ mCookedData->fabricCPU = fabric;
+ }
+ else
+ {
+ NvParameterized::Handle handle(*mCookedData);
+ int32_t arraysize = 0;
+
+ if (mCookedData->getParameterHandle("fabricGPU", handle) == NvParameterized::ERROR_NONE)
+ {
+ handle.getArraySize(arraysize, 0);
+ handle.resizeArray(arraysize + 1);
+ PX_ASSERT(mCookedData->fabricGPU.arraySizes[0] == arraysize+1);
+
+ ClothingCookedPhysX3ParamNS::FabricGPU_Type fabricGPU;
+ fabricGPU.fabricGPU = fabric;
+ fabricGPU.factory = factory.factory;
+ mCookedData->fabricGPU.buf[arraysize] = fabricGPU;
+ }
+ }
+
+
+ if (simulation.restLengthScale != 1.0f && fabric != NULL)
+ {
+ uint32_t numPhases = phases.size();
+ float* restValueScales = (float*)GetInternalApexSDK()->getTempMemory(numPhases * sizeof(float));
+ (fabric)->scaleRestvalues( simulation.restLengthScale );
+ GetInternalApexSDK()->releaseTempMemory(restValueScales);
+ }
+ }
+
+ if (fabric != NULL && mCloth == NULL)
+ {
+ PX_ASSERT(mCookedData->deformableInvVertexWeights.arraySizes[0] == (int32_t)mCookedData->numVertices);
+
+ Array<PxVec4> startPositions(mCookedData->numVertices);
+ for (uint32_t i = 0; i < mCookedData->numVertices; i++)
+ {
+ startPositions[i] = PxVec4(sdkWritebackPosition[i], mCookedData->deformableInvVertexWeights.buf[i]);
+ }
+
+ const PxVec4* pos = (const PxVec4*)startPositions.begin();
+
+ cloth::Range<const PxVec4> startPos(pos, pos + startPositions.size());
+
+ PX_PROFILE_ZONE("ClothingActorImpl::createCloth", GetInternalApexSDK()->getContextId());
+
+ mCloth = factory.factory->createCloth(startPos, *((cloth::Fabric*)fabric));
+ }
+
+ if (mCloth != NULL)
+ {
+ // setup capsules
+ const uint32_t numSupportedCapsules = 32;
+ const uint32_t* collisionIndicesEnd = (mCollisionCapsules.size() > 2 * numSupportedCapsules) ? &mCollisionCapsules[2 * numSupportedCapsules] : mCollisionCapsules.end();
+ cloth::Range<const uint32_t> cIndices(mCollisionCapsules.begin(), collisionIndicesEnd);
+ mCloth->setCapsules(cIndices,0,mCloth->getNumCapsules());
+
+ // setup convexes
+ cloth::Range<const uint32_t> convexes(mCollisionConvexes.begin(), mCollisionConvexes.end());
+ mCloth->setConvexes(convexes,0,mCloth->getNumConvexes());
+
+ mClothingScene->lockScene();
+ mClothingScene->getClothSolver(mUseCuda)->addCloth(mCloth);
+ mClothingScene->unlockScene();
+ mIsStatic = false;
+
+ // add virtual particles
+ const uint32_t numVirtualParticleIndices = (uint32_t)mCookedData->virtualParticleIndices.arraySizes[0];
+ const uint32_t numVirtualParticleWeights = (uint32_t)mCookedData->virtualParticleWeights.arraySizes[0];
+ if (numVirtualParticleIndices > 0)
+ {
+ cloth::Range<const uint32_t[4]> vIndices((const uint32_t(*)[4])(mCookedData->virtualParticleIndices.buf), (const uint32_t(*)[4])(mCookedData->virtualParticleIndices.buf + numVirtualParticleIndices));
+ cloth::Range<const PxVec3> weights((PxVec3*)mCookedData->virtualParticleWeights.buf, (PxVec3*)(mCookedData->virtualParticleWeights.buf + numVirtualParticleWeights));
+ mCloth->setVirtualParticles(vIndices, weights);
+ }
+
+ const uint32_t numSelfcollisionIndices = (uint32_t)mCookedData->selfCollisionIndices.arraySizes[0];
+ ModuleClothingImpl* module = static_cast<ModuleClothingImpl*>(mClothingScene->getModule());
+ if (module->useSparseSelfCollision() && numSelfcollisionIndices > 0)
+ {
+ cloth::Range<const uint32_t> vIndices(mCookedData->selfCollisionIndices.buf, mCookedData->selfCollisionIndices.buf + numSelfcollisionIndices);
+ mCloth->setSelfCollisionIndices(vIndices);
+ }
+
+ applyCollision();
+
+ mTeleported = true; // need to clear inertia
+ }
+ }
+
+
+ // configure phases
+ mPhaseConfigs.clear();
+
+ // if this is hit, PhaseConfig has changed. check if we need to adapt something below.
+ PX_COMPILE_TIME_ASSERT(sizeof(cloth::PhaseConfig) == 20);
+
+ const uint32_t numPhaseDescs = (uint32_t)mCookedData->deformablePhaseDescs.arraySizes[0];
+ for (uint32_t i = 0; i < numPhaseDescs; ++i)
+ {
+ cloth::PhaseConfig phaseConfig;
+ phaseConfig.mPhaseIndex = uint16_t(i);
+ phaseConfig.mStiffness = 1.0f;
+ phaseConfig.mStiffnessMultiplier = 1.0f;
+
+ mPhaseConfigs.pushBack(phaseConfig);
+ }
+
+ if (mCloth != NULL)
+ {
+ cloth::Range<cloth::PhaseConfig> phaseConfig(mPhaseConfigs.begin(), mPhaseConfigs.end());
+ mCloth->setPhaseConfig(phaseConfig);
+ }
+
+ // apply clothing material after phases are set up
+ if (material != NULL)
+ {
+ applyClothingMaterial(material, scaledGravity);
+ }
+
+ physicalMeshId = _physicalMeshId;
+
+ return (mCloth != NULL);
+}
+
+
+void Simulation::initCollision(tBoneActor* boneActors, uint32_t numBoneActors,
+ tBoneSphere* boneSpheres, uint32_t numBoneSpheres,
+ uint16_t* spherePairIndices, uint32_t numSpherePairIndices,
+ tBonePlane* bonePlanes, uint32_t numBonePlanes,
+ uint32_t* convexes, uint32_t numConvexes, tBoneEntry* bones,
+ const PxMat44* boneTransforms,
+ ResourceList& actorPlanes,
+ ResourceList& actorConvexes,
+ ResourceList& actorSpheres,
+ ResourceList& actorCapsules,
+ ResourceList& actorTriangleMeshes,
+ const tActorDescTemplate& /*actorDesc*/, const tShapeDescTemplate& /*shapeDesc*/, float actorScale,
+ const PxMat44& globalPose, bool localSpaceSim)
+{
+ // these need to be initialized here, because they are read in
+ // updateCollision
+ mLocalSpaceSim = localSpaceSim;
+ setGlobalPose(globalPose); // initialize current frame
+ setGlobalPose(globalPose); // initialize previous frame
+
+ if (numBoneActors + numBoneSpheres + actorPlanes.getSize() + actorSpheres.getSize() + actorTriangleMeshes.getSize() == 0)
+ {
+ return;
+ }
+
+ if (numBoneActors > 0 && numBoneSpheres > 0)
+ {
+ // ignore case where both exist
+ APEX_INVALID_PARAMETER("This asset contains regular collision volumes and new ones. Having both is not supported, ignoring the regular ones");
+ numBoneActors = 0;
+ }
+
+ mActorScale = actorScale;
+
+ // Note: each capsule will have two spheres at each end, nothing is shared, so the index map is quite trivial so far
+ for (uint32_t i = 0; i < numBoneActors; i++)
+ {
+ if (boneActors[i].convexVerticesCount == 0)
+ {
+ PX_ASSERT(boneActors[i].capsuleRadius > 0.0f);
+ if (mCollisionCapsules.size() < 32)
+ {
+ uint32_t index = mCollisionCapsules.size();
+ mCollisionCapsules.pushBack(index);
+ mCollisionCapsules.pushBack(index + 1);
+ }
+ else
+ {
+ uint32_t index = mCollisionCapsules.size() + mCollisionCapsulesInvalid.size();
+ mCollisionCapsulesInvalid.pushBack(index);
+ mCollisionCapsulesInvalid.pushBack(index + 1);
+ }
+ }
+ }
+
+ // now add the sphere pairs for PhysX3 capsules
+ for (uint32_t i = 0; i < numSpherePairIndices; i += 2)
+ {
+ if (spherePairIndices[i] < 32 && spherePairIndices[i + 1] < 32)
+ {
+ mCollisionCapsules.pushBack(spherePairIndices[i]);
+ mCollisionCapsules.pushBack(spherePairIndices[i + 1]);
+ }
+ else
+ {
+ mCollisionCapsulesInvalid.pushBack(spherePairIndices[i]);
+ mCollisionCapsulesInvalid.pushBack(spherePairIndices[i + 1]);
+ }
+ }
+ mNumAssetCapsules = mCollisionCapsules.size();
+ mNumAssetCapsulesInvalid = mCollisionCapsulesInvalid.size();
+
+ // convexes
+ for (uint32_t i = 0; i < numConvexes; ++i)
+ {
+ mCollisionConvexes.pushBack(convexes[i]);
+ }
+ mNumAssetConvexes = mCollisionConvexes.size();
+
+ // notify triangle meshes of initialization
+ for (uint32_t i = 0; i < actorTriangleMeshes.getSize(); ++i)
+ {
+ ClothingTriangleMeshImpl* mesh = (ClothingTriangleMeshImpl*)(actorTriangleMeshes.getResource(i));
+ mesh->setId(-1); // this makes sure that mesh->update does not try read non-existing previous frame data
+ }
+
+ updateCollision(boneActors, numBoneActors, boneSpheres, numBoneSpheres, bonePlanes, numBonePlanes, bones, boneTransforms,
+ actorPlanes, actorConvexes, actorSpheres, actorCapsules, actorTriangleMeshes, false);
+
+ if (!mCollisionCapsulesInvalid.empty())
+ {
+ PX_ASSERT(mCollisionSpheres.size() > 32);
+ if (mCollisionSpheres.size() > 32)
+ {
+ APEX_INVALID_PARAMETER("This asset has %d collision volumes, but only 32 are supported. %d will be ignored!", mCollisionSpheres.size(), mCollisionSpheres.size() - 32);
+ }
+ }
+}
+
+
+
+class CollisionCompare
+{
+public:
+ PX_INLINE bool operator()(const ApexResourceInterface* a, const ApexResourceInterface* b) const
+ {
+ ClothingCollisionImpl* collisionA = (ClothingCollisionImpl*)a;
+ ClothingCollisionImpl* collisionB = (ClothingCollisionImpl*)b;
+ return (uint32_t)collisionA->getId() < (uint32_t)collisionB->getId(); // cast to uint32_t so we get -1 at the end
+ }
+};
+
+
+
+void Simulation::updateCollision(tBoneActor* boneActors, uint32_t numBoneActors,
+ tBoneSphere* boneSpheres, uint32_t numBoneSpheres,
+ tBonePlane* bonePlanes, uint32_t numBonePlanes,
+ tBoneEntry* bones, const PxMat44* boneTransforms,
+ ResourceList& actorPlanes,
+ ResourceList& actorConvexes,
+ ResourceList& actorSpheres,
+ ResourceList& actorCapsules,
+ ResourceList& actorTriangleMeshes,
+ bool /*teleport*/)
+{
+ if (numBoneActors > 0 && numBoneSpheres > 0)
+ {
+ // error message already emitted in initCollision
+ numBoneActors = 0;
+ }
+
+ // Note: if we have more than 32 collision spheres, we add them to the array, but we don't pass more than 32 of them to the PxCloth (allows to still debug render them in red)
+
+ const float collisionThickness = simulation.thickness / 2.0f;
+
+ PX_ASSERT(mActorScale != 0.0f);
+
+ if (numBoneActors > 0)
+ {
+ // old style
+ if (mCollisionSpheres.empty())
+ {
+ // resize them the first time
+ uint32_t count = 0;
+ for (uint32_t i = 0; i < numBoneActors; i++)
+ {
+ count += (boneActors[i].convexVerticesCount == 0) ? 2 : 0;
+ }
+ mNumAssetSpheres = count;
+ mCollisionSpheres.resize(count);
+ }
+
+ uint32_t writeIndex = 0;
+ for (uint32_t i = 0; i < numBoneActors; i++)
+ {
+ if (boneActors[i].convexVerticesCount == 0)
+ {
+ PX_ASSERT(boneActors[i].capsuleRadius > 0.0f);
+ if (boneActors[i].capsuleRadius > 0.0f)
+ {
+ const int32_t boneIndex = boneActors[i].boneIndex;
+ PX_ASSERT(boneIndex >= 0);
+ if (boneIndex >= 0)
+ {
+ const PxMat44 boneBindPose = bones[boneIndex].bindPose;
+ const PxMat44& diff = boneTransforms[boneIndex];
+
+ const PxMat44 globalPose = diff * boneBindPose * (PxMat44)boneActors[i].localPose;
+
+ const PxVec3 vertex(0.0f, boneActors[i].capsuleHeight * 0.5f, 0.0f);
+ const float radius = (boneActors[i].capsuleRadius + collisionThickness) * mActorScale;
+ mCollisionSpheres[writeIndex++] = PxVec4(globalPose.transform(vertex), radius);
+ mCollisionSpheres[writeIndex++] = PxVec4(globalPose.transform(-vertex), radius);
+ }
+ }
+ }
+ }
+ PX_ASSERT(writeIndex == mNumAssetSpheres);
+ }
+ else if (numBoneSpheres > 0)
+ {
+ // new style
+
+ // write physx3 bone spheres
+ mNumAssetSpheres = numBoneSpheres;
+ mCollisionSpheres.resize(numBoneSpheres);
+ for (uint32_t i = 0; i < mCollisionSpheres.size(); ++i)
+ {
+ const int32_t boneIndex = boneSpheres[i].boneIndex;
+ PX_ASSERT(boneIndex >= 0);
+
+ const PxMat44 boneBindPose = bones[boneIndex].bindPose;
+ const PxMat44& diff = boneTransforms[boneIndex];
+
+ PxVec3 globalPos = diff.transform(boneBindPose.transform(boneSpheres[i].localPos));
+
+ mCollisionSpheres[i] = PxVec4(globalPos, (boneSpheres[i].radius + collisionThickness) * mActorScale);
+ }
+ }
+
+ // collision spheres from actor
+ if (mReleasedSphereIds.size() > 0)
+ {
+ // make sure the order of id's doesn't change
+ CollisionCompare compare;
+ actorSpheres.sort(compare);
+ }
+ mCollisionSpheres.resize(mNumAssetSpheres + actorSpheres.getSize());
+ for (uint32_t i = 0; i < actorSpheres.getSize(); ++i)
+ {
+ uint32_t sphereId = mNumAssetSpheres + i;
+ ClothingSphereImpl* actorSphere = DYNAMIC_CAST(ClothingSphereImpl*)(actorSpheres.getResource(i));
+ actorSphere->setId((int32_t)sphereId);
+ PxVec3 pos = actorSphere->getPosition();
+ if (mLocalSpaceSim)
+ {
+ pos = mGlobalPoseNormalizedInv.transform(pos);
+ }
+
+ PxVec4 sphere(pos, actorSphere->getRadius());
+ mCollisionSpheres[sphereId] = sphere;
+ }
+
+ // collision capsules from actor
+ mCollisionCapsules.resizeUninitialized(mNumAssetCapsules);
+ mCollisionCapsulesInvalid.resizeUninitialized(mNumAssetCapsulesInvalid);
+ for (uint32_t i = 0; i < actorCapsules.getSize(); ++i)
+ {
+ ClothingCapsuleImpl* actorCapsule = DYNAMIC_CAST(ClothingCapsuleImpl*)(actorCapsules.getResource(i));
+ ClothingSphereImpl** spheres = (ClothingSphereImpl**)actorCapsule->getSpheres();
+ uint32_t s0 = (uint32_t)spheres[0]->getId();
+ uint32_t s1 = (uint32_t)spheres[1]->getId();
+ if (s0 > 32 || s1 > 32)
+ {
+ mCollisionCapsulesInvalid.pushBack(s0);
+ mCollisionCapsulesInvalid.pushBack(s1);
+ }
+ else
+ {
+ mCollisionCapsules.pushBack(s0);
+ mCollisionCapsules.pushBack(s1);
+ }
+ }
+
+
+ // collision planes of convexes
+ mCollisionPlanes.resize(numBonePlanes + actorPlanes.getSize());
+ for (uint32_t i = 0; i < numBonePlanes; ++i)
+ {
+ const int32_t boneIndex = bonePlanes[i].boneIndex;
+ PX_ASSERT(boneIndex >= 0);
+ if (boneIndex >= 0)
+ {
+ const PxMat44 boneBindPose = bones[boneIndex].bindPose;
+ const PxMat44& diff = boneTransforms[boneIndex];
+
+ PxVec3 p = diff.transform(boneBindPose.transform(bonePlanes[i].n * -bonePlanes[i].d));
+ PxVec3 n = diff.rotate(boneBindPose.rotate(bonePlanes[i].n));
+
+ PxPlane skinnedPlane(p, n);
+
+ mCollisionPlanes[i] = PxVec4(skinnedPlane.n, skinnedPlane.d);
+ }
+ }
+
+
+ // collision convexes and planes from actor
+ mCollisionConvexes.resizeUninitialized(mNumAssetConvexes);
+ mCollisionConvexesInvalid.clear();
+
+ // planes
+ if (mReleasedPlaneIds.size() > 0)
+ {
+ // make sure the order of id's doesn't change
+ CollisionCompare compare;
+ actorPlanes.sort(compare);
+ }
+ for (uint32_t i = 0; i < actorPlanes.getSize(); ++i)
+ {
+ uint32_t planeId = (uint32_t)(numBonePlanes + i);
+ ClothingPlaneImpl* actorPlane = DYNAMIC_CAST(ClothingPlaneImpl*)(actorPlanes.getResource(i));
+ actorPlane->setId((int32_t)planeId);
+ PxPlane plane = actorPlane->getPlane();
+ if (mLocalSpaceSim)
+ {
+ PxVec3 p = plane.pointInPlane();
+ plane = PxPlane(mGlobalPoseNormalizedInv.transform(p), mGlobalPoseNormalizedInv.rotate(plane.n));
+ }
+ mCollisionPlanes[planeId] = PxVec4(plane.n, plane.d);
+
+ // create a convex for unreferenced planes (otherwise they don't collide)
+ if (actorPlane->getRefCount() == 0 && planeId <= 32)
+ {
+ mCollisionConvexes.pushBack(1u << planeId);
+ }
+ }
+
+ // convexes
+ for (uint32_t i = 0; i < actorConvexes.getSize(); ++i)
+ {
+ ClothingConvexImpl* convex = DYNAMIC_CAST(ClothingConvexImpl*)(actorConvexes.getResource(i));
+
+ uint32_t convexMask = 0;
+ ClothingPlaneImpl** planes = (ClothingPlaneImpl**)convex->getPlanes();
+ for (uint32_t j = 0; j < convex->getNumPlanes(); ++j)
+ {
+ ClothingPlaneImpl* plane = planes[j];
+ uint32_t planeId = (uint32_t)plane->getId();
+ if (planeId > 32)
+ {
+ convexMask = 0;
+ break;
+ }
+ convexMask |= 1 << planeId;
+ }
+
+ if (convexMask > 0)
+ {
+ mCollisionConvexes.pushBack(convexMask);
+ }
+ else
+ {
+ mCollisionConvexesInvalid.pushBack(convex);
+ }
+ }
+
+ // triangles
+ PX_ASSERT(mCollisionTrianglesOld.empty());
+ nvidia::Array<PxVec3> collisionTrianglesTemp; // mCollisionTriangles is used in update, so we cannot clear it
+ for (uint32_t i = 0; i < actorTriangleMeshes.getSize(); ++i)
+ {
+ ClothingTriangleMeshImpl* mesh = (ClothingTriangleMeshImpl*)(actorTriangleMeshes.getResource(i));
+
+ const PxMat44& pose = mesh->getPose();
+ PxTransform tm(pose);
+ if (mLocalSpaceSim)
+ {
+ tm = PxTransform(mGlobalPoseNormalizedInv) * tm;
+ }
+
+ mesh->update(tm, mCollisionTriangles, mCollisionTrianglesOld, collisionTrianglesTemp);
+ }
+ mCollisionTriangles.swap(collisionTrianglesTemp);
+}
+
+
+
+void Simulation::releaseCollision(ClothingCollisionImpl& collision)
+{
+ ClothingSphereImpl* sphere = DYNAMIC_CAST(ClothingSphereImpl*)(collision.isSphere());
+ if (sphere != NULL)
+ {
+ int32_t id = sphere->getId();
+ if (id != -1)
+ {
+ mReleasedSphereIds.pushBack((uint32_t)id);
+ }
+ return;
+ }
+
+ ClothingPlaneImpl* plane = DYNAMIC_CAST(ClothingPlaneImpl*)(collision.isPlane());
+ if (plane != NULL)
+ {
+ int32_t id = plane->getId();
+ if (id != -1)
+ {
+ mReleasedPlaneIds.pushBack((uint32_t)id);
+ }
+ return;
+ }
+}
+
+
+
+void Simulation::updateCollisionDescs(const tActorDescTemplate& /*actorDesc*/, const tShapeDescTemplate& /*shapeDesc*/)
+{
+}
+
+
+
+void Simulation::disablePhysX(Actor* /*dummy*/)
+{
+ PX_ASSERT(false);
+}
+
+
+
+void Simulation::reenablePhysX(Actor* /*newMaster*/, const PxMat44& /*globalPose*/)
+{
+ PX_ASSERT(false);
+}
+
+
+
+void Simulation::fetchResults(bool computePhysicsMeshNormals)
+{
+ if (mCloth != NULL)
+ {
+ {
+ cloth::Range<PxVec4> particles = mCloth->getCurrentParticles();
+
+ PX_ASSERT(particles.size() == sdkNumDeformableVertices);
+ for (uint32_t i = 0; i < sdkNumDeformableVertices; i++)
+ {
+ sdkWritebackPosition[i] = particles[i].getXYZ();
+ PX_ASSERT(sdkWritebackPosition[i].isFinite());
+ }
+ }
+
+ // compute the normals
+ if (computePhysicsMeshNormals)
+ {
+ memset(sdkWritebackNormal, 0, sizeof(PxVec3) * sdkNumDeformableVertices);
+ for (uint32_t i = 0; i < sdkNumDeformableIndices; i += 3)
+ {
+ PxVec3 v1 = sdkWritebackPosition[mIndices[i + 1]] - sdkWritebackPosition[mIndices[i]];
+ PxVec3 v2 = sdkWritebackPosition[mIndices[i + 2]] - sdkWritebackPosition[mIndices[i]];
+ PxVec3 faceNormal = v1.cross(v2);
+
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ sdkWritebackNormal[mIndices[i + j]] += faceNormal;
+ }
+ }
+
+ for (uint32_t i = 0; i < sdkNumDeformableVertices; i++)
+ {
+ sdkWritebackNormal[i].normalize();
+ }
+ }
+ }
+ else
+ {
+ for (uint32_t i = 0; i < sdkNumDeformableVertices; i++)
+ {
+ sdkWritebackPosition[i] = skinnedPhysicsPositions[i];
+ sdkWritebackNormal[i] = skinnedPhysicsNormals[i];
+ }
+ }
+}
+
+
+
+
+bool Simulation::isSimulationMeshDirty() const
+{
+ return true; // always expect something to change
+}
+
+
+
+void Simulation::clearSimulationMeshDirt()
+{
+}
+
+
+
+void Simulation::setStatic(bool on)
+{
+ if (on)
+ {
+ if (mIsStatic && !mCloth->isAsleep())
+ {
+ APEX_INTERNAL_ERROR("Cloth has not stayed static. Something must have woken it up.");
+ }
+ mCloth->putToSleep();
+ }
+ else
+ {
+ mCloth->wakeUp();
+ }
+ mIsStatic = on;
+}
+
+
+
+bool Simulation::applyPressure(float /*pressure*/)
+{
+ return false;
+}
+
+
+
+bool Simulation::raycast(const PxVec3& rayOrigin, const PxVec3& rayDirection, float& _hitTime, PxVec3& _hitNormal, uint32_t& _vertexIndex)
+{
+ const uint32_t numIndices = sdkNumDeformableIndices;
+ float hitTime = PX_MAX_F32;
+ uint32_t hitIndex = 0xffffffff;
+ uint32_t hitVertexIndex = 0;
+ for (uint32_t i = 0; i < numIndices; i += 3)
+ {
+ float t = 0, u = 0, v = 0;
+
+ if (APEX_RayTriangleIntersect(rayOrigin, rayDirection,
+ sdkWritebackPosition[mIndices[i + 0]],
+ sdkWritebackPosition[mIndices[i + 1]],
+ sdkWritebackPosition[mIndices[i + 2]],
+ t, u, v))
+ {
+ if (t < hitTime)
+ {
+ hitTime = t;
+ hitIndex = i;
+ float w = 1 - u - v;
+ if (w >= u && w >= v)
+ {
+ hitVertexIndex = mIndices[i];
+ }
+ else if (u > w && u >= v)
+ {
+ hitVertexIndex = mIndices[i + 1];
+ }
+ else
+ {
+ hitVertexIndex = mIndices[i + 2];
+ }
+ }
+ }
+ }
+
+ if (hitIndex != 0xffffffff)
+ {
+ _hitTime = hitTime;
+ _hitNormal = PxVec3(0.0f, 1.0f, 0.0f);
+ _vertexIndex = hitVertexIndex;
+ return true;
+ }
+
+ return false;
+}
+
+
+
+void Simulation::attachVertexToGlobalPosition(uint32_t vertexIndex, const PxVec3& globalPosition)
+{
+ if (mCloth == NULL)
+ {
+ return;
+ }
+
+ cloth::Range<PxVec4> curParticles = mCloth->getCurrentParticles();
+ cloth::Range<PxVec4> prevParticles = mCloth->getPreviousParticles();
+
+ PX_ASSERT(vertexIndex < curParticles.size());
+ PX_ASSERT(vertexIndex < prevParticles.size());
+
+ // the .w component contains inverse mass of the vertex
+ // the solver needs it set on both current and previous
+ // (current contains an adjusted mass, scaled or zeroed by distance constraints)
+ curParticles[vertexIndex] = PxVec4(globalPosition, 0.0f);
+ prevParticles[vertexIndex].w = 0;
+}
+
+
+
+void Simulation::freeVertex(uint32_t vertexIndex)
+{
+ if (mCloth == NULL)
+ {
+ return;
+ }
+
+ const float weight = mCookedData->deformableInvVertexWeights.buf[vertexIndex];
+
+ cloth::Range<PxVec4> curParticles = mCloth->getPreviousParticles();
+ cloth::Range<PxVec4> prevParticles = mCloth->getPreviousParticles();
+
+ PX_ASSERT(vertexIndex < curParticles.size());
+ PX_ASSERT(vertexIndex < prevParticles.size());
+
+ // the .w component contains inverse mass of the vertex
+ // the solver needs it set on both current and previous
+ // (current contains an adjusted mass, scaled or zeroed by distance constraints)
+ curParticles[vertexIndex].w = weight;
+ prevParticles[vertexIndex].w = weight;
+}
+
+
+
+void Simulation::setGlobalPose(const PxMat44& globalPose)
+{
+ mGlobalPosePrevious = mGlobalPose;
+ mGlobalPose = mGlobalPoseNormalized = globalPose;
+
+ mGlobalPoseNormalized.column0.normalize();
+ mGlobalPoseNormalized.column1.normalize();
+ mGlobalPoseNormalized.column2.normalize();
+
+ mGlobalPoseNormalizedInv = mGlobalPoseNormalized.inverseRT();
+
+ mTeleported = false;
+}
+
+
+
+void Simulation::applyGlobalPose()
+{
+ if (mCloth == NULL || mIsStatic)
+ {
+ return;
+ }
+
+ PxTransform pose = mLocalSpaceSim ? PxTransform(mGlobalPoseNormalized) : PxTransform(PxIdentity);
+
+ mCloth->setTranslation(pose.p);
+ mCloth->setRotation(pose.q);
+
+ if (mTeleported)
+ {
+ mCloth->clearInertia();
+ }
+}
+
+
+
+NvParameterized::Interface* Simulation::getCookedData()
+{
+ return NULL;
+}
+
+
+
+void Simulation::verifyTimeStep(float substepSize)
+{
+ mLastTimestep = substepSize;
+}
+
+
+#ifndef WITHOUT_DEBUG_VISUALIZE
+void Simulation::visualizeConvexes(RenderDebugInterface& renderDebug)
+{
+ if(mCloth != NULL && mCollisionConvexes.size() > 0)
+ {
+ ConvexMeshBuilder builder(&mCollisionPlanes[0]);
+
+
+ float scale = mCloth->getBoundingBoxScale().maxElement();
+
+ for(uint32_t i=0; i<mCollisionConvexes.size(); ++i)
+ {
+ builder(mCollisionConvexes[i], scale);
+ }
+
+ for (uint32_t i = 0; i < builder.mIndices.size(); i += 3)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->debugTri(builder.mVertices[builder.mIndices[i]], builder.mVertices[builder.mIndices[i+1]], builder.mVertices[builder.mIndices[i+2]]);
+ }
+ }
+}
+
+
+
+void Simulation::visualizeConvexesInvalid(RenderDebugInterface& renderDebug)
+{
+ // this is rather slow and unprecise
+ for (uint32_t i = 0; i < mCollisionConvexesInvalid.size(); ++i)
+ {
+ ClothingConvexImpl* convex = mCollisionConvexesInvalid[i];
+ ClothingPlaneImpl** convexPlanes = (ClothingPlaneImpl**)convex->getPlanes();
+ ConvexHullImpl hull;
+ hull.init();
+ Array<PxPlane> planes;
+ for (uint32_t j = 0; j < convex->getNumPlanes(); ++j)
+ {
+ PxPlane plane = convexPlanes[j]->getPlane();
+ if (mLocalSpaceSim)
+ {
+ PxVec3 p = plane.pointInPlane();
+ plane = PxPlane(mGlobalPoseNormalizedInv.transform(p), mGlobalPoseNormalizedInv.rotate(plane.n));
+ }
+ planes.pushBack(plane);
+ }
+
+ hull.buildFromPlanes(planes.begin(), planes.size(), 0.1f);
+
+ // TODO render triangles (or polygons)
+ for (uint32_t j = 0; j < hull.getEdgeCount(); j++)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(hull.getVertex(hull.getEdgeEndpointIndex(j, 0)), hull.getVertex(hull.getEdgeEndpointIndex(j, 1)));
+ }
+
+ if (hull.getEdgeCount() == 0)
+ {
+ float planeSize = mCloth ? mCloth->getBoundingBoxScale().maxElement() * 0.3f : 1.0f;
+ for (uint32_t j = 0; j < planes.size(); ++j)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->debugPlane(PxPlane(planes[j].n, planes[j].d), planeSize, planeSize);
+ }
+ }
+ }
+}
+#endif
+
+
+
+void Simulation::visualize(RenderDebugInterface& renderDebug, ClothingDebugRenderParams& clothingDebugParams)
+{
+#ifdef WITHOUT_DEBUG_VISUALIZE
+ PX_UNUSED(renderDebug);
+ PX_UNUSED(clothingDebugParams);
+#else
+ if (!clothingDebugParams.Actors)
+ {
+ return;
+ }
+
+ using RENDER_DEBUG::DebugColors;
+ using RENDER_DEBUG::DebugRenderState;
+ const PxMat44 globalPose = *RENDER_DEBUG_IFACE(&renderDebug)->getPoseTyped();
+
+ if (clothingDebugParams.CollisionShapes || clothingDebugParams.CollisionShapesWire)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->pushRenderState();
+
+ // Wireframe only when solid is not set, when both are on, just do the solid thing
+ if (!clothingDebugParams.CollisionShapes)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->removeFromCurrentState(DebugRenderState::SolidShaded);
+ RENDER_DEBUG_IFACE(&renderDebug)->removeFromCurrentState(DebugRenderState::SolidWireShaded);
+ }
+ else
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->addToCurrentState(DebugRenderState::SolidShaded);
+ RENDER_DEBUG_IFACE(&renderDebug)->removeFromCurrentState(DebugRenderState::SolidWireShaded);
+ }
+
+ const uint32_t colorLightGray = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::LightGray);
+ const uint32_t colorGray = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Gray);
+ const uint32_t colorRed = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Red);
+
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorLightGray);
+
+ PX_ALLOCA(usedSpheres, bool, mCollisionSpheres.size());
+ for (uint32_t i = 0; i < mCollisionSpheres.size(); i++)
+ {
+ usedSpheres[i] = false;
+ }
+
+ const uint32_t numIndices1 = mCollisionCapsules.size();
+ const uint32_t numIndices2 = mCollisionCapsulesInvalid.size();
+ const uint32_t numIndices = numIndices2 + numIndices1;
+ for (uint32_t i = 0; i < numIndices; i += 2)
+ {
+ const bool valid = i < numIndices1;
+ const uint32_t index1 = valid ? mCollisionCapsules[i + 0] : mCollisionCapsulesInvalid[i + 0 - numIndices1];
+ const uint32_t index2 = valid ? mCollisionCapsules[i + 1] : mCollisionCapsulesInvalid[i + 1 - numIndices1];
+
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(valid ? colorLightGray : colorRed);
+
+ PxVec3 pos1 = mCollisionSpheres[index1].getXYZ();
+ PxVec3 pos2 = mCollisionSpheres[index2].getXYZ();
+
+ PxVec3 capsuleAxis = pos1 - pos2;
+ const float axisHeight = capsuleAxis.normalize();
+
+ PxMat44 capsulePose;
+ {
+ // construct matrix from this
+ const PxVec3 capsuleDefaultAxis(0.0f, 1.0f, 0.0f);
+ PxVec3 axis = capsuleDefaultAxis.cross(capsuleAxis).getNormalized();
+ const float angle = PxAcos(capsuleDefaultAxis.dot(capsuleAxis));
+ if (angle < 0.001f || angle + 0.001 > PxPi || axis.isZero())
+ {
+ axis = PxVec3(0.0f, 1.0f, 0.0f);
+ }
+ PxQuat q(angle, axis);
+ capsulePose = PxMat44(q);
+ capsulePose.setPosition((pos1 + pos2) * 0.5f);
+ }
+
+ const float radius1 = mCollisionSpheres[index1].w;
+ const float radius2 = mCollisionSpheres[index2].w;
+
+ RENDER_DEBUG_IFACE(&renderDebug)->setPose(globalPose * capsulePose);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugCapsuleTapered(radius1, radius2, axisHeight, 2);
+
+ usedSpheres[index1] = true;
+ usedSpheres[index2] = true;
+ }
+
+ for (uint32_t i = 0; i < mCollisionSpheres.size(); i++)
+ {
+ if (!usedSpheres[i])
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(i < 32 ? colorGray : colorRed);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugSphere(mCollisionSpheres[i].getXYZ(), mCollisionSpheres[i].w);
+ }
+ }
+ RENDER_DEBUG_IFACE(&renderDebug)->setPose(globalPose);
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorLightGray);
+ visualizeConvexes(renderDebug);
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorRed);
+ visualizeConvexesInvalid(renderDebug);
+
+ // collision triangles
+ PX_ASSERT(mCollisionTriangles.size() % 3 == 0);
+ uint32_t numTriangleVertsInCloth = mCloth ? 3*mCloth->getNumTriangles() : mCollisionTriangles.size();
+ for (uint32_t i = 0; i < mCollisionTriangles.size(); i += 3)
+ {
+ if (i < numTriangleVertsInCloth)
+ {
+ // only 500 triangles simulated in cuda
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorLightGray);
+ }
+ else
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorRed);
+ }
+ RENDER_DEBUG_IFACE(&renderDebug)->debugTri(mCollisionTriangles[i + 0], mCollisionTriangles[i + 1], mCollisionTriangles[i + 2]);
+ }
+
+ RENDER_DEBUG_IFACE(&renderDebug)->popRenderState();
+ }
+
+ if (clothingDebugParams.LengthFibers ||
+ clothingDebugParams.CrossSectionFibers ||
+ clothingDebugParams.BendingFibers ||
+ clothingDebugParams.ShearingFibers)
+ {
+ const uint32_t colorGreen = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Green);
+ const uint32_t colorRed = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Red);
+
+ for (uint32_t pc = 0; pc < mPhaseConfigs.size(); ++pc)
+ {
+ const uint32_t phaseIndex = mPhaseConfigs[pc].mPhaseIndex;
+ PX_ASSERT(phaseIndex < (uint32_t)mCookedData->deformablePhaseDescs.arraySizes[0]);
+
+ const uint32_t setIndex = mCookedData->deformablePhaseDescs.buf[phaseIndex].setIndex;
+
+ const PxClothFabricPhaseType::Enum type = (PxClothFabricPhaseType::Enum)mCookedData->deformablePhaseDescs.buf[phaseIndex].phaseType;
+
+ float stretchRangeMultiplier = mPhaseConfigs[pc].mStretchLimit;
+ float compressionRangeMultiplier = mPhaseConfigs[pc].mCompressionLimit;
+
+ float stiffnessScale = mPhaseConfigs[pc].mStiffnessMultiplier;
+ uint8_t brightness = (uint8_t)(64 * stiffnessScale + 64);
+ if (stiffnessScale == 1.f)
+ {
+ brightness = 255;
+ }
+ else if (stiffnessScale == 0.f)
+ {
+ brightness = 0;
+ }
+ uint32_t rangeColor = uint32_t(brightness | (brightness << 8) | (brightness << 16));
+ uint32_t stretchRangeColor = rangeColor;
+ uint32_t compressionRangeColor = rangeColor;
+ if (stretchRangeMultiplier > 1.f)
+ {
+ // red
+ rangeColor |= 0xFF << 16;
+ }
+ else if (compressionRangeMultiplier < 1.f)
+ {
+ // blue
+ rangeColor |= 0xFF << 0;
+ }
+ if (stiffnessScale == 1)
+ {
+ rangeColor = 0xFFFFFF;
+ }
+
+ bool ok = false;
+ ok |= clothingDebugParams.LengthFibers && type == PxClothFabricPhaseType::eVERTICAL;
+ ok |= clothingDebugParams.CrossSectionFibers && type == PxClothFabricPhaseType::eHORIZONTAL;
+ ok |= clothingDebugParams.BendingFibers && type == PxClothFabricPhaseType::eBENDING;
+ ok |= clothingDebugParams.ShearingFibers && type == PxClothFabricPhaseType::eSHEARING;
+
+ if (ok)
+ {
+ const uint32_t fromIndex = setIndex ? mCookedData->deformableSets.buf[setIndex - 1].fiberEnd : 0;
+ const uint32_t toIndex = mCookedData->deformableSets.buf[setIndex].fiberEnd;
+
+ if ((int32_t)toIndex > mCookedData->deformableIndices.arraySizes[0])
+ {
+ break;
+ }
+
+ for (uint32_t f = fromIndex; f < toIndex; ++f)
+ {
+ uint32_t posIndex1 = mCookedData->deformableIndices.buf[2 * f];
+ uint32_t posIndex2 = mCookedData->deformableIndices.buf[2 * f + 1];
+
+ PX_ASSERT((int32_t)posIndex2 <= mCookedData->deformableIndices.arraySizes[0]);
+ PX_ASSERT(mCookedData->deformableIndices.buf[posIndex1] < sdkNumDeformableVertices);
+
+ PxVec3 pos1 = sdkWritebackPosition[posIndex1];
+ PxVec3 pos2 = sdkWritebackPosition[posIndex2];
+
+ const float restLength = mCookedData->deformableRestLengths.buf[f] * simulation.restLengthScale;
+ PxVec3 dir = pos2 - pos1;
+ PxVec3 middle = pos1 + 0.5f * dir;
+ const float simLength = dir.normalize();
+ PxVec3 edge = dir * restLength;
+ PxVec3 e1 = middle - 0.5f * edge;
+ PxVec3 e2 = middle + 0.5f * edge;
+
+ if (clothingDebugParams.FiberRange && type != PxClothFabricPhaseType::eBENDING)
+ {
+ PxVec3 stretchRangeOffset = edge;
+ PxVec3 compressionRangeOffset = edge;
+
+ if (stretchRangeMultiplier > 1.f)
+ {
+ stretchRangeOffset *= 0.5f * (1.0f - stretchRangeMultiplier);
+
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(stretchRangeColor);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(e1, e1 + stretchRangeOffset);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(e2, e2 - stretchRangeOffset);
+ }
+
+ if (compressionRangeMultiplier < 1.f)
+ {
+ compressionRangeOffset *= 0.5f * (1.0f - compressionRangeMultiplier);
+
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(compressionRangeColor);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(e1, e1 + compressionRangeOffset);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(e2, e2 - compressionRangeOffset);
+ }
+
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(0xFFFFFFFF);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugPoint(pos1, 0.01f);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugPoint(pos2, 0.01f);
+ if (compressionRangeMultiplier < 1.0f)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(e1 + compressionRangeOffset, e2 - compressionRangeOffset);
+ }
+ else
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(e1, e2);
+ }
+ }
+ else
+ {
+ if (simLength < restLength || type == PxClothFabricPhaseType::eBENDING)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->debugGradientLine(pos1, pos2, colorGreen, colorGreen);
+ }
+ else
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->debugGradientLine(pos1, e1, colorRed, colorRed);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugGradientLine(e1, e2, colorGreen, colorGreen);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugGradientLine(e2, pos2, colorRed, colorRed);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (clothingDebugParams.TethersActive || clothingDebugParams.TethersInactive)
+ {
+ const uint32_t colorDarkBlue = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Blue);
+ const uint32_t colorLightBlue = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::LightBlue);
+ const uint32_t colorGreen = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Green);
+ const uint32_t colorRed = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Red);
+
+ const uint32_t numTetherAnchors = (uint32_t)mCookedData->tetherAnchors.arraySizes[0];
+ for (uint32_t i = 0; i < numTetherAnchors; ++i)
+ {
+ uint32_t anchorIndex = mCookedData->tetherAnchors.buf[i];
+ PX_ASSERT(anchorIndex < sdkNumDeformableVertices);
+ const PxVec3 p1 = sdkWritebackPosition[anchorIndex];
+ const PxVec3 p2 = sdkWritebackPosition[i % sdkNumDeformableVertices];
+ PxVec3 dir = p2 - p1;
+ const float d = dir.normalize();
+ const float tetherLength = mCookedData->tetherLengths.buf[i];
+
+ if (d < tetherLength)
+ {
+ if (d < tetherLength * 0.99)
+ {
+ if (clothingDebugParams.TethersInactive)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorDarkBlue);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(p1, p2);
+ }
+ }
+ else if (clothingDebugParams.TethersActive)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorLightBlue);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(p1, p2);
+ }
+ }
+ else if (clothingDebugParams.TethersActive)
+ {
+ const PxVec3 p = p1 + tetherLength * dir;
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorLightBlue);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(p1, p);
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorGreen);
+ const PxVec3 p_ = p1 + dir * PxMin(tetherLength * mTetherLimit, d);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(p, p_);
+
+ if (d > tetherLength * mTetherLimit)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorRed);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(p_, p2);
+ }
+ }
+ }
+ }
+
+ if (clothingDebugParams.MassScale && mCloth != NULL && mCloth->getCollisionMassScale() > 0.0f)
+ {
+ cloth::Range<const PxVec4> curParticles = mCloth->getCurrentParticles();
+ cloth::Range<const PxVec4> prevParticles = mCloth->getPreviousParticles();
+
+ uint32_t colorRed = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Red);
+
+ RENDER_DEBUG_IFACE(&renderDebug)->pushRenderState();
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorRed);
+
+ // draw a point anywhere the mass difference between cur and prev is non-zero
+ for (uint32_t i = 0; i < curParticles.size(); ++i)
+ {
+ float curInvMass = curParticles[i][3];
+ float prevInvMass = prevParticles[i][3];
+ float massDelta = curInvMass - prevInvMass;
+
+ // ignore prevInvMass of 0.0f because it is probably a motion constraint
+ if (massDelta > 0.0f && prevInvMass > 0.0f)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->debugPoint(PxVec3(curParticles[i][0], curParticles[i][1], curParticles[i][2]), massDelta * 10.0f);
+ }
+ }
+
+ RENDER_DEBUG_IFACE(&renderDebug)->popRenderState();
+ }
+
+ if (clothingDebugParams.VirtualCollision)
+ {
+ uint32_t colorParticle = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Gold);
+ uint32_t colorVertex = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::White);
+
+ const uint32_t numVirtualParticleIndices = (uint32_t)mCookedData->virtualParticleIndices.arraySizes[0];
+ for (uint32_t i = 0; i < numVirtualParticleIndices; i += 4)
+ {
+ const PxVec3 positions[3] =
+ {
+ sdkWritebackPosition[mCookedData->virtualParticleIndices.buf[i + 0]],
+ sdkWritebackPosition[mCookedData->virtualParticleIndices.buf[i + 1]],
+ sdkWritebackPosition[mCookedData->virtualParticleIndices.buf[i + 2]],
+ };
+
+ const uint32_t weightIndex = mCookedData->virtualParticleIndices.buf[i + 3];
+
+ PxVec3 particlePos(0.0f);
+
+ uint32_t colors[3] =
+ {
+ colorVertex,
+ colorVertex,
+ colorVertex,
+ };
+
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ const float weight = mCookedData->virtualParticleWeights.buf[3 * weightIndex + j];
+ particlePos += weight * positions[j];
+
+ uint8_t* colorParts = (uint8_t*)(colors + j);
+ for (uint32_t k = 0; k < 4; k++)
+ {
+ colorParts[k] = (uint8_t)(weight * colorParts[k]);
+ }
+ }
+
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->debugGradientLine(particlePos, positions[j], colorParticle, colors[j]);
+ }
+ }
+ }
+
+ ModuleClothingImpl* module = static_cast<ModuleClothingImpl*>(mClothingScene->getModule());
+ if (clothingDebugParams.SelfCollision && module->useSparseSelfCollision())
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->pushRenderState();
+ RENDER_DEBUG_IFACE(&renderDebug)->addToCurrentState(DebugRenderState::SolidShaded);
+
+ const PxVec3* const positions = sdkWritebackPosition;
+ uint32_t* indices = mCookedData->selfCollisionIndices.buf;
+ uint32_t numIndices = (uint32_t)mCookedData->selfCollisionIndices.arraySizes[0];
+
+ PxMat44 pose = PxMat44(PxIdentity);
+ for (uint32_t i = 0; i < numIndices; ++i)
+ {
+ uint32_t index = indices[i];
+ pose.setPosition(positions[index]);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugSphere(pose.getPosition(), 0.5f * mCloth->getSelfCollisionDistance());
+ }
+ RENDER_DEBUG_IFACE(&renderDebug)->popRenderState();
+ }
+
+ if (clothingDebugParams.SelfCollisionAttenuation > 0.0f)
+ {
+ createAttenuationData();
+
+ RENDER_DEBUG_IFACE(&renderDebug)->pushRenderState();
+
+ for (uint32_t i = 0; i < mSelfCollisionAttenuationPairs.size(); i += 2)
+ {
+ float val = mSelfCollisionAttenuationValues[i/2];
+ PX_ASSERT(val <= 1.0f);
+
+ if (val > clothingDebugParams.SelfCollisionAttenuation)
+ continue;
+
+ uint8_t c = (uint8_t)(UINT8_MAX * val);
+ if (val == 0.0f)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(0x000000FF);
+ }
+ else
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(uint32_t(c << 16 | c << 8 | c));
+ }
+ PxVec3 p0 = sdkWritebackPosition[mSelfCollisionAttenuationPairs[i]];
+ PxVec3 p1 = sdkWritebackPosition[mSelfCollisionAttenuationPairs[i+1]];
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(p0, p1);
+ }
+
+ RENDER_DEBUG_IFACE(&renderDebug)->popRenderState();
+ }
+#endif // WITHOUT_DEBUG_VISUALIZE
+}
+
+
+#ifndef WITHOUT_DEBUG_VISUALIZE
+// solver logic is replicated here
+void Simulation::createAttenuationData()
+{
+ if (mSelfCollisionAttenuationPairs.size() > 0)
+ return;
+
+ PX_ASSERT(mSelfCollisionAttenuationValues.size() == 0);
+
+ float collD2 = mCloth->getSelfCollisionDistance();
+ collD2 = collD2 * collD2;
+
+ // it's just debug rendering, n^2 probably won't hurt us here
+ for (uint32_t i = 0; i < sdkNumDeformableVertices; ++i)
+ {
+ for (uint32_t j = i+1; j < sdkNumDeformableVertices; ++j)
+ {
+ float restD2 = (mRestPositions[j] - mRestPositions[i]).magnitudeSquared();
+ if (restD2 < collD2)
+ {
+ // closer than rest distance. pair is ignored by selfcollision
+ mSelfCollisionAttenuationPairs.pushBack(PxMin(i,j));
+ mSelfCollisionAttenuationPairs.pushBack(PxMax(i,j));
+ mSelfCollisionAttenuationValues.pushBack(0.0f);
+ }
+ else if(restD2 < 4*collD2)
+ {
+ // within the doubled rest distance. selfcollision stiffness is attenuated
+ mSelfCollisionAttenuationPairs.pushBack(PxMin(i,j));
+ mSelfCollisionAttenuationPairs.pushBack(PxMax(i,j));
+
+ float ratio = sqrtf(restD2 / collD2) - 1.0f;
+ mSelfCollisionAttenuationValues.pushBack(ratio);
+ }
+ }
+ }
+}
+#endif
+
+
+
+#ifndef WITHOUT_PVD
+void Simulation::updatePvd(pvdsdk::PvdDataStream& /*pvdStream*/, pvdsdk::PvdUserRenderer& pvdRenderer, ApexResourceInterface* clothingActor, bool localSpaceSim)
+{
+ // update rendering
+ pvdRenderer.setInstanceId(clothingActor);
+
+ PX_ASSERT(sdkNumDeformableIndices%3 == 0);
+ uint32_t numTriangles = sdkNumDeformableIndices/3;
+ pvdsdk::PvdDebugTriangle* pvdTriangles = (pvdsdk::PvdDebugTriangle*)GetInternalApexSDK()->getTempMemory(numTriangles * sizeof(pvdsdk::PvdDebugTriangle));
+ uint32_t color = (uint32_t)RENDER_DEBUG::DebugColors::Yellow;
+ for (uint32_t i = 0; i < numTriangles; ++i)
+ {
+ if (localSpaceSim)
+ {
+ pvdTriangles[i].pos0 = mGlobalPose.transform(sdkWritebackPosition[mIndices[3*i+0]]);
+ pvdTriangles[i].pos1 = mGlobalPose.transform(sdkWritebackPosition[mIndices[3*i+1]]);
+ pvdTriangles[i].pos2 = mGlobalPose.transform(sdkWritebackPosition[mIndices[3*i+2]]);
+ }
+ else
+ {
+ pvdTriangles[i].pos0 = sdkWritebackPosition[mIndices[3*i+0]];
+ pvdTriangles[i].pos1 = sdkWritebackPosition[mIndices[3*i+1]];
+ pvdTriangles[i].pos2 = sdkWritebackPosition[mIndices[3*i+2]];
+ }
+
+ pvdTriangles[i].color0 = color;
+ pvdTriangles[i].color1 = color;
+ pvdTriangles[i].color2 = color;
+ }
+ pvdRenderer.drawTriangles(pvdTriangles, numTriangles);
+ GetInternalApexSDK()->releaseTempMemory(pvdTriangles);
+}
+#endif
+
+
+
+GpuSimMemType::Enum Simulation::getGpuSimMemType() const
+{
+ // should we remove this?
+ /*
+ if (mUseCuda && mCloth != NULL)
+ {
+ cloth::Solver* solver = mClothingScene->getClothSolver(mUseCuda);
+ if (solver != NULL)
+ {
+ uint32_t numSharedPos = solver->getNumSharedPositions(mCloth);
+ GpuSimMemType::Enum type = (GpuSimMemType::Enum)numSharedPos;
+ return type;
+ }
+ }
+ */
+ return GpuSimMemType::UNDEFINED;
+}
+
+
+
+void Simulation::setPositions(PxVec3* /*positions*/)
+{
+ PX_ALWAYS_ASSERT();
+ // not necessary for now, maybe when supporting physics LOD
+}
+
+
+
+void Simulation::setConstrainCoefficients(const tConstrainCoeffs* assetCoeffs, float maxDistanceBias, float maxDistanceScale, float /*maxDistanceDeform*/, float /*actorScale*/)
+{
+ if (mCloth == NULL)
+ {
+ return;
+ }
+
+ // Note: the spherical constraint distances are only computed here. They get set in the updateConstrainPositions method
+ // The reason for this is that it doesn't behave well when being set twice. Also skinnedPhysicsPositions are not
+ // always initialized when this method is called!
+
+ PX_ASSERT(mConstrainCoeffs == NULL || mConstrainCoeffs == assetCoeffs);
+ mConstrainCoeffs = assetCoeffs;
+
+ // Note: maxDistanceScale already has actorScale included...
+
+ mMotionConstrainBias = -maxDistanceBias;
+ mMotionConstrainScale = maxDistanceScale;
+
+ if (mNumBackstopConstraints == -1)
+ {
+ mNumBackstopConstraints = 0;
+ for (uint32_t i = 0; i < sdkNumDeformableVertices; i++)
+ {
+ mNumBackstopConstraints += assetCoeffs[i].collisionSphereRadius > 0.0f ? 1 : 0;
+ }
+ }
+
+ if (mConstrainConstants.size() != sdkNumDeformableVertices)
+ {
+ mConstrainConstants.resize(sdkNumDeformableVertices, ConstrainConstants());
+
+ for (uint32_t i = 0; i < sdkNumDeformableVertices; i++)
+ {
+ mConstrainConstants[i].motionConstrainDistance = PxMax(0.0f, assetCoeffs[i].maxDistance);
+ mConstrainConstants[i].backstopDistance = PxMax(0.0f, assetCoeffs[i].collisionSphereDistance) + assetCoeffs[i].collisionSphereRadius;
+ mConstrainConstants[i].backstopRadius = assetCoeffs[i].collisionSphereRadius;
+ }
+
+ mConstrainConstantsDirty = true;
+ }
+}
+
+
+
+void Simulation::getVelocities(PxVec3* velocities) const
+{
+ if (mCloth == NULL)
+ {
+ return;
+ }
+
+ PX_PROFILE_ZONE("SimulationPxCloth::getVelocities", GetInternalApexSDK()->getContextId());
+
+ PX_ALIGN(16, PxMat44 oldFrameDiff) = PxMat44(PxIdentity);
+ bool useOldFrame = false;
+ if (mGlobalPose != mGlobalPosePrevious && mLocalSpaceSim && mLastTimestep > 0.0f)
+ {
+ oldFrameDiff = mGlobalPosePrevious;
+ oldFrameDiff.column0.normalize();
+ oldFrameDiff.column1.normalize();
+ oldFrameDiff.column2.normalize();
+ const float w = mCloth->getPreviousIterationDt() / mLastTimestep;
+ oldFrameDiff = interpolateMatrix(w, oldFrameDiff, mGlobalPoseNormalized);
+ oldFrameDiff = mGlobalPoseNormalized.inverseRT() * oldFrameDiff;
+ useOldFrame = true;
+ }
+
+ const float previousIterDt = mCloth->getPreviousIterationDt();
+ const float invTimeStep = previousIterDt > 0.0f ? 1.0f / previousIterDt : 0.0f;
+
+ const cloth::Range<PxVec4> newPositions = mCloth->getCurrentParticles();
+ const cloth::Range<PxVec4> oldPositions = mCloth->getPreviousParticles();
+
+ if (useOldFrame)
+ {
+ // use SIMD code only here, it was slower for the non-matrix-multiply codepath :(
+
+ // In localspace (and if the localspace has changed, i.e. frameDiff != ID) the previous positions are in a
+ // different frame, interpolated for each iteration. We need to generate that interpolated frame (20 lines above)
+ // and then apply the diff to the previous positions to move them into the same frame as the current positions.
+ // This is the same frame as we refer to 'current local space'.
+ using namespace physx::shdfnd::aos;
+ const Vec3V invTime = V3Load(invTimeStep);
+ PX_ASSERT(((size_t)(&newPositions[0].x) & 0xf) == 0); // 16 byte aligned?
+ PX_ASSERT(((size_t)(&oldPositions[0].x) & 0xf) == 0); // 16 byte aligned?
+ const Mat34V frameDiff = (Mat34V&)oldFrameDiff;
+
+ for (uint32_t i = 0; i < sdkNumDeformableVertices; i++)
+ {
+ const Vec3V newPos = Vec3V_From_Vec4V(V4LoadA(&newPositions[i].x));
+ const Vec3V oldPos = Vec3V_From_Vec4V(V4LoadA(&oldPositions[i].x));
+ const Vec3V oldPosReal = M34MulV3(frameDiff, oldPos);
+
+ const Vec3V velocity = V3Mul(V3Sub(newPos, oldPosReal), invTime);
+ V3StoreU(velocity, velocities[i]);
+ }
+ }
+ else
+ {
+ for (uint32_t i = 0; i < sdkNumDeformableVertices; i++)
+ {
+ const PxVec3& newPos = PxVec3(newPositions[i].x, newPositions[i].y, newPositions[i].z);
+ const PxVec3& oldPos = PxVec3(oldPositions[i].x, oldPositions[i].y, oldPositions[i].z);
+
+ PxVec3 d = newPos - oldPos;
+ velocities[i] = d * invTimeStep;
+ }
+ }
+
+ // no unmap since we only read
+}
+
+
+
+void Simulation::setVelocities(PxVec3* velocities)
+{
+ if (mCloth == NULL || mIsStatic)
+ {
+ return;
+ }
+
+ PX_PROFILE_ZONE("ClothingActorImpl::setVelocities", GetInternalApexSDK()->getContextId());
+
+ const float timeStep = mCloth->getPreviousIterationDt();
+
+ cloth::Range<PxVec4> newPositions = mCloth->getCurrentParticles();
+ cloth::Range<PxVec4> oldPositions = mCloth->getPreviousParticles(); // read the data, the .w is vital!
+
+ // assuming the weights are still up to date!
+
+ PX_ALIGN(16, PxMat44 oldFrameDiff) = PxMat44(PxIdentity);
+ bool useOldFrame = false;
+ if (mGlobalPose != mGlobalPosePrevious && mLocalSpaceSim)
+ {
+ oldFrameDiff = mGlobalPosePrevious;
+ oldFrameDiff.column0.normalize();
+ oldFrameDiff.column1.normalize();
+ oldFrameDiff.column2.normalize();
+ const float w = mCloth->getPreviousIterationDt() / mLastTimestep;
+ oldFrameDiff = interpolateMatrix(w, oldFrameDiff, mGlobalPoseNormalized);
+ oldFrameDiff = oldFrameDiff.inverseRT() * mGlobalPoseNormalized;
+ useOldFrame = true;
+ }
+
+ if (useOldFrame)
+ {
+ using namespace physx::shdfnd::aos;
+
+ const Vec3V time = V3Load(timeStep);
+
+ PX_ASSERT(((size_t)(&newPositions[0].x) & 0xf) == 0); // 16 byte aligned?
+ PX_ASSERT(((size_t)(&oldPositions[0].x) & 0xf) == 0); // 16 byte aligned?
+ const Mat34V frameDiff = (Mat34V&)oldFrameDiff;
+ BoolV mask = BTTTF();
+
+ for (uint32_t i = 0; i < sdkNumDeformableVertices; i++)
+ {
+ const Vec3V velocity = V3LoadU(velocities[i]);
+ const Vec4V newPos = V4LoadA(&newPositions[i].x);
+ const Vec4V oldWeight = V4Load(oldPositions[i].w);
+ const Vec3V oldPosReal = V3NegMulSub(velocity, time, Vec3V_From_Vec4V(newPos)); // newPos - velocity * time
+ const Vec3V oldPos = M34MulV3(frameDiff, oldPosReal);
+ const Vec4V oldPosOut = V4Sel(mask, Vec4V_From_Vec3V(oldPos), oldWeight);
+
+ aos::V4StoreA(oldPosOut, &oldPositions[i].x);
+ }
+ }
+ else
+ {
+ for (uint32_t i = 0; i < sdkNumDeformableVertices; i++)
+ {
+ PxVec3* oldPos = (PxVec3*)(oldPositions.begin() + i);
+ const PxVec3* const newPos = (const PxVec3 * const)(newPositions.begin() + i);
+ *oldPos = *newPos - velocities[i] * timeStep;
+ }
+ }
+}
+
+
+
+bool Simulation::applyWind(PxVec3* velocities, const PxVec3* normals, const tConstrainCoeffs* coeffs, const PxVec3& wind, float adaption, float /*dt*/)
+{
+ if (mCloth == NULL || mIsStatic)
+ {
+ return false;
+ }
+
+ // here we leave velocities untouched
+
+ if (adaption > 0.0f)
+ {
+ cloth::Range<PxVec4> accelerations = mCloth->getParticleAccelerations();
+ for (uint32_t i = 0; i < sdkNumDeformableVertices; i++)
+ {
+ PxVec3 velocity = velocities[i];
+ PxVec3 dv = wind - velocity;
+
+ if (coeffs[i].maxDistance > 0.0f && !dv.isZero())
+ {
+ // scale the wind depending on angle
+ PxVec3 normalizedDv = dv;
+ normalizedDv *= ModuleClothingHelpers::invSqrt(normalizedDv.magnitudeSquared());
+ const float dot = normalizedDv.dot(normals[i]);
+ dv *= PxMin(1.0f, PxAbs(dot) * adaption); // factor should not exceed 1.0f
+
+ // We set the acceleration such that we get
+ // end velocity = velocity + (wind - velocity) * dot * adaption * dt.
+ // using
+ // end velocity = velocity + acceleration * dt
+ accelerations[i] = PxVec4(dv, 0.0f);
+ }
+ else
+ {
+ accelerations[i].setZero();
+ }
+ }
+ }
+ else
+ {
+ mCloth->clearParticleAccelerations();
+ }
+
+ return false;
+}
+
+
+void Simulation::setTeleportWeight(float weight, bool reset, bool localSpaceSim)
+{
+ if (mCloth != NULL && weight > 0.0f && !mIsStatic)
+ {
+ mTeleported = true;
+
+ if (reset)
+ {
+ cloth::Range<PxVec4> curPos = mCloth->getCurrentParticles();
+ cloth::Range<PxVec4> prevPos = mCloth->getPreviousParticles();
+
+ const uint32_t numParticles = (uint32_t)curPos.size();
+ for (uint32_t i = 0; i < numParticles; i++)
+ {
+ curPos[i] = PxVec4(skinnedPhysicsPositions[i], curPos[i].w);
+ prevPos[i] = PxVec4(skinnedPhysicsPositions[i], prevPos[i].w);
+ }
+ mCloth->clearParticleAccelerations();
+ }
+ else if (!localSpaceSim)
+ {
+ cloth::Range<PxVec4> curPos = mCloth->getCurrentParticles();
+ cloth::Range<PxVec4> prevPos = mCloth->getPreviousParticles();
+
+ const uint32_t numParticles = (uint32_t)curPos.size();
+
+ PxMat44 globalPosePreviousNormalized = mGlobalPosePrevious;
+ globalPosePreviousNormalized.column0.normalize();
+ globalPosePreviousNormalized.column1.normalize();
+ globalPosePreviousNormalized.column2.normalize();
+
+ const PxMat44 realTransform = mGlobalPoseNormalized * globalPosePreviousNormalized.inverseRT();
+
+ for (uint32_t i = 0; i < numParticles; i++)
+ {
+ curPos[i] = PxVec4(realTransform.transform(sdkWritebackPosition[i]), curPos[i].w);
+ prevPos[i] = PxVec4(realTransform.transform(prevPos[i].getXYZ()), prevPos[i].w);
+ }
+ }
+ }
+
+ mLocalSpaceSim = localSpaceSim;
+}
+
+
+
+void Simulation::setSolverIterations(uint32_t /*iterations*/)
+{
+ /*
+ if (mCloth != NULL)
+ {
+ mSolverIterationsPerSecond = iterations * 50.0f;
+ mCloth->setSolverFrequency(mSolverIterationsPerSecond);
+ }
+ */
+}
+
+
+
+void Simulation::updateConstrainPositions(bool isDirty)
+{
+ if (mCloth == NULL || mIsStatic)
+ {
+ return;
+ }
+
+ PX_ASSERT(mConstrainCoeffs != NULL); // guarantees that setConstrainCoefficients has been called before!
+
+ if (mConstrainConstantsDirty || isDirty)
+ {
+ if (mTeleported)
+ {
+ mCloth->clearMotionConstraints();
+ }
+ cloth::Range<PxVec4> sphericalConstraints = mCloth->getMotionConstraints();
+
+ PX_ASSERT(sphericalConstraints.size() == sdkNumDeformableVertices);
+
+ for (uint32_t i = 0; i < sdkNumDeformableVertices; i++)
+ {
+ // we also must write the .w component to be sure everything works!
+ sphericalConstraints[i] = PxVec4(skinnedPhysicsPositions[i], mConstrainConstants[i].motionConstrainDistance);
+ }
+
+ if (mNumBackstopConstraints > 0)
+ {
+ if (mTeleported)
+ {
+ mCloth->clearSeparationConstraints();
+ }
+ cloth::Range<PxVec4> backstopConstraints = mCloth->getSeparationConstraints();
+
+ for (uint32_t i = 0; i < sdkNumDeformableVertices; i++)
+ {
+ backstopConstraints[i] = PxVec4(skinnedPhysicsPositions[i] - mConstrainConstants[i].backstopDistance * skinnedPhysicsNormals[i], mConstrainConstants[i].backstopRadius);
+ }
+ }
+
+ mConstrainConstantsDirty = false;
+ }
+
+ mCloth->setMotionConstraintScaleBias(mMotionConstrainScale, mMotionConstrainBias);
+}
+
+
+
+bool Simulation::applyClothingMaterial(tMaterial* material, PxVec3 scaledGravity)
+{
+ if (mCloth == NULL || material == NULL || mIsStatic)
+ {
+ return false;
+ }
+
+ // solver iterations
+ mCloth->setSolverFrequency(material->solverFrequency);
+
+ // filter window for handling dynamic timesteps. smooth over 2s.
+ mCloth->setAcceleationFilterWidth(2 * (uint32_t)material->solverFrequency);
+
+ // damping scale is here to remove the influence of the stiffness frequency from all damping values
+ // (or to be more precise, to use 10 as a stiffness frequency)
+ const float dampingStiffnessFrequency = 10.0f;
+ const float exponentDamping = dampingStiffnessFrequency / material->stiffnessFrequency * physx::shdfnd::log2(1 - material->damping);
+ const float exponentDrag = dampingStiffnessFrequency / material->stiffnessFrequency * physx::shdfnd::log2(1 - material->drag);
+ const float newDamping = 1.0f - ::expf(exponentDamping * 0.693147180559945309417f); // exp -> exp2, 0.69 = ln(2)
+ const float newDrag = 1.0f - ::expf(exponentDrag * 0.693147180559945309417f); // exp -> exp2
+
+ // damping
+ // TODO damping as vector
+ mCloth->setDamping(PxVec3(newDamping));
+
+ mCloth->setStiffnessFrequency(material->stiffnessFrequency);
+
+ // drag
+ // TODO expose linear and angular drag separately
+ mCloth->setLinearDrag(PxVec3(newDrag));
+ mCloth->setAngularDrag(PxVec3(newDrag));
+
+ // friction
+ mCloth->setFriction(material->friction);
+
+ // gravity
+ PxVec3 gravity;
+ gravity[0] = scaledGravity.x * material->gravityScale;
+ gravity[1] = scaledGravity.y * material->gravityScale;
+ gravity[2] = scaledGravity.z * material->gravityScale;
+ mScaledGravity = scaledGravity * material->gravityScale;
+ mCloth->setGravity(mScaledGravity);
+
+ // inertia scale
+ // TODO expose linear and angular inertia separately
+ mCloth->setLinearInertia(PxVec3(material->inertiaScale));
+ mCloth->setAngularInertia(PxVec3(material->inertiaScale));
+
+ // mass scale
+ mCloth->setCollisionMassScale(material->massScale);
+
+ // tether settings
+ mCloth->setTetherConstraintScale(material->tetherLimit);
+ mCloth->setTetherConstraintStiffness(material->tetherStiffness);
+
+
+ // remember for debug rendering
+ mTetherLimit = material->tetherLimit;
+
+ // self collision
+ // clear debug render data if it's not needed, or stale
+ if(mClothingScene->getDebugRenderParams()->SelfCollisionAttenuation == 0.0f || material->selfcollisionThickness * mActorScale != mCloth->getSelfCollisionDistance())
+ {
+ mSelfCollisionAttenuationPairs.clear();
+ mSelfCollisionAttenuationValues.clear();
+ }
+
+ if ( (mCloth->getSelfCollisionDistance() == 0.0f || mCloth->getSelfCollisionStiffness() == 0.0f)
+ && (material->selfcollisionThickness * mActorScale > 0.0f && material->selfcollisionStiffness > 0.0)
+ )
+ {
+ // turning on
+ setRestPositions(true);
+ }
+ else if( (mCloth->getSelfCollisionDistance() > 0.0f && mCloth->getSelfCollisionStiffness() > 0.0f)
+ && (material->selfcollisionThickness * mActorScale == 0.0f || material->selfcollisionStiffness == 0.0)
+ )
+ {
+ // turning off
+ setRestPositions(false);
+ }
+ mCloth->setSelfCollisionDistance(material->selfcollisionThickness * mActorScale);
+ mCloth->setSelfCollisionStiffness(material->selfcollisionStiffness);
+
+ for (uint32_t i = 0; i < mPhaseConfigs.size(); i++)
+ {
+ PxClothFabricPhaseType::Enum phaseType = (PxClothFabricPhaseType::Enum)mCookedData->deformablePhaseDescs.buf[mPhaseConfigs[i].mPhaseIndex].phaseType;
+
+ if (phaseType == PxClothFabricPhaseType::eVERTICAL)
+ {
+ mPhaseConfigs[i].mStiffness = material->verticalStretchingStiffness;
+ mPhaseConfigs[i].mStiffnessMultiplier = material->verticalStiffnessScaling.scale;
+ mPhaseConfigs[i].mCompressionLimit = material->verticalStiffnessScaling.compressionRange;
+ mPhaseConfigs[i].mStretchLimit = material->verticalStiffnessScaling.stretchRange;
+ }
+ else if (phaseType == PxClothFabricPhaseType::eHORIZONTAL)
+ {
+ mPhaseConfigs[i].mStiffness = material->horizontalStretchingStiffness;
+ mPhaseConfigs[i].mStiffnessMultiplier = material->horizontalStiffnessScaling.scale;
+ mPhaseConfigs[i].mCompressionLimit = material->horizontalStiffnessScaling.compressionRange;
+ mPhaseConfigs[i].mStretchLimit = material->horizontalStiffnessScaling.stretchRange;
+ }
+ else if (phaseType == PxClothFabricPhaseType::eBENDING)
+ {
+ mPhaseConfigs[i].mStiffness = material->bendingStiffness;
+ mPhaseConfigs[i].mStiffnessMultiplier = material->bendingStiffnessScaling.scale;
+ mPhaseConfigs[i].mCompressionLimit = material->bendingStiffnessScaling.compressionRange;
+ mPhaseConfigs[i].mStretchLimit = material->bendingStiffnessScaling.stretchRange;
+ }
+ else
+ {
+ PX_ASSERT(phaseType == PxClothFabricPhaseType::eSHEARING);
+ mPhaseConfigs[i].mStiffness = material->shearingStiffness;
+ mPhaseConfigs[i].mStiffnessMultiplier = material->shearingStiffnessScaling.scale;
+ mPhaseConfigs[i].mCompressionLimit = material->shearingStiffnessScaling.compressionRange;
+ mPhaseConfigs[i].mStretchLimit = material->shearingStiffnessScaling.stretchRange;
+ }
+ }
+
+ cloth::Range<cloth::PhaseConfig> phaseConfig(mPhaseConfigs.begin(), mPhaseConfigs.end());
+ mCloth->setPhaseConfig(phaseConfig);
+
+ return true;
+}
+
+
+
+void Simulation::setRestPositions(bool on)
+{
+ if (mCloth == NULL || mIsStatic)
+ return;
+
+
+ if (on)
+ {
+ PxVec4* tempRestPositions = (PxVec4*)GetInternalApexSDK()->getTempMemory(sdkNumDeformableVertices * sizeof(PxVec4));
+
+ for (uint32_t i = 0; i < sdkNumDeformableVertices; ++i)
+ {
+ tempRestPositions[i] = PxVec4(mRestPositions[i]*mActorScale, 0.0f);
+ }
+
+ mCloth->setRestPositions(cloth::Range<PxVec4>(tempRestPositions, tempRestPositions + sdkNumDeformableVertices));
+
+ GetInternalApexSDK()->releaseTempMemory(tempRestPositions);
+ }
+ else
+ {
+ mCloth->setRestPositions(cloth::Range<PxVec4>());
+ }
+}
+
+
+
+void Simulation::applyClothingDesc(tClothingDescTemplate& /*clothingTemplate*/)
+{
+}
+
+
+
+void Simulation::setInterCollisionChannels(uint32_t channels)
+{
+ if (mCloth != NULL)
+ {
+ mCloth->setUserData((void*)(size_t)channels);
+ }
+}
+
+
+#if APEX_UE4
+void Simulation::simulate(float dt)
+{
+ return mCloth->simulate(dt);
+}
+#endif
+
+
+void Simulation::setHalfPrecisionOption(bool isAllowed)
+{
+ if (mCloth != NULL)
+ {
+ mCloth->setHalfPrecisionOption(isAllowed);
+ }
+}
+
+
+
+void Simulation::releaseFabric(NvParameterized::Interface* _cookedData)
+{
+ if (::strcmp(_cookedData->className(), ClothingCookedPhysX3Param::staticClassName()) == 0)
+ {
+ ClothingCookedPhysX3Param* cookedData = static_cast<ClothingCookedPhysX3Param*>(_cookedData);
+
+ while (cookedData != NULL)
+ {
+ if (cookedData->fabricCPU != NULL)
+ {
+ cloth::Fabric* fabric = static_cast<cloth::Fabric*>(cookedData->fabricCPU);
+ delete fabric;
+ cookedData->fabricCPU = NULL;
+ }
+
+ for (int32_t i = 0; i < cookedData->fabricGPU.arraySizes[0]; ++i)
+ {
+ cloth::Fabric* fabric = static_cast<cloth::Fabric*>(cookedData->fabricGPU.buf[i].fabricGPU);
+ delete fabric;
+ }
+ NvParameterized::Handle handle(*cookedData);
+ if (cookedData->getParameterHandle("fabricGPU", handle) == NvParameterized::ERROR_NONE)
+ {
+ handle.resizeArray(0);
+ }
+
+ cookedData = static_cast<ClothingCookedPhysX3Param*>(cookedData->nextCookedData);
+ }
+ }
+}
+
+
+
+void Simulation::applyCollision()
+{
+ if (mCloth != NULL && !mIsStatic)
+ {
+ // spheres
+ uint32_t numReleased = mReleasedSphereIds.size();
+ if (numReleased > 0)
+ {
+ // remove all deleted spheres
+ // biggest id's first, such that we don't
+ // invalidate remaining id's
+ nvidia::sort<uint32_t>(&mReleasedSphereIds[0], numReleased);
+ for (int32_t i = (int32_t)numReleased-1; i >= 0; --i)
+ {
+ uint32_t id = mReleasedSphereIds[(uint32_t)i];
+ if(id < 32)
+ {
+ mCloth->setSpheres(cloth::Range<const PxVec4>(),id, id+1);
+ }
+ }
+ mReleasedSphereIds.clear();
+ }
+ PxVec4* end = (mCollisionSpheres.size() > 32) ? mCollisionSpheres.begin() + 32 : mCollisionSpheres.end();
+ cloth::Range<const PxVec4> spheres((PxVec4*)mCollisionSpheres.begin(), end);
+ mCloth->setSpheres(spheres, 0, mCloth->getNumSpheres());
+
+ // capsules
+ cloth::Range<const uint32_t> capsules(mCollisionCapsules.begin(), mCollisionCapsules.end());
+ mCloth->setCapsules(capsules, 0, mCloth->getNumCapsules());
+
+ // planes
+ numReleased = mReleasedPlaneIds.size();
+ if (numReleased > 0)
+ {
+ // remove all deleted planes
+ // biggest id's first, such that we don't
+ // invalidate remaining id's
+ nvidia::sort<uint32_t>(&mReleasedPlaneIds[0], numReleased);
+ for (int32_t i = (int32_t)numReleased-1; i >= 0; --i)
+ {
+ uint32_t id = mReleasedPlaneIds[(uint32_t)i];
+ if(id < 32)
+ {
+ mCloth->setPlanes(cloth::Range<const PxVec4>(),id, id+1);
+ }
+ }
+ mReleasedPlaneIds.clear();
+ }
+
+ end = (mCollisionPlanes.size() > 32) ? mCollisionPlanes.begin() + 32 : mCollisionPlanes.end();
+ cloth::Range<const PxVec4> planes((PxVec4*)mCollisionPlanes.begin(), end);
+ mCloth->setPlanes(planes, 0, mCloth->getNumPlanes());
+
+ // convexes
+ cloth::Range<const uint32_t> convexes(mCollisionConvexes.begin(), mCollisionConvexes.end());
+ mCloth->setConvexes(convexes,0,mCloth->getNumConvexes());
+
+ // triangle meshes
+ // If mCollisionTrianglesOld is empty, updateCollision hasn't been called.
+ // In that case there have been no changes, so use the same buffer for old
+ // and new triangle positions.
+ cloth::Range<const PxVec3> trianglesOld(
+ (mCollisionTrianglesOld.size() > 0) ? mCollisionTrianglesOld.begin() : mCollisionTriangles.begin(),
+ (mCollisionTrianglesOld.size() > 0) ? mCollisionTrianglesOld.end() : mCollisionTriangles.end()
+ );
+ cloth::Range<const PxVec3> triangles(mCollisionTriangles.begin(), mCollisionTriangles.end());
+ mCloth->setTriangles(trianglesOld, triangles, 0);
+ mCollisionTrianglesOld.clear();
+
+ mCloth->enableContinuousCollision(!simulation.disableCCD);
+ if (mTeleported)
+ {
+ mCloth->clearInterpolation();
+ }
+ }
+}
+
+
+
+bool Simulation::allocateHostMemory(MappedArray& mappedArray)
+{
+ bool allocated = false;
+ if (mappedArray.hostMemory.size() != mappedArray.deviceMemory.size())
+ {
+ mappedArray.hostMemory.resize((uint32_t)mappedArray.deviceMemory.size());
+ allocated = true; // read the first time to init the data!
+ }
+ return allocated;
+}
+
+
+
+ClothingSceneSimulateTask::ClothingSceneSimulateTask(SceneIntl* apexScene, ClothingScene* scene, ModuleClothingImpl* module, profile::PxProfileZoneManager* manager) :
+ mModule(module),
+ mApexScene(apexScene),
+ mScene(scene),
+ mSimulationDelta(0.0f),
+ mSolverGPU(NULL), mSolverCPU(NULL),
+ mProfileSolverGPU(NULL), mProfileSolverCPU(NULL),
+ mWaitForSolverTask(NULL),
+ mProfileManager(manager),
+ mFailedGpuFactory(false)
+{
+ PX_UNUSED(mFailedGpuFactory);
+#ifndef PHYSX_PROFILE_SDK
+ PX_UNUSED(mProfileSolverGPU);
+#endif
+}
+
+
+
+ClothingSceneSimulateTask::~ClothingSceneSimulateTask()
+{
+ PX_ASSERT(mSolverGPU == NULL);
+
+ if (mSolverCPU != NULL)
+ {
+ delete mSolverCPU;
+ mSolverCPU = NULL;
+ }
+
+#ifdef PHYSX_PROFILE_SDK
+ if (mProfileSolverGPU != NULL)
+ {
+ mProfileSolverGPU->release();
+ mProfileSolverGPU = NULL;
+ }
+
+ if (mProfileSolverCPU != NULL)
+ {
+ mProfileSolverCPU->release();
+ mProfileSolverCPU = NULL;
+ }
+#endif
+}
+
+
+
+void ClothingSceneSimulateTask::setWaitTask(PxBaseTask* waitForSolver)
+{
+ mWaitForSolverTask = waitForSolver;
+}
+
+
+
+void ClothingSceneSimulateTask::setDeltaTime(float simulationDelta)
+{
+ mSimulationDelta = simulationDelta;
+}
+
+
+
+float ClothingSceneSimulateTask::getDeltaTime()
+{
+ return mSimulationDelta;
+}
+
+
+
+cloth::Solver* ClothingSceneSimulateTask::getSolver(ClothFactory factory)
+{
+ PX_ASSERT(factory.factory != NULL);
+ PX_ASSERT(factory.mutex != NULL);
+
+#if PX_WINDOWS_FAMILY
+ if (factory.factory->getPlatform() == cloth::Factory::CUDA)
+ {
+ if (mSolverGPU == NULL)
+ {
+ PX_ASSERT(mProfileSolverGPU == NULL);
+ if (mProfileManager != NULL)
+ {
+#ifdef PHYSX_PROFILE_SDK
+ mProfileSolverGPU = &mProfileManager->createProfileZone("CUDA Cloth", profile::PxProfileNames());
+#endif
+ }
+
+ nvidia::Mutex::ScopedLock wlock(*factory.mutex);
+ mSolverGPU = factory.factory->createSolver(mProfileSolverGPU, mApexScene->getTaskManager());
+ }
+
+ PX_ASSERT(mSolverGPU != NULL);
+ return mSolverGPU;
+ }
+#endif
+
+ if (factory.factory->getPlatform() == cloth::Factory::CPU && mSolverCPU == NULL)
+ {
+ PX_ASSERT(mProfileSolverCPU == NULL);
+ if (mProfileManager != NULL)
+ {
+#ifdef PHYSX_PROFILE_SDK
+ mProfileSolverCPU = &mProfileManager->createProfileZone("CPU Cloth", profile::PxProfileNames());
+#endif
+ }
+
+ nvidia::Mutex::ScopedLock wlock(*factory.mutex);
+ mSolverCPU = factory.factory->createSolver(mProfileSolverCPU, mApexScene->getTaskManager());
+ }
+
+ PX_ASSERT(mSolverCPU != NULL);
+ return mSolverCPU;
+}
+
+
+
+void ClothingSceneSimulateTask::clearGpuSolver()
+{
+#if PX_WINDOWS_FAMILY
+
+#ifdef PHYSX_PROFILE_SDK
+ if (mProfileSolverGPU != NULL)
+ {
+ mProfileSolverGPU->release();
+ mProfileSolverGPU = NULL;
+ }
+#endif
+
+ if (mSolverGPU != NULL)
+ {
+ delete mSolverGPU;
+ mSolverGPU = NULL;
+ }
+#endif
+}
+
+
+
+void ClothingSceneSimulateTask::run()
+{
+ PX_ASSERT(mSimulationDelta > 0.0f);
+ PX_ASSERT(mWaitForSolverTask != NULL);
+
+ mScene->setSceneRunning(true);
+
+ PxBaseTask* task1 = NULL;
+ PxBaseTask* task2 = NULL;
+
+ float interCollisionDistance = mModule->getInterCollisionDistance();
+ float interCollisionStiffness = mModule->getInterCollisionStiffness();
+ uint32_t interCollisionIterations = mModule->getInterCollisionIterations();
+
+ if (mSolverCPU != NULL)
+ {
+ mSolverCPU->setInterCollisionDistance(interCollisionDistance);
+ mSolverCPU->setInterCollisionStiffness(interCollisionStiffness);
+ mSolverCPU->setInterCollisionNbIterations(interCollisionIterations);
+ mSolverCPU->setInterCollisionFilter(interCollisionFilter);
+
+ task1 = &mSolverCPU->simulate(mSimulationDelta, *mWaitForSolverTask);
+ }
+ if (mSolverGPU != NULL)
+ {
+ mSolverGPU->setInterCollisionDistance(interCollisionDistance);
+ mSolverGPU->setInterCollisionStiffness(interCollisionStiffness);
+ mSolverGPU->setInterCollisionNbIterations(interCollisionIterations);
+ mSolverGPU->setInterCollisionFilter(interCollisionFilter);
+
+ task2 = &mSolverGPU->simulate(mSimulationDelta, *mWaitForSolverTask);
+ }
+
+ // only remove the references when both simulate() methods have been called
+ if (task1 != NULL)
+ {
+ task1->removeReference();
+ }
+
+ if (task2 != NULL)
+ {
+ task2->removeReference();
+ }
+}
+
+
+
+const char* ClothingSceneSimulateTask::getName() const
+{
+ return "Simulate";
+}
+
+
+
+bool ClothingSceneSimulateTask::interCollisionFilter(void* user0, void* user1)
+{
+ size_t collisionChannels0 = reinterpret_cast<size_t>(user0);
+ size_t collisionChannels1 = reinterpret_cast<size_t>(user1);
+ return (collisionChannels0 & collisionChannels1) > 0;
+}
+
+
+
+WaitForSolverTask::WaitForSolverTask(ClothingScene* scene) :
+ mScene(scene)
+{
+}
+
+
+
+void WaitForSolverTask::run()
+{
+ mScene->setSceneRunning(false);
+ mScene->embeddedPostSim();
+}
+
+const char* WaitForSolverTask::getName() const
+{
+ return "WaitForSolverTask";
+}
+
+}
+} // namespace nvidia
diff --git a/APEX_1.4/module/clothing/include/AbstractMeshDescription.h b/APEX_1.4/module/clothing/include/AbstractMeshDescription.h
new file mode 100644
index 00000000..aac0e1e7
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/AbstractMeshDescription.h
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+
+#ifndef ABSTRACT_MESH_DESCRIPTION_H
+#define ABSTRACT_MESH_DESCRIPTION_H
+
+#include <ApexUsingNamespace.h>
+#include "PxVec3.h"
+
+class ClothConstrainCoefficients;
+
+
+namespace nvidia
+{
+namespace apex
+{
+
+class RenderDebugInterface;
+/**
+\brief a simplified, temporal container for a mesh with non-interleaved vertex buffers
+*/
+
+struct AbstractMeshDescription
+{
+ AbstractMeshDescription() : numVertices(0), numIndices(0), numBonesPerVertex(0),
+ pPosition(NULL), pNormal(NULL), pTangent(NULL), pTangent4(NULL), pBitangent(NULL),
+ pBoneIndices(NULL), pBoneWeights(NULL), pConstraints(NULL), pVertexFlags(NULL), pIndices(NULL),
+ avgEdgeLength(0.0f), avgTriangleArea(0.0f), pMin(0.0f), pMax(0.0f), centroid(0.0f), radius(0.0f) {}
+
+ /// the number of vertices in the mesh
+ uint32_t numVertices;
+ /// the number of indices in the mesh
+ uint32_t numIndices;
+ /// the number of bones per vertex in the boneIndex and boneWeights buffer. Can be 0
+ uint32_t numBonesPerVertex;
+
+ /// pointer to the positions array
+ PxVec3* PX_RESTRICT pPosition;
+ /// pointer to the normals array
+ PxVec3* PX_RESTRICT pNormal;
+ /// pointer to the tangents array
+ PxVec3* PX_RESTRICT pTangent;
+ /// alternative pointer to the tangents array, with float4
+ PxVec4* PX_RESTRICT pTangent4;
+ /// pointer to the bitangents/binormal array
+ PxVec3* PX_RESTRICT pBitangent;
+ /// pointer to the bone indices array
+ uint16_t* PX_RESTRICT pBoneIndices;
+ /// pointer to the bone weights array
+ float* PX_RESTRICT pBoneWeights;
+ /// pointer to the cloth constraints array
+ ClothConstrainCoefficients* PX_RESTRICT pConstraints;
+ /// pointer to per-vertex flags
+ uint32_t* PX_RESTRICT pVertexFlags;
+ /// pointer to the indices array
+ uint32_t* PX_RESTRICT pIndices;
+
+ /// updates the derived data
+ void UpdateDerivedInformation(RenderDebugInterface* renderDebug);
+
+ /// Derived Data, average Edge Length
+ float avgEdgeLength;
+ /// Derived Data, average Triangle Area
+ float avgTriangleArea;
+ /// Derived Data, Bounding Box min value
+ PxVec3 pMin;
+ /// Derived Data, Bounding Box max value
+ PxVec3 pMax;
+ /// Derived Data, Average of pMin and pMax
+ PxVec3 centroid;
+ /// Derived Data, Half the distance between pMin and pMax
+ float radius;
+};
+
+}
+}
+
+
+#endif // ABSTRACT_MESH_DESCRIPTION_H
diff --git a/APEX_1.4/module/clothing/include/ClothStructs.h b/APEX_1.4/module/clothing/include/ClothStructs.h
new file mode 100644
index 00000000..6a1bd07b
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/ClothStructs.h
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+
+#ifndef CLOTH_STRUCTS_H
+#define CLOTH_STRUCTS_H
+
+
+namespace nvidia
+{
+
+namespace shdfnd
+{
+template <typename Alloc> class MutexT;
+}
+
+namespace cloth
+{
+ class Factory;
+}
+
+namespace clothing
+{
+
+struct ClothFactory
+{
+ PX_INLINE ClothFactory(cloth::Factory* f, nvidia::MutexT< ReflectionAllocator<MutexImpl> >* m) : factory(f), mutex(m) {}
+
+ PX_INLINE void clear()
+ {
+ factory = NULL;
+ mutex = NULL;
+ }
+
+ cloth::Factory* factory;
+ nvidia::MutexT< ReflectionAllocator<MutexImpl> >* mutex;
+};
+
+
+}
+}
+
+
+#endif // CLOTH_STRUCTS_H
diff --git a/APEX_1.4/module/clothing/include/ClothingActorData.h b/APEX_1.4/module/clothing/include/ClothingActorData.h
new file mode 100644
index 00000000..fa788054
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/ClothingActorData.h
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ */
+
+
+#ifndef CLOTHING_ACTOR_DATA_H
+#define CLOTHING_ACTOR_DATA_H
+
+#include "ClothingAssetData.h"
+#include "PsMutex.h"
+#include "PxMat44.h"
+#include "PxVec3.h"
+
+#define BLOCK_SIZE_SKIN_PHYSICS (32768*6) + (8192*0)
+
+namespace nvidia
+{
+namespace clothing
+{
+
+/*
+ * A wrapper around the data contained in ClothingActorImpl minus all the interface stuff
+ */
+class ClothingActorData
+{
+public:
+
+ ClothingActorData();
+ ~ClothingActorData();
+
+ void skinToAnimation_NoPhysX(bool fromFetchResults);
+
+ void skinPhysicsMaxDist0Normals_NoPhysx();
+
+ void renderDataLock();
+
+ void renderDataUnLock();
+
+ void skinToPhysicalMesh_NoPhysX(bool fromFetchResults);
+
+ void skinToImmediateMap(const uint32_t* immediateClothMap_, uint32_t numGraphicalVertices_, uint32_t numSrcVertices_,
+ const PxVec3* srcPositions_);
+
+ void skinToImmediateMap(const uint32_t* immediateClothMap_, uint32_t numGraphicalVertices_, uint32_t numSrcVertices_,
+ const PxVec3* srcPositions_, const PxVec3* srcNormals_);
+
+ void finalizeSkinning_NoPhysX(bool fromFetchResults);
+
+ template <bool withNormals, bool withTangents>
+ void computeTangentSpaceUpdate(AbstractMeshDescription& destMesh, const ClothingMeshAssetData& rendermesh, uint32_t submeshIndex, const uint32_t* compressedTangentW);
+
+ void tickSynchAfterFetchResults_LocksPhysX();
+
+ uint32_t skinPhysicsSimpleMem() const;
+ void skinPhysicsMeshSimple();
+
+ PxBounds3 getRenderMeshAssetBoundsTransformed();
+
+ // is valid only after lodTick
+ bool calcIfSimplePhysicsMesh() const;
+
+ PX_ALIGN(16, nvidia::AtomicLockCopy mRenderLock);
+
+ ClothingAssetData mAsset;
+
+ PxBounds3 mNewBounds;
+
+ PX_ALIGN(16, PxMat44 mGlobalPose);
+ PxMat44 mInternalGlobalPose;
+
+ PxMat44* mInternalBoneMatricesCur;
+ PxMat44* mInternalBoneMatricesPrev;
+
+ PxVec3* mRenderingDataPosition;
+ PxVec3* mRenderingDataNormal;
+ PxVec4* mRenderingDataTangent;
+ PxVec3* mMorphDisplacementBuffer;
+
+ PxVec3* mSdkWritebackNormal;
+ PxVec3* mSdkWritebackPositions;
+
+ PxVec3* mSkinnedPhysicsPositions;
+ PxVec3* mSkinnedPhysicsNormals;
+
+ uint32_t mInternalMatricesCount;
+ uint32_t mMorphDisplacementBufferCount;
+ uint32_t mSdkDeformableVerticesCount;
+ uint32_t mSdkDeformableIndicesCount;
+
+ uint32_t mCurrentGraphicalLodId;
+ uint32_t mCurrentPhysicsSubmesh;
+
+ float mActorScale;
+
+ // Note - all these modified bools need to be written back to the actor!!!!
+ bool bInternalFrozen;
+ bool bShouldComputeRenderData;
+ bool bIsInitialized;
+ bool bIsSimulationMeshDirty;
+ bool bRecomputeNormals;
+ bool bRecomputeTangents;
+ bool bCorrectSimulationNormals;
+ bool bParallelCpuSkinning;
+ bool bIsClothingSimulationNull;
+};
+
+}
+} // namespace nvidia
+
+#endif // CLOTHING_ACTOR_DATA_H
diff --git a/APEX_1.4/module/clothing/include/ClothingActorImpl.h b/APEX_1.4/module/clothing/include/ClothingActorImpl.h
new file mode 100644
index 00000000..665cb740
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/ClothingActorImpl.h
@@ -0,0 +1,529 @@
+/*
+ * 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.
+ */
+
+
+#ifndef CLOTHING_ACTOR_IMPL_H
+#define CLOTHING_ACTOR_IMPL_H
+
+#include "ApexActor.h"
+#include "ModuleClothingHelpers.h"
+
+#include "ClothingActorParam.h"
+#include "ClothingMaterialLibraryParameters.h"
+#include "ClothingActorTasks.h"
+
+#include "ClothingActor.h"
+#include "ClothingActorData.h"
+
+#include "ClothingCollisionImpl.h"
+
+#include "ClothingRenderProxyImpl.h"
+
+#if !APEX_UE4
+#include "PsSync.h"
+#endif
+
+#pragma warning(push)
+#pragma warning(disable:4324)
+
+namespace physx
+{
+ namespace pvdsdk
+ {
+ class PvdDataStream;
+ class PvdConnectionManager;
+ }
+}
+
+namespace nvidia
+{
+namespace apex
+{
+class RenderMeshActorIntl;
+class RenderDebugInterface;
+class ClothingVelocityCallback;
+}
+namespace clothing
+{
+
+class ClothingActorProxy;
+class ClothingAssetImpl;
+class ClothingCookingTask;
+class ClothingMaterial;
+class ClothingPreviewProxy;
+class ClothingScene;
+class ClothingCookedParam;
+class SimulationAbstract;
+
+namespace ClothingMaterialLibraryParametersNS
+{
+struct ClothingMaterial_Type;
+}
+
+namespace ClothingPhysicalMeshParametersNS
+{
+struct SkinClothMapB_Type;
+struct SkinClothMapD_Type;
+struct PhysicalMesh_Type;
+}
+
+
+
+struct ClothingGraphicalMeshActor
+{
+ ClothingGraphicalMeshActor() : active(false), needsTangents(false), renderProxy(NULL)
+ {
+ }
+
+ bool active;
+ bool needsTangents;
+ Array<uint32_t> morphTargetVertexOffsets;
+
+ ClothingRenderProxyImpl* renderProxy;
+};
+
+
+#if !APEX_UE4
+class ClothingWaitForFetchTask : public PxTask
+{
+public:
+ ClothingWaitForFetchTask()
+ {
+ mWaiting.set();
+ }
+
+ virtual void run();
+ virtual void release();
+ virtual const char* getName() const;
+
+ Sync mWaiting;
+};
+#endif
+
+
+class ClothingActorImpl : public ApexActor, public ApexResource
+{
+public:
+ ClothingActorImpl(const NvParameterized::Interface& desc, ClothingActorProxy* apiProxy, ClothingPreviewProxy*, ClothingAssetImpl* asset, ClothingScene* scene);
+
+ ClothingActorProxy* mActorProxy;
+ ClothingPreviewProxy* mPreviewProxy;
+
+ // from ApexInterface
+ void release();
+
+ // from Actor
+ PX_INLINE ClothingAssetImpl* getOwner() const
+ {
+ return mAsset;
+ }
+ Renderable* getRenderable();
+
+ // from Renderable
+ void dispatchRenderResources(UserRenderer& api);
+
+ void initializeActorData();
+
+ void fetchResults();
+ void waitForFetchResults();
+
+ void syncActorData();
+ void reinitActorData()
+ {
+ bReinitActorData = 1;
+ }
+
+ ClothingActorData& getActorData();
+
+ void markRenderProxyReady();
+
+ // from ResourceProvider
+ void lockRenderResources()
+ {
+ ApexRenderable::renderDataLock();
+ }
+ void unlockRenderResources()
+ {
+ ApexRenderable::renderDataUnLock();
+ }
+ void updateRenderResources(bool rewriteBuffers, void* userRenderData);
+
+ // from ClothingActor
+ NvParameterized::Interface* getActorDesc();
+ void updateState(const PxMat44& globalPose, const PxMat44* newBoneMatrices, uint32_t boneMatricesByteStride, uint32_t numBoneMatrices, ClothingTeleportMode::Enum teleportMode);
+ void updateMaxDistanceScale(float scale, bool multipliable);
+ const PxMat44& getGlobalPose() const;
+ void setWind(float windAdaption, const PxVec3& windVelocity);
+ void setMaxDistanceBlendTime(float blendTime);
+ float getMaxDistanceBlendTime() const;
+ void setVisible(bool enable);
+ bool isVisibleBuffered() const;
+ bool isVisible() const;
+ void setFrozen(bool enable);
+ bool isFrozenBuffered() const;
+ bool shouldComputeRenderData() const;
+ ClothSolverMode::Enum getClothSolverMode() const;
+ void setGraphicalLOD(uint32_t lod);
+ uint32_t getGraphicalLod();
+
+ ClothingRenderProxy* acquireRenderProxy();
+
+ bool rayCast(const PxVec3& worldOrigin, const PxVec3& worldDirection, float& time, PxVec3& normal, uint32_t& vertexIndex);
+ void attachVertexToGlobalPosition(uint32_t vertexIndex, const PxVec3& worldPosition);
+ void freeVertex(uint32_t vertexIndex);
+
+ uint32_t getClothingMaterial() const;
+ void setClothingMaterial(uint32_t index);
+ void setOverrideMaterial(uint32_t submeshIndex, const char* overrideMaterialName);
+ void setVelocityCallback(ClothingVelocityCallback* callback)
+ {
+ mVelocityCallback = callback;
+ }
+ void setInterCollisionChannels(uint32_t channels)
+ {
+ mInterCollisionChannels = channels;
+ }
+ uint32_t getInterCollisionChannels()
+ {
+ return mInterCollisionChannels;
+ }
+ bool isHalfPrecisionAllowed() const
+ {
+ return mIsAllowedHalfPrecisionSolver;
+ }
+ void setHalfPrecision(bool isAllowed)
+ {
+ mIsAllowedHalfPrecisionSolver = isAllowed;
+ }
+
+ virtual void getLodRange(float& min, float& max, bool& intOnly) const;
+ virtual float getActiveLod() const;
+ virtual void forceLod(float lod);
+
+ virtual void getPhysicalMeshPositions(void* buffer, uint32_t byteStride);
+ virtual void getPhysicalMeshNormals(void* buffer, uint32_t byteStride);
+ virtual float getMaximumSimulationBudget() const;
+ virtual uint32_t getNumSimulationVertices() const;
+ virtual const PxVec3* getSimulationPositions();
+ virtual const PxVec3* getSimulationNormals();
+ virtual bool getSimulationVelocities(PxVec3* velocities);
+ virtual uint32_t getNumGraphicalVerticesActive(uint32_t submeshIndex) const;
+ virtual PxMat44 getRenderGlobalPose() const;
+ virtual const PxMat44* getCurrentBoneSkinningMatrices() const;
+
+ // PhysX scene management
+#if PX_PHYSICS_VERSION_MAJOR == 3
+ void setPhysXScene(PxScene*);
+ PxScene* getPhysXScene() const;
+#endif
+
+ // scene ticks
+ void tickSynchBeforeSimulate_LocksPhysX(float simulationDelta, float substepSize, uint32_t substepNumber, uint32_t numSubSteps);
+ void applyLockingTasks();
+ void updateConstrainPositions_LocksPhysX();
+ void applyCollision_LocksPhysX();
+ void applyGlobalPose_LocksPhysX();
+ void applyClothingMaterial_LocksPhysX();
+ void skinPhysicsMesh(bool useInterpolatedMatrices, float substepFraction);
+ void tickAsynch_NoPhysX();
+ bool needsManualSubstepping();
+ bool isSkinningDirty();
+
+ // LoD stuff
+ float getCost() const; // Should be removed?
+
+ // debug rendering
+#ifndef WITHOUT_PVD
+ void initPvdInstances(pvdsdk::PvdDataStream& pvdStream);
+ void destroyPvdInstances();
+ void updatePvd();
+#endif
+ void visualize();
+
+ // cleanup
+ void destroy();
+
+ // Tasks
+#if APEX_UE4
+ void initBeforeTickTasks(PxF32 deltaTime, PxF32 substepSize, PxU32 numSubSteps, PxTaskManager* taskManager, PxTaskID before, PxTaskID after);
+#else
+ void initBeforeTickTasks(float deltaTime, float substepSize, uint32_t numSubSteps);
+#endif
+
+ void submitTasksDuring(PxTaskManager* taskManager);
+ void setTaskDependenciesBefore(PxBaseTask* after);
+ PxTaskID setTaskDependenciesDuring(PxTaskID before, PxTaskID after);
+
+ void startBeforeTickTask();
+
+ PxTaskID getDuringTickTaskID()
+ {
+ return mDuringTickTask.getTaskID();
+ }
+
+#if !APEX_UE4
+ void setFetchContinuation();
+#endif
+ void startFetchTasks();
+
+ // teleport
+ void applyTeleport(bool skinningReady, uint32_t substepNumber);
+
+ // validation
+ static bool isValidDesc(const NvParameterized::Interface& params);
+
+ // Per Actor runtime cooking stuff
+ float getActorScale()
+ {
+ return mActorDesc->actorScale;
+ }
+ bool getHardwareAllowed()
+ {
+ return mActorDesc->useHardwareCloth;
+ }
+ ClothingCookedParam* getRuntimeCookedDataPhysX();
+
+
+ // collision functions
+ virtual ClothingPlane* createCollisionPlane(const PxPlane& pose);
+ virtual ClothingConvex* createCollisionConvex(ClothingPlane** planes, uint32_t numPlanes);
+ virtual ClothingSphere* createCollisionSphere(const PxVec3& positions, float radius);
+ virtual ClothingCapsule* createCollisionCapsule(ClothingSphere& sphere1, ClothingSphere& sphere2);
+ virtual ClothingTriangleMesh* createCollisionTriangleMesh();
+
+ void releaseCollision(ClothingCollisionImpl& collision);
+ void notifyCollisionChange()
+ {
+ bActorCollisionChanged = 1;
+ }
+
+#if APEX_UE4
+ void simulate(PxF32 dt);
+ void setFetchResultsSync() { mFetchResultsSync.set(); }
+#endif
+
+protected:
+ struct WriteBackInfo;
+
+ // rendering
+ void updateBoneBuffer(ClothingRenderProxyImpl* renderProxy);
+ void updateRenderMeshActorBuffer(bool freeBuffers, uint32_t graphicalLodId);
+ PxBounds3 getRenderMeshAssetBoundsTransformed();
+ void updateRenderProxy();
+
+ // handling interpolated skinning matrices
+ bool allocateEnoughBoneBuffers_NoPhysX(bool prepareForSubstepping);
+
+ // double buffering internal stuff
+ bool isSimulationRunning() const;
+ void updateScaledGravity(float substepSize);
+ void updateStateInternal_NoPhysX(bool prepareForSubstepping);
+
+ // compute intensive skinning stuff
+ template<bool withBackstop>
+ void skinPhysicsMeshInternal(bool useInterpolatedMatrices, float substepFraction);
+ void fillWritebackData_LocksPhysX(const WriteBackInfo& writeBackInfo);
+
+ // wind
+ void applyVelocityChanges_LocksPhysX(float simulationDelta);
+
+ // handling entities
+ bool isCookedDataReady();
+ void getSimulation(const WriteBackInfo& writeBackInfo);
+ void createPhysX_LocksPhysX(float simulationDelta);
+ void removePhysX_LocksPhysX();
+ void changePhysicsMesh_LocksPhysX(uint32_t oldGraphicalLodId, float simulationDelta);
+ void updateCollision_LocksPhysX(bool useInterpolatedMatrices);
+ void updateConstraintCoefficients_LocksPhysX();
+ void copyPositionAndNormal_NoPhysX(uint32_t numCopyVertices, SimulationAbstract* oldClothingSimulation);
+ void copyAndComputeVelocities_LocksPhysX(uint32_t numCopyVertices, SimulationAbstract* oldClothingSimulation, PxVec3* velocities, float simulationDelta) const;
+ void transferVelocities_LocksPhysX(const SimulationAbstract& oldClothingSimulation,
+ const ClothingPhysicalMeshParametersNS::SkinClothMapB_Type* pTCMB,
+ const ClothingPhysicalMeshParametersNS::SkinClothMapD_Type* pTCM,
+ uint32_t numVerticesInMap, const uint32_t* srcIndices, uint32_t numSrcIndices, uint32_t numSrcVertices,
+ PxVec3* oldVelocities, PxVec3* newVelocites, float simulationDelta);
+ PxVec3 computeVertexVelFromAnim(uint32_t vertexIndex, const ClothingPhysicalMeshParametersNS::PhysicalMesh_Type* physicalMesh, float simulationDelta) const;
+ void freeze_LocksPhysX(bool on);
+
+ // handling Abstract Simulation
+ void createSimulation(uint32_t physicalMeshId, NvParameterized::Interface* cookedData, const WriteBackInfo& writeBackInfo);
+
+
+ // handling Lod
+ uint32_t getGraphicalMeshIndex(uint32_t lod) const;
+ void lodTick_LocksPhysX(float simulationDelta);
+
+ // debug rendering
+ void visualizeSkinnedPositions(RenderDebugInterface& renderDebug, float positionRadius, bool maxDistanceOut, bool maxDistanceIn) const;
+ void visualizeBackstop(RenderDebugInterface& renderDebug) const;
+ void visualizeBackstopPrecise(RenderDebugInterface& renderDebug, float scale) const;
+ void visualizeBoneConnections(RenderDebugInterface& renderDebug, const PxVec3* positions, const uint16_t* boneIndices,
+ const float* boneWeights, uint32_t numBonesPerVertex, uint32_t numVertices) const;
+ void visualizeSpheres(RenderDebugInterface& renderDebug, const PxVec3* positions, uint32_t numPositions, float radius, uint32_t color, bool wire) const;
+
+ RenderMeshActorIntl* createRenderMeshActor(RenderMeshAssetIntl* renderMeshAsset);
+
+ ClothingMaterialLibraryParametersNS::ClothingMaterial_Type* getCurrentClothingMaterial() const;
+ bool clothingMaterialsEqual(ClothingMaterialLibraryParametersNS::ClothingMaterial_Type& a, ClothingMaterialLibraryParametersNS::ClothingMaterial_Type& b);
+
+ struct WriteBackInfo
+ {
+ WriteBackInfo() : oldSimulation(NULL), oldGraphicalLodId(0), simulationDelta(0.0f) {}
+ SimulationAbstract* oldSimulation;
+ uint32_t oldGraphicalLodId;
+ float simulationDelta;
+ };
+
+ // internal variables
+ ClothingAssetImpl* mAsset;
+ ClothingScene* mClothingScene;
+#if PX_PHYSICS_VERSION_MAJOR == 3
+ PxScene* mPhysXScene;
+#endif
+
+ ClothingActorParam* mActorDesc;
+ const char* mBackendName;
+
+ // current pose of this actor. If using skinning it could be set to idenftity matrix and simply rely on the skinning matrices (bones)
+ PX_ALIGN(16, PxMat44) mInternalGlobalPose;
+ PxMat44 mOldInternalGlobalPose;
+ PxMat44 mInternalInterpolatedGlobalPose;
+
+ // Bone matrices for physical mesh skinning - provided by the application either in the initial ClothingActorDesc or "updateBoneMatrices"
+ // number 0 is current, 1 is one frame old, 2 is 2 frames old
+ //PxMat44* mInternalBoneMatrices[2];
+ PxMat44* mInternalInterpolatedBoneMatrices;
+
+ // Number of cloth solver iterations that will be performed.
+ // If this is set to 0 the simulation enters "static" mode
+ uint32_t mCurrentSolverIterations;
+
+ PxVec3 mInternalScaledGravity;
+
+ float mInternalMaxDistanceBlendTime;
+ float mMaxDistReduction;
+
+ uint32_t mBufferedGraphicalLod;
+ uint32_t mCurrentGraphicalLodId;
+
+
+ Array<ClothingGraphicalMeshActor> mGraphicalMeshes;
+
+ Mutex mRenderProxyMutex;
+ ClothingRenderProxyImpl* mRenderProxyReady;
+
+ // for backwards compatibility, to make sure that dispatchRenderResources is
+ // called on the same render proxy as updateRenderResources
+ ClothingRenderProxyImpl* mRenderProxyURR;
+
+ ClothingActorData mData;
+
+ // PhysX SDK simulation objects
+ // Per-actor "skinned physical mesh" data is in mSimulationBulk.dynamicSimulationData
+ // these are skinned by APEX in "tickAsynch" using bone matrices provided by the application
+ // they are passed as constraints to the PhysX SDK (mCloth) in "tickSync"
+ // Per-actor "skinned rendering mesh" data - only used in if the ClothingAssetImpl uses the "skin cloth" approach
+ // these are skinned by APEX in "tickSynch" using the appropriate mesh-to-mesh skinning algorithm in the ClothingAssetImpl
+ SimulationAbstract* mClothingSimulation;
+
+ // Wind
+ ClothingActorParamNS::WindParameters_Type mInternalWindParams;
+
+ ClothingActorParamNS::ClothingActorFlags_Type mInternalFlags;
+
+ // max distance scale
+ ClothingActorParamNS::MaxDistanceScale_Type mInternalMaxDistanceScale;
+
+ // only needed to detect when it changes on the fly
+ float mCurrentMaxDistanceBias;
+
+ // bounds that are computed for the current frame, get copied over to RenderMeshActor during fetchResults
+ PxBounds3 mNewBounds;
+
+ bool bIsSimulationOn;
+ int32_t mForceSimulation;
+ PxVec3 mLodCentroid;
+ float mLodRadiusSquared;
+
+ // The Clothing Material
+ ClothingMaterialLibraryParametersNS::ClothingMaterial_Type mClothingMaterial;
+
+ // velocity callback
+ ClothingVelocityCallback* mVelocityCallback;
+
+ // inter collision
+ uint32_t mInterCollisionChannels;
+
+ bool mIsAllowedHalfPrecisionSolver;
+
+ // The tasks
+ ClothingActorBeforeTickTask mBeforeTickTask;
+ ClothingActorDuringTickTask mDuringTickTask;
+ ClothingActorFetchResultsTask mFetchResultsTask;
+
+ ClothingCookingTask* mActiveCookingTask;
+
+#if APEX_UE4
+ physx::shdfnd::Sync mFetchResultsSync;
+#else
+ ClothingWaitForFetchTask mWaitForFetchTask;
+#endif
+ bool mFetchResultsRunning;
+ Mutex mFetchResultsRunningMutex;
+
+ nvidia::Array<PxVec3> mWindDebugRendering;
+
+ // TODO make a better overrideMaterials API
+ HashMap<uint32_t, ApexSimpleString> mOverrideMaterials;
+
+ ResourceList mCollisionPlanes;
+ ResourceList mCollisionConvexes;
+ ResourceList mCollisionSpheres;
+ ResourceList mCollisionCapsules;
+ ResourceList mCollisionTriangleMeshes;
+
+ // bit flags - aggregate them at the end
+ uint32_t bGlobalPoseChanged : 1; // mBufferedGlobalPose was updated
+ uint32_t bBoneMatricesChanged : 1; // mBufferedBoneMatrices were updated
+ uint32_t bBoneBufferDirty : 1; // need to sync bones to the render mesh actor
+ uint32_t bMaxDistanceScaleChanged : 1; // mBufferedMaxDistanceScale was updated
+ uint32_t bBlendingAllowed : 1;
+
+ uint32_t bDirtyActorTemplate : 1;
+ uint32_t bDirtyShapeTemplate : 1;
+ uint32_t bDirtyClothingTemplate : 1;
+
+ uint32_t bBufferedVisible : 1;
+ uint32_t bInternalVisible : 1;
+
+ uint32_t bUpdateFrozenFlag : 1;
+ uint32_t bBufferedFrozen : 1;
+ uint32_t bInternalFrozen : 1;
+
+ uint32_t bPressureWarning : 1;
+ uint32_t bUnsucessfullCreation : 1;
+
+ ClothingTeleportMode::Enum bInternalTeleportDue : 3;
+
+ uint32_t bInternalScaledGravityChanged : 1;
+ uint32_t bReinitActorData : 1;
+
+ uint32_t bInternalLocalSpaceSim : 1;
+
+ uint32_t bActorCollisionChanged : 1;
+};
+
+}
+} // namespace nvidia
+
+
+#pragma warning(pop)
+
+#endif // CLOTHING_ACTOR_IMPL_H
diff --git a/APEX_1.4/module/clothing/include/ClothingActorProxy.h b/APEX_1.4/module/clothing/include/ClothingActorProxy.h
new file mode 100644
index 00000000..63e8b4a5
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/ClothingActorProxy.h
@@ -0,0 +1,392 @@
+/*
+ * 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.
+ */
+
+
+#ifndef CLOTHING_ACTOR_PROXY_H
+#define CLOTHING_ACTOR_PROXY_H
+
+#include "ClothingActor.h"
+#include "PsUserAllocated.h"
+#include "ClothingAssetImpl.h"
+#include "ApexRWLockable.h"
+#include "ClothingActorImpl.h"
+
+#include "ReadCheck.h"
+#include "WriteCheck.h"
+
+namespace nvidia
+{
+namespace clothing
+{
+
+class ClothingActorProxy : public ClothingActor, public UserAllocated, public ApexResourceInterface, ApexRWLockable
+{
+public:
+ APEX_RW_LOCKABLE_BOILERPLATE
+
+ ClothingActorImpl impl;
+
+#pragma warning(push)
+#pragma warning( disable : 4355 ) // disable warning about this pointer in argument list
+
+ ClothingActorProxy(const NvParameterized::Interface& desc, ClothingAssetImpl* asset, ClothingScene& clothingScene, ResourceList* list) :
+ impl(desc, this, NULL, asset, &clothingScene)
+ {
+ list->add(*this);
+ }
+
+#pragma warning(pop)
+
+ virtual void release()
+ {
+ impl.release(); // calls release method on asset
+ }
+
+ virtual uint32_t getListIndex() const
+ {
+ return impl.m_listIndex;
+ }
+
+ virtual void setListIndex(class ResourceList& list, uint32_t index)
+ {
+ impl.m_list = &list;
+ impl.m_listIndex = index;
+ }
+
+#ifndef WITHOUT_PVD
+ virtual void initPvdInstances(pvdsdk::PvdDataStream& pvdStream)
+ {
+ impl.initPvdInstances(pvdStream);
+ }
+#endif
+
+ virtual void destroy()
+ {
+ impl.destroy();
+ delete this;
+ }
+
+ // Actor base class
+ virtual Asset* getOwner() const
+ {
+ return impl.getOwner();
+ }
+ virtual PxBounds3 getBounds() const
+ {
+ return impl.getBounds();
+ }
+
+ virtual void lockRenderResources()
+ {
+ impl.lockRenderResources();
+ }
+
+ virtual void unlockRenderResources()
+ {
+ impl.unlockRenderResources();
+ }
+
+ virtual void updateRenderResources(bool rewriteBuffers, void* userRenderData)
+ {
+ URR_SCOPE;
+ impl.updateRenderResources(rewriteBuffers, userRenderData);
+ }
+
+ virtual void dispatchRenderResources(UserRenderer& renderer)
+ {
+ impl.dispatchRenderResources(renderer);
+ }
+
+ virtual NvParameterized::Interface* getActorDesc()
+ {
+ READ_ZONE();
+ return impl.getActorDesc();
+ }
+
+ virtual void updateState(const PxMat44& globalPose, const PxMat44* newBoneMatrices, uint32_t boneMatricesByteStride, uint32_t numBoneMatrices, ClothingTeleportMode::Enum teleportMode)
+ {
+ WRITE_ZONE();
+ impl.updateState(globalPose, newBoneMatrices, boneMatricesByteStride, numBoneMatrices, teleportMode);
+ }
+
+ virtual void updateMaxDistanceScale(float scale, bool multipliable)
+ {
+ WRITE_ZONE();
+ impl.updateMaxDistanceScale(scale, multipliable);
+ }
+
+ virtual const PxMat44& getGlobalPose() const
+ {
+ READ_ZONE();
+ return impl.getGlobalPose();
+ }
+
+ virtual void setWind(float windAdaption, const PxVec3& windVelocity)
+ {
+ WRITE_ZONE();
+ impl.setWind(windAdaption, windVelocity);
+ }
+
+ virtual void setMaxDistanceBlendTime(float blendTime)
+ {
+ WRITE_ZONE();
+ impl.setMaxDistanceBlendTime(blendTime);
+ }
+
+ virtual float getMaxDistanceBlendTime() const
+ {
+ READ_ZONE();
+ return impl.getMaxDistanceBlendTime();
+ }
+
+ virtual void getPhysicalMeshPositions(void* buffer, uint32_t byteStride)
+ {
+ READ_ZONE();
+ impl.getPhysicalMeshPositions(buffer, byteStride);
+ }
+
+ virtual void getPhysicalMeshNormals(void* buffer, uint32_t byteStride)
+ {
+ READ_ZONE();
+ impl.getPhysicalMeshNormals(buffer, byteStride);
+ }
+
+ virtual float getMaximumSimulationBudget() const
+ {
+ READ_ZONE();
+ return impl.getMaximumSimulationBudget();
+ }
+
+ virtual uint32_t getNumSimulationVertices() const
+ {
+ READ_ZONE();
+ return impl.getNumSimulationVertices();
+ }
+
+ virtual const PxVec3* getSimulationPositions()
+ {
+ READ_ZONE();
+ return impl.getSimulationPositions();
+ }
+
+ virtual const PxVec3* getSimulationNormals()
+ {
+ READ_ZONE();
+ return impl.getSimulationNormals();
+ }
+
+ virtual bool getSimulationVelocities(PxVec3* velocities)
+ {
+ READ_ZONE();
+ return impl.getSimulationVelocities(velocities);
+ }
+
+ virtual uint32_t getNumGraphicalVerticesActive(uint32_t submeshIndex) const
+ {
+ READ_ZONE();
+ return impl.getNumGraphicalVerticesActive(submeshIndex);
+ }
+
+ virtual PxMat44 getRenderGlobalPose() const
+ {
+ READ_ZONE();
+ return impl.getRenderGlobalPose();
+ }
+
+ virtual const PxMat44* getCurrentBoneSkinningMatrices() const
+ {
+ READ_ZONE();
+ return impl.getCurrentBoneSkinningMatrices();
+ }
+
+ virtual void setVisible(bool enable)
+ {
+ WRITE_ZONE();
+ impl.setVisible(enable);
+ }
+
+ virtual bool isVisible() const
+ {
+ READ_ZONE();
+ return impl.isVisibleBuffered();
+ }
+
+ virtual void setFrozen(bool enable)
+ {
+ WRITE_ZONE();
+ impl.setFrozen(enable);
+ }
+
+ virtual bool isFrozen() const
+ {
+ READ_ZONE();
+ return impl.isFrozenBuffered();
+ }
+
+ virtual ClothSolverMode::Enum getClothSolverMode() const
+ {
+ READ_ZONE();
+ return impl.getClothSolverMode();
+ }
+
+ virtual void setGraphicalLOD(uint32_t lod)
+ {
+ WRITE_ZONE();
+ impl.setGraphicalLOD(lod);
+ }
+
+ virtual uint32_t getGraphicalLod()
+ {
+ READ_ZONE();
+ return impl.getGraphicalLod();
+ }
+
+ virtual bool rayCast(const PxVec3& worldOrigin, const PxVec3& worldDirection, float& time, PxVec3& normal, uint32_t& vertexIndex)
+ {
+ READ_ZONE();
+ return impl.rayCast(worldOrigin, worldDirection, time, normal, vertexIndex);
+ }
+
+ virtual void attachVertexToGlobalPosition(uint32_t vertexIndex, const PxVec3& globalPosition)
+ {
+ WRITE_ZONE();
+ impl.attachVertexToGlobalPosition(vertexIndex, globalPosition);
+ }
+
+ virtual void freeVertex(uint32_t vertexIndex)
+ {
+ WRITE_ZONE();
+ impl.freeVertex(vertexIndex);
+ }
+
+ virtual uint32_t getClothingMaterial() const
+ {
+ READ_ZONE();
+ return impl.getClothingMaterial();
+ }
+
+ virtual void setClothingMaterial(uint32_t index)
+ {
+ WRITE_ZONE();
+ impl.setClothingMaterial(index);
+ }
+
+ virtual void setOverrideMaterial(uint32_t submeshIndex, const char* overrideMaterialName)
+ {
+ WRITE_ZONE();
+ impl.setOverrideMaterial(submeshIndex, overrideMaterialName);
+ }
+
+ virtual void setVelocityCallback(ClothingVelocityCallback* callback)
+ {
+ WRITE_ZONE();
+ impl.setVelocityCallback(callback);
+ }
+
+ virtual void setInterCollisionChannels(uint32_t channels)
+ {
+ WRITE_ZONE();
+ impl.setInterCollisionChannels(channels);
+ }
+
+ virtual uint32_t getInterCollisionChannels()
+ {
+ READ_ZONE();
+ return impl.getInterCollisionChannels();
+ }
+
+ virtual bool isHalfPrecisionAllowed() const
+ {
+ READ_ZONE();
+ return impl.isHalfPrecisionAllowed();
+ }
+
+ virtual void setHalfPrecision(bool isAllowed)
+ {
+ WRITE_ZONE();
+ return impl.setHalfPrecision(isAllowed);
+ }
+
+ virtual void getLodRange(float& min, float& max, bool& intOnly) const
+ {
+ READ_ZONE();
+ impl.getLodRange(min, max, intOnly);
+ }
+
+ virtual float getActiveLod() const
+ {
+ READ_ZONE();
+ return impl.getActiveLod();
+ }
+
+ virtual void forceLod(float lod)
+ {
+ WRITE_ZONE();
+ impl.forceLod(lod);
+ }
+
+ /**
+ \brief Selectively enables/disables debug visualization of a specific APEX actor. Default value it true.
+ */
+ virtual void setEnableDebugVisualization(bool state)
+ {
+ impl.setEnableDebugVisualization(state);
+ }
+
+ virtual ClothingPlane* createCollisionPlane(const PxPlane& plane)
+ {
+ WRITE_ZONE();
+ return impl.createCollisionPlane(plane);
+ }
+
+ virtual ClothingConvex* createCollisionConvex(ClothingPlane** planes, uint32_t numPlanes)
+ {
+ WRITE_ZONE();
+ return impl.createCollisionConvex(planes, numPlanes);
+ }
+
+ virtual ClothingSphere* createCollisionSphere(const PxVec3& position, float radius)
+ {
+ WRITE_ZONE();
+ return impl.createCollisionSphere(position, radius);
+ }
+
+ virtual ClothingCapsule* createCollisionCapsule(ClothingSphere& sphere1, ClothingSphere& sphere2)
+ {
+ WRITE_ZONE();
+ return impl.createCollisionCapsule(sphere1, sphere2);
+ }
+
+ virtual ClothingTriangleMesh* createCollisionTriangleMesh()
+ {
+ WRITE_ZONE();
+ return impl.createCollisionTriangleMesh();
+ }
+
+ virtual ClothingRenderProxy* acquireRenderProxy()
+ {
+ READ_ZONE();
+ return impl.acquireRenderProxy();
+ }
+
+#if APEX_UE4
+ virtual void simulate(PxF32 dt)
+ {
+ WRITE_ZONE();
+ impl.simulate(dt);
+ }
+#endif
+};
+
+
+}
+} // namespace nvidia
+
+#endif // CLOTHING_ACTOR_PROXY_H
diff --git a/APEX_1.4/module/clothing/include/ClothingActorTasks.h b/APEX_1.4/module/clothing/include/ClothingActorTasks.h
new file mode 100644
index 00000000..329c2142
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/ClothingActorTasks.h
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+
+#ifndef CLOTHING_ACTOR_TASKS_H
+#define CLOTHING_ACTOR_TASKS_H
+
+#include "PxTask.h"
+
+#if APEX_UE4
+#include "PsSync.h"
+#include "ApexInterface.h"
+#endif
+
+namespace nvidia
+{
+namespace clothing
+{
+
+class ClothingActorImpl;
+class ClothingActorData;
+
+
+class ClothingActorBeforeTickTask : public physx::PxLightCpuTask
+{
+public:
+ ClothingActorBeforeTickTask(ClothingActorImpl* actor) : mActor(actor), mDeltaTime(0.0f), mSubstepSize(0.0f), mNumSubSteps(0) {}
+#if APEX_UE4
+ ~ClothingActorBeforeTickTask() {}
+#endif
+
+ PX_INLINE void setDeltaTime(float simulationDelta, float substepSize, uint32_t numSubSteps)
+ {
+ mDeltaTime = simulationDelta;
+ mSubstepSize = substepSize;
+ mNumSubSteps = numSubSteps;
+ }
+
+ virtual void run();
+ virtual const char* getName() const;
+
+private:
+ ClothingActorImpl* mActor;
+ float mDeltaTime;
+ float mSubstepSize;
+ uint32_t mNumSubSteps;
+};
+
+
+
+class ClothingActorDuringTickTask : public physx::PxTask
+{
+public:
+ ClothingActorDuringTickTask(ClothingActorImpl* actor) : mActor(actor) {}
+
+ virtual void run();
+ virtual const char* getName() const;
+
+private:
+ ClothingActorImpl* mActor;
+};
+
+
+
+class ClothingActorFetchResultsTask :
+#if APEX_UE4
+ public PxTask
+#else
+ public physx::PxLightCpuTask
+#endif
+{
+public:
+ ClothingActorFetchResultsTask(ClothingActorImpl* actor) : mActor(actor) {}
+
+ virtual void run();
+ virtual const char* getName() const;
+#if APEX_UE4
+ virtual void release();
+#endif
+
+private:
+ ClothingActorImpl* mActor;
+};
+
+
+}
+} // namespace nvidia
+
+#endif
diff --git a/APEX_1.4/module/clothing/include/ClothingAssetAuthoringImpl.h b/APEX_1.4/module/clothing/include/ClothingAssetAuthoringImpl.h
new file mode 100644
index 00000000..06f8dafb
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/ClothingAssetAuthoringImpl.h
@@ -0,0 +1,265 @@
+/*
+ * 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.
+ */
+
+
+#ifndef CLOTHING_ASSET_AUTHORING_IMPL_H
+#define CLOTHING_ASSET_AUTHORING_IMPL_H
+
+
+#include "ClothingAssetAuthoring.h"
+#include "ClothingAssetImpl.h"
+#include "ClothingGraphicalLodParameters.h"
+#include "ApexAssetAuthoring.h"
+
+#include "ReadCheck.h"
+#include "WriteCheck.h"
+
+#ifndef WITHOUT_APEX_AUTHORING
+
+namespace nvidia
+{
+namespace clothing
+{
+
+class ClothingPhysicalMeshImpl;
+
+
+class ClothingAssetAuthoringImpl : public ClothingAssetAuthoring, public ApexAssetAuthoring, public ClothingAssetImpl
+{
+public:
+ APEX_RW_LOCKABLE_BOILERPLATE
+
+ ClothingAssetAuthoringImpl(ModuleClothingImpl* module, ResourceList& list, const char* name);
+ ClothingAssetAuthoringImpl(ModuleClothingImpl* module, ResourceList& list);
+ ClothingAssetAuthoringImpl(ModuleClothingImpl* module, ResourceList& list, NvParameterized::Interface* params, const char* name);
+
+ // from AssetAuthoring
+ virtual const char* getName(void) const
+ {
+ return ClothingAssetImpl::getName();
+ }
+ virtual const char* getObjTypeName() const
+ {
+ return CLOTHING_AUTHORING_TYPE_NAME;
+ }
+ virtual bool prepareForPlatform(nvidia::apex::PlatformTag);
+
+ virtual void setToolString(const char* toolName, const char* toolVersion, uint32_t toolChangelist)
+ {
+ ApexAssetAuthoring::setToolString(toolName, toolVersion, toolChangelist);
+ }
+
+ // from ApexInterface
+ virtual void release();
+
+ // from ClothingAssetAuthoring
+ virtual void setDefaultConstrainCoefficients(const ClothingConstrainCoefficients& coeff)
+ {
+ WRITE_ZONE();
+ mDefaultConstrainCoefficients = coeff;
+ }
+ virtual void setInvalidConstrainCoefficients(const ClothingConstrainCoefficients& coeff)
+ {
+ WRITE_ZONE();
+ mInvalidConstrainCoefficients = coeff;
+ }
+
+ virtual void setMeshes(uint32_t lod, RenderMeshAssetAuthoring* asset, ClothingPhysicalMesh* mesh,
+ float normalResemblance = 90, bool ignoreUnusedVertices = true,
+ IProgressListener* progress = NULL);
+ virtual bool addPlatformToGraphicalLod(uint32_t lod, PlatformTag platform);
+ virtual bool removePlatform(uint32_t lod, PlatformTag platform);
+ virtual uint32_t getNumPlatforms(uint32_t lod) const;
+ virtual PlatformTag getPlatform(uint32_t lod, uint32_t i) const;
+ virtual uint32_t getNumLods() const;
+ virtual int32_t getLodValue(uint32_t lod) const;
+ virtual void clearMeshes();
+ virtual ClothingPhysicalMesh* getClothingPhysicalMesh(uint32_t graphicalLod) const;
+
+ virtual void setBoneInfo(uint32_t boneIndex, const char* boneName, const PxMat44& bindPose, int32_t parentIndex);
+ virtual void setRootBone(const char* boneName);
+ virtual uint32_t addBoneConvex(const char* boneName, const PxVec3* positions, uint32_t numPositions);
+ virtual uint32_t addBoneConvex(uint32_t boneIndex, const PxVec3* positions, uint32_t numPositions);
+ virtual void addBoneCapsule(const char* boneName, float capsuleRadius, float capsuleHeight, const PxMat44& localPose);
+ virtual void addBoneCapsule(uint32_t boneIndex, float capsuleRadius, float capsuleHeight, const PxMat44& localPose);
+ virtual void clearBoneActors(const char* boneName);
+ virtual void clearBoneActors(uint32_t boneIndex);
+ virtual void clearAllBoneActors();
+
+ virtual void setCollision(const char** boneNames, float* radii, PxVec3* localPositions,
+ uint32_t numSpheres, uint16_t* pairs, uint32_t numPairs);
+ virtual void setCollision(uint32_t* boneIndices, float* radii, PxVec3* localPositions, uint32_t numSpheres,
+ uint16_t* pairs, uint32_t numPairs);
+ virtual void clearCollision();
+
+ virtual void setSimulationHierarchicalLevels(uint32_t levels)
+ {
+ WRITE_ZONE();
+ mParams->simulation.hierarchicalLevels = levels;
+ clearCooked();
+ }
+ virtual void setSimulationThickness(float thickness)
+ {
+ WRITE_ZONE();
+ mParams->simulation.thickness = thickness;
+ }
+ virtual void setSimulationVirtualParticleDensity(float density)
+ {
+ WRITE_ZONE();
+ PX_ASSERT(density >= 0.0f);
+ PX_ASSERT(density <= 1.0f);
+ mParams->simulation.virtualParticleDensity = PxClamp(density, 0.0f, 1.0f);
+ }
+ virtual void setSimulationSleepLinearVelocity(float sleep)
+ {
+ WRITE_ZONE();
+ mParams->simulation.sleepLinearVelocity = sleep;
+ }
+ virtual void setSimulationGravityDirection(const PxVec3& gravity)
+ {
+ WRITE_ZONE();
+ mParams->simulation.gravityDirection = gravity.getNormalized();
+ }
+
+ virtual void setSimulationDisableCCD(bool disable)
+ {
+ WRITE_ZONE();
+ mParams->simulation.disableCCD = disable;
+ }
+ virtual void setSimulationTwowayInteraction(bool enable)
+ {
+ WRITE_ZONE();
+ mParams->simulation.twowayInteraction = enable;
+ }
+ virtual void setSimulationUntangling(bool enable)
+ {
+ WRITE_ZONE();
+ mParams->simulation.untangling = enable;
+ }
+ virtual void setSimulationRestLengthScale(float scale)
+ {
+ WRITE_ZONE();
+ mParams->simulation.restLengthScale = scale;
+ }
+
+ virtual void setExportScale(float scale)
+ {
+ WRITE_ZONE();
+ mExportScale = scale;
+ }
+ virtual void applyTransformation(const PxMat44& transformation, float scale, bool applyToGraphics, bool applyToPhysics);
+ virtual void updateBindPoses(const PxMat44* newBindPoses, uint32_t newBindPosesCount, bool isInternalOrder, bool collisionMaintainWorldPose);
+ virtual void setDeriveNormalsFromBones(bool enable)
+ {
+ WRITE_ZONE();
+ mDeriveNormalsFromBones = enable;
+ }
+ virtual NvParameterized::Interface* getMaterialLibrary();
+ virtual bool setMaterialLibrary(NvParameterized::Interface* materialLibrary, uint32_t materialIndex, bool transferOwnership);
+ virtual NvParameterized::Interface* getRenderMeshAssetAuthoring(uint32_t lodLevel) const;
+
+ // parameterization
+ NvParameterized::Interface* getNvParameterized() const
+ {
+ return mParams;
+ }
+ virtual NvParameterized::Interface* releaseAndReturnNvParameterizedInterface();
+
+ // from NvParameterized::SerializationCallback
+ virtual void preSerialize(void* userData);
+
+ // from ApexAssetAuthoring
+ virtual void setToolString(const char* toolString);
+
+ // internal
+ void destroy();
+
+ virtual bool setBoneBindPose(uint32_t boneIndex, const PxMat44& bindPose);
+ virtual bool getBoneBindPose(uint32_t boneIndex, PxMat44& bindPose) const;
+
+private:
+ // bones
+ uint32_t addBoneConvexInternal(uint32_t boneIndex, const PxVec3* positions, uint32_t numPositions);
+ void addBoneCapsuleInternal(uint32_t boneIndex, float capsuleRadius, float capsuleHeight, const PxMat44& localPose);
+ void clearBoneActorsInternal(int32_t internalBoneIndex);
+ void compressBones() const;
+ void compressBoneCollision();
+ void collectBoneIndices(uint32_t numVertices, const uint16_t* boneIndices, const float* boneWeights, uint32_t numBonesPerVertex) const;
+
+ void updateMappingAuthoring(ClothingGraphicalLodParameters& graphLod, RenderMeshAssetIntl* renderMeshAssetCopy,
+ RenderMeshAssetAuthoringIntl* renderMeshAssetOrig, float normalResemblance,
+ bool ignoreUnusedVertices, IProgressListener* progress);
+ void sortSkinMapB(SkinClothMapB* skinClothMap, uint32_t skinClothMapSize, uint32_t* immediateClothMap, uint32_t immediateClothMapSize);
+
+ void setupPhysicalMesh(ClothingPhysicalMeshParameters& physicalMeshParameters) const;
+
+ bool checkSetMeshesInput(uint32_t lod, ClothingPhysicalMesh* nxPhysicalMesh, uint32_t& graphicalLodIndexTest);
+ void sortPhysicalMeshes();
+
+ // mesh reordering
+ void sortDeformableIndices(ClothingPhysicalMeshImpl& physicalMesh);
+
+
+ bool getGraphicalLodIndex(uint32_t lod, uint32_t& graphicalLodIndex) const;
+ uint32_t addGraphicalLod(uint32_t lod);
+
+ // cooking
+ void clearCooked();
+
+ // access
+ bool addGraphicalMesh(RenderMeshAssetAuthoring* renderMesh, uint32_t graphicalLodIndex);
+
+ Array<ClothingPhysicalMeshImpl*> mPhysicalMeshesInput;
+
+ float mExportScale;
+ bool mDeriveNormalsFromBones;
+ bool mOwnsMaterialLibrary;
+
+ ClothingConstrainCoefficients mDefaultConstrainCoefficients;
+ ClothingConstrainCoefficients mInvalidConstrainCoefficients;
+
+ const char* mPreviousCookedType;
+
+ ApexSimpleString mRootBoneName;
+
+ void initParams();
+
+ // immediate cloth: 1-to-1 mapping from physical to rendering mesh (except for LOD)
+ bool generateImmediateClothMap(const AbstractMeshDescription* targetMeshes, uint32_t numTargetMeshes,
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type& physicalMesh,
+ uint32_t* masterFlags, float epsilon, uint32_t& numNotFoundVertices,
+ float normalResemblance, ParamArray<uint32_t>& result, IProgressListener* progress) const;
+ bool generateSkinClothMap(const AbstractMeshDescription* targetMeshes, uint32_t numTargetMeshes,
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type& physicalMesh, uint32_t* masterFlags,
+ uint32_t* immediateMap, uint32_t numEmptyInImmediateMap, ParamArray<SkinClothMap>& result,
+ float& offsetAlongNormal, bool integrateImmediateMap, IProgressListener* progress) const;
+
+ void removeMaxDistance0Mapping(ClothingGraphicalLodParameters& graphicalLod, RenderMeshAssetIntl* renderMeshAsset) const;
+
+ bool generateTetraMap(const AbstractMeshDescription* targetMeshes, uint32_t numTargetMeshes,
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type& physicalMesh, uint32_t* masterFlags,
+ ParamArray<ClothingGraphicalLodParametersNS::TetraLink_Type>& result, IProgressListener* progress) const;
+ float computeBaryError(float baryX, float baryY) const;
+ float computeTriangleError(const TriangleWithNormals& triangle, const PxVec3& normal) const;
+
+
+ bool hasTangents(const RenderMeshAssetIntl& rma);
+ uint32_t getMaxNumGraphicalVertsActive(const ClothingGraphicalLodParameters& graphicalLod, uint32_t submeshIndex);
+ bool isMostlyImmediateSkinned(const RenderMeshAssetIntl& rma, const ClothingGraphicalLodParameters& graphicalLod);
+ bool conditionalMergeMapping(const RenderMeshAssetIntl& rma, ClothingGraphicalLodParameters& graphicalLod);
+
+};
+
+}
+} // namespace nvidia
+
+#endif // WITHOUT_APEX_AUTHORING
+
+#endif // CLOTHING_ASSET_AUTHORING_IMPL_H
diff --git a/APEX_1.4/module/clothing/include/ClothingAssetData.h b/APEX_1.4/module/clothing/include/ClothingAssetData.h
new file mode 100644
index 00000000..2e3d4f18
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/ClothingAssetData.h
@@ -0,0 +1,287 @@
+/*
+ * 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.
+ */
+
+
+#ifndef CLOTHING_ASSET_DATA
+#define CLOTHING_ASSET_DATA
+
+#include "PxSimpleTypes.h"
+#include "PxAssert.h"
+#include "AbstractMeshDescription.h"
+#include "RenderDataFormat.h"
+#include "PxBounds3.h"
+#include "PsAllocator.h"
+#include "RenderMeshAsset.h"
+
+namespace nvidia
+{
+namespace clothing
+{
+
+// forward declarations
+namespace ClothingGraphicalLodParametersNS
+{
+struct SkinClothMapB_Type;
+struct SkinClothMapD_Type;
+struct TetraLink_Type;
+}
+
+}
+
+//typedef ClothingGraphicalLodParametersNS::SkinClothMapB_Type SkinClothMapB_TypeLocal;
+//typedef ClothingGraphicalLodParametersNS::SkinClothMapC_Type SkinClothMapC_TypeLocal;
+//typedef ClothingGraphicalLodParametersNS::TetraLink_Type TetraLink_TypeLocal;
+
+struct VertexUVLocal
+{
+ VertexUVLocal() {}
+ VertexUVLocal(float _u, float _v)
+ {
+ set(_u, _v);
+ }
+ VertexUVLocal(const float uv[])
+ {
+ set(uv);
+ }
+
+ void set(float _u, float _v)
+ {
+ u = _u;
+ v = _v;
+ }
+
+ void set(const float uv[])
+ {
+ u = uv[0];
+ v = uv[1];
+ }
+
+ float& operator [](int i)
+ {
+ PX_ASSERT(i >= 0 && i <= 1);
+ return (&u)[i];
+ }
+
+ const float& operator [](int i) const
+ {
+ PX_ASSERT(i >= 0 && i <= 1);
+ return (&u)[i];
+ }
+
+ float u, v;
+};
+
+PX_COMPILE_TIME_ASSERT(sizeof(VertexUVLocal) == sizeof(VertexUV));
+
+struct TetraEncoding_Local
+{
+ float sign[4];
+ uint32_t lastVtxIdx;
+};
+
+#define TETRA_LUT_SIZE_LOCAL 6
+static const TetraEncoding_Local tetraTableLocal[TETRA_LUT_SIZE_LOCAL] =
+{
+ { {0, 0, 0, 1}, 0},
+ { {1, 0, 0, 1}, 2},
+ { {1, 0, 1, 1}, 1},
+
+ { { -1, -1, -1, 0}, 0},
+ { {0, -1, -1, 0}, 2 },
+ { {0, -1, 0, 0}, 1 }
+};
+
+
+namespace clothing
+{
+
+//This seems to be the data we are interested in in each submesh...
+class ClothingAssetSubMesh
+{
+
+public:
+ ClothingAssetSubMesh();
+
+ const PxVec3* PX_RESTRICT mPositions;
+ const PxVec3* PX_RESTRICT mNormals;
+ const PxVec4* PX_RESTRICT mTangents;
+
+ const float* PX_RESTRICT mBoneWeights;
+ const uint16_t* PX_RESTRICT mBoneIndices;
+
+ const uint32_t* PX_RESTRICT mIndices;
+
+ VertexUVLocal* mUvs;
+
+ RenderDataFormat::Enum mPositionOutFormat;
+ RenderDataFormat::Enum mNormalOutFormat;
+ RenderDataFormat::Enum mTangentOutFormat;
+ RenderDataFormat::Enum mBoneWeightOutFormat;
+ RenderDataFormat::Enum mUvFormat;
+
+ uint32_t mVertexCount;
+ uint32_t mIndicesCount;
+ uint32_t mUvCount;
+ uint32_t mNumBonesPerVertex;
+
+ uint32_t mCurrentMaxVertexSimulation;
+ uint32_t mCurrentMaxVertexAdditionalSimulation;
+ uint32_t mCurrentMaxIndexSimulation;
+};
+
+class ClothingMeshAssetData
+{
+public:
+
+ ClothingMeshAssetData();
+
+ const uint32_t* mImmediateClothMap;
+ ClothingGraphicalLodParametersNS::SkinClothMapD_Type* mSkinClothMap;
+ ClothingGraphicalLodParametersNS::SkinClothMapB_Type* mSkinClothMapB;
+ ClothingGraphicalLodParametersNS::TetraLink_Type* mTetraMap;
+
+ uint32_t mImmediateClothMapCount;
+ uint32_t mSkinClothMapCount;
+ uint32_t mSkinClothMapBCount;
+ uint32_t mTetraMapCount;
+
+ uint32_t mSubmeshOffset;
+ uint32_t mSubMeshCount;
+
+ //Index of the physics mesh this lod relates to
+ uint32_t mPhysicalMeshId;
+
+ float mSkinClothMapThickness;
+ float mSkinClothMapOffset;
+
+ PxBounds3 mBounds;
+
+ bool bActive;
+ bool bNeedsTangents;
+};
+
+
+//A physical clothing mesh
+class ClothingPhysicalMeshData
+{
+public:
+ ClothingPhysicalMeshData();
+
+ PxVec3* mVertices;
+ uint32_t mVertexCount;
+ uint32_t mSimulatedVertexCount;
+ uint32_t mMaxDistance0VerticesCount;
+
+ PxVec3* mNormals;
+ PxVec3* mSkinningNormals;
+ uint16_t* mBoneIndices;
+ float* mBoneWeights;
+ uint8_t* mOptimizationData;
+ uint32_t* mIndices;
+
+ uint32_t mSkinningNormalsCount;
+ uint32_t mBoneWeightsCount;
+ uint32_t mOptimizationDataCount;
+ uint32_t mIndicesCount;
+ uint32_t mSimulatedIndicesCount;
+
+ uint32_t mNumBonesPerVertex;
+};
+
+//A clothing asset contains a set of submeshes + some other data that we might be interested in...
+class ClothingAssetData
+{
+public:
+ ClothingAssetData();
+ ~ClothingAssetData();
+
+ uint8_t* mData;
+ uint32_t* mCompressedNumBonesPerVertex;
+ uint32_t* mCompressedTangentW;
+ uint32_t* mExt2IntMorphMapping;
+ uint32_t mCompressedNumBonesPerVertexCount;
+ uint32_t mCompressedTangentWCount;
+ uint32_t mExt2IntMorphMappingCount;
+
+ uint32_t mAssetSize;
+ uint32_t mGraphicalLodsCount;
+ uint32_t mPhysicalMeshesCount;
+ uint32_t mPhysicalMeshOffset;
+
+
+ uint32_t mBoneCount;
+
+ uint32_t mRootBoneIndex;
+
+ ClothingMeshAssetData* GetLod(const uint32_t lod) const
+ {
+ return ((ClothingMeshAssetData*)mData) + lod;
+ }
+
+ ClothingAssetSubMesh* GetSubmesh(const uint32_t lod, const uint32_t submeshIndex) const
+ {
+ return GetSubmesh(GetLod(lod), submeshIndex);
+ }
+
+ ClothingAssetSubMesh* GetSubmesh(const ClothingMeshAssetData* asset, const uint32_t submeshIndex) const
+ {
+ return ((ClothingAssetSubMesh*)(mData + asset->mSubmeshOffset)) + submeshIndex;
+ }
+
+ ClothingPhysicalMeshData* GetPhysicalMesh(const uint32_t index) const
+ {
+ return ((ClothingPhysicalMeshData*)(mData + mPhysicalMeshOffset)) + index;
+ }
+
+ const uint32_t* getCompressedNumBonesPerVertex(uint32_t graphicalLod, uint32_t submeshIndex, uint32_t& mapSize);
+ const uint32_t* getCompressedTangentW(uint32_t graphicalLod, uint32_t submeshIndex, uint32_t& mapSize);
+
+ uint32_t* getMorphMapping(uint32_t graphicalLod);
+
+ template<bool withNormals, bool withBones, bool withMorph, bool withTangents>
+ void skinToBonesInternal(AbstractMeshDescription& destMesh, uint32_t submeshIndex, uint32_t graphicalMeshIndex, uint32_t startVertex,
+ PxMat44* compositeMatrices, PxVec3* morphDisplacements);
+
+ void skinToBones(AbstractMeshDescription& destMesh, uint32_t submeshIndex, uint32_t graphicalMeshIndex, uint32_t startVertex,
+ PxMat44* compositeMatrices, PxVec3* morphDisplacements);
+
+ template<bool computeNormals>
+ uint32_t skinClothMap(PxVec3* dstPositions, PxVec3* dstNormals, PxVec4* dstTangents, uint32_t numVertices,
+ const AbstractMeshDescription& srcPM, ClothingGraphicalLodParametersNS::SkinClothMapD_Type* map,
+ uint32_t numVerticesInMap, float offsetAlongNormal, float actorScale) const;
+
+ void getNormalsAndVerticesForFace(PxVec3* vtx, PxVec3* nrm, uint32_t i, const AbstractMeshDescription& srcPM) const;
+
+ uint32_t skinClothMapBSkinVertex(PxVec3& dstPos, PxVec3* dstNormal, uint32_t vIndex,
+ ClothingGraphicalLodParametersNS::SkinClothMapB_Type* pTCMB, const ClothingGraphicalLodParametersNS::SkinClothMapB_Type* pTCMBEnd,
+ const AbstractMeshDescription& srcPM) const;
+
+ uint32_t skinClothMapB(PxVec3* dstPositions, PxVec3* dstNormals, uint32_t numVertices,
+ const AbstractMeshDescription& srcPM, ClothingGraphicalLodParametersNS::SkinClothMapB_Type* map,
+ uint32_t numVerticesInMap, bool computeNormals) const;
+
+ bool skinToTetraMesh(AbstractMeshDescription& destMesh,
+ const AbstractMeshDescription& srcPM,
+ const ClothingMeshAssetData& graphicalLod);
+
+ ClothingPhysicalMeshData* GetPhysicalMeshFromLod(const uint32_t graphicalLod) const
+ {
+ PX_ASSERT(graphicalLod < mGraphicalLodsCount);
+ const uint32_t physicalMeshId = GetLod(graphicalLod)->mPhysicalMeshId;
+ PX_ASSERT(physicalMeshId < mPhysicalMeshesCount);
+ return GetPhysicalMesh(physicalMeshId);
+ }
+
+};
+
+}
+} // namespace nvidia
+
+#endif // CLOTHING_ASSET_DATA
diff --git a/APEX_1.4/module/clothing/include/ClothingAssetImpl.h b/APEX_1.4/module/clothing/include/ClothingAssetImpl.h
new file mode 100644
index 00000000..6809d53e
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/ClothingAssetImpl.h
@@ -0,0 +1,494 @@
+/*
+ * 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.
+ */
+
+
+#ifndef CLOTHING_ASSET_IMPL_H
+#define CLOTHING_ASSET_IMPL_H
+
+#include "ClothingAsset.h"
+
+#include "ApexResource.h"
+#include "PsMemoryBuffer.h"
+#include "ApexRWLockable.h"
+#include "ClothingCooking.h"
+#include "ModuleClothingImpl.h"
+#include "ModuleClothingHelpers.h"
+
+#include "RenderDebugInterface.h"
+#include "ApexAssetTracker.h"
+#include "ParamArray.h"
+
+#include "ReadCheck.h"
+#include "WriteCheck.h"
+
+namespace nvidia
+{
+namespace apex
+{
+struct AbstractMeshDescription;
+class ApexActorSource;
+class ApexRenderMeshAsset;
+class PhysXObjectDescIntl;
+class RenderMeshAssetIntl;
+
+template <class T_Module, class T_Asset, class T_AssetAuthoring>
+class ApexAuthorableObject;
+}
+namespace clothing
+{
+typedef ClothingGraphicalLodParametersNS::SkinClothMapB_Type SkinClothMapB;
+typedef ClothingGraphicalLodParametersNS::SkinClothMapD_Type SkinClothMap;
+typedef ClothingGraphicalLodParametersNS::TetraLink_Type TetraLink;
+
+
+class ClothingActorImpl;
+class ClothingActorProxy;
+class ClothingAssetData;
+class ClothingMaterial;
+class ClothingPhysicalMeshImpl;
+class CookingAbstract;
+class ClothingPreviewProxy;
+
+class SimulationAbstract;
+class ClothingPlaneImpl;
+
+#define NUM_VERTICES_PER_CACHE_BLOCK 8 // 128 / sizeof boneWeights per vertex (4 float), this is the biggest per vertex data
+
+
+#define DEFAULT_PM_OFFSET_ALONG_NORMAL_FACTOR 0.1f // Magic value that phil introduced for the mesh-mesh-skinning
+
+struct TetraEncoding
+{
+ float sign[4];
+ uint32_t lastVtxIdx;
+};
+
+
+
+#define TETRA_LUT_SIZE 6
+static const TetraEncoding tetraTable[TETRA_LUT_SIZE] =
+{
+ { { 0, 0, 0, 1 }, 0},
+ { { 1, 0, 0, 1 }, 2},
+ { { 1, 0, 1, 1 }, 1},
+
+ { { -1, -1, -1, 0 }, 0},
+ { { 0, -1, -1, 0 }, 2},
+ { { 0, -1, 0, 0 }, 1}
+};
+
+
+
+struct ClothingGraphicalMeshAssetWrapper
+{
+ ClothingGraphicalMeshAssetWrapper(const RenderMeshAsset* renderMeshAsset) : meshAsset(renderMeshAsset)
+ {
+ }
+ const RenderMeshAsset* meshAsset;
+
+ uint32_t getSubmeshCount() const
+ {
+ if (meshAsset == NULL)
+ return 0;
+
+ return meshAsset->getSubmeshCount();
+ }
+
+ uint32_t getNumTotalVertices() const
+ {
+ if (meshAsset == NULL)
+ return 0;
+
+ uint32_t count = 0;
+ for (uint32_t i = 0; i < meshAsset->getSubmeshCount(); i++)
+ {
+ count += meshAsset->getSubmesh(i).getVertexCount(0); // only 1 part is supported
+ }
+ return count;
+ }
+
+ uint32_t getNumVertices(uint32_t submeshIndex) const
+ {
+ if (meshAsset == NULL)
+ return 0;
+
+ return meshAsset->getSubmesh(submeshIndex).getVertexBuffer().getVertexCount();
+ }
+
+ uint32_t getNumBonesPerVertex(uint32_t submeshIndex) const
+ {
+ if (meshAsset == NULL)
+ return 0;
+
+ if (submeshIndex < meshAsset->getSubmeshCount())
+ {
+ const VertexFormat& format = meshAsset->getSubmesh(submeshIndex).getVertexBuffer().getFormat();
+ return vertexSemanticFormatElementCount(RenderVertexSemantic::BONE_INDEX,
+ format.getBufferFormat((uint32_t)format.getBufferIndexFromID(format.getSemanticID(RenderVertexSemantic::BONE_INDEX))));
+ }
+ return 0;
+ }
+
+ const void* getVertexBuffer(uint32_t submeshIndex, RenderVertexSemantic::Enum semantic, RenderDataFormat::Enum& outFormat) const
+ {
+ if (meshAsset == NULL)
+ return NULL;
+
+ const VertexBuffer& vb = meshAsset->getSubmesh(submeshIndex).getVertexBuffer();
+ const VertexFormat& vf = vb.getFormat();
+ uint32_t bufferIndex = (uint32_t)vf.getBufferIndexFromID(vf.getSemanticID((RenderVertexSemantic::Enum)semantic));
+ return vb.getBufferAndFormat(outFormat, bufferIndex);
+ }
+
+ uint32_t getNumIndices(uint32_t submeshIndex)
+ {
+ if (meshAsset == NULL)
+ return 0;
+
+ return meshAsset->getSubmesh(submeshIndex).getIndexCount(0);
+ }
+
+ const void* getIndexBuffer(uint32_t submeshIndex)
+ {
+ if (meshAsset == NULL)
+ return NULL;
+
+ return meshAsset->getSubmesh(submeshIndex).getIndexBuffer(0);
+ }
+
+ bool hasChannel(const char* bufferName = NULL, RenderVertexSemantic::Enum semantic = RenderVertexSemantic::NUM_SEMANTICS) const
+ {
+ if (meshAsset == NULL)
+ return false;
+
+ PX_ASSERT((bufferName != NULL) != (semantic != RenderVertexSemantic::NUM_SEMANTICS));
+ PX_ASSERT((bufferName == NULL) != (semantic == RenderVertexSemantic::NUM_SEMANTICS));
+
+ for (uint32_t i = 0; i < meshAsset->getSubmeshCount(); i++)
+ {
+ RenderDataFormat::Enum outFormat = RenderDataFormat::UNSPECIFIED;
+ const VertexFormat& format = meshAsset->getSubmesh(i).getVertexBuffer().getFormat();
+
+ VertexFormat::BufferID id = bufferName ? format.getID(bufferName) : format.getSemanticID(semantic);
+ outFormat = format.getBufferFormat((uint32_t)format.getBufferIndexFromID(id));
+
+ if (outFormat != RenderDataFormat::UNSPECIFIED)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+private:
+ void operator=(ClothingGraphicalMeshAssetWrapper&);
+};
+
+
+
+class ClothingAssetImpl : public ClothingAsset, public ApexResourceInterface, public ApexResource, public ClothingCookingLock, public NvParameterized::SerializationCallback, public ApexRWLockable
+{
+protected:
+ // used for authoring asset creation only!
+ ClothingAssetImpl(ModuleClothingImpl* module, ResourceList& list, const char* name);
+ ClothingAssetImpl(ModuleClothingImpl*, ResourceList&, NvParameterized::Interface*, const char*);
+
+public:
+ APEX_RW_LOCKABLE_BOILERPLATE
+
+ uint32_t initializeAssetData(ClothingAssetData& assetData, const uint32_t uvChannel);
+
+ // from Asset
+ PX_INLINE const char* getName() const
+ {
+ return mName.c_str();
+ }
+ PX_INLINE AuthObjTypeID getObjTypeID() const
+ {
+ return mAssetTypeID;
+ }
+ PX_INLINE const char* getObjTypeName() const
+ {
+ return CLOTHING_AUTHORING_TYPE_NAME;
+ }
+
+ virtual uint32_t forceLoadAssets();
+ virtual NvParameterized::Interface* getDefaultActorDesc();
+ virtual NvParameterized::Interface* getDefaultAssetPreviewDesc();
+ virtual const NvParameterized::Interface* getAssetNvParameterized() const
+ {
+ return mParams;
+ }
+ virtual Actor* createApexActor(const NvParameterized::Interface& params, Scene& apexScene);
+
+ virtual AssetPreview* createApexAssetPreview(const ::NvParameterized::Interface& /*params*/, AssetPreviewScene* /*previewScene*/)
+ {
+ PX_ALWAYS_ASSERT();
+ return NULL;
+ }
+
+ virtual NvParameterized::Interface* releaseAndReturnNvParameterizedInterface();
+ virtual bool isValidForActorCreation(const ::NvParameterized::Interface& parms, Scene& apexScene) const;
+ virtual bool isDirty() const;
+
+ // from ApexInterface
+ virtual void release();
+
+ // from ClothingAsset
+ PX_INLINE uint32_t getNumActors() const
+ {
+ READ_ZONE();
+ return mActors.getSize();
+ }
+ virtual ClothingActor* getActor(uint32_t index);
+ PX_INLINE PxBounds3 getBoundingBox() const
+ {
+ READ_ZONE();
+ return mParams->boundingBox;
+ }
+ virtual float getMaximumSimulationBudget(uint32_t solverIterations) const;
+ virtual uint32_t getNumGraphicalLodLevels() const;
+ virtual uint32_t getGraphicalLodValue(uint32_t lodLevel) const;
+ virtual float getBiggestMaxDistance() const;
+ virtual bool remapBoneIndex(const char* name, uint32_t newIndex);
+ PX_INLINE uint32_t getNumBones() const
+ {
+ READ_ZONE();
+ return mBones.size();
+ }
+ PX_INLINE uint32_t getNumUsedBones() const
+ {
+ READ_ZONE();
+ return mParams->bonesReferenced;
+ }
+ PX_INLINE uint32_t getNumUsedBonesForMesh() const
+ {
+ return mParams->bonesReferencedByMesh;
+ }
+ virtual const char* getBoneName(uint32_t internalIndex) const;
+ virtual bool getBoneBasePose(uint32_t internalIndex, PxMat44& result) const;
+ virtual void getBoneMapping(uint32_t* internal2externalMap) const;
+ virtual uint32_t prepareMorphTargetMapping(const PxVec3* originalPositions, uint32_t numPositions, float epsilon);
+
+ // from ApexResource
+ uint32_t getListIndex() const
+ {
+ READ_ZONE();
+ return m_listIndex;
+ }
+ void setListIndex(class ResourceList& list, uint32_t index)
+ {
+ m_list = &list;
+ m_listIndex = index;
+ }
+
+ // from NvParameterized::SerializationCallback
+ virtual void preSerialize(void* userData_);
+
+ // graphical meshes
+ PX_INLINE uint32_t getNumGraphicalMeshes() const
+ {
+ return mGraphicalLods.size();
+ }
+
+ RenderMeshAssetIntl* getGraphicalMesh(uint32_t index);
+ const ClothingGraphicalLodParameters* getGraphicalLod(uint32_t index) const;
+
+ // actor handling
+ void releaseClothingActor(ClothingActor& actor);
+ void releaseClothingPreview(ClothingPreview& preview);
+
+ // module stuff
+ PX_INLINE ModuleClothingImpl* getModuleClothing() const
+ {
+ PX_ASSERT(mModule != NULL);
+ return mModule;
+ }
+
+ // actor access to the asset
+ bool writeBoneMatrices(PxMat44 localPose, const PxMat44* newBoneMatrices,
+ const uint32_t byteStride, const uint32_t numBones, PxMat44* dest, bool isInternalOrder, bool multInvBindPose);
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type* getPhysicalMeshFromLod(uint32_t graphicalLodId) const;
+
+ void releaseCookedInstances();
+
+ PX_INLINE bool getSimulationDisableCCD() const
+ {
+ return mParams->simulation.disableCCD;
+ }
+ ClothingPhysicalMeshParametersNS::SkinClothMapB_Type* getTransitionMapB(uint32_t dstPhysicalMeshId, uint32_t srcPhysicalMeshId, float& thickness, float& offset);
+ ClothingPhysicalMeshParametersNS::SkinClothMapD_Type* getTransitionMap(uint32_t dstPhysicalMeshId, uint32_t srcPhysicalMeshId, float& thickness, float& offset);
+
+ // cooked stuff
+ NvParameterized::Interface* getCookedData(float actorScale);
+ uint32_t getCookedPhysXVersion() const;
+ ClothSolverMode::Enum getClothSolverMode() const;
+
+ // create deformables
+ SimulationAbstract* getSimulation(uint32_t physicalMeshId, NvParameterized::Interface* cookedParam, ClothingScene* clothingScene);
+ void returnSimulation(SimulationAbstract* simulation);
+ void destroySimulation(SimulationAbstract* simulation);
+
+ void initCollision( SimulationAbstract* simulation, const PxMat44* boneTansformations,
+ ResourceList& actorPlanes,
+ ResourceList& actorConvexes,
+ ResourceList& actorSpheres,
+ ResourceList& actorCapsules,
+ ResourceList& actorTriangleMeshes,
+ const ClothingActorParam* actorParam,
+ const PxMat44& globalPose, bool localSpaceSim);
+
+ void updateCollision(SimulationAbstract* simulation, const PxMat44* boneTansformationse,
+ ResourceList& actorPlanes,
+ ResourceList& actorConvexes,
+ ResourceList& actorSpheres,
+ ResourceList& actorCapsules,
+ ResourceList& actorTriangleMeshes,
+ bool teleport);
+
+ uint32_t getPhysicalMeshID(uint32_t graphicalLodId) const;
+
+ // bone stuff
+ PX_INLINE const PxMat44& getBoneBindPose(uint32_t i)
+ {
+ PX_ASSERT(i < mBones.size());
+ return mBones[i].bindPose;
+ }
+
+ PX_INLINE uint32_t getBoneExternalIndex(uint32_t i)
+ {
+ PX_ASSERT(i < mBones.size());
+ return (uint32_t)mBones[i].externalIndex;
+ }
+
+ // debug rendering
+ void visualizeSkinCloth(RenderDebugInterface& renderDebug,
+ AbstractMeshDescription& srcPM, bool showTets, float actorScale) const;
+ void visualizeSkinClothMap(RenderDebugInterface& renderDebug, AbstractMeshDescription& srcPM,
+ SkinClothMapB* skinClothMapB, uint32_t skinClothMapBSize,
+ SkinClothMap* skinClothMap, uint32_t skinClothMapSize,
+ float actorScale, bool onlyBad, bool invalidBary) const;
+ void visualizeBones(RenderDebugInterface& renderDebug, const PxMat44* matrices, bool skeleton, float boneFramesScale, float boneNamesScale);
+
+
+ // expose render data
+ virtual const RenderMeshAsset* getRenderMeshAsset(uint32_t lodLevel) const;
+ virtual uint32_t getMeshSkinningMapSize(uint32_t lod);
+ virtual void getMeshSkinningMap(uint32_t lod, ClothingMeshSkinningMap* map);
+ virtual bool releaseGraphicalData();
+
+ void setupInvBindMatrices();
+
+ // unified cooking
+ void prepareCookingJob(CookingAbstract& job, float scale, PxVec3* gravityDirection, PxVec3* morphedPhysicalMesh);
+
+ // morph targets
+ uint32_t* getMorphMapping(uint32_t graphicalLod, uint32_t submeshIndex);
+ uint32_t getPhysicalMeshOffset(uint32_t physicalMeshId);
+ void getDisplacedPhysicalMeshPositions(PxVec3* morphDisplacements, ParamArray<PxVec3> displacedMeshPositions);
+
+ // faster cpu skinning
+ void initializeCompressedNumBonesPerVertex();
+ uint32_t getRootBoneIndex();
+
+ uint32_t getInterCollisionChannels();
+
+protected:
+ void destroy();
+
+ int32_t getBoneInternalIndex(const char* boneName) const;
+ int32_t getBoneInternalIndex(uint32_t boneIndex) const;
+
+ bool reorderGraphicsVertices(uint32_t graphicalLodId, bool perfWarning);
+ bool reorderDeformableVertices(ClothingPhysicalMeshImpl& physicalMesh);
+
+ float getMaxMaxDistance(ClothingPhysicalMeshParametersNS::PhysicalMesh_Type& physicalMesh,
+ uint32_t index, uint32_t numIndices) const;
+
+ uint32_t getCorrespondingPhysicalVertices(const ClothingGraphicalLodParameters& graphLod, uint32_t submeshIndex,
+ uint32_t graphicalVertexIndex, const AbstractMeshDescription& pMesh,
+ uint32_t submeshVertexOffset, uint32_t indices[4], float trust[4]) const;
+
+ void getNormalsAndVerticesForFace(PxVec3* vtx, PxVec3* nrm, uint32_t i,
+ const AbstractMeshDescription& srcPM) const;
+ bool setBoneName(uint32_t internalIndex, const char* name);
+ void clearMapping(uint32_t graphicalLodId);
+ void updateBoundingBox();
+
+ bool mergeMapping(ClothingGraphicalLodParameters* graphicalLod);
+ bool findTriangleForImmediateVertex(uint32_t& faceIndex, uint32_t& indexInTriangle, uint32_t physVertIndex,
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type& physicalMesh) const;
+
+#ifndef WITHOUT_PVD
+ void initPvdInstances(pvdsdk::PvdDataStream& pvdStream);
+ void destroyPvdInstances();
+#endif
+
+ // the parent
+ ModuleClothingImpl* mModule;
+
+ // the parameterized object
+ ClothingAssetParameters* mParams;
+
+ // the meshes
+ ParamArray<ClothingPhysicalMeshParameters*> mPhysicalMeshes;
+
+ ParamArray<ClothingGraphicalLodParameters*> mGraphicalLods;
+
+ mutable ParamArray<ClothingAssetParametersNS::BoneEntry_Type> mBones;
+ Array<PxMat44> mInvBindPoses; // not serialized!
+
+ mutable ParamArray<ClothingAssetParametersNS::BoneSphere_Type> mBoneSpheres;
+ mutable ParamArray<uint16_t> mSpherePairs;
+ mutable ParamArray<ClothingAssetParametersNS::ActorEntry_Type> mBoneActors;
+ mutable ParamArray<PxVec3> mBoneVertices;
+ mutable ParamArray<ClothingAssetParametersNS::BonePlane_Type> mBonePlanes;
+ mutable ParamArray<uint32_t> mCollisionConvexes; // bitmap for indices into mBonePlanes array
+
+private:
+ // internal methods
+ float getMaxDistReduction(ClothingPhysicalMeshParameters& physicalMesh, float maxDistanceMultiplier) const;
+
+ static const char* getClassName()
+ {
+ return CLOTHING_AUTHORING_TYPE_NAME;
+ }
+
+ Array<uint32_t> mCompressedNumBonesPerVertex;
+ Array<uint32_t> mCompressedTangentW;
+ nvidia::Mutex mCompressedNumBonesPerVertexMutex;
+
+ ApexSimpleString mName;
+
+ // Keep track of all ClothingActorImpl objects created from this ClothingAssetImpl
+ ResourceList mActors;
+ ResourceList mPreviews;
+
+
+ Array<SimulationAbstract*> mUnusedSimulation;
+ nvidia::Mutex mUnusedSimulationMutex;
+
+ static AuthObjTypeID mAssetTypeID;
+ friend class ModuleClothingImpl;
+
+
+ Array<uint32_t> mExt2IntMorphMapping;
+ uint32_t mExt2IntMorphMappingMaxValue; // this is actually one larger than max
+
+ bool mDirty;
+ bool mMorphMappingWarning;
+
+ template <class T_Module, class T_Asset, class T_AssetAuthoring>
+ friend class nvidia::apex::ApexAuthorableObject;
+};
+
+}
+} // namespace nvidia
+
+#endif // CLOTHING_ASSET_IMPL_H
diff --git a/APEX_1.4/module/clothing/include/ClothingCollisionImpl.h b/APEX_1.4/module/clothing/include/ClothingCollisionImpl.h
new file mode 100644
index 00000000..efac0473
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/ClothingCollisionImpl.h
@@ -0,0 +1,422 @@
+/*
+ * 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.
+ */
+
+
+#ifndef CLOTHING_COLLISION_IMPL_H
+#define CLOTHING_COLLISION_IMPL_H
+
+#include "ApexResource.h"
+#include "ApexSDKHelpers.h"
+#include "ClothingCollision.h"
+#include "ApexRWLockable.h"
+
+#include "ReadCheck.h"
+#include "WriteCheck.h"
+
+namespace nvidia
+{
+namespace clothing
+{
+
+class ClothingActorImpl;
+
+
+class ClothingCollisionImpl : public ApexResource, public ApexResourceInterface, public ApexRWLockable
+{
+public:
+ APEX_RW_LOCKABLE_BOILERPLATE
+
+ ClothingCollisionImpl(ResourceList& list, ClothingActorImpl& owner);
+
+ /* ApexResourceInterface */
+ virtual void release();
+
+ uint32_t getListIndex() const
+ {
+ return m_listIndex;
+ }
+ void setListIndex(ResourceList& list, uint32_t index)
+ {
+ m_listIndex = index;
+ m_list = &list;
+ }
+
+ void destroy();
+
+ void setId(int32_t id)
+ {
+ mId = id;
+ }
+ int32_t getId() const
+ {
+ return mId;
+ }
+
+ virtual ClothingPlane* isPlane() { READ_ZONE(); return NULL;}
+ virtual ClothingConvex* isConvex() { READ_ZONE(); return NULL;}
+ virtual ClothingSphere* isSphere() { READ_ZONE(); return NULL;}
+ virtual ClothingCapsule* isCapsule() { READ_ZONE(); return NULL;}
+ virtual ClothingTriangleMesh* isTriangleMesh() { READ_ZONE(); return NULL;}
+
+protected:
+
+ ClothingActorImpl& mOwner;
+ bool mInRelease;
+
+ int32_t mId;
+
+private:
+ ClothingCollisionImpl& operator=(const ClothingCollisionImpl&);
+};
+
+
+/************************************************************************/
+// ClothingPlaneImpl
+/************************************************************************/
+class ClothingPlaneImpl : public ClothingPlane, public ClothingCollisionImpl
+{
+public:
+ APEX_RW_LOCKABLE_BOILERPLATE
+
+ ClothingPlaneImpl(ResourceList& list, ClothingActorImpl& owner, const PxPlane& plane) :
+ ClothingCollisionImpl(list, owner),
+ mPlane(plane),
+ mRefCount(0)
+ {
+ }
+
+ virtual ClothingCollisionType::Enum getType() const
+ {
+ READ_ZONE();
+ return ClothingCollisionType::Plane;
+ }
+ virtual ClothingPlane* isPlane() { return this; }
+ virtual ClothingConvex* isConvex() { return NULL; }
+ virtual ClothingSphere* isSphere() { return NULL; }
+ virtual ClothingCapsule* isCapsule() { return NULL; }
+ virtual ClothingTriangleMesh* isTriangleMesh() { return NULL; }
+
+ virtual void release()
+ {
+ if (mRefCount > 0)
+ {
+ APEX_DEBUG_WARNING("Cannot release ClothingPlane that is referenced by a ClothingConvex. Release convex first.");
+ return;
+ }
+
+ ClothingCollisionImpl::release();
+ }
+
+ virtual void setPlane(const PxPlane& plane);
+ virtual PxPlane& getPlane()
+ {
+ return mPlane;
+ }
+
+ void incRefCount()
+ {
+ ++mRefCount;
+ }
+ void decRefCount()
+ {
+ PX_ASSERT(mRefCount > 0);
+ --mRefCount;
+ }
+ virtual uint32_t getRefCount() const
+ {
+ return (uint32_t)mRefCount;
+ }
+
+protected:
+ PxPlane mPlane;
+
+ int32_t mRefCount;
+};
+
+
+
+/************************************************************************/
+// ClothingConvexImpl
+/************************************************************************/
+class ClothingConvexImpl : public ClothingConvex, public ClothingCollisionImpl
+{
+public:
+ APEX_RW_LOCKABLE_BOILERPLATE
+
+ ClothingConvexImpl(ResourceList& list, ClothingActorImpl& owner, ClothingPlane** planes, uint32_t numPlanes) :
+ ClothingCollisionImpl(list, owner)
+ {
+ mPlanes.resize(numPlanes);
+ for (uint32_t i = 0; i < numPlanes; ++i)
+ {
+ mPlanes[i] = DYNAMIC_CAST(ClothingPlaneImpl*)(planes[i]);
+ mPlanes[i]->incRefCount();
+ }
+ }
+
+ virtual ClothingCollisionType::Enum getType() const
+ {
+ return ClothingCollisionType::Convex;
+ }
+ virtual ClothingPlane* isPlane() { return NULL; }
+ virtual ClothingConvex* isConvex() { return this; }
+ virtual ClothingSphere* isSphere() { return NULL; }
+ virtual ClothingCapsule* isCapsule() { return NULL; }
+ virtual ClothingTriangleMesh* isTriangleMesh() { return NULL; }
+
+ virtual void release()
+ {
+ for (uint32_t i = 0; i < mPlanes.size(); ++i)
+ {
+ mPlanes[i]->decRefCount();
+ }
+
+ ClothingCollisionImpl::release();
+ }
+
+ virtual void releaseWithPlanes()
+ {
+ for (uint32_t i = 0; i < mPlanes.size(); ++i)
+ {
+ mPlanes[i]->decRefCount();
+ mPlanes[i]->release();
+ }
+
+ ClothingCollisionImpl::release();
+ }
+
+ virtual uint32_t getNumPlanes()
+ {
+ return mPlanes.size();
+ }
+
+ virtual ClothingPlane** getPlanes()
+ {
+ return (ClothingPlane**)&mPlanes[0];
+ }
+
+protected:
+ Array<ClothingPlaneImpl*> mPlanes;
+};
+
+
+
+
+/************************************************************************/
+// ClothingSphereImpl
+/************************************************************************/
+class ClothingSphereImpl : public ClothingSphere, public ClothingCollisionImpl
+{
+public:
+ APEX_RW_LOCKABLE_BOILERPLATE
+
+ ClothingSphereImpl(ResourceList& list, ClothingActorImpl& owner, const PxVec3& position, float radius) :
+ ClothingCollisionImpl(list, owner),
+ mPosition(position),
+ mRadius(radius),
+ mRefCount(0)
+ {
+ }
+
+ virtual ClothingCollisionType::Enum getType() const
+ {
+ return ClothingCollisionType::Sphere;
+ }
+ virtual ClothingPlane* isPlane() { return NULL; }
+ virtual ClothingConvex* isConvex() { return NULL; }
+ virtual ClothingSphere* isSphere() { return this; }
+ virtual ClothingCapsule* isCapsule() { return NULL; }
+ virtual ClothingTriangleMesh* isTriangleMesh() { return NULL; }
+
+ virtual void release()
+ {
+ if (mRefCount > 0)
+ {
+ APEX_DEBUG_WARNING("Cannot release ClothingSphere that is referenced by an ClothingCapsule. Release capsule first.");
+ return;
+ }
+
+ ClothingCollisionImpl::release();
+ }
+
+ virtual void setPosition(const PxVec3& position);
+ virtual const PxVec3& getPosition() const
+ {
+ return mPosition;
+ }
+
+ virtual void setRadius(float radius);
+ virtual float getRadius() const
+ {
+ return mRadius;
+ }
+
+ void incRefCount()
+ {
+ ++mRefCount;
+ }
+ void decRefCount()
+ {
+ PX_ASSERT(mRefCount > 0);
+ --mRefCount;
+ }
+ virtual uint32_t getRefCount() const
+ {
+ return mRefCount;
+ }
+
+protected:
+ PxVec3 mPosition;
+ float mRadius;
+
+ uint32_t mRefCount;
+};
+
+
+
+
+/************************************************************************/
+// ClothingCapsuleImpl
+/************************************************************************/
+class ClothingCapsuleImpl : public ClothingCapsule, public ClothingCollisionImpl
+{
+public:
+ APEX_RW_LOCKABLE_BOILERPLATE
+
+ ClothingCapsuleImpl(ResourceList& list, ClothingActorImpl& owner, ClothingSphere& sphere1, ClothingSphere& sphere2) :
+ ClothingCollisionImpl(list, owner)
+ {
+ mSpheres[0] = (DYNAMIC_CAST(ClothingSphereImpl*)(&sphere1));
+ mSpheres[0]->incRefCount();
+
+ mSpheres[1] = (DYNAMIC_CAST(ClothingSphereImpl*)(&sphere2));
+ mSpheres[1]->incRefCount();
+ }
+
+ virtual ClothingCollisionType::Enum getType() const
+ {
+ return ClothingCollisionType::Capsule;
+ }
+ virtual ClothingPlane* isPlane() { return NULL; }
+ virtual ClothingConvex* isConvex() { return NULL; }
+ virtual ClothingSphere* isSphere() { return NULL; }
+ virtual ClothingCapsule* isCapsule() { return this; }
+ virtual ClothingTriangleMesh* isTriangleMesh() { return NULL; }
+
+ virtual void release()
+ {
+ mSpheres[0]->decRefCount();
+ mSpheres[1]->decRefCount();
+
+ ClothingCollisionImpl::release();
+ }
+
+ virtual void releaseWithSpheres()
+ {
+ mSpheres[0]->decRefCount();
+ mSpheres[1]->decRefCount();
+
+ mSpheres[0]->release();
+ mSpheres[1]->release();
+
+ ClothingCollisionImpl::release();
+ }
+
+ virtual ClothingSphere** getSpheres()
+ {
+ return (ClothingSphere**)mSpheres;
+ }
+
+protected:
+ ClothingSphereImpl* mSpheres[2];
+};
+
+
+
+
+/************************************************************************/
+// ClothingTriangleMeshImpl
+/************************************************************************/
+
+struct ClothingTriangle
+{
+ PxVec3 v[3];
+ uint32_t id;
+
+ bool operator<(const ClothingTriangle& other) const
+ {
+ return id < other.id;
+ }
+};
+
+class ClothingTriangleMeshImpl : public ClothingTriangleMesh, public ClothingCollisionImpl
+{
+public:
+ APEX_RW_LOCKABLE_BOILERPLATE
+
+ ClothingTriangleMeshImpl(ResourceList& list, ClothingActorImpl& owner) :
+ ClothingCollisionImpl(list, owner),
+ mPose(PxMat44(PxIdentity))
+ {
+ }
+
+ virtual ClothingCollisionType::Enum getType() const
+ {
+ return ClothingCollisionType::TriangleMesh;
+ }
+ virtual ClothingPlane* isPlane() { return NULL; }
+ virtual ClothingConvex* isConvex() { return NULL; }
+ virtual ClothingSphere* isSphere() { return NULL; }
+ virtual ClothingCapsule* isCapsule() { return NULL; }
+ virtual ClothingTriangleMesh* isTriangleMesh() { return this; }
+
+ virtual uint32_t lockTriangles(const uint32_t** ids, const PxVec3** triangles);
+ virtual uint32_t lockTrianglesWrite(const uint32_t** ids, PxVec3** triangles);
+ virtual void unlockTriangles();
+
+ virtual void addTriangle(uint32_t id, const PxVec3& v0, const PxVec3& v1, const PxVec3& v2);
+ virtual void addTriangles(const uint32_t* ids, const PxVec3* triangleVertices, uint32_t numTriangles);
+
+ virtual void removeTriangle(uint32_t id);
+ virtual void removeTriangles(const uint32_t* ids, uint32_t numTriangles);
+ virtual void clearTriangles();
+
+ virtual void release()
+ {
+ ClothingCollisionImpl::release();
+ }
+
+ virtual void setPose(PxMat44 pose);
+ virtual const PxMat44& getPose() const
+ {
+ return mPose;
+ }
+
+ void update(const PxTransform& tm, const nvidia::Array<PxVec3>& allTrianglesOld, nvidia::Array<PxVec3>& allTrianglesOldTemp, nvidia::Array<PxVec3>& allTriangles);
+
+protected:
+ void sortAddAndRemoves();
+
+ PxMat44 mPose;
+ Array<PxVec3> mTriangles;
+ Array<uint32_t> mIds;
+
+ Array<uint32_t> mRemoved;
+ Array<ClothingTriangle> mAddedTriangles;
+
+ Mutex mLock;
+};
+
+
+}
+} // namespace nvidia
+
+
+#endif // CLOTHING_COLLISION_IMPL_H \ No newline at end of file
diff --git a/APEX_1.4/module/clothing/include/ClothingCooking.h b/APEX_1.4/module/clothing/include/ClothingCooking.h
new file mode 100644
index 00000000..9292539c
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/ClothingCooking.h
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+
+#ifndef CLOTHING_COOKING_H
+#define CLOTHING_COOKING_H
+
+#include "ApexUsingNamespace.h"
+#include "PsUserAllocated.h"
+
+#include "PxTask.h"
+
+namespace NvParameterized
+{
+class Interface;
+}
+
+
+namespace nvidia
+{
+namespace clothing
+{
+
+class ClothingScene;
+class CookingAbstract;
+
+
+class ClothingCookingLock
+{
+public:
+ ClothingCookingLock() : mNumCookingDependencies(0) {}
+ ~ClothingCookingLock()
+ {
+ PX_ASSERT(mNumCookingDependencies == 0);
+ }
+
+ int32_t numCookingDependencies()
+ {
+ return mNumCookingDependencies;
+ }
+ void lockCooking();
+ void unlockCooking();
+private:
+ int32_t mNumCookingDependencies;
+};
+
+
+
+/* These tasks contain a cooking job. They have no dependencies on each other, but the ClothingScene
+ * make sure there's only ever one of them running (per ClothingScene that is).
+ * ClothingScene::submitCookingTasks() will launch a new one only if no other cooking task is running.
+ * At ClothingScene::fetchResults() this will be checked again.
+ */
+class ClothingCookingTask : public UserAllocated, public PxLightCpuTask
+{
+public:
+ ClothingCookingTask(ClothingScene* clothingScene, CookingAbstract& job);
+ ~ClothingCookingTask();
+
+
+ CookingAbstract* job;
+ ClothingCookingTask* nextTask;
+
+ // from LightCpuTask
+ void initCooking(PxTaskManager& tm, PxBaseTask* c);
+ virtual const char* getName() const
+ {
+ return "ClothingCookingTask";
+ }
+ virtual void run();
+
+ NvParameterized::Interface* getResult();
+
+ void lockObject(ClothingCookingLock* lockedObject);
+ void unlockObject();
+
+ bool waitsForBeingScheduled()
+ {
+ return mRefCount > 0;
+ }
+ bool readyForRelease()
+ {
+ return mState == ReadyForRelease;
+ }
+ void abort();
+
+private:
+ enum State
+ {
+ Uninit,
+ WaitForRun,
+ Running,
+ Aborting,
+ WaitForFetch,
+ ReadyForRelease,
+ };
+ State mState;
+ ClothingScene* mClothingScene;
+ NvParameterized::Interface* mResult;
+ ClothingCookingLock* mLockedObject;
+};
+
+}
+} // namespace nvidia
+
+
+#endif // CLOTHING_COOKING_H
diff --git a/APEX_1.4/module/clothing/include/ClothingGlobals.h b/APEX_1.4/module/clothing/include/ClothingGlobals.h
new file mode 100644
index 00000000..1ceb8554
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/ClothingGlobals.h
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+
+#ifndef CLOTHING_GLOBALS_H
+#define CLOTHING_GLOBALS_H
+
+#include "ApexUsingNamespace.h"
+
+namespace nvidia
+{
+namespace clothing
+{
+
+
+struct ClothingConstants
+{
+ enum Enum
+ {
+ ImmediateClothingInSkinFlag = 0x80000000, // only highest (sign?) bit. The rest is the index in the clothSkinMapB
+ ImmediateClothingInvertNormal = 0x40000000, // if second highest bit is set, invert the normal from Cloth
+ ImmediateClothingBadNormal = 0x20000000, // the normal is neither correct nor inverted, just different, use mesh-mesh skinning from neighboring triangles
+ ImmediateClothingInvalidValue = 0x1fffffff, // the lowest bit is set, all others are maxed out
+ ImmediateClothingReadMask = 0x0fffffff, // read mask, use this to read the number (two flags can still be put there so far)
+ };
+};
+
+}
+} // namespace nvidia
+
+
+#endif // CLOTHING_GLOBALS_H
diff --git a/APEX_1.4/module/clothing/include/ClothingPhysicalMeshImpl.h b/APEX_1.4/module/clothing/include/ClothingPhysicalMeshImpl.h
new file mode 100644
index 00000000..c78f8ede
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/ClothingPhysicalMeshImpl.h
@@ -0,0 +1,207 @@
+/*
+ * 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.
+ */
+
+
+#ifndef CLOTHING_PHYSICAL_MESH_IMPL_H
+#define CLOTHING_PHYSICAL_MESH_IMPL_H
+
+#include "ClothingPhysicalMesh.h"
+#include "PsUserAllocated.h"
+#include "ApexResource.h"
+#include "PsArray.h"
+#include "ParamArray.h"
+#include "ClothingPhysicalMeshParameters.h"
+#include "ModuleClothingImpl.h"
+#include "ApexRWLockable.h"
+#include "nvparameterized/NvParameterized.h"
+#include "ReadCheck.h"
+
+namespace nvidia
+{
+namespace apex
+{
+class ApexQuadricSimplifier;
+}
+namespace clothing
+{
+class ModuleClothingImpl;
+
+
+class ClothingPhysicalMeshImpl : public ClothingPhysicalMesh, public ApexResourceInterface, public ApexResource, public NvParameterized::SerializationCallback, public ApexRWLockable
+{
+private:
+ ClothingPhysicalMeshImpl(ModuleClothingImpl* module, ClothingPhysicalMeshParameters* params, ResourceList* list);
+ friend class ModuleClothingImpl;
+
+public:
+ APEX_RW_LOCKABLE_BOILERPLATE
+
+ virtual void release();
+ void destroy();
+
+ virtual uint32_t getNumVertices() const;
+ virtual uint32_t getNumSimulatedVertices() const;
+ virtual uint32_t getNumMaxDistance0Vertices() const;
+
+ virtual uint32_t getNumIndices() const;
+ virtual uint32_t getNumSimulatedIndices() const;
+
+ virtual uint32_t getNumBonesPerVertex() const
+ {
+ READ_ZONE();
+ return mParams->physicalMesh.numBonesPerVertex;
+ }
+
+ virtual void getIndices(void* indexDestination, uint32_t byteStride, uint32_t numIndices) const;
+
+ virtual bool isTetrahedralMesh() const
+ {
+ READ_ZONE();
+ return mParams->physicalMesh.isTetrahedralMesh;
+ }
+
+ virtual void simplify(uint32_t subdivisions, int32_t maxSteps, float maxError, IProgressListener* progress);
+
+ // user overwrites geometry
+ virtual void setGeometry(bool tetraMesh, uint32_t numVertices, uint32_t vertexByteStride, const void* vertices, const uint32_t* masterFlags,
+ uint32_t numIndices, uint32_t indexByteStride, const void* indices);
+
+ // direct access to specific buffers
+ virtual bool getIndices(uint32_t* indices, uint32_t byteStride) const;
+ virtual bool getVertices(PxVec3* vertices, uint32_t byteStride) const ;
+ virtual bool getNormals(PxVec3* vertices, uint32_t byteStride) const ;
+ virtual bool getBoneIndices(uint16_t* boneIndices, uint32_t byteStride) const;
+ virtual bool getBoneWeights(float* boneWeights, uint32_t byteStride) const;
+ virtual bool getConstrainCoefficients(ClothingConstrainCoefficients* values, uint32_t byteStride) const;
+ virtual void getStats(ClothingPhysicalMeshStats& stats) const;
+
+ virtual void allocateMasterFlagsBuffer();
+ virtual void allocateConstrainCoefficientBuffer();
+ virtual ClothingConstrainCoefficients* getConstrainCoefficientBuffer() const
+ {
+ READ_ZONE();
+ PX_COMPILE_TIME_ASSERT(sizeof(ClothingConstrainCoefficients) == sizeof(ClothingPhysicalMeshParametersNS::ConstrainCoefficient_Type));
+ return (ClothingConstrainCoefficients*)mParams->physicalMesh.constrainCoefficients.buf;
+ }
+
+ // from NvParameterized::SerializationCallback
+ void preSerialize(void* userData_ = NULL);
+
+ void permuteBoneIndices(Array<int32_t>& old2newBoneIndices);
+ void applyTransformation(const PxMat44& transformation, float scale);
+ void applyPermutation(const Array<uint32_t>& permutation);
+
+ void makeCopy(ClothingPhysicalMeshParameters* params);
+ void allocateNormalBuffer();
+ void allocateSkinningNormalsBuffer();
+ void allocateBoneIndexAndWeightBuffers();
+ void freeAdditionalBuffers();
+ PX_INLINE void setNumBonesPerVertex(uint32_t numBonesPerVertex)
+ {
+ mParams->physicalMesh.numBonesPerVertex = numBonesPerVertex;
+ }
+
+ PX_INLINE uint16_t* getBoneIndicesBuffer()
+ {
+ return mParams->physicalMesh.boneIndices.buf;
+ }
+ PX_INLINE float* getBoneWeightsBuffer()
+ {
+ return mParams->physicalMesh.boneWeights.buf;
+ }
+ PX_INLINE PxVec3* getPositionBuffer()
+ {
+ return mParams->physicalMesh.vertices.buf;
+ }
+ PX_INLINE PxVec3* getNormalBuffer()
+ {
+ return mParams->physicalMesh.normals.buf;
+ }
+ PX_INLINE PxVec3* getSkinningNormalBuffer()
+ {
+ return mParams->physicalMesh.skinningNormals.buf;
+ }
+ PX_INLINE uint32_t* getMasterFlagsBuffer()
+ {
+ return mMasterFlags.begin();
+ }
+
+ PX_INLINE uint32_t* getIndicesBuffer()
+ {
+ return mParams->physicalMesh.indices.buf;
+ }
+
+ PX_INLINE float getMaxMaxDistance()
+ {
+ return mParams->physicalMesh.maximumMaxDistance;
+ }
+ void updateMaxMaxDistance();
+
+ void addBoneToVertex(uint32_t vertexNumber, uint16_t boneIndex, float boneWeight);
+ void sortBonesOfVertex(uint32_t vertexNumber);
+ void normalizeBonesOfVertex(uint32_t vertexNumber);
+
+ void updateSkinningNormals();
+ void smoothNormals(uint32_t numIterations);
+
+ void updateOptimizationData();
+
+ ClothingPhysicalMeshParameters* getNvParameterized() const
+ {
+ return mParams;
+ }
+
+ // from ApexResource
+ uint32_t getListIndex() const
+ {
+ return m_listIndex;
+ }
+ void setListIndex(class ResourceList& list, uint32_t index)
+ {
+ m_list = &list;
+ m_listIndex = index;
+ }
+
+private:
+ void writeBackData();
+ void clearMiscBuffers();
+ void computeEdgeLengths() const;
+
+ bool removeDuplicatedTriangles(uint32_t numIndices, uint32_t indexByteStride, const void* indices);
+ void computeNeighborInformation(Array<int32_t> &neighbors);
+ void fixTriangleOrientations();
+
+ ModuleClothingImpl* mModule;
+
+ ClothingPhysicalMeshParameters* mParams;
+ bool ownsParams;
+
+ ParamArray<PxVec3> mVertices;
+ ParamArray<PxVec3> mNormals;
+ ParamArray<PxVec3> mSkinningNormals;
+ ParamArray<ClothingPhysicalMeshParametersNS::ConstrainCoefficient_Type> mConstrainCoefficients;
+ ParamArray<uint16_t> mBoneIndices;
+ ParamArray<float> mBoneWeights;
+ ParamArray<uint32_t> mIndices;
+
+ uint32_t mNumSimulatedVertices;
+ uint32_t mNumMaxDistanc0Vertices;
+ uint32_t mNumSimulatedIndices;
+
+ Array<uint32_t> mMasterFlags;
+
+ ApexQuadricSimplifier* mSimplifier;
+ bool isDirty;
+};
+
+}
+} // namespace nvidia
+
+#endif // CLOTHING_PHYSICAL_MESH_IMPL_H
diff --git a/APEX_1.4/module/clothing/include/ClothingPreviewProxy.h b/APEX_1.4/module/clothing/include/ClothingPreviewProxy.h
new file mode 100644
index 00000000..39ffedee
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/ClothingPreviewProxy.h
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+
+#ifndef CLOTHING_PREVIEW_PROXY_H
+#define CLOTHING_PREVIEW_PROXY_H
+
+#include "ClothingPreview.h"
+#include "ClothingActorImpl.h"
+#include "Renderable.h"
+#include "ApexRWLockable.h"
+#include "WriteCheck.h"
+#include "ReadCheck.h"
+
+namespace nvidia
+{
+namespace clothing
+{
+
+class ClothingPreviewProxy : public ClothingPreview, public UserAllocated, public ApexResourceInterface, public ApexRWLockable
+{
+ ClothingActorImpl impl;
+
+public:
+ APEX_RW_LOCKABLE_BOILERPLATE
+#pragma warning( disable : 4355 ) // disable warning about this pointer in argument list
+ ClothingPreviewProxy(const NvParameterized::Interface& desc, ClothingAssetImpl* asset, ResourceList* list) :
+ impl(desc, NULL, this, asset, NULL)
+ {
+ list->add(*this);
+ }
+
+ virtual void release()
+ {
+ impl.release();
+ }
+
+ virtual uint32_t getListIndex() const
+ {
+ return impl.m_listIndex;
+ }
+
+ virtual void setListIndex(class ResourceList& list, uint32_t index)
+ {
+ impl.m_list = &list;
+ impl.m_listIndex = index;
+ }
+
+ virtual void setPose(const PxMat44& pose)
+ {
+ WRITE_ZONE();
+ impl.updateState(pose, NULL, 0, 0, ClothingTeleportMode::Continuous);
+ }
+
+ virtual const PxMat44 getPose() const
+ {
+ READ_ZONE();
+ return impl.getGlobalPose();
+ }
+
+ virtual void lockRenderResources()
+ {
+ impl.lockRenderResources();
+ }
+
+ virtual void unlockRenderResources()
+ {
+ impl.unlockRenderResources();
+ }
+
+ virtual void updateRenderResources(bool rewriteBuffers = false, void* userRenderData = 0)
+ {
+ Renderable* renderable = impl.getRenderable();
+ if (renderable != NULL)
+ {
+ renderable->updateRenderResources(rewriteBuffers, userRenderData);
+ }
+ }
+
+ virtual void dispatchRenderResources(UserRenderer& renderer)
+ {
+ WRITE_ZONE();
+ Renderable* renderable = impl.getRenderable();
+ if (renderable != NULL)
+ {
+ renderable->dispatchRenderResources(renderer);
+ }
+ }
+
+ virtual PxBounds3 getBounds() const
+ {
+ READ_ZONE();
+ return impl.getBounds();
+ }
+
+
+ virtual void updateState(const PxMat44& globalPose, const PxMat44* newBoneMatrices, uint32_t boneMatricesByteStride, uint32_t numBoneMatrices)
+ {
+ WRITE_ZONE();
+ impl.updateState(globalPose, newBoneMatrices, boneMatricesByteStride, numBoneMatrices, ClothingTeleportMode::Continuous);
+ }
+
+ void destroy()
+ {
+ impl.destroy();
+ delete this;
+ }
+
+ virtual ~ClothingPreviewProxy() {}
+};
+
+}
+} // namespace nvidia
+
+#endif // CLOTHING_PREVIEW_PROXY_H
diff --git a/APEX_1.4/module/clothing/include/ClothingRenderProxyImpl.h b/APEX_1.4/module/clothing/include/ClothingRenderProxyImpl.h
new file mode 100644
index 00000000..f5a42833
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/ClothingRenderProxyImpl.h
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+
+#ifndef CLOTHING_RENDER_PROXY_IMPL_H
+#define CLOTHING_RENDER_PROXY_IMPL_H
+
+#include "ClothingRenderProxy.h"
+#include "PxMat44.h"
+#include "PxBounds3.h"
+#include "PsHashMap.h"
+#include "ApexString.h"
+#include "ApexRWLockable.h"
+
+namespace nvidia
+{
+namespace apex
+{
+class RenderMeshActorIntl;
+class RenderMeshAssetIntl;
+}
+namespace clothing
+{
+class ClothingActorParam;
+class ClothingScene;
+
+
+class ClothingRenderProxyImpl : public ClothingRenderProxy, public UserAllocated, public ApexRWLockable
+{
+public:
+ APEX_RW_LOCKABLE_BOILERPLATE
+
+ ClothingRenderProxyImpl(RenderMeshAssetIntl* rma, bool useFallbackSkinning, bool useCustomVertexBuffer, const nvidia::HashMap<uint32_t, ApexSimpleString>& overrideMaterials, const PxVec3* morphTargetNewPositions, const uint32_t* morphTargetVertexOffsets, ClothingScene* scene);
+ virtual ~ClothingRenderProxyImpl();
+
+ // from ApexInterface
+ virtual void release();
+
+ // from Renderable
+ virtual void dispatchRenderResources(UserRenderer& api);
+ virtual PxBounds3 getBounds() const
+ {
+ return mBounds;
+ }
+ void setBounds(const PxBounds3& bounds)
+ {
+ mBounds = bounds;
+ }
+
+ // from RenderDataProvider.h
+ virtual void lockRenderResources();
+ virtual void unlockRenderResources();
+ virtual void updateRenderResources(bool rewriteBuffers = false, void* userRenderData = 0);
+
+ void setPose(const PxMat44& pose)
+ {
+ mPose = pose;
+ }
+
+ // from ClothingRenderProxy.h
+ virtual bool hasSimulatedData() const;
+
+ RenderMeshActorIntl* getRenderMeshActor();
+ RenderMeshAssetIntl* getRenderMeshAsset();
+
+ bool usesFallbackSkinning() const
+ {
+ return mUseFallbackSkinning;
+ }
+
+ bool usesCustomVertexBuffer() const
+ {
+ return renderingDataPosition != NULL;
+ }
+
+ const PxVec3* getMorphTargetBuffer() const
+ {
+ return mMorphTargetNewPositions;
+ }
+
+ void setOverrideMaterial(uint32_t i, const char* overrideMaterialName);
+ bool overrideMaterialsEqual(const nvidia::HashMap<uint32_t, ApexSimpleString>& overrideMaterials);
+
+ uint32_t getTimeInPool() const;
+ void setTimeInPool(uint32_t time);
+
+ void notifyAssetRelease();
+
+ PxVec3* renderingDataPosition;
+ PxVec3* renderingDataNormal;
+ PxVec4* renderingDataTangent;
+
+private:
+ RenderMeshActorIntl* createRenderMeshActor(RenderMeshAssetIntl* renderMeshAsset, ClothingActorParam* actorDesc);
+
+ PxBounds3 mBounds;
+ PxMat44 mPose;
+
+ RenderMeshActorIntl* mRenderMeshActor;
+ RenderMeshAssetIntl* mRenderMeshAsset;
+
+ ClothingScene* mScene;
+
+ bool mUseFallbackSkinning;
+ HashMap<uint32_t, ApexSimpleString> mOverrideMaterials;
+ const PxVec3* mMorphTargetNewPositions; // just to compare, only read it in constructor (it may be released)
+
+ uint32_t mTimeInPool;
+
+ Mutex mRMALock;
+};
+
+}
+} // namespace nvidia
+
+#endif // CLOTHING_RENDER_PROXY_IMPL_H
diff --git a/APEX_1.4/module/clothing/include/ClothingScene.h b/APEX_1.4/module/clothing/include/ClothingScene.h
new file mode 100644
index 00000000..0e194358
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/ClothingScene.h
@@ -0,0 +1,233 @@
+/*
+ * 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.
+ */
+
+
+#ifndef CLOTHING_SCENE_H
+#define CLOTHING_SCENE_H
+
+#include "ApexContext.h"
+#include "ModuleIntl.h"
+#include "ApexResource.h"
+
+#include "ClothStructs.h"
+
+#include "PsSync.h"
+#include "PxTask.h"
+#include "PsTime.h"
+
+#if APEX_UE4
+#define CLOTHING_BEFORE_TICK_START_TASK_NAME "ClothingScene::ClothingBeforeTickStartTask"
+#endif
+
+#if APEX_CUDA_SUPPORT
+namespace nvidia
+{
+class PhysXGpuIndicator;
+}
+#endif
+
+namespace nvidia
+{
+
+namespace cloth
+{
+class Cloth;
+class Factory;
+class Solver;
+}
+
+
+namespace apex
+{
+class DebugRenderParams;
+class RenderMeshAssetIntl;
+class ApexSimpleString;
+}
+
+namespace clothing
+{
+class ModuleClothingImpl;
+class ClothingAssetImpl;
+class ClothingCookingTask;
+class ClothingDebugRenderParams;
+
+class ClothingRenderProxyImpl;
+
+
+class ClothingScene : public ModuleSceneIntl, public ApexContext, public ApexResourceInterface, public ApexResource
+{
+public:
+ ClothingScene(ModuleClothingImpl& module, SceneIntl& scene, RenderDebugInterface* renderDebug, ResourceList& list);
+ ~ClothingScene();
+
+ /* ModuleSceneIntl */
+ virtual void simulate(float elapsedTime);
+ virtual bool needsManualSubstepping() const;
+ virtual void interStep(uint32_t substepNumber, uint32_t maxSubSteps);
+ virtual void submitTasks(float elapsedTime, float substepSize, uint32_t numSubSteps);
+ virtual void setTaskDependencies();
+ virtual void fetchResults();
+
+#if PX_PHYSICS_VERSION_MAJOR == 3
+ void setModulePhysXScene(PxScene*);
+ PxScene* getModulePhysXScene() const
+ {
+ return mPhysXScene;
+ }
+#endif
+
+ void release();
+ void visualize();
+
+ virtual Module* getModule();
+
+ virtual SceneStats* getStats()
+ {
+ return 0;
+ }
+
+ bool lockRenderResources()
+ {
+ renderLockAllActors(); // Lock options not implemented yet
+ return true;
+ }
+
+ bool unlockRenderResources()
+ {
+ renderUnLockAllActors(); // Lock options not implemented yet
+ return true;
+ }
+
+ /* ApexResourceInterface */
+ uint32_t getListIndex() const
+ {
+ return m_listIndex;
+ }
+ void setListIndex(ResourceList& list, uint32_t index)
+ {
+ m_listIndex = index;
+ m_list = &list;
+ }
+
+ bool isSimulating() const;
+
+ void registerAsset(ClothingAssetImpl* asset);
+ void unregisterAsset(ClothingAssetImpl* asset);
+ void removeRenderProxies(ClothingAssetImpl* asset);
+
+ uint32_t submitCookingTask(ClothingCookingTask* newTask);
+
+ float getAverageSimulationFrequency()
+ {
+ return mAverageSimulationFrequency;
+ }
+
+ SceneIntl* getApexScene()
+ {
+ return mApexScene;
+ }
+
+ const ClothingDebugRenderParams* getDebugRenderParams() const
+ {
+ return mClothingDebugRenderParams;
+ }
+
+ ClothFactory getClothFactory(bool& useCuda);
+ cloth::Solver* getClothSolver(bool useCuda);
+
+ void lockScene();
+ void unlockScene();
+
+ void setSceneRunning(bool on);
+
+ void embeddedPostSim();
+
+ // render proxy pool
+ ClothingRenderProxyImpl* getRenderProxy(RenderMeshAssetIntl* rma, bool useFallbackSkinning, bool useCustomVertexBuffer, const HashMap<uint32_t, ApexSimpleString>& overrideMaterials, const PxVec3* morphTargetNewPositions, const uint32_t* morphTargetVertexOffsets);
+ void tickRenderProxies();
+
+protected:
+
+ ModuleClothingImpl* mModule;
+ SceneIntl* mApexScene;
+#if PX_PHYSICS_VERSION_MAJOR == 3
+ PxScene* mPhysXScene;
+#endif
+
+ Array<ClothingAssetImpl*> mClothingAssets;
+ nvidia::Mutex mClothingAssetsMutex;
+
+ float mSumBenefit;
+
+ void destroy();
+
+ class ClothingBeforeTickStartTask : public PxTask
+ {
+ public:
+ ClothingBeforeTickStartTask() : m_pScene(NULL)
+ {
+ }
+
+ void setScene(ClothingScene* pScene)
+ {
+ m_pScene = pScene;
+ }
+
+ virtual void run();
+ virtual const char* getName() const;
+
+ ClothingScene* m_pScene;
+ } mClothingBeforeTickStartTask;
+
+private:
+
+ class WaitForSolverTask* mWaitForSolverTask;
+ class ClothingSceneSimulateTask* mSimulationTask;
+ nvidia::Mutex mSceneLock;
+ int32_t mSceneRunning;
+
+ RenderDebugInterface* mRenderDebug;
+
+ DebugRenderParams* mDebugRenderParams;
+ ClothingDebugRenderParams* mClothingDebugRenderParams;
+
+ ClothingCookingTask* mCurrentCookingTask;
+ nvidia::Mutex mCookingTaskMutex;
+
+ Array<float> mLastSimulationDeltas;
+ uint32_t mCurrentSimulationDelta;
+ float mAverageSimulationFrequency;
+
+#ifndef _DEBUG
+ // For statistics
+ uint32_t mFramesCount;
+ float mSimulatedTime;
+ float mTimestep;
+#endif
+
+ nvidia::Time mClothingSimulationTime;
+
+ ClothFactory mCpuFactory;
+#if APEX_CUDA_SUPPORT
+ ClothFactory mGpuFactory;
+ PhysXGpuIndicator* mPhysXGpuIndicator;
+#endif
+
+ Mutex mRenderProxiesLock;
+ nvidia::HashMap<RenderMeshAssetIntl*, nvidia::Array<ClothingRenderProxyImpl*> > mRenderProxies;
+
+ friend class ModuleClothingImpl;
+ friend class ClothingActorImpl;
+};
+
+}
+} // namespace nvidia
+
+#endif // CLOTHING_SCENE_H
diff --git a/APEX_1.4/module/clothing/include/Cooking.h b/APEX_1.4/module/clothing/include/Cooking.h
new file mode 100644
index 00000000..c8f3e8a4
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/Cooking.h
@@ -0,0 +1,167 @@
+/*
+ * 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.
+ */
+
+
+#ifndef COOKING_H
+#define COOKING_H
+
+#include "CookingAbstract.h"
+
+#include <PxVec3.h>
+#include <PsArray.h>
+
+// Tae - 301 -> 302: fiberless cooker change
+#define COOKED_DATA_VERSION 302
+
+namespace nvidia
+{
+namespace clothing
+{
+
+class ClothingCookedPhysX3Param;
+
+class Cooking : public CookingAbstract
+{
+public:
+ Cooking(bool withFibers) : mWithFibers(withFibers) {}
+
+ virtual NvParameterized::Interface* execute();
+ static uint32_t getCookingVersion()
+ {
+ return COOKED_DATA_VERSION;
+ }
+
+private:
+ ClothingCookedPhysX3Param* trivialCooker(uint32_t subMeshIndex) const;
+ ClothingCookedPhysX3Param* fiberCooker(uint32_t subMeshIndex) const;
+
+ void computeUniqueEdges(uint32_t subMeshIndex);
+ void refineUniqueEdges(uint32_t physicalMeshIndex);
+ void computeVertexWeights(ClothingCookedPhysX3Param* cookedData, uint32_t subMeshIndex) const;
+ void createVirtualParticles(ClothingCookedPhysX3Param* cookedData, uint32_t subMeshIndex);
+ void createSelfcollisionIndices(ClothingCookedPhysX3Param* cookedData, uint32_t subMeshIndex) const;
+ bool verifyValidity(const ClothingCookedPhysX3Param* cookedData, uint32_t subMeshIndex);
+ void fillOutSetsDesc(ClothingCookedPhysX3Param* cookedData);
+ void groupPhases(ClothingCookedPhysX3Param* cookedData, uint32_t subMeshIndex, uint32_t startIndex, uint32_t endIndex, Array<uint32_t>& phaseEnds) const;
+
+ void dumpObj(const char* filename, uint32_t subMeshIndex) const;
+ void dumpApx(const char* filename, const NvParameterized::Interface* data) const;
+
+ bool mWithFibers;
+
+ static bool mTetraWarning;
+
+ struct Edge
+ {
+ Edge();
+ Edge(uint32_t v0, uint32_t v1, uint32_t v2);
+
+ uint32_t vertex0, vertex1;
+ uint32_t vertex2, vertex3;
+ float maxAngle;
+ bool isQuadDiagonal;
+ bool isUsed;
+
+ PX_FORCE_INLINE bool operator()(const Edge& e1, const Edge& e2) const
+ {
+ return e1 < e2;
+ }
+
+ PX_FORCE_INLINE bool operator!=(const Edge& other) const
+ {
+ return vertex0 != other.vertex0 || vertex1 != other.vertex1;
+ }
+ PX_FORCE_INLINE bool operator==(const Edge& other) const
+ {
+ return vertex0 == other.vertex0 && vertex1 == other.vertex1;
+ }
+ PX_FORCE_INLINE bool operator<(const Edge& other) const
+ {
+ if (vertex0 != other.vertex0)
+ {
+ return vertex0 < other.vertex0;
+ }
+
+ return vertex1 < other.vertex1;
+ }
+
+ PX_FORCE_INLINE uint32_t largestIndex() const
+ {
+ uint32_t largest = PxMax(vertex0, vertex1);
+ largest = PxMax(largest, vertex2);
+ if (vertex3 != 0xffffffff)
+ {
+ largest = PxMax(largest, vertex3);
+ }
+ return largest;
+ }
+ };
+
+ struct SortHiddenEdges
+ {
+ SortHiddenEdges(nvidia::Array<Edge>& uniqueEdges) : mUniqueEdges(uniqueEdges) {}
+
+ bool operator()(uint32_t a, uint32_t b) const
+ {
+ return mUniqueEdges[a].maxAngle < mUniqueEdges[b].maxAngle;
+ }
+
+ private:
+ SortHiddenEdges& operator=(const SortHiddenEdges&);
+
+ nvidia::Array<Edge>& mUniqueEdges;
+ };
+
+ nvidia::Array<Edge> mUniqueEdges;
+ uint32_t findUniqueEdge(uint32_t index1, uint32_t index2) const;
+
+ struct VirtualParticle
+ {
+ VirtualParticle(uint32_t i0, uint32_t i1, uint32_t i2)
+ {
+ indices[0] = i0;
+ indices[1] = i1;
+ indices[2] = i2;
+ tableIndex = 0;
+ }
+
+ void rotate(uint32_t count)
+ {
+ while (count--)
+ {
+ const uint32_t temp = indices[2];
+ indices[2] = indices[1];
+ indices[1] = indices[0];
+ indices[0] = temp;
+ }
+ }
+
+ uint32_t indices[3];
+ uint32_t tableIndex;
+ };
+
+ struct EdgeAndLength
+ {
+ EdgeAndLength(uint32_t edgeNumber, float length) : mEdgeNumber(edgeNumber), mLength(length) {}
+ uint32_t mEdgeNumber;
+ float mLength;
+
+ bool operator<(const EdgeAndLength& other) const
+ {
+ return mLength < other.mLength;
+ }
+ };
+};
+
+}
+}
+
+
+#endif // COOKING_H
diff --git a/APEX_1.4/module/clothing/include/CookingAbstract.h b/APEX_1.4/module/clothing/include/CookingAbstract.h
new file mode 100644
index 00000000..992d7a78
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/CookingAbstract.h
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+
+
+#ifndef COOKING_ABSTRACT_H
+#define COOKING_ABSTRACT_H
+
+#include "PsUserAllocated.h"
+#include "PxVec3.h"
+#include "PsArray.h"
+#include "ApexUsingNamespace.h"
+
+namespace NvParameterized
+{
+class Interface;
+}
+
+namespace nvidia
+{
+namespace clothing
+{
+
+namespace ClothingAssetParametersNS
+{
+struct BoneEntry_Type;
+struct ActorEntry_Type;
+}
+
+typedef ClothingAssetParametersNS::BoneEntry_Type BoneEntry;
+typedef ClothingAssetParametersNS::ActorEntry_Type BoneActorEntry;
+
+using namespace physx::shdfnd;
+
+class CookingAbstract : public nvidia::UserAllocated
+{
+public:
+ CookingAbstract() : mBoneActors(NULL), mNumBoneActors(0), mBoneEntries(NULL), mNumBoneEntries(0), mBoneVertices(NULL), mMaxConvexVertices(256),
+ mFreeTempMemoryWhenDone(NULL), mScale(1.0f), mVirtualParticleDensity(0.0f), mSelfcollisionRadius(0.0f)
+ {
+ }
+
+ virtual ~CookingAbstract()
+ {
+ if (mFreeTempMemoryWhenDone != NULL)
+ {
+ PX_FREE(mFreeTempMemoryWhenDone);
+ mFreeTempMemoryWhenDone = NULL;
+ }
+ }
+
+ struct PhysicalMesh
+ {
+ PhysicalMesh() : meshID(0), isTetrahedral(false), vertices(NULL), numVertices(0), numSimulatedVertices(0), numMaxDistance0Vertices(0),
+ indices(NULL), numIndices(0), numSimulatedIndices(0), largestTriangleArea(0.0f), smallestTriangleArea(0.0f) {}
+
+ uint32_t meshID;
+ bool isTetrahedral;
+
+ PxVec3* vertices;
+ uint32_t numVertices;
+ uint32_t numSimulatedVertices;
+ uint32_t numMaxDistance0Vertices;
+
+ uint32_t* indices;
+ uint32_t numIndices;
+ uint32_t numSimulatedIndices;
+
+ void computeTriangleAreas();
+ float largestTriangleArea;
+ float smallestTriangleArea;
+ };
+
+ void addPhysicalMesh(const PhysicalMesh& physicalMesh);
+ void setConvexBones(const BoneActorEntry* boneActors, uint32_t numBoneActors, const BoneEntry* boneEntries, uint32_t numBoneEntries, const PxVec3* boneVertices, uint32_t maxConvexVertices);
+
+ void freeTempMemoryWhenDone(void* memory)
+ {
+ mFreeTempMemoryWhenDone = memory;
+ }
+ void setScale(float scale)
+ {
+ mScale = scale;
+ }
+ void setVirtualParticleDensity(float density)
+ {
+ PX_ASSERT(density >= 0.0f);
+ PX_ASSERT(density <= 1.0f);
+ mVirtualParticleDensity = density;
+ }
+ void setSelfcollisionRadius(float radius)
+ {
+ PX_ASSERT(radius >= 0.0f);
+ mSelfcollisionRadius = radius;
+ }
+ void setGravityDirection(const PxVec3& gravityDir)
+ {
+ mGravityDirection = gravityDir;
+ mGravityDirection.normalize();
+ }
+
+ virtual NvParameterized::Interface* execute() = 0;
+
+ bool isValid() const;
+
+protected:
+ Array<PhysicalMesh> mPhysicalMeshes;
+
+ const BoneActorEntry* mBoneActors;
+ uint32_t mNumBoneActors;
+ const BoneEntry* mBoneEntries;
+ uint32_t mNumBoneEntries;
+ const PxVec3* mBoneVertices;
+ uint32_t mMaxConvexVertices;
+
+ void* mFreeTempMemoryWhenDone;
+ float mScale;
+
+ float mVirtualParticleDensity;
+ float mSelfcollisionRadius;
+
+ PxVec3 mGravityDirection;
+};
+
+}
+} // namespace nvidia
+
+#endif // COOKING_ABSTRACT_H
diff --git a/APEX_1.4/module/clothing/include/CookingPhysX.h b/APEX_1.4/module/clothing/include/CookingPhysX.h
new file mode 100644
index 00000000..60ff9aaa
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/CookingPhysX.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+
+#ifndef COOKING_PHYS_X_H
+#define COOKING_PHYS_X_H
+
+#include "CookingAbstract.h"
+
+namespace nvidia
+{
+namespace apex
+{
+template<class T>
+class ParamArray;
+}
+namespace clothing
+{
+
+
+class CookingPhysX : public CookingAbstract
+{
+public:
+
+ virtual NvParameterized::Interface* execute() { return 0;}
+
+ static uint32_t getCookingVersion()
+ {
+#if PX_PHYSICS_VERSION_MAJOR == 3
+ return PX_PHYSICS_VERSION;
+#else
+ return 0;
+#endif
+ }
+
+protected:
+};
+
+}
+} // namespace nvidia
+
+
+#endif // COOKING_PHYS_X_H
diff --git a/APEX_1.4/module/clothing/include/ModuleClothingHelpers.h b/APEX_1.4/module/clothing/include/ModuleClothingHelpers.h
new file mode 100644
index 00000000..f2f43c1c
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/ModuleClothingHelpers.h
@@ -0,0 +1,461 @@
+/*
+ * 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.
+ */
+
+
+#ifndef MODULE_CLOTHING_HELPERS_H
+#define MODULE_CLOTHING_HELPERS_H
+
+#include "RenderMeshAssetIntl.h"
+#include "RenderDebugInterface.h"
+#include "PsUserAllocated.h"
+#include "ApexSharedUtils.h"
+
+namespace nvidia
+{
+namespace clothing
+{
+
+class ClothingCookedParam;
+
+// used for mesh skinning map creation
+struct TriangleWithNormals
+{
+ void init()
+ {
+ // bestDot and worstDot store the difference of the vertex normals from the face normal
+ PxVec3 faceNormal = (vertices[1] - vertices[0]).cross(vertices[2] - vertices[0]);
+ faceNormal.normalize();
+ float bestDot = -1.0f;
+ float worstDot = 1.0f;
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ const float dot = faceNormal.dot(normals[j]);
+ bestDot = PxMax(bestDot, dot);
+ worstDot = PxMin(worstDot, dot);
+ }
+
+ doNotUse = worstDot < 0.0f || bestDot < 0.5f; // bestDot has more than 60 degrees difference from faceNormal
+
+ // init the rest of the triangle members
+ timestamp = -1;
+ valid = 0;
+
+ bounds.minimum = bounds.maximum = vertices[0];
+ bounds.include(vertices[1]);
+ bounds.include(vertices[2]);
+ PX_ASSERT(!bounds.isEmpty());
+ }
+
+ PxVec3 vertices[3];
+ PxVec3 normals[3];
+ uint32_t faceIndex0;
+ int32_t timestamp : 30;
+ uint32_t valid : 2;
+
+ PxBounds3 bounds;
+
+ PxVec3 tempBaryVertex;
+ PxVec3 tempBaryNormal;
+ PxVec3 tempBaryTangent;
+
+ uint32_t master;
+
+ bool doNotUse;
+};
+
+
+
+class ModuleClothingHelpers
+{
+public:
+ /**
+ \brief A fast inverse square root. Mainly used to normalize vectors more quickly (and less accurately)
+ */
+ inline static float invSqrt(float input)
+ {
+ const float halfInput = 0.5f * input;
+ int32_t i = *(int*)&input;
+
+ i = 0x5f375a86 - (i >> 1);
+ input = *(float*) & i;
+ input = input * (1.5f - halfInput * input * input);
+ return input;
+ }
+
+
+ static float triangleArea(const PxVec3& v1, const PxVec3& v2, const PxVec3& v3)
+ {
+ const PxVec3 a = v2 - v1;
+ const PxVec3 b = v3 - v1;
+ const PxVec3 c = a.cross(b);
+ //PxVec3 normal = c;
+ //normal.normalize();
+ //const float area = normal.dot(c) * 0.5f;
+ //return area;
+ return c.magnitude() * 0.5f;
+ }
+
+#pragma warning(push)
+#pragma warning(disable:4127) // (conditional expression is constant)
+ template<bool method1>
+ static PxVec3 computeTriBarycentricCoords(const PxVec3& a, const PxVec3& b, const PxVec3& c, const PxVec3& g)
+ {
+ PxVec3 bary(0, 0, 0);
+ if (method1)
+ {
+ const float abc = triangleArea(a, b, c);
+
+ // Convert our position from local space into barycentric coordinates + offset from surface.
+ if (abc > 0.0f)
+ {
+ PxVec3 Edge0 = b - a;
+ PxVec3 Edge1 = c - a;
+
+ PxVec3 planeNormal = Edge0.cross(Edge1);
+ planeNormal.normalize();
+
+ // See comments in set() for computation of d
+ float planeD = -a.dot(planeNormal);
+
+ // Valid for plane equation a*x + b*y + c*z + d = 0
+ const float distance = g.dot(planeNormal) + planeD;
+
+ // project on plane
+ const PxVec3 p = g - planeNormal * distance;
+
+ bary.x = triangleArea(p, b, c) / abc;
+ bary.y = triangleArea(p, c, a) / abc;
+ bary.z = distance;
+ }
+ }
+ else
+ {
+ // triangle's normal
+ PxVec3 faceNormal = (b - a).cross(c - a);
+ faceNormal.normalize();
+
+ // distance to plane
+ float h = (g - a).dot(faceNormal);
+
+ // project g onto plane
+ PxVec3 pg = g - (h * faceNormal);
+
+ // compute barycentric coordinates of g in <a,b,c>
+ float s(0), t(0);
+ generateBarycentricCoordinatesTri(a, b, c, pg, s, t);
+
+ // PH: s and t are not the barycentric coordinate of a and b, but of b and c
+ bary.x = 1 - s - t;
+ bary.y = s;
+ bary.z = h;
+ }
+ return bary;
+ }
+#pragma warning(pop)
+
+ static float TetraVolume(const PxVec3& p0, const PxVec3& p1, const PxVec3& p2, const PxVec3& p3)
+ {
+ return (p1 - p0).cross(p2 - p0).dot(p3 - p0) * (1.0f / 6.0f);
+ }
+
+
+
+ static PxVec3 computeTetraBarycentricCoords(const PxVec3& p0, const PxVec3& p1, const PxVec3& p2, const PxVec3& p3, const PxVec3& p)
+ {
+ float tetraVol = TetraVolume(p0, p1, p2, p3);
+ PX_ASSERT(tetraVol != 0.0f);
+ PxVec3 bary;
+ bary.x = TetraVolume(p, p1, p2, p3) / tetraVol;
+ bary.y = TetraVolume(p, p2, p0, p3) / tetraVol;
+ bary.z = TetraVolume(p, p3, p0, p1) / tetraVol;
+ /*
+ bary.x = PxAbs(bary.x);
+ bary.y = PxAbs(bary.y);
+ bary.z = PxAbs(bary.z);
+ */
+
+ return bary;
+ }
+
+
+
+ static float barycentricDist(const PxVec3& barycentricCoords)
+ {
+ float dist = 0.0f;
+ if (-barycentricCoords.x > dist)
+ {
+ dist = -barycentricCoords.x;
+ }
+ if (-barycentricCoords.y > dist)
+ {
+ dist = -barycentricCoords.y;
+ }
+ if (-barycentricCoords.z > dist)
+ {
+ dist = -barycentricCoords.z;
+ }
+ float sum = barycentricCoords.x + barycentricCoords.y + barycentricCoords.z - 1.0f;
+ if (sum > dist)
+ {
+ dist = sum;
+ }
+ return dist;
+ }
+
+
+ static bool pointInTetra(const PxVec3& p0, const PxVec3& p1, const PxVec3& p2, const PxVec3& p3, const PxVec3& p, const float epsilon)
+ {
+ PxVec3 n = (p1 - p0).cross(p2 - p0);
+ float s0 = n.dot(p - p0);
+
+ n = (p2 - p0).cross(p3 - p0);
+ float s1 = n.dot(p - p0);
+
+ n = (p3 - p0).cross(p1 - p0);
+ float s2 = n.dot(p - p0);
+
+ n = (p3 - p1).cross(p2 - p1);
+ float s3 = n.dot(p - p1);
+
+ return ((s0 >= -epsilon) && (s1 >= -epsilon) && (s2 >= -epsilon) && (s3 >= -epsilon)) ||
+ ((s0 <= epsilon) && (s1 <= epsilon) && (s2 <= epsilon) && (s3 <= epsilon));
+ }
+
+
+
+ struct Ellipsoid
+ {
+ PxVec3 center;
+ PxVec3 xAxis; // contains scale
+ PxVec3 yAxis; // contains scale
+ PxVec3 zAxis; // contains scale
+ };
+
+
+
+ float GetWeight(float value, float maxValue)
+ {
+ float x = PxAbs(value) / PxAbs(maxValue);
+ if (value > 1.0)
+ {
+ value = 1.0;
+ }
+ if (value < 0.0)
+ {
+ value = 0.0;
+ }
+ //return cos(HalfPi*x)*cos(HalfPi*x);
+ return PxExp(-x * x * 4);
+ }
+
+
+
+ // Returns a value 0 and 1 if inside, > 1 if outside
+ float GetEllipsoidDistance(const Ellipsoid& e, const PxVec3& p)
+ {
+#define SQR(_x) ((_x)*(_x))
+
+ PxVec3 cp = p - e.center;
+ float xProj = cp.dot(e.xAxis);
+ float yProj = cp.dot(e.yAxis);
+ float zProj = cp.dot(e.zAxis);
+
+ return sqrtf(SQR(xProj) + SQR(yProj) + SQR(zProj));
+ }
+
+
+
+ float GetEllipsoidWeight(const Ellipsoid& e, const PxVec3& p)
+ {
+ float d = GetEllipsoidDistance(e, p);
+ return GetWeight(d, 1.0f);
+ }
+
+
+
+ static PxVec3 projectOnPlane(const PxVec3& planeNormal, float planeD, const PxVec3& point, const PxVec3& projectionDirection)
+ {
+ // from http://en.wikipedia.org/wiki/Line-plane_intersection
+
+ //t={-d-\mathbf{l}_a\cdot\mathbf{n} \over (\mathbf{l}_b-\mathbf{l}_a)\cdot\mathbf{n}}.
+
+ const float nominator = -planeD - point.dot(planeNormal);
+ const float denominator = projectionDirection.dot(planeNormal);
+
+ if (denominator != 0.0f)
+ {
+ const float t = nominator / denominator;
+
+ return point + t * projectionDirection;
+ }
+
+ return point;
+ }
+
+
+ /**
+ Given target point p and triangle with points p1, p2, p3 and normals n1, n2, n3.
+ Find barycentric coordinates (x, y, z) and height h, such that z = 1-x-y and
+ x*p1+y*p2+z*p3 + (x*n1+y*p2+y*p3)*h
+
+ This means finding a point on the triangle where the interpolated normal goes through the target point.
+ FinalBary will contain (x, y, h).
+ */
+ static bool iterateOnTriangle(uint32_t maxIterations, float convergenceThreshold, const TriangleWithNormals& triangle, const PxVec3& position,
+ PxVec3& finalBary)
+ {
+ uint32_t iteration = 0;
+
+ PxVec3 planeNormal = (triangle.vertices[1] - triangle.vertices[0]).cross(triangle.vertices[2] - triangle.vertices[0]);
+ planeNormal.normalize();
+ const float planeD = -triangle.vertices[0].dot(planeNormal);
+
+ // start with normal from the middle of the triangle
+ PxVec3 trustedBary(1.0f / 3.0f);
+ //PxVec3 tempNormal = planeNormal;
+ PxVec3 tempNormal = trustedBary.x * triangle.normals[0] + trustedBary.y * triangle.normals[1] + trustedBary.z * triangle.normals[2];
+
+ float baryConvergence = PX_MAX_F32;
+
+ float trust = 1.0f;
+ while (iteration++ < maxIterations)
+ {
+ PxVec3 tempPosOnTriangle = projectOnPlane(planeNormal, planeD, position, tempNormal);
+ PxVec3 tempBary = ModuleClothingHelpers::computeTriBarycentricCoords<false>(triangle.vertices[0], triangle.vertices[1], triangle.vertices[2], tempPosOnTriangle);
+
+ // projectOnPlane should lead to position on plane
+ if (PxAbs(tempBary.z) > 0.001f)
+ {
+ return false;
+ }
+
+ // compute real bary coordinate
+ tempBary.z = 1.0f - tempBary.x - tempBary.y;
+
+ const PxVec3 errorVec = tempBary - trustedBary;
+ baryConvergence = errorVec.dot(errorVec);
+
+ // average bary coordinate, graded sum of new values
+ trustedBary *= (1.0f - trust);
+ trustedBary += trust * tempBary;
+
+ // do we still maintain the barycentric invariant?
+ if (PxAbs(1.0f - (trustedBary.x + trustedBary.y + trustedBary.z)) > 0.001f)
+ {
+ return false;
+ }
+
+ // find new normal
+ tempNormal = trustedBary.x * triangle.normals[0] + trustedBary.y * triangle.normals[1] + trustedBary.z * triangle.normals[2];
+
+ if (baryConvergence < convergenceThreshold)
+ {
+ break;
+ }
+
+ trust *= 0.8f;
+ }
+
+ if (baryConvergence < convergenceThreshold)
+ {
+ const PxVec3 posOnTriangle = trustedBary.x * triangle.vertices[0] + trustedBary.y * triangle.vertices[1] + trustedBary.z * triangle.vertices[2];
+
+ const float length = tempNormal.normalize();
+ float avgHeight = tempNormal.dot(position - posOnTriangle) / length;
+
+ finalBary = trustedBary;
+ finalBary.z = avgHeight;
+
+ return true;
+ }
+
+ return false;
+ }
+
+
+
+ static void computeTriangleBarys(TriangleWithNormals& triangle, const PxVec3& position, const PxVec3& normal, const PxVec3& tangent, float thickness, int32_t timeStamp, bool onlyTangent)
+ {
+ // todo PH: assert is finite!
+
+ if (triangle.timestamp < timeStamp)
+ {
+ triangle.valid = 0;
+
+ // This is the value that is used when nothing is hit
+ triangle.tempBaryVertex = PxVec3(PX_MAX_F32);
+ triangle.tempBaryNormal = PxVec3(PX_MAX_F32);
+ triangle.tempBaryTangent = PxVec3(PX_MAX_F32);
+
+ PxVec3 positionBary(PX_MAX_F32);
+ PxVec3 normalBary(PX_MAX_F32);
+ PxVec3 tangentBary(PX_MAX_F32);
+
+ if (onlyTangent || iterateOnTriangle(100, 0.0001f, triangle, position, positionBary))
+ {
+ triangle.valid = 1;
+
+ triangle.tempBaryVertex = positionBary;
+ PX_ASSERT(triangle.tempBaryVertex.isFinite());
+
+ if (!normal.isZero())
+ {
+ if (iterateOnTriangle(100, 0.0001f, triangle, normal, normalBary))
+ {
+ triangle.valid = 2;
+
+ triangle.tempBaryNormal = normalBary;
+ PX_ASSERT(triangle.tempBaryNormal.isFinite());
+ }
+ else
+ {
+ PxVec3 newNormal = normal;
+ for (uint32_t iter = 0; iter < 10; iter++)
+ {
+ // changing normal size might help
+ newNormal = (position + newNormal) / 2.0f;
+ if (iterateOnTriangle(10, 0.0001f, triangle, newNormal, normalBary))
+ {
+ triangle.valid = 2;
+
+ triangle.tempBaryNormal = normalBary;
+ PX_ASSERT(triangle.tempBaryNormal.isFinite());
+
+ break;
+ }
+ }
+ if (triangle.valid != 2)
+ {
+ // now this is a really low approximation, but still better than nothing
+ triangle.tempBaryNormal = triangle.tempBaryVertex;
+ triangle.tempBaryNormal.z += thickness;
+ }
+ }
+ }
+
+ if (!tangent.isZero())
+ {
+ if(iterateOnTriangle(1, PX_MAX_F32, triangle, tangent, tangentBary))
+ {
+ triangle.tempBaryTangent = tangentBary;
+ PX_ASSERT(triangle.tempBaryTangent.isFinite());
+ }
+ }
+ }
+
+ triangle.timestamp = timeStamp;
+ }
+ }
+};
+
+}
+} // namespace nvidia
+
+#endif // MODULE_CLOTHING_HELPERS_H
diff --git a/APEX_1.4/module/clothing/include/ModuleClothingImpl.h b/APEX_1.4/module/clothing/include/ModuleClothingImpl.h
new file mode 100644
index 00000000..4cf91642
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/ModuleClothingImpl.h
@@ -0,0 +1,268 @@
+/*
+ * 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.
+ */
+
+
+#ifndef MODULE_CLOTHING_IMPL_H
+#define MODULE_CLOTHING_IMPL_H
+
+#include "ModuleClothing.h"
+#include "ClothingAsset.h"
+#include "ApexSDKIntl.h"
+#include "ModuleIntl.h"
+#include "ModuleBase.h"
+#include "ApexSDKHelpers.h"
+#include "ModuleClothingRegistration.h"
+#include "ClothStructs.h"
+#include "ApexRWLockable.h"
+#include "ApexPvdClient.h"
+// The clothing GPU source is in a separate DLL, we're going to load it and get a CuFactory create method
+#if PX_WINDOWS_FAMILY
+#include "ModuleUpdateLoader.h"
+#endif
+
+class ClothingPhysicalMeshParameters;
+
+namespace physx
+{
+ class PxCudaContextManager;
+}
+
+namespace nvidia
+{
+#if APEX_CUDA_SUPPORT
+ namespace cloth
+ {
+ class CuFactory;
+ }
+#endif
+
+namespace apex
+{
+class ApexIsoMesh;
+class RenderMeshAssetAuthoringIntl;
+class ClothingAsset;
+class ClothingAssetAuthoring;
+}
+namespace clothing
+{
+class ClothingScene;
+class ClothingAssetImpl;
+class ClothingAssetAuthoringImpl;
+class ClothingPhysicalMeshImpl;
+class CookingAbstract;
+class DummyActor;
+class DummyAsset;
+class SimulationAbstract;
+
+
+class BackendFactory
+{
+public:
+ virtual bool isMatch(const char* simulationBackend) = 0;
+ virtual const char* getName() = 0;
+ virtual uint32_t getCookingVersion() = 0;
+ virtual uint32_t getCookedDataVersion(const NvParameterized::Interface* cookedData) = 0;
+ virtual CookingAbstract* createCookingJob() = 0;
+ virtual void releaseCookedInstances(NvParameterized::Interface* cookedData) = 0;
+ virtual SimulationAbstract* createSimulation(ClothingScene* clothingScene, bool useHW) = 0;
+};
+
+
+
+class ModuleClothingImpl : public ModuleClothing, public ModuleIntl, public ModuleBase, public ApexRWLockable
+{
+public:
+ APEX_RW_LOCKABLE_BOILERPLATE
+
+ ModuleClothingImpl(ApexSDKIntl* sdk);
+
+ // from ApexInterface
+ PX_INLINE void release()
+ {
+ ModuleBase::release();
+ }
+
+ // from Module
+ void init(NvParameterized::Interface& desc);
+ NvParameterized::Interface* getDefaultModuleDesc();
+ PX_INLINE const char* getName() const
+ {
+ return ModuleBase::getName();
+ }
+ AuthObjTypeID getModuleID() const;
+
+ RenderableIterator* createRenderableIterator(const Scene&);
+
+ ClothingPhysicalMesh* createEmptyPhysicalMesh();
+ ClothingPhysicalMesh* createSingleLayeredMesh(RenderMeshAssetAuthoring* asset, uint32_t subdivisionSize, bool mergeVertices, bool closeHoles, IProgressListener* progress);
+
+ PX_INLINE NvParameterized::Interface* getApexClothingActorParams(void) const
+ {
+ return mApexClothingActorParams;
+ }
+ PX_INLINE NvParameterized::Interface* getApexClothingPreviewParams(void) const
+ {
+ return mApexClothingPreviewParams;
+ }
+
+ // from ModuleIntl
+ virtual void destroy();
+ virtual ModuleSceneIntl* createInternalModuleScene(SceneIntl&, RenderDebugInterface*);
+ virtual void releaseModuleSceneIntl(ModuleSceneIntl&);
+ virtual uint32_t forceLoadAssets();
+
+#ifndef WITHOUT_PVD
+ virtual void initPvdClasses(pvdsdk::PvdDataStream& pvdDataStream);
+ virtual void initPvdInstances(pvdsdk::PvdDataStream& pvdDataStream);
+ virtual void destroyPvdInstances();
+#endif
+
+ // own methods
+
+ ClothingScene* getClothingScene(const Scene& scene);
+
+ ClothingPhysicalMeshImpl* createPhysicalMeshInternal(ClothingPhysicalMeshParameters* mesh);
+
+ void releasePhysicalMesh(ClothingPhysicalMeshImpl* physicalMesh);
+ void unregisterAssetWithScenes(ClothingAssetImpl* asset);
+ void notifyReleaseGraphicalData(ClothingAssetImpl* asset);
+
+ Actor* getDummyActor();
+
+ // This pointer will not be released by this module!
+ virtual void registerBackendFactory(BackendFactory* factory);
+ virtual void unregisterBackendFactory(BackendFactory* factory);
+ // this works both with the name of the simulation backend, or the cooking data type
+ BackendFactory* getBackendFactory(const char* simulationBackend);
+
+ ClothFactory createClothFactory(PxCudaContextManager* contextManager);
+ void releaseClothFactory(PxCudaContextManager* contextManager);
+
+ PX_INLINE uint32_t getMaxUnusedPhysXResources() const
+ {
+ return mInternalModuleParams.maxUnusedPhysXResources;
+ }
+ PX_INLINE uint32_t getMaxNumCompartments() const
+ {
+ return mInternalModuleParams.maxNumCompartments;
+ }
+ PX_INLINE bool allowAsyncFetchResults() const
+ {
+ return mInternalModuleParams.asyncFetchResults;
+ }
+ PX_INLINE bool allowAsyncCooking() const
+ {
+ return mInternalModuleParams.allowAsyncCooking;
+ }
+ PX_INLINE uint32_t getAvgSimFrequencyWindowSize() const
+ {
+ return mInternalModuleParams.avgSimFrequencyWindow;
+ }
+ PX_INLINE bool allowApexWorkBetweenSubsteps() const
+ {
+ return mInternalModuleParams.allowApexWorkBetweenSubsteps;
+ }
+ PX_INLINE float getInterCollisionDistance() const
+ {
+ return mInternalModuleParams.interCollisionDistance;
+ }
+ PX_INLINE float getInterCollisionStiffness() const
+ {
+ return mInternalModuleParams.interCollisionStiffness;
+ }
+ PX_INLINE uint32_t getInterCollisionIterations() const
+ {
+ return mInternalModuleParams.interCollisionIterations;
+ }
+ PX_INLINE void setInterCollisionDistance(float distance)
+ {
+ mInternalModuleParams.interCollisionDistance = distance;
+ }
+ PX_INLINE void setInterCollisionStiffness(float stiffness)
+ {
+ mInternalModuleParams.interCollisionStiffness = stiffness;
+ }
+ PX_INLINE void setInterCollisionIterations(uint32_t iterations)
+ {
+ mInternalModuleParams.interCollisionIterations = iterations;
+ }
+ PX_INLINE bool useSparseSelfCollision() const
+ {
+ return mInternalModuleParams.sparseSelfCollision;
+ }
+ PX_INLINE uint32_t getMaxTimeRenderProxyInPool() const
+ {
+ return mInternalModuleParams.maxTimeRenderProxyInPool;
+ }
+
+private:
+ ClothingPhysicalMesh* createSingleLayeredMeshInternal(RenderMeshAssetAuthoringIntl* asset, uint32_t subdivisionSize, bool mergeVertices, bool closeHoles, IProgressListener* progress);
+
+ ResourceList mClothingSceneList;
+ ResourceList mPhysicalMeshes;
+ ResourceList mAssetAuthorableObjectFactories;
+
+ DummyActor* mDummyActor;
+ DummyAsset* mDummyAsset;
+ nvidia::Mutex mDummyProtector;
+
+ class ClothingBackendFactory : public BackendFactory, public nvidia::UserAllocated
+ {
+ public:
+ virtual bool isMatch(const char* simulationBackend);
+ virtual const char* getName();
+ virtual uint32_t getCookingVersion();
+ virtual uint32_t getCookedDataVersion(const NvParameterized::Interface* cookedData);
+ virtual CookingAbstract* createCookingJob();
+ virtual void releaseCookedInstances(NvParameterized::Interface* cookedData);
+ virtual SimulationAbstract* createSimulation(ClothingScene* clothingScene, bool useHW);
+ };
+
+ ClothingBackendFactory mBackendFactory;
+
+ Array<BackendFactory*> mBackendFactories;
+
+ ClothingModuleParameters* mModuleParams;
+ ClothingModuleParametersNS::ParametersStruct mInternalModuleParams;
+
+ NvParameterized::Interface* mApexClothingActorParams;
+ NvParameterized::Interface* mApexClothingPreviewParams;
+
+ nvidia::Mutex mFactoryMutex;
+ cloth::Factory* mCpuFactory;
+ uint32_t mCpuFactoryReferenceCount;
+
+#if APEX_CUDA_SUPPORT
+ void* mGpuDllHandle;
+
+ // this function is declared in CreateCuFactory.h and implemented in CreateCuFactory.cpp, which is in in APEX_ClothingGPU
+ typedef nvidia::cloth::CuFactory* (PxCreateCuFactory_FUNC)(PxCudaContextManager* contextManager);
+ PxCreateCuFactory_FUNC* mPxCreateCuFactoryFunc;
+
+ struct GpuFactoryEntry
+ {
+ GpuFactoryEntry(cloth::Factory* f, PxCudaContextManager* c) : factoryGpu(f), contextManager(c), referenceCount(0) {}
+
+ cloth::Factory* factoryGpu;
+ PxCudaContextManager* contextManager;
+ uint32_t referenceCount;
+ };
+
+ nvidia::Array<GpuFactoryEntry> mGpuFactories;
+#endif
+
+
+ virtual ~ModuleClothingImpl() {}
+};
+
+}
+} // namespace nvidia
+
+#endif // MODULE_CLOTHING_IMPL_H
diff --git a/APEX_1.4/module/clothing/include/ModuleEventDefs.h b/APEX_1.4/module/clothing/include/ModuleEventDefs.h
new file mode 100644
index 00000000..27aa23db
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/ModuleEventDefs.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+
+// This file is used to define a list of AgPerfMon events.
+//
+// This file is included exclusively by AgPerfMonEventSrcAPI.h
+// and by AgPerfMonEventSrcAPI.cpp, for the purpose of building
+// an enumeration (enum xx) and an array of strings ()
+// that contain the list of events.
+//
+// This file should only contain event definitions, using the
+// DEFINE_EVENT macro. E.g.:
+//
+// DEFINE_EVENT(sample_name_1)
+// DEFINE_EVENT(sample_name_2)
+// DEFINE_EVENT(sample_name_3)
+
+
+DEFINE_EVENT(ClothingActorCPUSkinningGraphics)
+DEFINE_EVENT(ClothingActorCreatePhysX)
+DEFINE_EVENT(ClothingActorFallbackSkinning)
+
+DEFINE_EVENT(ClothingActorUpdateStateInternal)
+DEFINE_EVENT(ClothingActorInterpolateMatrices)
+DEFINE_EVENT(ClothingActorUpdateCollision)
+DEFINE_EVENT(ClothingActorApplyVelocityChanges)
+
+DEFINE_EVENT(ClothingActorLodTick)
+DEFINE_EVENT(ClothingActorMeshMeshSkinning)
+DEFINE_EVENT(ClothingActorMorphTarget)
+DEFINE_EVENT(ClothingActorRecomputeTangentSpace)
+DEFINE_EVENT(ClothingActorSDKCreateClothSoftbody)
+DEFINE_EVENT(ClothingActorUpdateBounds)
+DEFINE_EVENT(ClothingActorUpdateCompressedSkinning)
+DEFINE_EVENT(ClothingActorUpdateRenderResources)
+DEFINE_EVENT(ClothingActorUpdateVertexBuffer)
+DEFINE_EVENT(ClothingActorVelocityShader)
+DEFINE_EVENT(ClothingActorWind)
+DEFINE_EVENT(ClothingActorTeleport)
+DEFINE_EVENT(ClothingActorTransformGraphicalMeshes)
+
+DEFINE_EVENT(ClothingAssetDeserialize)
+DEFINE_EVENT(ClothingAssetLoad)
+
+DEFINE_EVENT(ClothingSceneDistributeSolverIterations)
diff --git a/APEX_1.4/module/clothing/include/ModulePerfScope.h b/APEX_1.4/module/clothing/include/ModulePerfScope.h
new file mode 100644
index 00000000..94e74d98
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/ModulePerfScope.h
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+
+#ifndef MODULE_PERF_SCOPE_H
+#define MODULE_PERF_SCOPE_H
+
+#define MODULE_NAMESPACE clothing
+#include "ModuleProfileCommon.h"
+
+#endif
diff --git a/APEX_1.4/module/clothing/include/Simulation.h b/APEX_1.4/module/clothing/include/Simulation.h
new file mode 100644
index 00000000..a576074b
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/Simulation.h
@@ -0,0 +1,315 @@
+/*
+ * 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.
+ */
+
+
+#ifndef SIMULATION_H
+#define SIMULATION_H
+
+#include "SimulationAbstract.h"
+
+#include <PsHashMap.h>
+#include <PxTask.h>
+#include <PxProfileZone.h>
+#include <PxProfileZoneManager.h>
+
+#include "Range.h"
+#include "Types.h"
+#include "PhaseConfig.h"
+
+#include "ClothStructs.h"
+
+#if PX_WINDOWS_FAMILY
+#include "ApexString.h"
+#endif
+
+
+namespace physx
+{
+ namespace pvdsdk
+ {
+ class ApexPvdClient;
+ }
+}
+
+namespace nvidia
+{
+using namespace physx::profile;
+
+namespace cloth
+{
+class Cloth;
+class Factory;
+class Solver;
+}
+
+
+namespace apex
+{
+class SceneIntl;
+class DebugRenderParams;
+class RenderDebugInterface;
+}
+namespace clothing
+{
+class ModuleClothingImpl;
+class ClothingCookedPhysX3Param;
+class ClothingDebugRenderParams;
+
+class ClothingConvexImpl;
+
+
+struct TriangleMeshId
+{
+ TriangleMeshId(uint32_t id_, uint32_t numTriangles_) : id(id_), numTriangles(numTriangles_)
+ {
+ }
+
+ uint32_t id;
+ uint32_t numTriangles;
+
+ bool operator<(const TriangleMeshId& other) const
+ {
+ return id < other.id;
+ }
+};
+
+class Simulation : public SimulationAbstract
+{
+public:
+
+ Simulation(ClothingScene* clothingScene, bool useCuda);
+ virtual ~Simulation();
+
+ virtual bool needsExpensiveCreation();
+ virtual bool needsAdaptiveTargetFrequency();
+ virtual bool needsManualSubstepping();
+ virtual bool needsLocalSpaceGravity();
+ virtual uint32_t getNumSolverIterations() const;
+ virtual SimulationType::Enum getType() const { return SimulationType::CLOTH3x; }
+ virtual bool setCookedData(NvParameterized::Interface* cookedData, float actorScale);
+ virtual bool initPhysics(uint32_t _physicalMeshId, uint32_t* indices, PxVec3* restPositions, tMaterial* material, const PxMat44& globalPose, const PxVec3& scaledGravity, bool localSpaceSim);
+
+ virtual void initCollision(tBoneActor* boneActors, uint32_t numBoneActors,
+ tBoneSphere* boneSpheres, uint32_t numBoneSpheres,
+ uint16_t* spherePairIndices, uint32_t numSpherePairs,
+ tBonePlane* bonePlanes, uint32_t numBonePlanes,
+ uint32_t* convexes, uint32_t numConvexes,
+ tBoneEntry* bones, const PxMat44* boneTransforms,
+ ResourceList& actorPlanes,
+ ResourceList& actorConvexes,
+ ResourceList& actorSpheres,
+ ResourceList& actorCapsules,
+ ResourceList& actorTriangleMeshes,
+ const tActorDescTemplate& actorDesc, const tShapeDescTemplate& shapeDesc, float actorScale,
+ const PxMat44& globalPose, bool localSpaceSim);
+
+ virtual void updateCollision(tBoneActor* boneActors, uint32_t numBoneActors,
+ tBoneSphere* boneSpheres, uint32_t numBoneSpheres,
+ tBonePlane* bonePlanes, uint32_t numBonePlanes,
+ tBoneEntry* bones, const PxMat44* boneTransforms,
+ ResourceList& actorPlanes,
+ ResourceList& actorConvexes,
+ ResourceList& actorSpheres,
+ ResourceList& actorCapsules,
+ ResourceList& actorTriangleMeshes,
+ bool teleport);
+
+ virtual void releaseCollision(ClothingCollisionImpl& releaseCollision);
+
+ virtual void updateCollisionDescs(const tActorDescTemplate& actorDesc, const tShapeDescTemplate& shapeDesc);
+
+ virtual void disablePhysX(Actor* dummy);
+ virtual void reenablePhysX(Actor* newMaster, const PxMat44& globalPose);
+
+ virtual void fetchResults(bool computePhysicsMeshNormals);
+ virtual bool isSimulationMeshDirty() const;
+ virtual void clearSimulationMeshDirt();
+
+ virtual void setStatic(bool on);
+ virtual bool applyPressure(float pressure);
+
+ virtual bool raycast(const PxVec3& rayOrigin, const PxVec3& rayDirection, float& hitTime, PxVec3& hitNormal, uint32_t& vertexIndex);
+ virtual void attachVertexToGlobalPosition(uint32_t vertexIndex, const PxVec3& globalPosition);
+ virtual void freeVertex(uint32_t vertexIndex);
+
+ virtual void setGlobalPose(const PxMat44& globalPose);
+ virtual void applyGlobalPose();
+
+ virtual NvParameterized::Interface* getCookedData();
+
+ // debugging and debug rendering
+ virtual void verifyTimeStep(float substepSize);
+ virtual void visualize(RenderDebugInterface& renderDebug, ClothingDebugRenderParams& clothingDebugParams);
+#ifndef WITHOUT_PVD
+ virtual void updatePvd(pvdsdk::PvdDataStream& pvdStream, pvdsdk::PvdUserRenderer& pvdRenderer, ApexResourceInterface* clothingActor, bool localSpaceSim);
+#endif
+ virtual GpuSimMemType::Enum getGpuSimMemType() const;
+
+ // R/W Access to simulation data
+ virtual void setPositions(PxVec3* positions);
+ virtual void setConstrainCoefficients(const tConstrainCoeffs* assetCoeffs, float maxDistanceBias, float maxDistanceScale, float maxDistanceDeform, float actorScale);
+ virtual void getVelocities(PxVec3* velocities) const;
+ virtual void setVelocities(PxVec3* velocities);
+ virtual bool applyWind(PxVec3* velocities, const PxVec3* normals, const tConstrainCoeffs* assetCoeffs, const PxVec3& wind, float adaption, float dt);
+
+ // actually important
+ virtual void setTeleportWeight(float weight, bool reset, bool localSpaceSim);
+ virtual void setSolverIterations(uint32_t iterations);
+ virtual void updateConstrainPositions(bool isDirty);
+ virtual bool applyClothingMaterial(tMaterial* material, PxVec3 scaledGravity);
+ virtual void applyClothingDesc(tClothingDescTemplate& clothingTemplate);
+ virtual void setInterCollisionChannels(uint32_t channels);
+ virtual void setHalfPrecisionOption(bool isAllowed);
+
+#if APEX_UE4
+ virtual void simulate(float dt);
+#endif
+
+ // cleanup code
+ static void releaseFabric(NvParameterized::Interface* cookedData);
+
+private:
+ void applyCollision();
+
+ void setRestPositions(bool on);
+
+#ifndef WITHOUT_DEBUG_VISUALIZE
+ void visualizeConvexes(RenderDebugInterface& renderDebug);
+ void visualizeConvexesInvalid(RenderDebugInterface& renderDebug);
+ void createAttenuationData();
+#endif
+
+ struct MappedArray
+ {
+ cloth::Range<PxVec4> deviceMemory;
+ nvidia::Array<PxVec4> hostMemory;
+ };
+
+ static bool allocateHostMemory(MappedArray& mappedMemory);
+
+ // data owned by asset or actor
+ ClothingCookedPhysX3Param* mCookedData;
+
+ // data owned by asset
+ const uint32_t* mIndices;
+ const PxVec3* mRestPositions;
+ const tConstrainCoeffs* mConstrainCoeffs;
+
+ // own data
+ cloth::Cloth* mCloth;
+
+ nvidia::Array<uint32_t> mCollisionCapsules;
+ nvidia::Array<uint32_t> mCollisionCapsulesInvalid;
+ nvidia::Array<PxVec4> mCollisionSpheres;
+ nvidia::Array<PxVec4> mCollisionPlanes;
+ nvidia::Array<uint32_t> mCollisionConvexes;
+ nvidia::Array<ClothingConvexImpl*> mCollisionConvexesInvalid;
+ nvidia::Array<PxVec3> mCollisionTrianglesOld;
+ nvidia::Array<PxVec3> mCollisionTriangles;
+ uint32_t mNumAssetSpheres;
+ uint32_t mNumAssetCapsules;
+ uint32_t mNumAssetCapsulesInvalid;
+ uint32_t mNumAssetConvexes;
+ nvidia::Array<uint32_t> mReleasedSphereIds;
+ nvidia::Array<uint32_t> mReleasedPlaneIds;
+
+ struct ConstrainConstants
+ {
+ ConstrainConstants() : motionConstrainDistance(0.0f), backstopDistance(0.0f), backstopRadius(0.0f) {}
+ float motionConstrainDistance;
+ float backstopDistance;
+ float backstopRadius;
+ };
+
+ nvidia::Array<ConstrainConstants> mConstrainConstants;
+ bool mConstrainConstantsDirty;
+ float mMotionConstrainScale;
+ float mMotionConstrainBias;
+ int32_t mNumBackstopConstraints;
+ nvidia::Array<PxVec4> mBackstopConstraints;
+
+ PxVec3 mScaledGravity;
+ float mLastTimestep;
+
+ nvidia::Array<cloth::PhaseConfig> mPhaseConfigs;
+
+ bool mLocalSpaceSim;
+
+ nvidia::Array<uint32_t> mSelfCollisionAttenuationPairs;
+ nvidia::Array<float> mSelfCollisionAttenuationValues;
+
+ PX_ALIGN(16, PxMat44 mGlobalPose);
+ PxMat44 mGlobalPosePrevious;
+ PxMat44 mGlobalPoseNormalized;
+ PxMat44 mGlobalPoseNormalizedInv;
+ float mActorScale;
+ float mTetherLimit;
+ bool mTeleported;
+ bool mIsStatic;
+};
+
+
+
+class ClothingSceneSimulateTask : public PxTask, public UserAllocated
+{
+public:
+ ClothingSceneSimulateTask(SceneIntl* apexScene, ClothingScene* scene, ModuleClothingImpl* module, profile::PxProfileZoneManager* manager);
+ virtual ~ClothingSceneSimulateTask();
+
+ void setWaitTask(PxBaseTask* waitForSolver);
+
+ void setDeltaTime(float simulationDelta);
+ float getDeltaTime();
+
+ // this must only be called from ClothingScene::getClothSolver() !!!
+ cloth::Solver* getSolver(ClothFactory factory);
+
+ void clearGpuSolver();
+
+ virtual void run();
+ virtual const char* getName() const;
+
+private:
+ static bool interCollisionFilter(void* user0, void* user1);
+
+ ModuleClothingImpl* mModule;
+ SceneIntl* mApexScene;
+ ClothingScene* mScene;
+ float mSimulationDelta;
+
+ cloth::Solver* mSolverGPU;
+ cloth::Solver* mSolverCPU;
+ PxProfileZone* mProfileSolverGPU;
+ PxProfileZone* mProfileSolverCPU;
+
+ PxBaseTask* mWaitForSolverTask;
+
+ profile::PxProfileZoneManager* mProfileManager;
+ bool mFailedGpuFactory;
+};
+
+
+class WaitForSolverTask : public PxTask, public UserAllocated
+{
+public:
+ WaitForSolverTask(ClothingScene* scene);
+
+ virtual void run();
+ virtual const char* getName() const;
+
+private:
+ ClothingScene* mScene;
+};
+
+
+}
+} // namespace nvidia
+
+#endif // SIMULATION_H
diff --git a/APEX_1.4/module/clothing/include/SimulationAbstract.h b/APEX_1.4/module/clothing/include/SimulationAbstract.h
new file mode 100644
index 00000000..6e750141
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/SimulationAbstract.h
@@ -0,0 +1,261 @@
+/*
+ * 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.
+ */
+
+
+#ifndef SIMULATION_ABSTRACT_H
+#define SIMULATION_ABSTRACT_H
+
+#include "ApexUsingNamespace.h"
+#include "PsUserAllocated.h"
+
+#include "ApexDefs.h"
+
+#include "ClothingActorParam.h"
+
+// some params files
+#include "ClothingMaterialLibraryParameters.h"
+#include "ClothingAssetParameters.h"
+#include "ClothingPhysicalMeshParameters.h"
+
+#include "ApexPvdClient.h"
+
+namespace physx
+{
+#if APEX_UE4
+ class PxBaseTask;
+#endif
+
+ namespace pvdsdk
+ {
+ class PvdDataStream;
+ class PvdUserRenderer;
+ }
+}
+
+namespace nvidia
+{
+namespace apex
+{
+class ResourceList;
+class RenderDebugInterface;
+class ApexResourceInterface;
+class Actor;
+}
+namespace clothing
+{
+class ClothingScene;
+class ClothingDebugRenderParams;
+class ClothingCollisionImpl;
+
+
+struct GpuSimMemType
+{
+ enum Enum
+ {
+ UNDEFINED = -1,
+ GLOBAL = 0,
+ MIXED = 1,
+ SHARED = 2
+ };
+};
+
+
+struct SimulationType
+{
+ enum Enum
+ {
+ CLOTH2x,
+ SOFTBODY2x,
+ CLOTH3x
+ };
+};
+
+
+class SimulationAbstract : public UserAllocated
+{
+public:
+ typedef ClothingMaterialLibraryParametersNS::ClothingMaterial_Type tMaterial;
+ typedef ClothingActorParamNS::ClothDescTemplate_Type tClothingDescTemplate;
+ typedef ClothingActorParamNS::ActorDescTemplate_Type tActorDescTemplate;
+ typedef ClothingActorParamNS::ShapeDescTemplate_Type tShapeDescTemplate;
+ typedef ClothingAssetParametersNS::SimulationParams_Type tSimParams;
+ typedef ClothingAssetParametersNS::ActorEntry_Type tBoneActor;
+ typedef ClothingAssetParametersNS::BoneSphere_Type tBoneSphere;
+ typedef ClothingAssetParametersNS::BonePlane_Type tBonePlane;
+ typedef ClothingAssetParametersNS::BoneEntry_Type tBoneEntry;
+ typedef ClothingPhysicalMeshParametersNS::ConstrainCoefficient_Type tConstrainCoeffs;
+
+ SimulationAbstract(ClothingScene* clothingScene) : physicalMeshId(0xffffffff), submeshId(0xffffffff),
+ skinnedPhysicsPositions(NULL), skinnedPhysicsNormals(NULL),
+ sdkNumDeformableVertices(0), sdkWritebackPosition(NULL), sdkWritebackNormal(NULL), sdkNumDeformableIndices(0),
+ mRegisteredActor(NULL), mClothingScene(clothingScene), mUseCuda(false)
+ {
+ ::memset(&simulation, 0, sizeof(simulation));
+ }
+
+ virtual ~SimulationAbstract()
+ {
+ if (sdkWritebackPosition != NULL)
+ {
+ PX_FREE(sdkWritebackPosition);
+ sdkWritebackPosition = sdkWritebackNormal = NULL;
+ }
+
+ if (skinnedPhysicsPositions != NULL)
+ {
+ PX_FREE(skinnedPhysicsPositions);
+ skinnedPhysicsPositions = skinnedPhysicsNormals = NULL;
+ }
+
+ PX_ASSERT(mRegisteredActor == NULL);
+ }
+
+ void init(uint32_t numVertices, uint32_t numIndices, bool writebackNormals);
+ void initSimulation(const ClothingAssetParametersNS::SimulationParams_Type& s);
+
+ virtual bool needsExpensiveCreation() = 0;
+ virtual bool needsAdaptiveTargetFrequency() = 0;
+ virtual bool needsManualSubstepping() = 0;
+ virtual bool needsLocalSpaceGravity() = 0;
+ virtual SimulationType::Enum getType() const = 0;
+ virtual bool isGpuSim() const { return mUseCuda; }
+ virtual uint32_t getNumSolverIterations() const = 0;
+ virtual GpuSimMemType::Enum getGpuSimMemType() const { return GpuSimMemType::UNDEFINED; }
+ virtual bool setCookedData(NvParameterized::Interface* cookedData, float actorScale) = 0;
+ virtual bool initPhysics(uint32_t physicalMeshId, uint32_t* indices, PxVec3* restPositions, tMaterial* material, const PxMat44& globalPose, const PxVec3& scaledGravity, bool localSpaceSim) = 0;
+
+ // collision
+ virtual void initCollision( tBoneActor* boneActors, uint32_t numBoneActors,
+ tBoneSphere* boneSpheres, uint32_t numBoneSpheres,
+ uint16_t* spherePairIndices, uint32_t numSpherePairs,
+ tBonePlane* bonePlanes, uint32_t numBonePlanes,
+ uint32_t* convexes, uint32_t numConvexes,
+ tBoneEntry* bones, const PxMat44* boneTransforms,
+ ResourceList& actorPlanes,
+ ResourceList& actorConvexes,
+ ResourceList& actorSpheres,
+ ResourceList& actorCapsules,
+ ResourceList& actorTriangleMeshes,
+ const tActorDescTemplate& actorDesc, const tShapeDescTemplate& shapeDesc, float actorScale,
+ const PxMat44& globalPose, bool localSpaceSim) = 0;
+
+ virtual void updateCollision( tBoneActor* boneActors, uint32_t numBoneActors,
+ tBoneSphere* boneSpheres, uint32_t numBoneSpheres,
+ tBonePlane* bonePlanes, uint32_t numBonePlanes,
+ tBoneEntry* bones, const PxMat44* boneTransforms,
+ ResourceList& actorPlanes,
+ ResourceList& actorConvexes,
+ ResourceList& actorSpheres,
+ ResourceList& actorCapsules,
+ ResourceList& actorTriangleMeshes,
+ bool teleport) = 0;
+
+ virtual void updateCollisionDescs(const tActorDescTemplate& actorDesc, const tShapeDescTemplate& shapeDesc) = 0;
+ virtual void applyCollision() {};
+ virtual void releaseCollision(ClothingCollisionImpl& /*collision*/) {}
+
+ virtual void swapCollision(SimulationAbstract* /*oldSimulation*/) {}
+
+ virtual void registerPhysX(Actor* actor)
+ {
+ PX_ASSERT(mRegisteredActor == NULL);
+ mRegisteredActor = actor;
+
+ PX_ASSERT(physicalMeshId != 0xffffffff);
+ }
+
+ virtual void unregisterPhysX()
+ {
+ PX_ASSERT(mRegisteredActor != NULL);
+ mRegisteredActor = NULL;
+
+ PX_ASSERT(physicalMeshId != 0xffffffff);
+ }
+
+ virtual void disablePhysX(Actor* dummy) = 0;
+ virtual void reenablePhysX(Actor* newMaster, const PxMat44& globalPose) = 0;
+
+ virtual void fetchResults(bool computePhysicsMeshNormals) = 0;
+ virtual bool isSimulationMeshDirty() const = 0;
+ virtual void clearSimulationMeshDirt() = 0;
+
+ virtual void setStatic(bool on) = 0;
+ virtual bool applyPressure(float pressure) = 0;
+
+ virtual void setGlobalPose(const PxMat44& globalPose) = 0;
+ virtual void applyGlobalPose() {};
+
+ virtual bool raycast(const PxVec3& rayOrigin, const PxVec3& rayDirection, float& hitTime, PxVec3& hitNormal, uint32_t& vertexIndex) = 0;
+ virtual void attachVertexToGlobalPosition(uint32_t vertexIndex, const PxVec3& globalPosition) = 0;
+ virtual void freeVertex(uint32_t vertexIndex) = 0;
+
+ virtual NvParameterized::Interface* getCookedData() = 0;
+
+ // debugging and debug rendering
+ virtual void verifyTimeStep(float substepSize) = 0;
+ virtual void visualize(RenderDebugInterface& renderDebug, ClothingDebugRenderParams& clothingDebugParams) = 0;
+#ifndef WITHOUT_PVD
+ virtual void updatePvd(pvdsdk::PvdDataStream& /*pvdStream*/, pvdsdk::PvdUserRenderer& /*pvdRenderer*/, ApexResourceInterface* /*ClothingActorImpl*/, bool /*localSpaceSim*/) {};
+#endif
+
+ // R/W Access to simulation data
+ virtual void setPositions(PxVec3* positions) = 0;
+ virtual void setConstrainCoefficients(const tConstrainCoeffs* assetCoeffs, float maxDistanceBias, float maxDistanceScale, float maxDistanceDeform, float actorScale) = 0;
+ virtual void getVelocities(PxVec3* velocities) const = 0;
+ virtual void setVelocities(PxVec3* velocities) = 0;
+
+ virtual bool applyWind(PxVec3* velocities, const PxVec3* normals, const tConstrainCoeffs* assetCoeffs, const PxVec3& wind, float adaption, float dt) = 0;
+
+ // actually important
+ virtual void setTeleportWeight(float weight, bool reset, bool localSpaceSim) = 0;
+ virtual void setSolverIterations(uint32_t iterations) = 0;
+ virtual void updateConstrainPositions(bool isDirty) = 0;
+ virtual bool applyClothingMaterial(tMaterial* material, PxVec3 scaledGravity) = 0;
+ virtual void applyClothingDesc(tClothingDescTemplate& clothingTemplate) = 0;
+ virtual void setInterCollisionChannels(uint32_t /*channels*/) {};
+ virtual void setHalfPrecisionOption(bool /*isAllowed*/) {};
+
+ ClothingScene* getClothingScene() const
+ {
+ return mClothingScene;
+ }
+
+#if APEX_UE4
+ virtual void simulate(float) {}
+#endif
+
+ uint32_t physicalMeshId;
+ uint32_t submeshId;
+
+ PxVec3* skinnedPhysicsPositions;
+ PxVec3* skinnedPhysicsNormals;
+
+ // Results produced by PhysX SDK's Cloth simulation
+ uint32_t sdkNumDeformableVertices;
+ PxVec3* sdkWritebackPosition;
+ PxVec3* sdkWritebackNormal;
+
+ uint32_t sdkNumDeformableIndices;
+
+protected:
+ tSimParams simulation;
+
+ Actor* mRegisteredActor;
+
+ ClothingScene* mClothingScene;
+ bool mUseCuda;
+
+};
+
+}
+} // namespace nvidia
+
+
+#endif // SIMULATION_ABSTRACT_H
diff --git a/APEX_1.4/module/clothing/include/autogen/ClothingActorParam.h b/APEX_1.4/module/clothing/include/autogen/ClothingActorParam.h
new file mode 100644
index 00000000..db7ba860
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/autogen/ClothingActorParam.h
@@ -0,0 +1,351 @@
+// 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) 2008-2015 NVIDIA Corporation. All rights reserved.
+
+// This file was generated by NvParameterized/scripts/GenParameterized.pl
+
+
+#ifndef HEADER_ClothingActorParam_h
+#define HEADER_ClothingActorParam_h
+
+#include "NvParametersTypes.h"
+
+#ifndef NV_PARAMETERIZED_ONLY_LAYOUTS
+#include "nvparameterized/NvParameterized.h"
+#include "nvparameterized/NvParameterizedTraits.h"
+#include "NvParameters.h"
+#include "NvTraitsInternal.h"
+#endif
+
+namespace nvidia
+{
+namespace clothing
+{
+
+#if PX_VC
+#pragma warning(push)
+#pragma warning(disable: 4324) // structure was padded due to __declspec(align())
+#endif
+
+namespace ClothingActorParamNS
+{
+
+struct GroupsMask_Type;
+struct ClothDescTemplate_Type;
+struct ShapeDescFlags_Type;
+struct ShapeDescTemplate_Type;
+struct ActorDescTemplate_Type;
+struct WindParameters_Type;
+struct MaxDistanceScale_Type;
+struct ClothingActorFlags_Type;
+
+struct MAT44_DynamicArray1D_Type
+{
+ physx::PxMat44* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct VEC3_DynamicArray1D_Type
+{
+ physx::PxVec3* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct STRING_DynamicArray1D_Type
+{
+ NvParameterized::DummyStringStruct* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct ActorDescTemplate_Type
+{
+ uint64_t userData;
+ uint64_t name;
+};
+struct GroupsMask_Type
+{
+ uint32_t bits0;
+ uint32_t bits1;
+ uint32_t bits2;
+ uint32_t bits3;
+};
+struct ClothDescTemplate_Type
+{
+ float collisionResponseCoefficient;
+ uint16_t collisionGroup;
+ GroupsMask_Type groupsMask;
+ physx::PxBounds3 validBounds;
+ uint64_t compartment;
+ uint64_t userData;
+};
+struct MaxDistanceScale_Type
+{
+ float Scale;
+ bool Multipliable;
+};
+struct ClothingActorFlags_Type
+{
+ bool ParallelCpuSkinning;
+ bool RecomputeNormals;
+ bool RecomputeTangents;
+ bool Visualize;
+ bool CorrectSimulationNormals;
+ bool ComputeRenderData;
+ bool ComputePhysicsMeshNormals;
+};
+struct ShapeDescFlags_Type
+{
+ bool NX_SF_VISUALIZATION;
+ bool NX_SF_DISABLE_COLLISION;
+ bool NX_SF_DISABLE_RAYCASTING;
+ bool NX_SF_DYNAMIC_DYNAMIC_CCD;
+ bool NX_SF_DISABLE_SCENE_QUERIES;
+};
+struct ShapeDescTemplate_Type
+{
+ ShapeDescFlags_Type flags;
+ uint16_t collisionGroup;
+ GroupsMask_Type groupsMask;
+ uint16_t materialIndex;
+ uint64_t userData;
+ uint64_t name;
+};
+struct WindParameters_Type
+{
+ physx::PxVec3 Velocity;
+ float Adaption;
+};
+
+struct ParametersStruct
+{
+
+ physx::PxMat44 globalPose;
+ bool useHardwareCloth;
+ ClothingActorFlags_Type flags;
+ bool fallbackSkinning;
+ bool slowStart;
+ bool useInternalBoneOrder;
+ bool updateStateWithGlobalMatrices;
+ uint32_t uvChannelForTangentUpdate;
+ float maxDistanceBlendTime;
+ uint32_t clothingMaterialIndex;
+ WindParameters_Type windParams;
+ MaxDistanceScale_Type maxDistanceScale;
+ uint64_t userData;
+ MAT44_DynamicArray1D_Type boneMatrices;
+ ClothDescTemplate_Type clothDescTemplate;
+ ShapeDescTemplate_Type shapeDescTemplate;
+ ActorDescTemplate_Type actorDescTemplate;
+ float actorScale;
+ NvParameterized::Interface* runtimeCooked;
+ VEC3_DynamicArray1D_Type morphDisplacements;
+ VEC3_DynamicArray1D_Type morphPhysicalMeshNewPositions;
+ VEC3_DynamicArray1D_Type morphGraphicalMeshNewPositions;
+ bool allowAdaptiveTargetFrequency;
+ bool useVelocityClamping;
+ physx::PxBounds3 vertexVelocityClamp;
+ float pressure;
+ bool multiplyGlobalPoseIntoBones;
+ STRING_DynamicArray1D_Type overrideMaterialNames;
+ const char* simulationBackend;
+ bool freezeByLOD;
+ bool localSpaceSim;
+ int32_t teleportMode;
+
+};
+
+static const uint32_t checksum[] = { 0xf1063127, 0xe3a4d0e2, 0x61f25577, 0x4e838af4, };
+
+} // namespace ClothingActorParamNS
+
+#ifndef NV_PARAMETERIZED_ONLY_LAYOUTS
+class ClothingActorParam : public NvParameterized::NvParameters, public ClothingActorParamNS::ParametersStruct
+{
+public:
+ ClothingActorParam(NvParameterized::Traits* traits, void* buf = 0, int32_t* refCount = 0);
+
+ virtual ~ClothingActorParam();
+
+ virtual void destroy();
+
+ static const char* staticClassName(void)
+ {
+ return("ClothingActorParam");
+ }
+
+ const char* className(void) const
+ {
+ return(staticClassName());
+ }
+
+ static const uint32_t ClassVersion = ((uint32_t)0 << 16) + (uint32_t)18;
+
+ static uint32_t staticVersion(void)
+ {
+ return ClassVersion;
+ }
+
+ uint32_t version(void) const
+ {
+ return(staticVersion());
+ }
+
+ static const uint32_t ClassAlignment = 8;
+
+ static const uint32_t* staticChecksum(uint32_t& bits)
+ {
+ bits = 8 * sizeof(ClothingActorParamNS::checksum);
+ return ClothingActorParamNS::checksum;
+ }
+
+ static void freeParameterDefinitionTable(NvParameterized::Traits* traits);
+
+ const uint32_t* checksum(uint32_t& bits) const
+ {
+ return staticChecksum(bits);
+ }
+
+ const ClothingActorParamNS::ParametersStruct& parameters(void) const
+ {
+ ClothingActorParam* tmpThis = const_cast<ClothingActorParam*>(this);
+ return *(static_cast<ClothingActorParamNS::ParametersStruct*>(tmpThis));
+ }
+
+ ClothingActorParamNS::ParametersStruct& parameters(void)
+ {
+ return *(static_cast<ClothingActorParamNS::ParametersStruct*>(this));
+ }
+
+ virtual NvParameterized::ErrorType getParameterHandle(const char* long_name, NvParameterized::Handle& handle) const;
+ virtual NvParameterized::ErrorType getParameterHandle(const char* long_name, NvParameterized::Handle& handle);
+
+ void initDefaults(void);
+
+protected:
+
+ virtual const NvParameterized::DefinitionImpl* getParameterDefinitionTree(void);
+ virtual const NvParameterized::DefinitionImpl* getParameterDefinitionTree(void) const;
+
+
+ virtual void getVarPtr(const NvParameterized::Handle& handle, void*& ptr, size_t& offset) const;
+
+private:
+
+ void buildTree(void);
+ void initDynamicArrays(void);
+ void initStrings(void);
+ void initReferences(void);
+ void freeDynamicArrays(void);
+ void freeStrings(void);
+ void freeReferences(void);
+
+ static bool mBuiltFlag;
+ static NvParameterized::MutexType mBuiltFlagMutex;
+};
+
+class ClothingActorParamFactory : public NvParameterized::Factory
+{
+ static const char* const vptr;
+
+public:
+
+ virtual void freeParameterDefinitionTable(NvParameterized::Traits* traits)
+ {
+ ClothingActorParam::freeParameterDefinitionTable(traits);
+ }
+
+ virtual NvParameterized::Interface* create(NvParameterized::Traits* paramTraits)
+ {
+ // placement new on this class using mParameterizedTraits
+
+ void* newPtr = paramTraits->alloc(sizeof(ClothingActorParam), ClothingActorParam::ClassAlignment);
+ if (!NvParameterized::IsAligned(newPtr, ClothingActorParam::ClassAlignment))
+ {
+ NV_PARAM_TRAITS_WARNING(paramTraits, "Unaligned memory allocation for class ClothingActorParam");
+ paramTraits->free(newPtr);
+ return 0;
+ }
+
+ memset(newPtr, 0, sizeof(ClothingActorParam)); // always initialize memory allocated to zero for default values
+ return NV_PARAM_PLACEMENT_NEW(newPtr, ClothingActorParam)(paramTraits);
+ }
+
+ virtual NvParameterized::Interface* finish(NvParameterized::Traits* paramTraits, void* bufObj, void* bufStart, int32_t* refCount)
+ {
+ if (!NvParameterized::IsAligned(bufObj, ClothingActorParam::ClassAlignment)
+ || !NvParameterized::IsAligned(bufStart, ClothingActorParam::ClassAlignment))
+ {
+ NV_PARAM_TRAITS_WARNING(paramTraits, "Unaligned memory allocation for class ClothingActorParam");
+ return 0;
+ }
+
+ // Init NvParameters-part
+ // We used to call empty constructor of ClothingActorParam here
+ // but it may call default constructors of members and spoil the data
+ NV_PARAM_PLACEMENT_NEW(bufObj, NvParameterized::NvParameters)(paramTraits, bufStart, refCount);
+
+ // Init vtable (everything else is already initialized)
+ *(const char**)bufObj = vptr;
+
+ return (ClothingActorParam*)bufObj;
+ }
+
+ virtual const char* getClassName()
+ {
+ return (ClothingActorParam::staticClassName());
+ }
+
+ virtual uint32_t getVersion()
+ {
+ return (ClothingActorParam::staticVersion());
+ }
+
+ virtual uint32_t getAlignment()
+ {
+ return (ClothingActorParam::ClassAlignment);
+ }
+
+ virtual const uint32_t* getChecksum(uint32_t& bits)
+ {
+ return (ClothingActorParam::staticChecksum(bits));
+ }
+};
+#endif // NV_PARAMETERIZED_ONLY_LAYOUTS
+
+} // namespace clothing
+} // namespace nvidia
+
+#if PX_VC
+#pragma warning(pop)
+#endif
+
+#endif
diff --git a/APEX_1.4/module/clothing/include/autogen/ClothingAssetParameters.h b/APEX_1.4/module/clothing/include/autogen/ClothingAssetParameters.h
new file mode 100644
index 00000000..5a56d6ec
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/autogen/ClothingAssetParameters.h
@@ -0,0 +1,374 @@
+// 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) 2008-2015 NVIDIA Corporation. All rights reserved.
+
+// This file was generated by NvParameterized/scripts/GenParameterized.pl
+
+
+#ifndef HEADER_ClothingAssetParameters_h
+#define HEADER_ClothingAssetParameters_h
+
+#include "NvParametersTypes.h"
+
+#ifndef NV_PARAMETERIZED_ONLY_LAYOUTS
+#include "nvparameterized/NvParameterized.h"
+#include "nvparameterized/NvParameterizedTraits.h"
+#include "NvParameters.h"
+#include "NvTraitsInternal.h"
+#endif
+
+namespace nvidia
+{
+namespace clothing
+{
+
+#if PX_VC
+#pragma warning(push)
+#pragma warning(disable: 4324) // structure was padded due to __declspec(align())
+#endif
+
+namespace ClothingAssetParametersNS
+{
+
+struct BoneEntry_Type;
+struct ActorEntry_Type;
+struct BoneSphere_Type;
+struct BonePlane_Type;
+struct CookedEntry_Type;
+struct SimulationParams_Type;
+
+struct REF_DynamicArray1D_Type
+{
+ NvParameterized::Interface** buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct BoneEntry_DynamicArray1D_Type
+{
+ BoneEntry_Type* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct ActorEntry_DynamicArray1D_Type
+{
+ ActorEntry_Type* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct VEC3_DynamicArray1D_Type
+{
+ physx::PxVec3* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct BoneSphere_DynamicArray1D_Type
+{
+ BoneSphere_Type* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct U16_DynamicArray1D_Type
+{
+ uint16_t* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct BonePlane_DynamicArray1D_Type
+{
+ BonePlane_Type* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct U32_DynamicArray1D_Type
+{
+ uint32_t* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct CookedEntry_DynamicArray1D_Type
+{
+ CookedEntry_Type* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct BonePlane_Type
+{
+ int32_t boneIndex;
+ physx::PxVec3 n;
+ float d;
+};
+struct BoneSphere_Type
+{
+ int32_t boneIndex;
+ float radius;
+ physx::PxVec3 localPos;
+};
+struct SimulationParams_Type
+{
+ uint32_t hierarchicalLevels;
+ float thickness;
+ float virtualParticleDensity;
+ physx::PxVec3 gravityDirection;
+ float sleepLinearVelocity;
+ bool disableCCD;
+ bool untangling;
+ bool twowayInteraction;
+ float restLengthScale;
+};
+struct CookedEntry_Type
+{
+ float scale;
+ NvParameterized::Interface* cookedData;
+};
+struct BoneEntry_Type
+{
+ int32_t internalIndex;
+ int32_t externalIndex;
+ uint32_t numMeshReferenced;
+ uint32_t numRigidBodiesReferenced;
+ int32_t parentIndex;
+ physx::PxMat44 bindPose;
+ NvParameterized::DummyStringStruct name;
+};
+struct ActorEntry_Type
+{
+ int32_t boneIndex;
+ uint32_t convexVerticesStart;
+ uint32_t convexVerticesCount;
+ float capsuleRadius;
+ float capsuleHeight;
+ physx::PxMat44 localPose;
+};
+
+struct ParametersStruct
+{
+
+ REF_DynamicArray1D_Type physicalMeshes;
+ REF_DynamicArray1D_Type graphicalLods;
+ SimulationParams_Type simulation;
+ BoneEntry_DynamicArray1D_Type bones;
+ uint32_t bonesReferenced;
+ uint32_t bonesReferencedByMesh;
+ uint32_t rootBoneIndex;
+ ActorEntry_DynamicArray1D_Type boneActors;
+ VEC3_DynamicArray1D_Type boneVertices;
+ BoneSphere_DynamicArray1D_Type boneSpheres;
+ U16_DynamicArray1D_Type boneSphereConnections;
+ BonePlane_DynamicArray1D_Type bonePlanes;
+ U32_DynamicArray1D_Type collisionConvexes;
+ CookedEntry_DynamicArray1D_Type cookedData;
+ physx::PxBounds3 boundingBox;
+ NvParameterized::Interface* materialLibrary;
+ uint32_t materialIndex;
+ uint32_t interCollisionChannels;
+ NvParameterized::DummyStringStruct toolString;
+
+};
+
+static const uint32_t checksum[] = { 0x1095fcd4, 0x7327d8f7, 0xefaa63f8, 0x5bda9add, };
+
+} // namespace ClothingAssetParametersNS
+
+#ifndef NV_PARAMETERIZED_ONLY_LAYOUTS
+class ClothingAssetParameters : public NvParameterized::NvParameters, public ClothingAssetParametersNS::ParametersStruct
+{
+public:
+ ClothingAssetParameters(NvParameterized::Traits* traits, void* buf = 0, int32_t* refCount = 0);
+
+ virtual ~ClothingAssetParameters();
+
+ virtual void destroy();
+
+ static const char* staticClassName(void)
+ {
+ return("ClothingAssetParameters");
+ }
+
+ const char* className(void) const
+ {
+ return(staticClassName());
+ }
+
+ static const uint32_t ClassVersion = ((uint32_t)0 << 16) + (uint32_t)14;
+
+ static uint32_t staticVersion(void)
+ {
+ return ClassVersion;
+ }
+
+ uint32_t version(void) const
+ {
+ return(staticVersion());
+ }
+
+ static const uint32_t ClassAlignment = 8;
+
+ static const uint32_t* staticChecksum(uint32_t& bits)
+ {
+ bits = 8 * sizeof(ClothingAssetParametersNS::checksum);
+ return ClothingAssetParametersNS::checksum;
+ }
+
+ static void freeParameterDefinitionTable(NvParameterized::Traits* traits);
+
+ const uint32_t* checksum(uint32_t& bits) const
+ {
+ return staticChecksum(bits);
+ }
+
+ const ClothingAssetParametersNS::ParametersStruct& parameters(void) const
+ {
+ ClothingAssetParameters* tmpThis = const_cast<ClothingAssetParameters*>(this);
+ return *(static_cast<ClothingAssetParametersNS::ParametersStruct*>(tmpThis));
+ }
+
+ ClothingAssetParametersNS::ParametersStruct& parameters(void)
+ {
+ return *(static_cast<ClothingAssetParametersNS::ParametersStruct*>(this));
+ }
+
+ virtual NvParameterized::ErrorType getParameterHandle(const char* long_name, NvParameterized::Handle& handle) const;
+ virtual NvParameterized::ErrorType getParameterHandle(const char* long_name, NvParameterized::Handle& handle);
+
+ void initDefaults(void);
+
+protected:
+
+ virtual const NvParameterized::DefinitionImpl* getParameterDefinitionTree(void);
+ virtual const NvParameterized::DefinitionImpl* getParameterDefinitionTree(void) const;
+
+
+ virtual void getVarPtr(const NvParameterized::Handle& handle, void*& ptr, size_t& offset) const;
+
+private:
+
+ void buildTree(void);
+ void initDynamicArrays(void);
+ void initStrings(void);
+ void initReferences(void);
+ void freeDynamicArrays(void);
+ void freeStrings(void);
+ void freeReferences(void);
+
+ static bool mBuiltFlag;
+ static NvParameterized::MutexType mBuiltFlagMutex;
+};
+
+class ClothingAssetParametersFactory : public NvParameterized::Factory
+{
+ static const char* const vptr;
+
+public:
+
+ virtual void freeParameterDefinitionTable(NvParameterized::Traits* traits)
+ {
+ ClothingAssetParameters::freeParameterDefinitionTable(traits);
+ }
+
+ virtual NvParameterized::Interface* create(NvParameterized::Traits* paramTraits)
+ {
+ // placement new on this class using mParameterizedTraits
+
+ void* newPtr = paramTraits->alloc(sizeof(ClothingAssetParameters), ClothingAssetParameters::ClassAlignment);
+ if (!NvParameterized::IsAligned(newPtr, ClothingAssetParameters::ClassAlignment))
+ {
+ NV_PARAM_TRAITS_WARNING(paramTraits, "Unaligned memory allocation for class ClothingAssetParameters");
+ paramTraits->free(newPtr);
+ return 0;
+ }
+
+ memset(newPtr, 0, sizeof(ClothingAssetParameters)); // always initialize memory allocated to zero for default values
+ return NV_PARAM_PLACEMENT_NEW(newPtr, ClothingAssetParameters)(paramTraits);
+ }
+
+ virtual NvParameterized::Interface* finish(NvParameterized::Traits* paramTraits, void* bufObj, void* bufStart, int32_t* refCount)
+ {
+ if (!NvParameterized::IsAligned(bufObj, ClothingAssetParameters::ClassAlignment)
+ || !NvParameterized::IsAligned(bufStart, ClothingAssetParameters::ClassAlignment))
+ {
+ NV_PARAM_TRAITS_WARNING(paramTraits, "Unaligned memory allocation for class ClothingAssetParameters");
+ return 0;
+ }
+
+ // Init NvParameters-part
+ // We used to call empty constructor of ClothingAssetParameters here
+ // but it may call default constructors of members and spoil the data
+ NV_PARAM_PLACEMENT_NEW(bufObj, NvParameterized::NvParameters)(paramTraits, bufStart, refCount);
+
+ // Init vtable (everything else is already initialized)
+ *(const char**)bufObj = vptr;
+
+ return (ClothingAssetParameters*)bufObj;
+ }
+
+ virtual const char* getClassName()
+ {
+ return (ClothingAssetParameters::staticClassName());
+ }
+
+ virtual uint32_t getVersion()
+ {
+ return (ClothingAssetParameters::staticVersion());
+ }
+
+ virtual uint32_t getAlignment()
+ {
+ return (ClothingAssetParameters::ClassAlignment);
+ }
+
+ virtual const uint32_t* getChecksum(uint32_t& bits)
+ {
+ return (ClothingAssetParameters::staticChecksum(bits));
+ }
+};
+#endif // NV_PARAMETERIZED_ONLY_LAYOUTS
+
+} // namespace clothing
+} // namespace nvidia
+
+#if PX_VC
+#pragma warning(pop)
+#endif
+
+#endif
diff --git a/APEX_1.4/module/clothing/include/autogen/ClothingCookedParam.h b/APEX_1.4/module/clothing/include/autogen/ClothingCookedParam.h
new file mode 100644
index 00000000..c4306292
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/autogen/ClothingCookedParam.h
@@ -0,0 +1,297 @@
+// 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) 2008-2015 NVIDIA Corporation. All rights reserved.
+
+// This file was generated by NvParameterized/scripts/GenParameterized.pl
+
+
+#ifndef HEADER_ClothingCookedParam_h
+#define HEADER_ClothingCookedParam_h
+
+#include "NvParametersTypes.h"
+
+#ifndef NV_PARAMETERIZED_ONLY_LAYOUTS
+#include "nvparameterized/NvParameterized.h"
+#include "nvparameterized/NvParameterizedTraits.h"
+#include "NvParameters.h"
+#include "NvTraitsInternal.h"
+#endif
+
+namespace nvidia
+{
+namespace clothing
+{
+
+#if PX_VC
+#pragma warning(push)
+#pragma warning(disable: 4324) // structure was padded due to __declspec(align())
+#endif
+
+namespace ClothingCookedParamNS
+{
+
+struct CookedPhysicalMesh_Type;
+
+struct U8_DynamicArray1D_Type
+{
+ uint8_t* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct POINTER_DynamicArray1D_Type
+{
+ void** buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct CookedPhysicalMesh_DynamicArray1D_Type
+{
+ CookedPhysicalMesh_Type* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct F32_DynamicArray1D_Type
+{
+ float* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct U32_DynamicArray1D_Type
+{
+ uint32_t* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct VEC3_DynamicArray1D_Type
+{
+ physx::PxVec3* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct CookedPhysicalMesh_Type
+{
+ uint32_t physicalMeshId;
+ uint32_t cookedDataOffset;
+ uint32_t cookedDataLength;
+ void* deformableMeshPointer;
+ uint32_t deformableInvParticleWeightsOffset;
+ uint32_t virtualParticleIndicesOffset;
+ uint32_t virtualParticleIndicesLength;
+};
+
+struct ParametersStruct
+{
+
+ float actorScale;
+ U8_DynamicArray1D_Type convexCookedData;
+ POINTER_DynamicArray1D_Type convexMeshPointers;
+ CookedPhysicalMesh_DynamicArray1D_Type cookedPhysicalMeshes;
+ U8_DynamicArray1D_Type deformableCookedData;
+ uint32_t cookedDataVersion;
+ F32_DynamicArray1D_Type deformableInvParticleWeights;
+ U32_DynamicArray1D_Type virtualParticleIndices;
+ VEC3_DynamicArray1D_Type virtualParticleWeights;
+
+};
+
+static const uint32_t checksum[] = { 0x140bacb3, 0x5ea948eb, 0x14dd612e, 0x6ad11b93, };
+
+} // namespace ClothingCookedParamNS
+
+#ifndef NV_PARAMETERIZED_ONLY_LAYOUTS
+class ClothingCookedParam : public NvParameterized::NvParameters, public ClothingCookedParamNS::ParametersStruct
+{
+public:
+ ClothingCookedParam(NvParameterized::Traits* traits, void* buf = 0, int32_t* refCount = 0);
+
+ virtual ~ClothingCookedParam();
+
+ virtual void destroy();
+
+ static const char* staticClassName(void)
+ {
+ return("ClothingCookedParam");
+ }
+
+ const char* className(void) const
+ {
+ return(staticClassName());
+ }
+
+ static const uint32_t ClassVersion = ((uint32_t)0 << 16) + (uint32_t)3;
+
+ static uint32_t staticVersion(void)
+ {
+ return ClassVersion;
+ }
+
+ uint32_t version(void) const
+ {
+ return(staticVersion());
+ }
+
+ static const uint32_t ClassAlignment = 8;
+
+ static const uint32_t* staticChecksum(uint32_t& bits)
+ {
+ bits = 8 * sizeof(ClothingCookedParamNS::checksum);
+ return ClothingCookedParamNS::checksum;
+ }
+
+ static void freeParameterDefinitionTable(NvParameterized::Traits* traits);
+
+ const uint32_t* checksum(uint32_t& bits) const
+ {
+ return staticChecksum(bits);
+ }
+
+ const ClothingCookedParamNS::ParametersStruct& parameters(void) const
+ {
+ ClothingCookedParam* tmpThis = const_cast<ClothingCookedParam*>(this);
+ return *(static_cast<ClothingCookedParamNS::ParametersStruct*>(tmpThis));
+ }
+
+ ClothingCookedParamNS::ParametersStruct& parameters(void)
+ {
+ return *(static_cast<ClothingCookedParamNS::ParametersStruct*>(this));
+ }
+
+ virtual NvParameterized::ErrorType getParameterHandle(const char* long_name, NvParameterized::Handle& handle) const;
+ virtual NvParameterized::ErrorType getParameterHandle(const char* long_name, NvParameterized::Handle& handle);
+
+ void initDefaults(void);
+
+protected:
+
+ virtual const NvParameterized::DefinitionImpl* getParameterDefinitionTree(void);
+ virtual const NvParameterized::DefinitionImpl* getParameterDefinitionTree(void) const;
+
+
+ virtual void getVarPtr(const NvParameterized::Handle& handle, void*& ptr, size_t& offset) const;
+
+private:
+
+ void buildTree(void);
+ void initDynamicArrays(void);
+ void initStrings(void);
+ void initReferences(void);
+ void freeDynamicArrays(void);
+ void freeStrings(void);
+ void freeReferences(void);
+
+ static bool mBuiltFlag;
+ static NvParameterized::MutexType mBuiltFlagMutex;
+};
+
+class ClothingCookedParamFactory : public NvParameterized::Factory
+{
+ static const char* const vptr;
+
+public:
+
+ virtual void freeParameterDefinitionTable(NvParameterized::Traits* traits)
+ {
+ ClothingCookedParam::freeParameterDefinitionTable(traits);
+ }
+
+ virtual NvParameterized::Interface* create(NvParameterized::Traits* paramTraits)
+ {
+ // placement new on this class using mParameterizedTraits
+
+ void* newPtr = paramTraits->alloc(sizeof(ClothingCookedParam), ClothingCookedParam::ClassAlignment);
+ if (!NvParameterized::IsAligned(newPtr, ClothingCookedParam::ClassAlignment))
+ {
+ NV_PARAM_TRAITS_WARNING(paramTraits, "Unaligned memory allocation for class ClothingCookedParam");
+ paramTraits->free(newPtr);
+ return 0;
+ }
+
+ memset(newPtr, 0, sizeof(ClothingCookedParam)); // always initialize memory allocated to zero for default values
+ return NV_PARAM_PLACEMENT_NEW(newPtr, ClothingCookedParam)(paramTraits);
+ }
+
+ virtual NvParameterized::Interface* finish(NvParameterized::Traits* paramTraits, void* bufObj, void* bufStart, int32_t* refCount)
+ {
+ if (!NvParameterized::IsAligned(bufObj, ClothingCookedParam::ClassAlignment)
+ || !NvParameterized::IsAligned(bufStart, ClothingCookedParam::ClassAlignment))
+ {
+ NV_PARAM_TRAITS_WARNING(paramTraits, "Unaligned memory allocation for class ClothingCookedParam");
+ return 0;
+ }
+
+ // Init NvParameters-part
+ // We used to call empty constructor of ClothingCookedParam here
+ // but it may call default constructors of members and spoil the data
+ NV_PARAM_PLACEMENT_NEW(bufObj, NvParameterized::NvParameters)(paramTraits, bufStart, refCount);
+
+ // Init vtable (everything else is already initialized)
+ *(const char**)bufObj = vptr;
+
+ return (ClothingCookedParam*)bufObj;
+ }
+
+ virtual const char* getClassName()
+ {
+ return (ClothingCookedParam::staticClassName());
+ }
+
+ virtual uint32_t getVersion()
+ {
+ return (ClothingCookedParam::staticVersion());
+ }
+
+ virtual uint32_t getAlignment()
+ {
+ return (ClothingCookedParam::ClassAlignment);
+ }
+
+ virtual const uint32_t* getChecksum(uint32_t& bits)
+ {
+ return (ClothingCookedParam::staticChecksum(bits));
+ }
+};
+#endif // NV_PARAMETERIZED_ONLY_LAYOUTS
+
+} // namespace clothing
+} // namespace nvidia
+
+#if PX_VC
+#pragma warning(pop)
+#endif
+
+#endif
diff --git a/APEX_1.4/module/clothing/include/autogen/ClothingCookedPhysX3Param.h b/APEX_1.4/module/clothing/include/autogen/ClothingCookedPhysX3Param.h
new file mode 100644
index 00000000..51dd9241
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/autogen/ClothingCookedPhysX3Param.h
@@ -0,0 +1,310 @@
+// 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) 2008-2015 NVIDIA Corporation. All rights reserved.
+
+// This file was generated by NvParameterized/scripts/GenParameterized.pl
+
+
+#ifndef HEADER_ClothingCookedPhysX3Param_h
+#define HEADER_ClothingCookedPhysX3Param_h
+
+#include "NvParametersTypes.h"
+
+#ifndef NV_PARAMETERIZED_ONLY_LAYOUTS
+#include "nvparameterized/NvParameterized.h"
+#include "nvparameterized/NvParameterizedTraits.h"
+#include "NvParameters.h"
+#include "NvTraitsInternal.h"
+#endif
+
+namespace nvidia
+{
+namespace clothing
+{
+
+#if PX_VC
+#pragma warning(push)
+#pragma warning(disable: 4324) // structure was padded due to __declspec(align())
+#endif
+
+namespace ClothingCookedPhysX3ParamNS
+{
+
+struct PhaseDesc_Type;
+struct SetDesc_Type;
+struct FabricGPU_Type;
+
+struct F32_DynamicArray1D_Type
+{
+ float* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct U32_DynamicArray1D_Type
+{
+ uint32_t* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct SetDesc_DynamicArray1D_Type
+{
+ SetDesc_Type* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct PhaseDesc_DynamicArray1D_Type
+{
+ PhaseDesc_Type* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct FabricGPU_DynamicArray1D_Type
+{
+ FabricGPU_Type* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct SetDesc_Type
+{
+ uint32_t fiberEnd;
+ uint32_t longestFiber;
+ uint32_t shortestFiber;
+ uint32_t numEdges;
+ float avgEdgeLength;
+ uint32_t avgFiberLength;
+};
+struct PhaseDesc_Type
+{
+ uint32_t phaseType;
+ uint32_t setIndex;
+ uint32_t restValueOffset;
+};
+struct FabricGPU_Type
+{
+ void* fabricGPU;
+ void* factory;
+};
+
+struct ParametersStruct
+{
+
+ uint32_t physicalMeshId;
+ uint32_t numVertices;
+ F32_DynamicArray1D_Type deformableRestLengths;
+ U32_DynamicArray1D_Type deformableIndices;
+ U32_DynamicArray1D_Type selfCollisionIndices;
+ U32_DynamicArray1D_Type selfCollisionNormalIndices;
+ U32_DynamicArray1D_Type selfCollisionNormalSetSizes;
+ SetDesc_DynamicArray1D_Type deformableSets;
+ PhaseDesc_DynamicArray1D_Type deformablePhaseDescs;
+ U32_DynamicArray1D_Type tetherAnchors;
+ F32_DynamicArray1D_Type tetherLengths;
+ F32_DynamicArray1D_Type deformableInvVertexWeights;
+ U32_DynamicArray1D_Type virtualParticleIndices;
+ F32_DynamicArray1D_Type virtualParticleWeights;
+ uint32_t cookedDataVersion;
+ void* fabricCPU;
+ FabricGPU_DynamicArray1D_Type fabricGPU;
+ NvParameterized::Interface* nextCookedData;
+
+};
+
+static const uint32_t checksum[] = { 0x05292657, 0xc602622e, 0xa6989638, 0xf1f9e34f, };
+
+} // namespace ClothingCookedPhysX3ParamNS
+
+#ifndef NV_PARAMETERIZED_ONLY_LAYOUTS
+class ClothingCookedPhysX3Param : public NvParameterized::NvParameters, public ClothingCookedPhysX3ParamNS::ParametersStruct
+{
+public:
+ ClothingCookedPhysX3Param(NvParameterized::Traits* traits, void* buf = 0, int32_t* refCount = 0);
+
+ virtual ~ClothingCookedPhysX3Param();
+
+ virtual void destroy();
+
+ static const char* staticClassName(void)
+ {
+ return("ClothingCookedPhysX3Param");
+ }
+
+ const char* className(void) const
+ {
+ return(staticClassName());
+ }
+
+ static const uint32_t ClassVersion = ((uint32_t)0 << 16) + (uint32_t)5;
+
+ static uint32_t staticVersion(void)
+ {
+ return ClassVersion;
+ }
+
+ uint32_t version(void) const
+ {
+ return(staticVersion());
+ }
+
+ static const uint32_t ClassAlignment = 8;
+
+ static const uint32_t* staticChecksum(uint32_t& bits)
+ {
+ bits = 8 * sizeof(ClothingCookedPhysX3ParamNS::checksum);
+ return ClothingCookedPhysX3ParamNS::checksum;
+ }
+
+ static void freeParameterDefinitionTable(NvParameterized::Traits* traits);
+
+ const uint32_t* checksum(uint32_t& bits) const
+ {
+ return staticChecksum(bits);
+ }
+
+ const ClothingCookedPhysX3ParamNS::ParametersStruct& parameters(void) const
+ {
+ ClothingCookedPhysX3Param* tmpThis = const_cast<ClothingCookedPhysX3Param*>(this);
+ return *(static_cast<ClothingCookedPhysX3ParamNS::ParametersStruct*>(tmpThis));
+ }
+
+ ClothingCookedPhysX3ParamNS::ParametersStruct& parameters(void)
+ {
+ return *(static_cast<ClothingCookedPhysX3ParamNS::ParametersStruct*>(this));
+ }
+
+ virtual NvParameterized::ErrorType getParameterHandle(const char* long_name, NvParameterized::Handle& handle) const;
+ virtual NvParameterized::ErrorType getParameterHandle(const char* long_name, NvParameterized::Handle& handle);
+
+ void initDefaults(void);
+
+protected:
+
+ virtual const NvParameterized::DefinitionImpl* getParameterDefinitionTree(void);
+ virtual const NvParameterized::DefinitionImpl* getParameterDefinitionTree(void) const;
+
+
+ virtual void getVarPtr(const NvParameterized::Handle& handle, void*& ptr, size_t& offset) const;
+
+private:
+
+ void buildTree(void);
+ void initDynamicArrays(void);
+ void initStrings(void);
+ void initReferences(void);
+ void freeDynamicArrays(void);
+ void freeStrings(void);
+ void freeReferences(void);
+
+ static bool mBuiltFlag;
+ static NvParameterized::MutexType mBuiltFlagMutex;
+};
+
+class ClothingCookedPhysX3ParamFactory : public NvParameterized::Factory
+{
+ static const char* const vptr;
+
+public:
+
+ virtual void freeParameterDefinitionTable(NvParameterized::Traits* traits)
+ {
+ ClothingCookedPhysX3Param::freeParameterDefinitionTable(traits);
+ }
+
+ virtual NvParameterized::Interface* create(NvParameterized::Traits* paramTraits)
+ {
+ // placement new on this class using mParameterizedTraits
+
+ void* newPtr = paramTraits->alloc(sizeof(ClothingCookedPhysX3Param), ClothingCookedPhysX3Param::ClassAlignment);
+ if (!NvParameterized::IsAligned(newPtr, ClothingCookedPhysX3Param::ClassAlignment))
+ {
+ NV_PARAM_TRAITS_WARNING(paramTraits, "Unaligned memory allocation for class ClothingCookedPhysX3Param");
+ paramTraits->free(newPtr);
+ return 0;
+ }
+
+ memset(newPtr, 0, sizeof(ClothingCookedPhysX3Param)); // always initialize memory allocated to zero for default values
+ return NV_PARAM_PLACEMENT_NEW(newPtr, ClothingCookedPhysX3Param)(paramTraits);
+ }
+
+ virtual NvParameterized::Interface* finish(NvParameterized::Traits* paramTraits, void* bufObj, void* bufStart, int32_t* refCount)
+ {
+ if (!NvParameterized::IsAligned(bufObj, ClothingCookedPhysX3Param::ClassAlignment)
+ || !NvParameterized::IsAligned(bufStart, ClothingCookedPhysX3Param::ClassAlignment))
+ {
+ NV_PARAM_TRAITS_WARNING(paramTraits, "Unaligned memory allocation for class ClothingCookedPhysX3Param");
+ return 0;
+ }
+
+ // Init NvParameters-part
+ // We used to call empty constructor of ClothingCookedPhysX3Param here
+ // but it may call default constructors of members and spoil the data
+ NV_PARAM_PLACEMENT_NEW(bufObj, NvParameterized::NvParameters)(paramTraits, bufStart, refCount);
+
+ // Init vtable (everything else is already initialized)
+ *(const char**)bufObj = vptr;
+
+ return (ClothingCookedPhysX3Param*)bufObj;
+ }
+
+ virtual const char* getClassName()
+ {
+ return (ClothingCookedPhysX3Param::staticClassName());
+ }
+
+ virtual uint32_t getVersion()
+ {
+ return (ClothingCookedPhysX3Param::staticVersion());
+ }
+
+ virtual uint32_t getAlignment()
+ {
+ return (ClothingCookedPhysX3Param::ClassAlignment);
+ }
+
+ virtual const uint32_t* getChecksum(uint32_t& bits)
+ {
+ return (ClothingCookedPhysX3Param::staticChecksum(bits));
+ }
+};
+#endif // NV_PARAMETERIZED_ONLY_LAYOUTS
+
+} // namespace clothing
+} // namespace nvidia
+
+#if PX_VC
+#pragma warning(pop)
+#endif
+
+#endif
diff --git a/APEX_1.4/module/clothing/include/autogen/ClothingDebugRenderParams.h b/APEX_1.4/module/clothing/include/autogen/ClothingDebugRenderParams.h
new file mode 100644
index 00000000..92a84a0e
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/autogen/ClothingDebugRenderParams.h
@@ -0,0 +1,270 @@
+// 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) 2008-2015 NVIDIA Corporation. All rights reserved.
+
+// This file was generated by NvParameterized/scripts/GenParameterized.pl
+
+
+#ifndef HEADER_ClothingDebugRenderParams_h
+#define HEADER_ClothingDebugRenderParams_h
+
+#include "NvParametersTypes.h"
+
+#ifndef NV_PARAMETERIZED_ONLY_LAYOUTS
+#include "nvparameterized/NvParameterized.h"
+#include "nvparameterized/NvParameterizedTraits.h"
+#include "NvParameters.h"
+#include "NvTraitsInternal.h"
+#endif
+
+namespace nvidia
+{
+namespace clothing
+{
+
+#if PX_VC
+#pragma warning(push)
+#pragma warning(disable: 4324) // structure was padded due to __declspec(align())
+#endif
+
+namespace ClothingDebugRenderParamsNS
+{
+
+
+
+struct ParametersStruct
+{
+
+ bool Actors;
+ float SkinnedPositions;
+ bool Backstop;
+ float BackstopPrecise;
+ bool MaxDistance;
+ bool MaxDistanceInwards;
+ bool SkinMapAll;
+ bool SkinMapBad;
+ bool SkinMapActual;
+ bool SkinMapInvalidBary;
+ float PhysicsMeshWire;
+ float PhysicsMeshSolid;
+ float PhysicsMeshNormals;
+ bool Skeleton;
+ float BoneFrames;
+ float BoneNames;
+ float Velocities;
+ float Wind;
+ bool GraphicalVertexBones;
+ bool PhysicalVertexBones;
+ bool CollisionShapes;
+ bool CollisionShapesWire;
+ bool LengthFibers;
+ bool CrossSectionFibers;
+ bool BendingFibers;
+ bool ShearingFibers;
+ bool ZerostretchFibers;
+ bool TethersActive;
+ bool TethersInactive;
+ bool VirtualCollision;
+ bool FiberRange;
+ bool ShowInLocalSpace;
+ bool GlobalPose;
+ bool RecomputeSubmeshes;
+ bool RecomputeVertices;
+ bool PhysicsMeshIndices;
+ bool MassScale;
+ bool SelfCollision;
+ bool SelfCollisionWire;
+ float SelfCollisionAttenuation;
+ bool SolverMode;
+
+};
+
+static const uint32_t checksum[] = { 0x0814367c, 0x9b811470, 0x122fd821, 0xd5717b8e, };
+
+} // namespace ClothingDebugRenderParamsNS
+
+#ifndef NV_PARAMETERIZED_ONLY_LAYOUTS
+class ClothingDebugRenderParams : public NvParameterized::NvParameters, public ClothingDebugRenderParamsNS::ParametersStruct
+{
+public:
+ ClothingDebugRenderParams(NvParameterized::Traits* traits, void* buf = 0, int32_t* refCount = 0);
+
+ virtual ~ClothingDebugRenderParams();
+
+ virtual void destroy();
+
+ static const char* staticClassName(void)
+ {
+ return("ClothingDebugRenderParams");
+ }
+
+ const char* className(void) const
+ {
+ return(staticClassName());
+ }
+
+ static const uint32_t ClassVersion = ((uint32_t)0 << 16) + (uint32_t)0;
+
+ static uint32_t staticVersion(void)
+ {
+ return ClassVersion;
+ }
+
+ uint32_t version(void) const
+ {
+ return(staticVersion());
+ }
+
+ static const uint32_t ClassAlignment = 8;
+
+ static const uint32_t* staticChecksum(uint32_t& bits)
+ {
+ bits = 8 * sizeof(ClothingDebugRenderParamsNS::checksum);
+ return ClothingDebugRenderParamsNS::checksum;
+ }
+
+ static void freeParameterDefinitionTable(NvParameterized::Traits* traits);
+
+ const uint32_t* checksum(uint32_t& bits) const
+ {
+ return staticChecksum(bits);
+ }
+
+ const ClothingDebugRenderParamsNS::ParametersStruct& parameters(void) const
+ {
+ ClothingDebugRenderParams* tmpThis = const_cast<ClothingDebugRenderParams*>(this);
+ return *(static_cast<ClothingDebugRenderParamsNS::ParametersStruct*>(tmpThis));
+ }
+
+ ClothingDebugRenderParamsNS::ParametersStruct& parameters(void)
+ {
+ return *(static_cast<ClothingDebugRenderParamsNS::ParametersStruct*>(this));
+ }
+
+ virtual NvParameterized::ErrorType getParameterHandle(const char* long_name, NvParameterized::Handle& handle) const;
+ virtual NvParameterized::ErrorType getParameterHandle(const char* long_name, NvParameterized::Handle& handle);
+
+ void initDefaults(void);
+
+protected:
+
+ virtual const NvParameterized::DefinitionImpl* getParameterDefinitionTree(void);
+ virtual const NvParameterized::DefinitionImpl* getParameterDefinitionTree(void) const;
+
+
+ virtual void getVarPtr(const NvParameterized::Handle& handle, void*& ptr, size_t& offset) const;
+
+private:
+
+ void buildTree(void);
+ void initDynamicArrays(void);
+ void initStrings(void);
+ void initReferences(void);
+ void freeDynamicArrays(void);
+ void freeStrings(void);
+ void freeReferences(void);
+
+ static bool mBuiltFlag;
+ static NvParameterized::MutexType mBuiltFlagMutex;
+};
+
+class ClothingDebugRenderParamsFactory : public NvParameterized::Factory
+{
+ static const char* const vptr;
+
+public:
+
+ virtual void freeParameterDefinitionTable(NvParameterized::Traits* traits)
+ {
+ ClothingDebugRenderParams::freeParameterDefinitionTable(traits);
+ }
+
+ virtual NvParameterized::Interface* create(NvParameterized::Traits* paramTraits)
+ {
+ // placement new on this class using mParameterizedTraits
+
+ void* newPtr = paramTraits->alloc(sizeof(ClothingDebugRenderParams), ClothingDebugRenderParams::ClassAlignment);
+ if (!NvParameterized::IsAligned(newPtr, ClothingDebugRenderParams::ClassAlignment))
+ {
+ NV_PARAM_TRAITS_WARNING(paramTraits, "Unaligned memory allocation for class ClothingDebugRenderParams");
+ paramTraits->free(newPtr);
+ return 0;
+ }
+
+ memset(newPtr, 0, sizeof(ClothingDebugRenderParams)); // always initialize memory allocated to zero for default values
+ return NV_PARAM_PLACEMENT_NEW(newPtr, ClothingDebugRenderParams)(paramTraits);
+ }
+
+ virtual NvParameterized::Interface* finish(NvParameterized::Traits* paramTraits, void* bufObj, void* bufStart, int32_t* refCount)
+ {
+ if (!NvParameterized::IsAligned(bufObj, ClothingDebugRenderParams::ClassAlignment)
+ || !NvParameterized::IsAligned(bufStart, ClothingDebugRenderParams::ClassAlignment))
+ {
+ NV_PARAM_TRAITS_WARNING(paramTraits, "Unaligned memory allocation for class ClothingDebugRenderParams");
+ return 0;
+ }
+
+ // Init NvParameters-part
+ // We used to call empty constructor of ClothingDebugRenderParams here
+ // but it may call default constructors of members and spoil the data
+ NV_PARAM_PLACEMENT_NEW(bufObj, NvParameterized::NvParameters)(paramTraits, bufStart, refCount);
+
+ // Init vtable (everything else is already initialized)
+ *(const char**)bufObj = vptr;
+
+ return (ClothingDebugRenderParams*)bufObj;
+ }
+
+ virtual const char* getClassName()
+ {
+ return (ClothingDebugRenderParams::staticClassName());
+ }
+
+ virtual uint32_t getVersion()
+ {
+ return (ClothingDebugRenderParams::staticVersion());
+ }
+
+ virtual uint32_t getAlignment()
+ {
+ return (ClothingDebugRenderParams::ClassAlignment);
+ }
+
+ virtual const uint32_t* getChecksum(uint32_t& bits)
+ {
+ return (ClothingDebugRenderParams::staticChecksum(bits));
+ }
+};
+#endif // NV_PARAMETERIZED_ONLY_LAYOUTS
+
+} // namespace clothing
+} // namespace nvidia
+
+#if PX_VC
+#pragma warning(pop)
+#endif
+
+#endif
diff --git a/APEX_1.4/module/clothing/include/autogen/ClothingGraphicalLodParameters.h b/APEX_1.4/module/clothing/include/autogen/ClothingGraphicalLodParameters.h
new file mode 100644
index 00000000..596b8871
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/autogen/ClothingGraphicalLodParameters.h
@@ -0,0 +1,335 @@
+// 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) 2008-2015 NVIDIA Corporation. All rights reserved.
+
+// This file was generated by NvParameterized/scripts/GenParameterized.pl
+
+
+#ifndef HEADER_ClothingGraphicalLodParameters_h
+#define HEADER_ClothingGraphicalLodParameters_h
+
+#include "NvParametersTypes.h"
+
+#ifndef NV_PARAMETERIZED_ONLY_LAYOUTS
+#include "nvparameterized/NvParameterized.h"
+#include "nvparameterized/NvParameterizedTraits.h"
+#include "NvParameters.h"
+#include "NvTraitsInternal.h"
+#endif
+
+namespace nvidia
+{
+namespace clothing
+{
+
+#if PX_VC
+#pragma warning(push)
+#pragma warning(disable: 4324) // structure was padded due to __declspec(align())
+#endif
+
+namespace ClothingGraphicalLodParametersNS
+{
+
+struct SkinClothMapB_Type;
+struct SkinClothMapC_Type;
+struct SkinClothMapD_Type;
+struct TetraLink_Type;
+struct PhysicsMeshPartitioning_Type;
+
+struct STRING_DynamicArray1D_Type
+{
+ NvParameterized::DummyStringStruct* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct U32_DynamicArray1D_Type
+{
+ uint32_t* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct SkinClothMapB_DynamicArray1D_Type
+{
+ SkinClothMapB_Type* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct SkinClothMapD_DynamicArray1D_Type
+{
+ SkinClothMapD_Type* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct TetraLink_DynamicArray1D_Type
+{
+ TetraLink_Type* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct PhysicsMeshPartitioning_DynamicArray1D_Type
+{
+ PhysicsMeshPartitioning_Type* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct SkinClothMapC_Type
+{
+ physx::PxVec3 vertexBary;
+ uint32_t faceIndex0;
+ physx::PxVec3 normalBary;
+ uint32_t vertexIndexPlusOffset;
+};
+struct PhysicsMeshPartitioning_Type
+{
+ uint32_t graphicalSubmesh;
+ uint32_t numSimulatedVertices;
+ uint32_t numSimulatedVerticesAdditional;
+ uint32_t numSimulatedIndices;
+};
+struct SkinClothMapD_Type
+{
+ physx::PxVec3 vertexBary;
+ uint32_t vertexIndex0;
+ physx::PxVec3 normalBary;
+ uint32_t vertexIndex1;
+ physx::PxVec3 tangentBary;
+ uint32_t vertexIndex2;
+ uint32_t vertexIndexPlusOffset;
+};
+struct SkinClothMapB_Type
+{
+ physx::PxVec3 vtxTetraBary;
+ uint32_t vertexIndexPlusOffset;
+ physx::PxVec3 nrmTetraBary;
+ uint32_t faceIndex0;
+ uint32_t tetraIndex;
+ uint32_t submeshIndex;
+};
+struct TetraLink_Type
+{
+ physx::PxVec3 vertexBary;
+ uint32_t tetraIndex0;
+ physx::PxVec3 normalBary;
+ uint32_t _dummyForAlignment;
+};
+
+struct ParametersStruct
+{
+
+ STRING_DynamicArray1D_Type platforms;
+ uint32_t lod;
+ uint32_t physicalMeshId;
+ NvParameterized::Interface* renderMeshAsset;
+ void* renderMeshAssetPointer;
+ U32_DynamicArray1D_Type immediateClothMap;
+ SkinClothMapB_DynamicArray1D_Type skinClothMapB;
+ SkinClothMapD_DynamicArray1D_Type skinClothMap;
+ float skinClothMapThickness;
+ float skinClothMapOffset;
+ TetraLink_DynamicArray1D_Type tetraMap;
+ uint32_t renderMeshAssetSorting;
+ PhysicsMeshPartitioning_DynamicArray1D_Type physicsMeshPartitioning;
+
+};
+
+static const uint32_t checksum[] = { 0xb82a1fab, 0xfd43a015, 0x35b1be8a, 0x80ebc50f, };
+
+} // namespace ClothingGraphicalLodParametersNS
+
+#ifndef NV_PARAMETERIZED_ONLY_LAYOUTS
+class ClothingGraphicalLodParameters : public NvParameterized::NvParameters, public ClothingGraphicalLodParametersNS::ParametersStruct
+{
+public:
+ ClothingGraphicalLodParameters(NvParameterized::Traits* traits, void* buf = 0, int32_t* refCount = 0);
+
+ virtual ~ClothingGraphicalLodParameters();
+
+ virtual void destroy();
+
+ static const char* staticClassName(void)
+ {
+ return("ClothingGraphicalLodParameters");
+ }
+
+ const char* className(void) const
+ {
+ return(staticClassName());
+ }
+
+ static const uint32_t ClassVersion = ((uint32_t)0 << 16) + (uint32_t)5;
+
+ static uint32_t staticVersion(void)
+ {
+ return ClassVersion;
+ }
+
+ uint32_t version(void) const
+ {
+ return(staticVersion());
+ }
+
+ static const uint32_t ClassAlignment = 8;
+
+ static const uint32_t* staticChecksum(uint32_t& bits)
+ {
+ bits = 8 * sizeof(ClothingGraphicalLodParametersNS::checksum);
+ return ClothingGraphicalLodParametersNS::checksum;
+ }
+
+ static void freeParameterDefinitionTable(NvParameterized::Traits* traits);
+
+ const uint32_t* checksum(uint32_t& bits) const
+ {
+ return staticChecksum(bits);
+ }
+
+ const ClothingGraphicalLodParametersNS::ParametersStruct& parameters(void) const
+ {
+ ClothingGraphicalLodParameters* tmpThis = const_cast<ClothingGraphicalLodParameters*>(this);
+ return *(static_cast<ClothingGraphicalLodParametersNS::ParametersStruct*>(tmpThis));
+ }
+
+ ClothingGraphicalLodParametersNS::ParametersStruct& parameters(void)
+ {
+ return *(static_cast<ClothingGraphicalLodParametersNS::ParametersStruct*>(this));
+ }
+
+ virtual NvParameterized::ErrorType getParameterHandle(const char* long_name, NvParameterized::Handle& handle) const;
+ virtual NvParameterized::ErrorType getParameterHandle(const char* long_name, NvParameterized::Handle& handle);
+
+ void initDefaults(void);
+
+protected:
+
+ virtual const NvParameterized::DefinitionImpl* getParameterDefinitionTree(void);
+ virtual const NvParameterized::DefinitionImpl* getParameterDefinitionTree(void) const;
+
+
+ virtual void getVarPtr(const NvParameterized::Handle& handle, void*& ptr, size_t& offset) const;
+
+private:
+
+ void buildTree(void);
+ void initDynamicArrays(void);
+ void initStrings(void);
+ void initReferences(void);
+ void freeDynamicArrays(void);
+ void freeStrings(void);
+ void freeReferences(void);
+
+ static bool mBuiltFlag;
+ static NvParameterized::MutexType mBuiltFlagMutex;
+};
+
+class ClothingGraphicalLodParametersFactory : public NvParameterized::Factory
+{
+ static const char* const vptr;
+
+public:
+
+ virtual void freeParameterDefinitionTable(NvParameterized::Traits* traits)
+ {
+ ClothingGraphicalLodParameters::freeParameterDefinitionTable(traits);
+ }
+
+ virtual NvParameterized::Interface* create(NvParameterized::Traits* paramTraits)
+ {
+ // placement new on this class using mParameterizedTraits
+
+ void* newPtr = paramTraits->alloc(sizeof(ClothingGraphicalLodParameters), ClothingGraphicalLodParameters::ClassAlignment);
+ if (!NvParameterized::IsAligned(newPtr, ClothingGraphicalLodParameters::ClassAlignment))
+ {
+ NV_PARAM_TRAITS_WARNING(paramTraits, "Unaligned memory allocation for class ClothingGraphicalLodParameters");
+ paramTraits->free(newPtr);
+ return 0;
+ }
+
+ memset(newPtr, 0, sizeof(ClothingGraphicalLodParameters)); // always initialize memory allocated to zero for default values
+ return NV_PARAM_PLACEMENT_NEW(newPtr, ClothingGraphicalLodParameters)(paramTraits);
+ }
+
+ virtual NvParameterized::Interface* finish(NvParameterized::Traits* paramTraits, void* bufObj, void* bufStart, int32_t* refCount)
+ {
+ if (!NvParameterized::IsAligned(bufObj, ClothingGraphicalLodParameters::ClassAlignment)
+ || !NvParameterized::IsAligned(bufStart, ClothingGraphicalLodParameters::ClassAlignment))
+ {
+ NV_PARAM_TRAITS_WARNING(paramTraits, "Unaligned memory allocation for class ClothingGraphicalLodParameters");
+ return 0;
+ }
+
+ // Init NvParameters-part
+ // We used to call empty constructor of ClothingGraphicalLodParameters here
+ // but it may call default constructors of members and spoil the data
+ NV_PARAM_PLACEMENT_NEW(bufObj, NvParameterized::NvParameters)(paramTraits, bufStart, refCount);
+
+ // Init vtable (everything else is already initialized)
+ *(const char**)bufObj = vptr;
+
+ return (ClothingGraphicalLodParameters*)bufObj;
+ }
+
+ virtual const char* getClassName()
+ {
+ return (ClothingGraphicalLodParameters::staticClassName());
+ }
+
+ virtual uint32_t getVersion()
+ {
+ return (ClothingGraphicalLodParameters::staticVersion());
+ }
+
+ virtual uint32_t getAlignment()
+ {
+ return (ClothingGraphicalLodParameters::ClassAlignment);
+ }
+
+ virtual const uint32_t* getChecksum(uint32_t& bits)
+ {
+ return (ClothingGraphicalLodParameters::staticChecksum(bits));
+ }
+};
+#endif // NV_PARAMETERIZED_ONLY_LAYOUTS
+
+} // namespace clothing
+} // namespace nvidia
+
+#if PX_VC
+#pragma warning(pop)
+#endif
+
+#endif
diff --git a/APEX_1.4/module/clothing/include/autogen/ClothingMaterialLibraryParameters.h b/APEX_1.4/module/clothing/include/autogen/ClothingMaterialLibraryParameters.h
new file mode 100644
index 00000000..0edd6155
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/autogen/ClothingMaterialLibraryParameters.h
@@ -0,0 +1,277 @@
+// 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) 2008-2015 NVIDIA Corporation. All rights reserved.
+
+// This file was generated by NvParameterized/scripts/GenParameterized.pl
+
+
+#ifndef HEADER_ClothingMaterialLibraryParameters_h
+#define HEADER_ClothingMaterialLibraryParameters_h
+
+#include "NvParametersTypes.h"
+
+#ifndef NV_PARAMETERIZED_ONLY_LAYOUTS
+#include "nvparameterized/NvParameterized.h"
+#include "nvparameterized/NvParameterizedTraits.h"
+#include "NvParameters.h"
+#include "NvTraitsInternal.h"
+#endif
+
+namespace nvidia
+{
+namespace clothing
+{
+
+#if PX_VC
+#pragma warning(push)
+#pragma warning(disable: 4324) // structure was padded due to __declspec(align())
+#endif
+
+namespace ClothingMaterialLibraryParametersNS
+{
+
+struct StiffnessScaling_Type;
+struct ClothingMaterial_Type;
+
+struct ClothingMaterial_DynamicArray1D_Type
+{
+ ClothingMaterial_Type* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct StiffnessScaling_Type
+{
+ float compressionRange;
+ float stretchRange;
+ float scale;
+};
+struct ClothingMaterial_Type
+{
+ NvParameterized::DummyStringStruct materialName;
+ float verticalStretchingStiffness;
+ float horizontalStretchingStiffness;
+ float bendingStiffness;
+ float shearingStiffness;
+ float tetherStiffness;
+ float tetherLimit;
+ bool orthoBending;
+ StiffnessScaling_Type verticalStiffnessScaling;
+ StiffnessScaling_Type horizontalStiffnessScaling;
+ StiffnessScaling_Type bendingStiffnessScaling;
+ StiffnessScaling_Type shearingStiffnessScaling;
+ float damping;
+ float stiffnessFrequency;
+ float drag;
+ bool comDamping;
+ float friction;
+ float massScale;
+ uint32_t solverIterations;
+ float solverFrequency;
+ float gravityScale;
+ float inertiaScale;
+ float hardStretchLimitation;
+ float maxDistanceBias;
+ uint32_t hierarchicalSolverIterations;
+ float selfcollisionThickness;
+ float selfcollisionSquashScale;
+ float selfcollisionStiffness;
+};
+
+struct ParametersStruct
+{
+
+ ClothingMaterial_DynamicArray1D_Type materials;
+
+};
+
+static const uint32_t checksum[] = { 0xf827ceb7, 0xd03d140a, 0x0c8ae038, 0x16333673, };
+
+} // namespace ClothingMaterialLibraryParametersNS
+
+#ifndef NV_PARAMETERIZED_ONLY_LAYOUTS
+class ClothingMaterialLibraryParameters : public NvParameterized::NvParameters, public ClothingMaterialLibraryParametersNS::ParametersStruct
+{
+public:
+ ClothingMaterialLibraryParameters(NvParameterized::Traits* traits, void* buf = 0, int32_t* refCount = 0);
+
+ virtual ~ClothingMaterialLibraryParameters();
+
+ virtual void destroy();
+
+ static const char* staticClassName(void)
+ {
+ return("ClothingMaterialLibraryParameters");
+ }
+
+ const char* className(void) const
+ {
+ return(staticClassName());
+ }
+
+ static const uint32_t ClassVersion = ((uint32_t)0 << 16) + (uint32_t)14;
+
+ static uint32_t staticVersion(void)
+ {
+ return ClassVersion;
+ }
+
+ uint32_t version(void) const
+ {
+ return(staticVersion());
+ }
+
+ static const uint32_t ClassAlignment = 8;
+
+ static const uint32_t* staticChecksum(uint32_t& bits)
+ {
+ bits = 8 * sizeof(ClothingMaterialLibraryParametersNS::checksum);
+ return ClothingMaterialLibraryParametersNS::checksum;
+ }
+
+ static void freeParameterDefinitionTable(NvParameterized::Traits* traits);
+
+ const uint32_t* checksum(uint32_t& bits) const
+ {
+ return staticChecksum(bits);
+ }
+
+ const ClothingMaterialLibraryParametersNS::ParametersStruct& parameters(void) const
+ {
+ ClothingMaterialLibraryParameters* tmpThis = const_cast<ClothingMaterialLibraryParameters*>(this);
+ return *(static_cast<ClothingMaterialLibraryParametersNS::ParametersStruct*>(tmpThis));
+ }
+
+ ClothingMaterialLibraryParametersNS::ParametersStruct& parameters(void)
+ {
+ return *(static_cast<ClothingMaterialLibraryParametersNS::ParametersStruct*>(this));
+ }
+
+ virtual NvParameterized::ErrorType getParameterHandle(const char* long_name, NvParameterized::Handle& handle) const;
+ virtual NvParameterized::ErrorType getParameterHandle(const char* long_name, NvParameterized::Handle& handle);
+
+ void initDefaults(void);
+
+protected:
+
+ virtual const NvParameterized::DefinitionImpl* getParameterDefinitionTree(void);
+ virtual const NvParameterized::DefinitionImpl* getParameterDefinitionTree(void) const;
+
+
+ virtual void getVarPtr(const NvParameterized::Handle& handle, void*& ptr, size_t& offset) const;
+
+private:
+
+ void buildTree(void);
+ void initDynamicArrays(void);
+ void initStrings(void);
+ void initReferences(void);
+ void freeDynamicArrays(void);
+ void freeStrings(void);
+ void freeReferences(void);
+
+ static bool mBuiltFlag;
+ static NvParameterized::MutexType mBuiltFlagMutex;
+};
+
+class ClothingMaterialLibraryParametersFactory : public NvParameterized::Factory
+{
+ static const char* const vptr;
+
+public:
+
+ virtual void freeParameterDefinitionTable(NvParameterized::Traits* traits)
+ {
+ ClothingMaterialLibraryParameters::freeParameterDefinitionTable(traits);
+ }
+
+ virtual NvParameterized::Interface* create(NvParameterized::Traits* paramTraits)
+ {
+ // placement new on this class using mParameterizedTraits
+
+ void* newPtr = paramTraits->alloc(sizeof(ClothingMaterialLibraryParameters), ClothingMaterialLibraryParameters::ClassAlignment);
+ if (!NvParameterized::IsAligned(newPtr, ClothingMaterialLibraryParameters::ClassAlignment))
+ {
+ NV_PARAM_TRAITS_WARNING(paramTraits, "Unaligned memory allocation for class ClothingMaterialLibraryParameters");
+ paramTraits->free(newPtr);
+ return 0;
+ }
+
+ memset(newPtr, 0, sizeof(ClothingMaterialLibraryParameters)); // always initialize memory allocated to zero for default values
+ return NV_PARAM_PLACEMENT_NEW(newPtr, ClothingMaterialLibraryParameters)(paramTraits);
+ }
+
+ virtual NvParameterized::Interface* finish(NvParameterized::Traits* paramTraits, void* bufObj, void* bufStart, int32_t* refCount)
+ {
+ if (!NvParameterized::IsAligned(bufObj, ClothingMaterialLibraryParameters::ClassAlignment)
+ || !NvParameterized::IsAligned(bufStart, ClothingMaterialLibraryParameters::ClassAlignment))
+ {
+ NV_PARAM_TRAITS_WARNING(paramTraits, "Unaligned memory allocation for class ClothingMaterialLibraryParameters");
+ return 0;
+ }
+
+ // Init NvParameters-part
+ // We used to call empty constructor of ClothingMaterialLibraryParameters here
+ // but it may call default constructors of members and spoil the data
+ NV_PARAM_PLACEMENT_NEW(bufObj, NvParameterized::NvParameters)(paramTraits, bufStart, refCount);
+
+ // Init vtable (everything else is already initialized)
+ *(const char**)bufObj = vptr;
+
+ return (ClothingMaterialLibraryParameters*)bufObj;
+ }
+
+ virtual const char* getClassName()
+ {
+ return (ClothingMaterialLibraryParameters::staticClassName());
+ }
+
+ virtual uint32_t getVersion()
+ {
+ return (ClothingMaterialLibraryParameters::staticVersion());
+ }
+
+ virtual uint32_t getAlignment()
+ {
+ return (ClothingMaterialLibraryParameters::ClassAlignment);
+ }
+
+ virtual const uint32_t* getChecksum(uint32_t& bits)
+ {
+ return (ClothingMaterialLibraryParameters::staticChecksum(bits));
+ }
+};
+#endif // NV_PARAMETERIZED_ONLY_LAYOUTS
+
+} // namespace clothing
+} // namespace nvidia
+
+#if PX_VC
+#pragma warning(pop)
+#endif
+
+#endif
diff --git a/APEX_1.4/module/clothing/include/autogen/ClothingModuleParameters.h b/APEX_1.4/module/clothing/include/autogen/ClothingModuleParameters.h
new file mode 100644
index 00000000..9f8142ed
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/autogen/ClothingModuleParameters.h
@@ -0,0 +1,240 @@
+// 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) 2008-2015 NVIDIA Corporation. All rights reserved.
+
+// This file was generated by NvParameterized/scripts/GenParameterized.pl
+
+
+#ifndef HEADER_ClothingModuleParameters_h
+#define HEADER_ClothingModuleParameters_h
+
+#include "NvParametersTypes.h"
+
+#ifndef NV_PARAMETERIZED_ONLY_LAYOUTS
+#include "nvparameterized/NvParameterized.h"
+#include "nvparameterized/NvParameterizedTraits.h"
+#include "NvParameters.h"
+#include "NvTraitsInternal.h"
+#endif
+
+namespace nvidia
+{
+namespace clothing
+{
+
+#if PX_VC
+#pragma warning(push)
+#pragma warning(disable: 4324) // structure was padded due to __declspec(align())
+#endif
+
+namespace ClothingModuleParametersNS
+{
+
+
+
+struct ParametersStruct
+{
+
+ uint32_t maxNumCompartments;
+ uint32_t maxUnusedPhysXResources;
+ bool allowAsyncCooking;
+ bool asyncFetchResults;
+ uint32_t avgSimFrequencyWindow;
+ bool allowApexWorkBetweenSubsteps;
+ float interCollisionDistance;
+ float interCollisionStiffness;
+ uint32_t interCollisionIterations;
+ bool sparseSelfCollision;
+ uint32_t maxTimeRenderProxyInPool;
+
+};
+
+static const uint32_t checksum[] = { 0x15043a9d, 0x77224355, 0x4c92d234, 0x3bbce77c, };
+
+} // namespace ClothingModuleParametersNS
+
+#ifndef NV_PARAMETERIZED_ONLY_LAYOUTS
+class ClothingModuleParameters : public NvParameterized::NvParameters, public ClothingModuleParametersNS::ParametersStruct
+{
+public:
+ ClothingModuleParameters(NvParameterized::Traits* traits, void* buf = 0, int32_t* refCount = 0);
+
+ virtual ~ClothingModuleParameters();
+
+ virtual void destroy();
+
+ static const char* staticClassName(void)
+ {
+ return("ClothingModuleParameters");
+ }
+
+ const char* className(void) const
+ {
+ return(staticClassName());
+ }
+
+ static const uint32_t ClassVersion = ((uint32_t)0 << 16) + (uint32_t)1;
+
+ static uint32_t staticVersion(void)
+ {
+ return ClassVersion;
+ }
+
+ uint32_t version(void) const
+ {
+ return(staticVersion());
+ }
+
+ static const uint32_t ClassAlignment = 8;
+
+ static const uint32_t* staticChecksum(uint32_t& bits)
+ {
+ bits = 8 * sizeof(ClothingModuleParametersNS::checksum);
+ return ClothingModuleParametersNS::checksum;
+ }
+
+ static void freeParameterDefinitionTable(NvParameterized::Traits* traits);
+
+ const uint32_t* checksum(uint32_t& bits) const
+ {
+ return staticChecksum(bits);
+ }
+
+ const ClothingModuleParametersNS::ParametersStruct& parameters(void) const
+ {
+ ClothingModuleParameters* tmpThis = const_cast<ClothingModuleParameters*>(this);
+ return *(static_cast<ClothingModuleParametersNS::ParametersStruct*>(tmpThis));
+ }
+
+ ClothingModuleParametersNS::ParametersStruct& parameters(void)
+ {
+ return *(static_cast<ClothingModuleParametersNS::ParametersStruct*>(this));
+ }
+
+ virtual NvParameterized::ErrorType getParameterHandle(const char* long_name, NvParameterized::Handle& handle) const;
+ virtual NvParameterized::ErrorType getParameterHandle(const char* long_name, NvParameterized::Handle& handle);
+
+ void initDefaults(void);
+
+protected:
+
+ virtual const NvParameterized::DefinitionImpl* getParameterDefinitionTree(void);
+ virtual const NvParameterized::DefinitionImpl* getParameterDefinitionTree(void) const;
+
+
+ virtual void getVarPtr(const NvParameterized::Handle& handle, void*& ptr, size_t& offset) const;
+
+private:
+
+ void buildTree(void);
+ void initDynamicArrays(void);
+ void initStrings(void);
+ void initReferences(void);
+ void freeDynamicArrays(void);
+ void freeStrings(void);
+ void freeReferences(void);
+
+ static bool mBuiltFlag;
+ static NvParameterized::MutexType mBuiltFlagMutex;
+};
+
+class ClothingModuleParametersFactory : public NvParameterized::Factory
+{
+ static const char* const vptr;
+
+public:
+
+ virtual void freeParameterDefinitionTable(NvParameterized::Traits* traits)
+ {
+ ClothingModuleParameters::freeParameterDefinitionTable(traits);
+ }
+
+ virtual NvParameterized::Interface* create(NvParameterized::Traits* paramTraits)
+ {
+ // placement new on this class using mParameterizedTraits
+
+ void* newPtr = paramTraits->alloc(sizeof(ClothingModuleParameters), ClothingModuleParameters::ClassAlignment);
+ if (!NvParameterized::IsAligned(newPtr, ClothingModuleParameters::ClassAlignment))
+ {
+ NV_PARAM_TRAITS_WARNING(paramTraits, "Unaligned memory allocation for class ClothingModuleParameters");
+ paramTraits->free(newPtr);
+ return 0;
+ }
+
+ memset(newPtr, 0, sizeof(ClothingModuleParameters)); // always initialize memory allocated to zero for default values
+ return NV_PARAM_PLACEMENT_NEW(newPtr, ClothingModuleParameters)(paramTraits);
+ }
+
+ virtual NvParameterized::Interface* finish(NvParameterized::Traits* paramTraits, void* bufObj, void* bufStart, int32_t* refCount)
+ {
+ if (!NvParameterized::IsAligned(bufObj, ClothingModuleParameters::ClassAlignment)
+ || !NvParameterized::IsAligned(bufStart, ClothingModuleParameters::ClassAlignment))
+ {
+ NV_PARAM_TRAITS_WARNING(paramTraits, "Unaligned memory allocation for class ClothingModuleParameters");
+ return 0;
+ }
+
+ // Init NvParameters-part
+ // We used to call empty constructor of ClothingModuleParameters here
+ // but it may call default constructors of members and spoil the data
+ NV_PARAM_PLACEMENT_NEW(bufObj, NvParameterized::NvParameters)(paramTraits, bufStart, refCount);
+
+ // Init vtable (everything else is already initialized)
+ *(const char**)bufObj = vptr;
+
+ return (ClothingModuleParameters*)bufObj;
+ }
+
+ virtual const char* getClassName()
+ {
+ return (ClothingModuleParameters::staticClassName());
+ }
+
+ virtual uint32_t getVersion()
+ {
+ return (ClothingModuleParameters::staticVersion());
+ }
+
+ virtual uint32_t getAlignment()
+ {
+ return (ClothingModuleParameters::ClassAlignment);
+ }
+
+ virtual const uint32_t* getChecksum(uint32_t& bits)
+ {
+ return (ClothingModuleParameters::staticChecksum(bits));
+ }
+};
+#endif // NV_PARAMETERIZED_ONLY_LAYOUTS
+
+} // namespace clothing
+} // namespace nvidia
+
+#if PX_VC
+#pragma warning(pop)
+#endif
+
+#endif
diff --git a/APEX_1.4/module/clothing/include/autogen/ClothingPhysicalMeshParameters.h b/APEX_1.4/module/clothing/include/autogen/ClothingPhysicalMeshParameters.h
new file mode 100644
index 00000000..0b282933
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/autogen/ClothingPhysicalMeshParameters.h
@@ -0,0 +1,373 @@
+// 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) 2008-2015 NVIDIA Corporation. All rights reserved.
+
+// This file was generated by NvParameterized/scripts/GenParameterized.pl
+
+
+#ifndef HEADER_ClothingPhysicalMeshParameters_h
+#define HEADER_ClothingPhysicalMeshParameters_h
+
+#include "NvParametersTypes.h"
+
+#ifndef NV_PARAMETERIZED_ONLY_LAYOUTS
+#include "nvparameterized/NvParameterized.h"
+#include "nvparameterized/NvParameterizedTraits.h"
+#include "NvParameters.h"
+#include "NvTraitsInternal.h"
+#endif
+
+namespace nvidia
+{
+namespace clothing
+{
+
+#if PX_VC
+#pragma warning(push)
+#pragma warning(disable: 4324) // structure was padded due to __declspec(align())
+#endif
+
+namespace ClothingPhysicalMeshParametersNS
+{
+
+struct SkinClothMapB_Type;
+struct SkinClothMapC_Type;
+struct SkinClothMapD_Type;
+struct TetraLink_Type;
+struct ConstrainCoefficient_Type;
+struct PhysicalMesh_Type;
+
+struct VEC3_DynamicArray1D_Type
+{
+ physx::PxVec3* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct ConstrainCoefficient_DynamicArray1D_Type
+{
+ ConstrainCoefficient_Type* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct U16_DynamicArray1D_Type
+{
+ uint16_t* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct F32_DynamicArray1D_Type
+{
+ float* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct U8_DynamicArray1D_Type
+{
+ uint8_t* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct U32_DynamicArray1D_Type
+{
+ uint32_t* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct SkinClothMapB_DynamicArray1D_Type
+{
+ SkinClothMapB_Type* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct SkinClothMapD_DynamicArray1D_Type
+{
+ SkinClothMapD_Type* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct SkinClothMapC_Type
+{
+ physx::PxVec3 vertexBary;
+ uint32_t faceIndex0;
+ physx::PxVec3 normalBary;
+ uint32_t vertexIndexPlusOffset;
+};
+struct ConstrainCoefficient_Type
+{
+ float maxDistance;
+ float collisionSphereRadius;
+ float collisionSphereDistance;
+};
+struct PhysicalMesh_Type
+{
+ uint32_t numVertices;
+ uint32_t numSimulatedVertices;
+ uint32_t numMaxDistance0Vertices;
+ uint32_t numIndices;
+ uint32_t numSimulatedIndices;
+ uint32_t numBonesPerVertex;
+ VEC3_DynamicArray1D_Type vertices;
+ VEC3_DynamicArray1D_Type normals;
+ VEC3_DynamicArray1D_Type skinningNormals;
+ ConstrainCoefficient_DynamicArray1D_Type constrainCoefficients;
+ U16_DynamicArray1D_Type boneIndices;
+ F32_DynamicArray1D_Type boneWeights;
+ U8_DynamicArray1D_Type optimizationData;
+ bool hasNegativeBackstop;
+ bool isClosed;
+ U32_DynamicArray1D_Type indices;
+ float maximumMaxDistance;
+ uint32_t physicalMeshSorting;
+ float shortestEdgeLength;
+ float averageEdgeLength;
+ bool isTetrahedralMesh;
+ bool flipNormals;
+};
+struct SkinClothMapD_Type
+{
+ physx::PxVec3 vertexBary;
+ uint32_t vertexIndex0;
+ physx::PxVec3 normalBary;
+ uint32_t vertexIndex1;
+ physx::PxVec3 tangentBary;
+ uint32_t vertexIndex2;
+ uint32_t vertexIndexPlusOffset;
+};
+struct SkinClothMapB_Type
+{
+ physx::PxVec3 vtxTetraBary;
+ uint32_t vertexIndexPlusOffset;
+ physx::PxVec3 nrmTetraBary;
+ uint32_t faceIndex0;
+ uint32_t tetraIndex;
+ uint32_t submeshIndex;
+};
+struct TetraLink_Type
+{
+ physx::PxVec3 vertexBary;
+ uint32_t tetraIndex0;
+ physx::PxVec3 normalBary;
+ uint32_t _dummyForAlignment;
+};
+
+struct ParametersStruct
+{
+
+ PhysicalMesh_Type physicalMesh;
+ SkinClothMapB_DynamicArray1D_Type transitionUpB;
+ SkinClothMapD_DynamicArray1D_Type transitionUp;
+ float transitionUpThickness;
+ float transitionUpOffset;
+ SkinClothMapB_DynamicArray1D_Type transitionDownB;
+ SkinClothMapD_DynamicArray1D_Type transitionDown;
+ float transitionDownThickness;
+ float transitionDownOffset;
+ uint32_t referenceCount;
+
+};
+
+static const uint32_t checksum[] = { 0x436eae3d, 0xbb86cc6f, 0xab9fa108, 0x26281bae, };
+
+} // namespace ClothingPhysicalMeshParametersNS
+
+#ifndef NV_PARAMETERIZED_ONLY_LAYOUTS
+class ClothingPhysicalMeshParameters : public NvParameterized::NvParameters, public ClothingPhysicalMeshParametersNS::ParametersStruct
+{
+public:
+ ClothingPhysicalMeshParameters(NvParameterized::Traits* traits, void* buf = 0, int32_t* refCount = 0);
+
+ virtual ~ClothingPhysicalMeshParameters();
+
+ virtual void destroy();
+
+ static const char* staticClassName(void)
+ {
+ return("ClothingPhysicalMeshParameters");
+ }
+
+ const char* className(void) const
+ {
+ return(staticClassName());
+ }
+
+ static const uint32_t ClassVersion = ((uint32_t)0 << 16) + (uint32_t)11;
+
+ static uint32_t staticVersion(void)
+ {
+ return ClassVersion;
+ }
+
+ uint32_t version(void) const
+ {
+ return(staticVersion());
+ }
+
+ static const uint32_t ClassAlignment = 8;
+
+ static const uint32_t* staticChecksum(uint32_t& bits)
+ {
+ bits = 8 * sizeof(ClothingPhysicalMeshParametersNS::checksum);
+ return ClothingPhysicalMeshParametersNS::checksum;
+ }
+
+ static void freeParameterDefinitionTable(NvParameterized::Traits* traits);
+
+ const uint32_t* checksum(uint32_t& bits) const
+ {
+ return staticChecksum(bits);
+ }
+
+ const ClothingPhysicalMeshParametersNS::ParametersStruct& parameters(void) const
+ {
+ ClothingPhysicalMeshParameters* tmpThis = const_cast<ClothingPhysicalMeshParameters*>(this);
+ return *(static_cast<ClothingPhysicalMeshParametersNS::ParametersStruct*>(tmpThis));
+ }
+
+ ClothingPhysicalMeshParametersNS::ParametersStruct& parameters(void)
+ {
+ return *(static_cast<ClothingPhysicalMeshParametersNS::ParametersStruct*>(this));
+ }
+
+ virtual NvParameterized::ErrorType getParameterHandle(const char* long_name, NvParameterized::Handle& handle) const;
+ virtual NvParameterized::ErrorType getParameterHandle(const char* long_name, NvParameterized::Handle& handle);
+
+ void initDefaults(void);
+
+protected:
+
+ virtual const NvParameterized::DefinitionImpl* getParameterDefinitionTree(void);
+ virtual const NvParameterized::DefinitionImpl* getParameterDefinitionTree(void) const;
+
+
+ virtual void getVarPtr(const NvParameterized::Handle& handle, void*& ptr, size_t& offset) const;
+
+private:
+
+ void buildTree(void);
+ void initDynamicArrays(void);
+ void initStrings(void);
+ void initReferences(void);
+ void freeDynamicArrays(void);
+ void freeStrings(void);
+ void freeReferences(void);
+
+ static bool mBuiltFlag;
+ static NvParameterized::MutexType mBuiltFlagMutex;
+};
+
+class ClothingPhysicalMeshParametersFactory : public NvParameterized::Factory
+{
+ static const char* const vptr;
+
+public:
+
+ virtual void freeParameterDefinitionTable(NvParameterized::Traits* traits)
+ {
+ ClothingPhysicalMeshParameters::freeParameterDefinitionTable(traits);
+ }
+
+ virtual NvParameterized::Interface* create(NvParameterized::Traits* paramTraits)
+ {
+ // placement new on this class using mParameterizedTraits
+
+ void* newPtr = paramTraits->alloc(sizeof(ClothingPhysicalMeshParameters), ClothingPhysicalMeshParameters::ClassAlignment);
+ if (!NvParameterized::IsAligned(newPtr, ClothingPhysicalMeshParameters::ClassAlignment))
+ {
+ NV_PARAM_TRAITS_WARNING(paramTraits, "Unaligned memory allocation for class ClothingPhysicalMeshParameters");
+ paramTraits->free(newPtr);
+ return 0;
+ }
+
+ memset(newPtr, 0, sizeof(ClothingPhysicalMeshParameters)); // always initialize memory allocated to zero for default values
+ return NV_PARAM_PLACEMENT_NEW(newPtr, ClothingPhysicalMeshParameters)(paramTraits);
+ }
+
+ virtual NvParameterized::Interface* finish(NvParameterized::Traits* paramTraits, void* bufObj, void* bufStart, int32_t* refCount)
+ {
+ if (!NvParameterized::IsAligned(bufObj, ClothingPhysicalMeshParameters::ClassAlignment)
+ || !NvParameterized::IsAligned(bufStart, ClothingPhysicalMeshParameters::ClassAlignment))
+ {
+ NV_PARAM_TRAITS_WARNING(paramTraits, "Unaligned memory allocation for class ClothingPhysicalMeshParameters");
+ return 0;
+ }
+
+ // Init NvParameters-part
+ // We used to call empty constructor of ClothingPhysicalMeshParameters here
+ // but it may call default constructors of members and spoil the data
+ NV_PARAM_PLACEMENT_NEW(bufObj, NvParameterized::NvParameters)(paramTraits, bufStart, refCount);
+
+ // Init vtable (everything else is already initialized)
+ *(const char**)bufObj = vptr;
+
+ return (ClothingPhysicalMeshParameters*)bufObj;
+ }
+
+ virtual const char* getClassName()
+ {
+ return (ClothingPhysicalMeshParameters::staticClassName());
+ }
+
+ virtual uint32_t getVersion()
+ {
+ return (ClothingPhysicalMeshParameters::staticVersion());
+ }
+
+ virtual uint32_t getAlignment()
+ {
+ return (ClothingPhysicalMeshParameters::ClassAlignment);
+ }
+
+ virtual const uint32_t* getChecksum(uint32_t& bits)
+ {
+ return (ClothingPhysicalMeshParameters::staticChecksum(bits));
+ }
+};
+#endif // NV_PARAMETERIZED_ONLY_LAYOUTS
+
+} // namespace clothing
+} // namespace nvidia
+
+#if PX_VC
+#pragma warning(pop)
+#endif
+
+#endif
diff --git a/APEX_1.4/module/clothing/include/autogen/ClothingPreviewParam.h b/APEX_1.4/module/clothing/include/autogen/ClothingPreviewParam.h
new file mode 100644
index 00000000..a6b2093c
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/autogen/ClothingPreviewParam.h
@@ -0,0 +1,243 @@
+// 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) 2008-2015 NVIDIA Corporation. All rights reserved.
+
+// This file was generated by NvParameterized/scripts/GenParameterized.pl
+
+
+#ifndef HEADER_ClothingPreviewParam_h
+#define HEADER_ClothingPreviewParam_h
+
+#include "NvParametersTypes.h"
+
+#ifndef NV_PARAMETERIZED_ONLY_LAYOUTS
+#include "nvparameterized/NvParameterized.h"
+#include "nvparameterized/NvParameterizedTraits.h"
+#include "NvParameters.h"
+#include "NvTraitsInternal.h"
+#endif
+
+namespace nvidia
+{
+namespace clothing
+{
+
+#if PX_VC
+#pragma warning(push)
+#pragma warning(disable: 4324) // structure was padded due to __declspec(align())
+#endif
+
+namespace ClothingPreviewParamNS
+{
+
+
+struct MAT44_DynamicArray1D_Type
+{
+ physx::PxMat44* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+
+struct ParametersStruct
+{
+
+ physx::PxMat44 globalPose;
+ bool fallbackSkinning;
+ bool useInternalBoneOrder;
+ bool updateStateWithGlobalMatrices;
+ uint64_t userData;
+ MAT44_DynamicArray1D_Type boneMatrices;
+
+};
+
+static const uint32_t checksum[] = { 0x614ffe9f, 0x273131aa, 0xa5bdd27c, 0xfe7fba5b, };
+
+} // namespace ClothingPreviewParamNS
+
+#ifndef NV_PARAMETERIZED_ONLY_LAYOUTS
+class ClothingPreviewParam : public NvParameterized::NvParameters, public ClothingPreviewParamNS::ParametersStruct
+{
+public:
+ ClothingPreviewParam(NvParameterized::Traits* traits, void* buf = 0, int32_t* refCount = 0);
+
+ virtual ~ClothingPreviewParam();
+
+ virtual void destroy();
+
+ static const char* staticClassName(void)
+ {
+ return("ClothingPreviewParam");
+ }
+
+ const char* className(void) const
+ {
+ return(staticClassName());
+ }
+
+ static const uint32_t ClassVersion = ((uint32_t)0 << 16) + (uint32_t)0;
+
+ static uint32_t staticVersion(void)
+ {
+ return ClassVersion;
+ }
+
+ uint32_t version(void) const
+ {
+ return(staticVersion());
+ }
+
+ static const uint32_t ClassAlignment = 8;
+
+ static const uint32_t* staticChecksum(uint32_t& bits)
+ {
+ bits = 8 * sizeof(ClothingPreviewParamNS::checksum);
+ return ClothingPreviewParamNS::checksum;
+ }
+
+ static void freeParameterDefinitionTable(NvParameterized::Traits* traits);
+
+ const uint32_t* checksum(uint32_t& bits) const
+ {
+ return staticChecksum(bits);
+ }
+
+ const ClothingPreviewParamNS::ParametersStruct& parameters(void) const
+ {
+ ClothingPreviewParam* tmpThis = const_cast<ClothingPreviewParam*>(this);
+ return *(static_cast<ClothingPreviewParamNS::ParametersStruct*>(tmpThis));
+ }
+
+ ClothingPreviewParamNS::ParametersStruct& parameters(void)
+ {
+ return *(static_cast<ClothingPreviewParamNS::ParametersStruct*>(this));
+ }
+
+ virtual NvParameterized::ErrorType getParameterHandle(const char* long_name, NvParameterized::Handle& handle) const;
+ virtual NvParameterized::ErrorType getParameterHandle(const char* long_name, NvParameterized::Handle& handle);
+
+ void initDefaults(void);
+
+protected:
+
+ virtual const NvParameterized::DefinitionImpl* getParameterDefinitionTree(void);
+ virtual const NvParameterized::DefinitionImpl* getParameterDefinitionTree(void) const;
+
+
+ virtual void getVarPtr(const NvParameterized::Handle& handle, void*& ptr, size_t& offset) const;
+
+private:
+
+ void buildTree(void);
+ void initDynamicArrays(void);
+ void initStrings(void);
+ void initReferences(void);
+ void freeDynamicArrays(void);
+ void freeStrings(void);
+ void freeReferences(void);
+
+ static bool mBuiltFlag;
+ static NvParameterized::MutexType mBuiltFlagMutex;
+};
+
+class ClothingPreviewParamFactory : public NvParameterized::Factory
+{
+ static const char* const vptr;
+
+public:
+
+ virtual void freeParameterDefinitionTable(NvParameterized::Traits* traits)
+ {
+ ClothingPreviewParam::freeParameterDefinitionTable(traits);
+ }
+
+ virtual NvParameterized::Interface* create(NvParameterized::Traits* paramTraits)
+ {
+ // placement new on this class using mParameterizedTraits
+
+ void* newPtr = paramTraits->alloc(sizeof(ClothingPreviewParam), ClothingPreviewParam::ClassAlignment);
+ if (!NvParameterized::IsAligned(newPtr, ClothingPreviewParam::ClassAlignment))
+ {
+ NV_PARAM_TRAITS_WARNING(paramTraits, "Unaligned memory allocation for class ClothingPreviewParam");
+ paramTraits->free(newPtr);
+ return 0;
+ }
+
+ memset(newPtr, 0, sizeof(ClothingPreviewParam)); // always initialize memory allocated to zero for default values
+ return NV_PARAM_PLACEMENT_NEW(newPtr, ClothingPreviewParam)(paramTraits);
+ }
+
+ virtual NvParameterized::Interface* finish(NvParameterized::Traits* paramTraits, void* bufObj, void* bufStart, int32_t* refCount)
+ {
+ if (!NvParameterized::IsAligned(bufObj, ClothingPreviewParam::ClassAlignment)
+ || !NvParameterized::IsAligned(bufStart, ClothingPreviewParam::ClassAlignment))
+ {
+ NV_PARAM_TRAITS_WARNING(paramTraits, "Unaligned memory allocation for class ClothingPreviewParam");
+ return 0;
+ }
+
+ // Init NvParameters-part
+ // We used to call empty constructor of ClothingPreviewParam here
+ // but it may call default constructors of members and spoil the data
+ NV_PARAM_PLACEMENT_NEW(bufObj, NvParameterized::NvParameters)(paramTraits, bufStart, refCount);
+
+ // Init vtable (everything else is already initialized)
+ *(const char**)bufObj = vptr;
+
+ return (ClothingPreviewParam*)bufObj;
+ }
+
+ virtual const char* getClassName()
+ {
+ return (ClothingPreviewParam::staticClassName());
+ }
+
+ virtual uint32_t getVersion()
+ {
+ return (ClothingPreviewParam::staticVersion());
+ }
+
+ virtual uint32_t getAlignment()
+ {
+ return (ClothingPreviewParam::ClassAlignment);
+ }
+
+ virtual const uint32_t* getChecksum(uint32_t& bits)
+ {
+ return (ClothingPreviewParam::staticChecksum(bits));
+ }
+};
+#endif // NV_PARAMETERIZED_ONLY_LAYOUTS
+
+} // namespace clothing
+} // namespace nvidia
+
+#if PX_VC
+#pragma warning(pop)
+#endif
+
+#endif
diff --git a/APEX_1.4/module/clothing/include/autogen/ModuleClothingRegistration.h b/APEX_1.4/module/clothing/include/autogen/ModuleClothingRegistration.h
new file mode 100644
index 00000000..4e8a5605
--- /dev/null
+++ b/APEX_1.4/module/clothing/include/autogen/ModuleClothingRegistration.h
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+
+#ifndef MODULE_MODULECLOTHINGREGISTRATIONH_H
+#define MODULE_MODULECLOTHINGREGISTRATIONH_H
+
+#include "PsAllocator.h"
+#include "NvRegistrationsForTraitsBase.h"
+#include "nvparameterized/NvParameterizedTraits.h"
+#include "PxAssert.h"
+#include <stdint.h>
+
+// INCLUDE GENERATED FACTORIES
+#include "ClothingActorParam.h"
+#include "ClothingAssetParameters.h"
+#include "ClothingCookedParam.h"
+#include "ClothingCookedPhysX3Param.h"
+#include "ClothingDebugRenderParams.h"
+#include "ClothingGraphicalLodParameters.h"
+#include "ClothingMaterialLibraryParameters.h"
+#include "ClothingModuleParameters.h"
+#include "ClothingPhysicalMeshParameters.h"
+#include "ClothingPreviewParam.h"
+
+
+// INCLUDE GENERATED CONVERSION
+
+
+namespace nvidia {
+namespace clothing {
+
+
+class ModuleClothingRegistration : public NvParameterized::RegistrationsForTraitsBase
+{
+public:
+ static void invokeRegistration(NvParameterized::Traits* parameterizedTraits)
+ {
+ if (parameterizedTraits)
+ {
+ ModuleClothingRegistration().registerAll(*parameterizedTraits);
+ }
+ }
+
+ static void invokeUnregistration(NvParameterized::Traits* parameterizedTraits)
+ {
+ if (parameterizedTraits)
+ {
+ ModuleClothingRegistration().unregisterAll(*parameterizedTraits);
+ }
+ }
+
+ void registerAvailableFactories(NvParameterized::Traits& parameterizedTraits)
+ {
+ ::NvParameterized::Factory* factoriesToRegister[] = {
+// REGISTER GENERATED FACTORIES
+ new nvidia::clothing::ClothingActorParamFactory(),
+ new nvidia::clothing::ClothingAssetParametersFactory(),
+ new nvidia::clothing::ClothingCookedParamFactory(),
+ new nvidia::clothing::ClothingCookedPhysX3ParamFactory(),
+ new nvidia::clothing::ClothingDebugRenderParamsFactory(),
+ new nvidia::clothing::ClothingGraphicalLodParametersFactory(),
+ new nvidia::clothing::ClothingMaterialLibraryParametersFactory(),
+ new nvidia::clothing::ClothingModuleParametersFactory(),
+ new nvidia::clothing::ClothingPhysicalMeshParametersFactory(),
+ new nvidia::clothing::ClothingPreviewParamFactory(),
+
+ };
+
+ for (size_t i = 0; i < sizeof(factoriesToRegister)/sizeof(factoriesToRegister[0]); ++i)
+ {
+ parameterizedTraits.registerFactory(*factoriesToRegister[i]);
+ }
+ }
+
+ virtual void registerAvailableConverters(NvParameterized::Traits& parameterizedTraits)
+ {
+// REGISTER GENERATED CONVERSION
+PX_UNUSED(parameterizedTraits);
+
+ }
+
+ void unregisterAvailableFactories(NvParameterized::Traits& parameterizedTraits)
+ {
+ struct FactoryDesc
+ {
+ const char* name;
+ uint32_t version;
+ };
+
+ ::NvParameterized::Factory* factoriesToUnregister[] = {
+// UNREGISTER GENERATED FACTORIES
+ new nvidia::clothing::ClothingActorParamFactory(),
+ new nvidia::clothing::ClothingAssetParametersFactory(),
+ new nvidia::clothing::ClothingCookedParamFactory(),
+ new nvidia::clothing::ClothingCookedPhysX3ParamFactory(),
+ new nvidia::clothing::ClothingDebugRenderParamsFactory(),
+ new nvidia::clothing::ClothingGraphicalLodParametersFactory(),
+ new nvidia::clothing::ClothingMaterialLibraryParametersFactory(),
+ new nvidia::clothing::ClothingModuleParametersFactory(),
+ new nvidia::clothing::ClothingPhysicalMeshParametersFactory(),
+ new nvidia::clothing::ClothingPreviewParamFactory(),
+
+ };
+
+ for (size_t i = 0; i < sizeof(factoriesToUnregister)/sizeof(factoriesToUnregister[0]); ++i)
+ {
+ ::NvParameterized::Factory* removedFactory = parameterizedTraits.removeFactory(factoriesToUnregister[i]->getClassName(), factoriesToUnregister[i]->getVersion());
+ if (!removedFactory)
+ {
+ PX_ASSERT_WITH_MESSAGE(0, "Factory can not be removed!");
+ }
+ else
+ {
+ removedFactory->freeParameterDefinitionTable(&parameterizedTraits);
+ delete removedFactory;
+ delete factoriesToUnregister[i];
+ }
+ }
+ }
+
+ virtual void unregisterAvailableConverters(NvParameterized::Traits& parameterizedTraits)
+ {
+// UNREGISTER GENERATED CONVERSION
+PX_UNUSED(parameterizedTraits);
+
+ }
+
+};
+
+
+}
+} //nvidia::clothing
+
+#endif
diff --git a/APEX_1.4/module/clothing/src/ClothingActorData.cpp b/APEX_1.4/module/clothing/src/ClothingActorData.cpp
new file mode 100644
index 00000000..a3084779
--- /dev/null
+++ b/APEX_1.4/module/clothing/src/ClothingActorData.cpp
@@ -0,0 +1,1161 @@
+/*
+ * 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 "ApexSimdMath.h"
+#include "PxPreprocessor.h"
+#include "RenderDataFormat.h"
+#include "ClothingActorData.h"
+#include "AbstractMeshDescription.h"
+#include "PsIntrinsics.h"
+#include "PxMat44.h"
+#include "ApexSDKIntl.h"
+
+#include "ClothingGlobals.h"
+
+#include "ProfilerCallback.h"
+
+using namespace physx::shdfnd;
+
+#pragma warning(disable : 4101 4127) // unreferenced local variable and conditional is constant
+
+#define NX_PARAMETERIZED_ONLY_LAYOUTS
+#include "ClothingGraphicalLodParameters.h"
+
+#include "PsIntrinsics.h"
+#include "PsVecMath.h"
+
+namespace nvidia
+{
+namespace clothing
+{
+
+
+ClothingActorData::ClothingActorData() :
+ mNewBounds(PxBounds3::empty()),
+
+ mGlobalPose(PxVec4(1.0f)),
+ mInternalGlobalPose(PxVec4(1.0f)),
+
+ mInternalBoneMatricesCur(NULL),
+ mInternalBoneMatricesPrev(NULL),
+ mRenderingDataPosition(NULL),
+ mRenderingDataNormal(NULL),
+ mRenderingDataTangent(NULL),
+ mMorphDisplacementBuffer(NULL),
+ mSdkWritebackNormal(NULL),
+ mSdkWritebackPositions(NULL),
+ mSkinnedPhysicsPositions(NULL),
+ mSkinnedPhysicsNormals(NULL),
+
+ mInternalMatricesCount(0),
+ mMorphDisplacementBufferCount(0),
+ mSdkDeformableVerticesCount(0),
+ mSdkDeformableIndicesCount(0),
+ mCurrentGraphicalLodId(0),
+ mCurrentPhysicsSubmesh(0),
+
+ mActorScale(0.0f),
+
+ bInternalFrozen(false),
+ bShouldComputeRenderData(false),
+ bIsInitialized(false),
+ bIsSimulationMeshDirty(false),
+ bRecomputeNormals(false),
+ bRecomputeTangents(false),
+ bCorrectSimulationNormals(false),
+ bParallelCpuSkinning(false),
+ bIsClothingSimulationNull(false)
+{
+}
+
+
+
+ClothingActorData::~ClothingActorData()
+{
+ PX_ASSERT(mInternalBoneMatricesCur == NULL); // properly deallocated
+}
+
+
+
+void ClothingActorData::renderDataLock()
+{
+ mRenderLock.lock();
+}
+
+
+
+void ClothingActorData::renderDataUnLock()
+{
+ //TODO - release a mutex here
+ mRenderLock.unlock();
+}
+
+
+
+void ClothingActorData::skinPhysicsMaxDist0Normals_NoPhysx()
+{
+ if (mSdkWritebackNormal == NULL /*|| bInternalFrozen == 1*/)
+ {
+ return;
+ }
+
+ //ClothingPhysicalMeshParametersNS::PhysicalMesh_Type* physicalMesh = mAsset->getPhysicalMeshFromLod(mCurrentGraphicalLodId);
+
+ ClothingPhysicalMeshData* physicalMesh = mAsset.GetPhysicalMeshFromLod(mCurrentGraphicalLodId);
+ const PxVec3* PX_RESTRICT _normals = physicalMesh->mSkinningNormals;
+
+ if (_normals == NULL)
+ {
+ return;
+ }
+
+ if (physicalMesh->mMaxDistance0VerticesCount == 0)
+ {
+ return;
+ }
+
+ const uint32_t startVertex = physicalMesh->mSimulatedVertexCount - physicalMesh->mMaxDistance0VerticesCount;
+ const uint32_t numVertices = physicalMesh->mSimulatedVertexCount;
+ const uint32_t numBoneIndicesPerVertex = physicalMesh->mNumBonesPerVertex;
+
+ // offset the normals array as well
+ _normals += startVertex;
+
+ const uint32_t UnrollSize = 160;
+ const uint32_t vertCount = numVertices - startVertex;
+ const uint32_t numIterations = (vertCount + UnrollSize - 1) / UnrollSize;
+
+ PxVec3* PX_RESTRICT targetNormals = mSdkWritebackNormal + startVertex;
+
+ //uint32_t tags[2] = {10, 11};
+ //const uint32_t prefetchRange = (startVertex & 0xfffffff0); //A multiple of 16 before this prefetch, with the assumption that normals is 16-byte aligned!
+ //C_Prefetcher<2, sizeof(PxVec3) * UnrollSize> normPrefetcher(tags, (void*)(normals + prefetchRange), (void*)(normals + numVertices));
+
+ if (mInternalBoneMatricesCur == NULL || numBoneIndicesPerVertex == 0)
+ {
+ if (mActorScale == 1.0f)
+ {
+ for (uint32_t a = 0; a < numIterations; ++a)
+ {
+ const uint32_t numToProcess = PxMin(UnrollSize, (vertCount - (UnrollSize * a)));
+ const PxVec3* PX_RESTRICT localNormals = (const PxVec3 * PX_RESTRICT)(void*)_normals;
+ for (uint32_t i = 0; i < numToProcess; i++)
+ {
+ targetNormals[i] = mInternalGlobalPose.rotate(localNormals[i]);
+ }
+ targetNormals += UnrollSize;
+ _normals += UnrollSize;
+ }
+ }
+ else
+ {
+ const float recipActorScale = 1.f / mActorScale;
+ for (uint32_t a = 0; a < numIterations; ++a)
+ {
+ const uint32_t numToProcess = PxMin(UnrollSize, (vertCount - (UnrollSize * a)));
+ const PxVec3* PX_RESTRICT localNormals = (const PxVec3 * PX_RESTRICT)(void*)_normals;
+ for (uint32_t i = 0; i < numToProcess; i++)
+ {
+ targetNormals[i] = mInternalGlobalPose.rotate(localNormals[i]) * recipActorScale;
+ }
+ targetNormals += UnrollSize;
+ _normals += UnrollSize;
+ }
+ }
+ }
+ else
+ {
+ //OK a slight refactor is required here - we don't want to fetch in everything only to
+ const uint32_t startBoneIndex = startVertex * numBoneIndicesPerVertex;
+ //Another problem - this is an arbitrarily large amount of data that has to be fetched here!!!! Consider revising
+
+ const uint16_t* PX_RESTRICT eaSimBoneIndices = &physicalMesh->mBoneIndices[startBoneIndex];
+ const float* PX_RESTRICT eaSimBoneWeights = &physicalMesh->mBoneWeights[startBoneIndex];
+
+ const PxMat44* const PX_RESTRICT matrices = (const PxMat44*)mInternalBoneMatricesCur;
+
+ for (uint32_t a = 0; a < numIterations; ++a)
+ {
+ const uint32_t numToProcess = PxMin(UnrollSize, (vertCount - (UnrollSize * a)));
+ const PxVec3* PX_RESTRICT localNormals = (const PxVec3 * PX_RESTRICT)(void*)_normals;
+
+ const uint16_t* const PX_RESTRICT simBoneIndices = (const uint16_t * const PX_RESTRICT)(void*)eaSimBoneIndices;
+ const float* const PX_RESTRICT simBoneWeights = (const float * const PX_RESTRICT)(void*)eaSimBoneWeights;
+
+ eaSimBoneIndices += numBoneIndicesPerVertex * numToProcess;
+ eaSimBoneWeights += numBoneIndicesPerVertex * numToProcess;
+
+ for (uint32_t i = 0; i < numToProcess; i++)
+ {
+ PxVec3 normal(0.0f, 0.0f, 0.0f);
+ for (uint32_t j = 0; j < numBoneIndicesPerVertex; j++)
+ {
+ const float weight = simBoneWeights[i * numBoneIndicesPerVertex + j];
+
+ if (weight > 0.f)
+ {
+ PX_ASSERT(weight <= 1.0f);
+ const uint32_t index = simBoneIndices[i * numBoneIndicesPerVertex + j];
+
+ const PxMat44& bone = matrices[index];
+
+ normal += bone.rotate(localNormals[i]) * weight; // 12% here
+ }
+ else
+ {
+ // PH: Assuming sorted weights is faster
+ break;
+ }
+ }
+
+ normal.normalize();
+ targetNormals[i] = normal;
+ }
+ targetNormals += UnrollSize;
+ _normals += UnrollSize;
+ }
+
+ }
+
+}
+
+
+void ClothingActorData::skinToAnimation_NoPhysX(bool fromFetchResults)
+{
+ // This optimization only works if the render data from last frame is still there.
+ // So this can only be used if we're using the same ClothingRenderProxy again.
+ //if (!bIsSimulationMeshDirty)
+ //{
+ // return;
+ //}
+
+ PX_PROFILE_ZONE("ClothingActorImpl::skinToAnimation", GetInternalApexSDK()->getContextId());
+
+ //const bool recomputeNormals = bRecomputeNormals;
+
+ // PH: If fromFetchResults is true, renderLock does not need to be aquired as it is already aquired by ApexScene::fetchResults()
+ if (!fromFetchResults)
+ {
+ renderDataLock();
+ }
+
+ for (uint32_t graphicalLod = 0; graphicalLod < mAsset.mGraphicalLodsCount; graphicalLod++)
+ {
+ ClothingMeshAssetData& meshAsset = *mAsset.GetLod(graphicalLod);
+ if (!meshAsset.bActive)
+ {
+ continue;
+ }
+
+ uint32_t submeshVertexOffset = 0;
+
+ for (uint32_t submeshIndex = 0; submeshIndex < meshAsset.mSubMeshCount; submeshIndex++)
+ {
+ AbstractMeshDescription renderData;
+ ClothingAssetSubMesh* pSubMesh = mAsset.GetSubmesh(&meshAsset, submeshIndex);
+ renderData.numVertices = pSubMesh->mVertexCount;
+
+ renderData.pPosition = mRenderingDataPosition + submeshVertexOffset;
+
+ renderData.pNormal = mRenderingDataNormal + submeshVertexOffset;
+
+ if (mRenderingDataTangent != NULL)
+ {
+ renderData.pTangent4 = mRenderingDataTangent + submeshVertexOffset;
+ }
+
+ PxMat44* matrices = NULL;
+ PX_ALIGN(16, PxMat44 alignedGlobalPose); // matrices must be 16 byte aligned!
+ if (mInternalBoneMatricesCur == NULL)
+ {
+ matrices = &alignedGlobalPose;
+ alignedGlobalPose = mInternalGlobalPose;
+ }
+ else
+ {
+ matrices = (PxMat44*)mInternalBoneMatricesCur;
+ PX_ASSERT(matrices != NULL);
+ }
+
+ mAsset.skinToBones(renderData, submeshIndex, graphicalLod, pSubMesh->mCurrentMaxVertexSimulation, matrices, mMorphDisplacementBuffer);
+
+ submeshVertexOffset += pSubMesh->mVertexCount;
+ }
+ }
+
+ if (!fromFetchResults)
+ {
+ renderDataUnLock();
+ }
+}
+
+template<bool computeNormals>
+uint32_t ClothingAssetData::skinClothMap(PxVec3* dstPositions, PxVec3* dstNormals, PxVec4* dstTangents, uint32_t numVertices,
+ const AbstractMeshDescription& srcPM, ClothingGraphicalLodParametersNS::SkinClothMapD_Type* map,
+ uint32_t numVerticesInMap, float offsetAlongNormal, float actorScale) const
+{
+ PX_ASSERT(srcPM.numIndices % 3 == 0);
+
+ const ClothingGraphicalLodParametersNS::SkinClothMapD_Type* PX_RESTRICT pTCM = map;
+ nvidia::prefetchLine(pTCM);
+
+ const float invOffsetAlongNormal = 1.0f / offsetAlongNormal;
+
+ uint32_t numVerticesWritten = 0;
+ uint32_t numTangentsWritten = 0;
+ const uint32_t numVerticesTotal = numVertices;
+
+ uint32_t firstMiss = numVerticesInMap;
+
+ const uint32_t unrollCount = 256;
+
+ const uint32_t numIterations = (numVerticesInMap + unrollCount - 1) / unrollCount;
+
+ //uint32_t vertexIndex = 0;
+ for (uint32_t a = 0; a < numIterations; ++a)
+ {
+ const uint32_t numToProcess = PxMin(numVerticesInMap - (a * unrollCount), unrollCount);
+ const ClothingGraphicalLodParametersNS::SkinClothMapD_Type* PX_RESTRICT pTCMLocal =
+ (const ClothingGraphicalLodParametersNS::SkinClothMapD_Type * PX_RESTRICT)(void*)pTCM;
+
+ for (uint32_t j = 0; j < numToProcess; ++j)
+ {
+ nvidia::prefetchLine(pTCMLocal + 1);
+
+ //PX_ASSERT(vertexIndex == pTCMLocal->vertexIndexPlusOffset);
+ uint32_t vertexIndex = pTCMLocal->vertexIndexPlusOffset;
+ const uint32_t physVertIndex0 = pTCMLocal->vertexIndex0;
+ const uint32_t physVertIndex1 = pTCMLocal->vertexIndex1;
+ const uint32_t physVertIndex2 = pTCMLocal->vertexIndex2;
+
+ if (vertexIndex >= numVerticesTotal)
+ {
+ pTCM++;
+ pTCMLocal++;
+ //vertexIndex++;
+ continue;
+ }
+
+ // TODO do only 1 test, make sure physVertIndex0 is the smallest index
+ if (physVertIndex0 >= srcPM.numVertices || physVertIndex1 >= srcPM.numVertices || physVertIndex2 >= srcPM.numVertices)
+ {
+ firstMiss = PxMin(firstMiss, vertexIndex);
+ pTCM++;
+ pTCMLocal++;
+ //vertexIndex++;
+ continue;
+ }
+
+ numVerticesWritten++;
+
+ //PX_ASSERT(!vertexWriteCache.IsStomped());
+
+ const PxVec3 vtx[3] =
+ {
+ *(PxVec3*)&srcPM.pPosition[physVertIndex0],
+ *(PxVec3*)&srcPM.pPosition[physVertIndex1],
+ *(PxVec3*)&srcPM.pPosition[physVertIndex2],
+ };
+
+ //PX_ASSERT(!vertexWriteCache.IsStomped());
+
+ const PxVec3 nrm[3] =
+ {
+ *(PxVec3*)&srcPM.pNormal[physVertIndex0],
+ *(PxVec3*)&srcPM.pNormal[physVertIndex1],
+ *(PxVec3*)&srcPM.pNormal[physVertIndex2],
+ };
+
+ //PX_ASSERT(!vertexWriteCache.IsStomped());
+
+ PxVec3 bary = pTCMLocal->vertexBary;
+ const float vHeight = bary.z * actorScale;
+ bary.z = 1.0f - bary.x - bary.y;
+
+ const PxVec3 positionVertex = bary.x * vtx[0] + bary.y * vtx[1] + bary.z * vtx[2];
+ const PxVec3 positionNormal = (bary.x * nrm[0] + bary.y * nrm[1] + bary.z * nrm[2]) * vHeight;
+
+ const PxVec3 resultPosition = positionVertex + positionNormal;
+ //Write back - to use a DMA list
+
+ PxVec3* dstPosition = (PxVec3*)&dstPositions[vertexIndex];
+
+ *dstPosition = resultPosition;
+
+ PX_ASSERT(resultPosition.isFinite());
+
+ if (computeNormals)
+ {
+ bary = pTCMLocal->normalBary;
+ const float nHeight = bary.z * actorScale;
+ bary.z = 1.0f - bary.x - bary.y;
+
+ const PxVec3 normalVertex = bary.x * vtx[0] + bary.y * vtx[1] + bary.z * vtx[2];
+ const PxVec3 normalNormal = (bary.x * nrm[0] + bary.y * nrm[1] + bary.z * nrm[2]) * nHeight;
+
+ PxVec3* dstNormal = (PxVec3*)&dstNormals[vertexIndex];
+
+ // we multiply in invOffsetAlongNormal in order to get a newNormal that is closer to size 1,
+ // so the normalize approximation will be better
+ PxVec3 newNormal = ((normalVertex + normalNormal) - (resultPosition)) * invOffsetAlongNormal;
+#if 1
+ // PH: Normally this is accurate enough. For testing we can also use the second
+ const PxVec3 resultNormal = newNormal * nvidia::recipSqrtFast(newNormal.magnitudeSquared());
+ *dstNormal = resultNormal;
+#else
+ newNormal.normalize();
+ *dstNormal = newNormal;
+#endif
+ }
+ if (dstTangents != NULL)
+ {
+ bary = pTCMLocal->tangentBary;
+ const float nHeight = bary.z * actorScale;
+ bary.z = 1.0f - bary.x - bary.y;
+
+ const PxVec3 tangentVertex = bary.x * vtx[0] + bary.y * vtx[1] + bary.z * vtx[2];
+ const PxVec3 tangentTangent = (bary.x * nrm[0] + bary.y * nrm[1] + bary.z * nrm[2]) * nHeight;
+
+ PxVec4* dstTangent = (PxVec4*)&dstTangents[vertexIndex];
+
+ // we multiply in invOffsetAlongNormal in order to get a newNormal that is closer to size 1,
+ // so the normalize approximation will be better
+ PxVec3 newTangent = ((tangentVertex + tangentTangent) - (resultPosition)) * invOffsetAlongNormal;
+#if 1
+ // PH: Normally this is accurate enough. For testing we can also use the second
+ const PxVec3 resultTangent = newTangent * nvidia::recipSqrtFast(newTangent.magnitudeSquared());
+
+ uint32_t arrayIndex = numTangentsWritten / 4;
+ uint32_t offset = numTangentsWritten % 4;
+ float w = ((mCompressedTangentW[arrayIndex] >> offset) & 1) ? 1.f : -1.f;
+
+ *dstTangent = PxVec4(resultTangent, w);
+#else
+ newTangent.normalize();
+ *dstTangent = newTangent;
+#endif
+ }
+
+ pTCM++;
+ pTCMLocal++;
+ //vertexIndex++;
+ }
+ }
+
+ return firstMiss;
+}
+
+
+#if PX_ANDROID || PX_LINUX
+template uint32_t ClothingAssetData::skinClothMap<true>(PxVec3* dstPositions, PxVec3* dstNormals, PxVec4* dstTangents, uint32_t numVertices,
+ const AbstractMeshDescription& srcPM, ClothingGraphicalLodParametersNS::SkinClothMapD_Type* map,
+ uint32_t numVerticesInMap, float offsetAlongNormal, float actorScale) const;
+
+template uint32_t ClothingAssetData::skinClothMap<false>(PxVec3* dstPositions, PxVec3* dstNormals, PxVec4* dstTangents, uint32_t numVertices,
+ const AbstractMeshDescription& srcPM, ClothingGraphicalLodParametersNS::SkinClothMapD_Type* map,
+ uint32_t numVerticesInMap, float offsetAlongNormal, float actorScale) const;
+#endif
+
+void ClothingActorData::skinToImmediateMap(const uint32_t* immediateClothMap_, uint32_t numGraphicalVertices_, uint32_t numSrcVertices_,
+ const PxVec3* srcPositions_)
+{
+ const uint32_t* PX_RESTRICT immediateClothMap = immediateClothMap_;
+
+ const PxVec3* PX_RESTRICT srcPositions = srcPositions_;
+ PxVec3* PX_RESTRICT destPositions = mRenderingDataPosition;
+
+ const uint32_t numGraphicalVertices = numGraphicalVertices_;
+ const uint32_t numSrcVertices = numSrcVertices_;
+
+ const uint32_t WorkSize = 512;
+
+ const uint32_t numIterations = (numGraphicalVertices + WorkSize - 1) / WorkSize;
+
+ for (uint32_t a = 0; a < numIterations; ++a)
+ {
+ const uint32_t numToProcess = PxMin(numGraphicalVertices - (a * WorkSize), WorkSize);
+
+ const uint32_t* PX_RESTRICT immediateClothMapLocal = (const uint32_t * PX_RESTRICT)(void*)&immediateClothMap[a * WorkSize];
+ PxVec3* PX_RESTRICT destPositionsLocal = (PxVec3 * PX_RESTRICT)(void*)&destPositions[a * WorkSize];
+
+ for (uint32_t j = 0; j < numToProcess; ++j)
+ {
+ const uint32_t mapEntry = immediateClothMapLocal[j];
+ const uint32_t index = mapEntry & ClothingConstants::ImmediateClothingReadMask;
+ const uint32_t flags = mapEntry & ~ClothingConstants::ImmediateClothingReadMask;
+
+ if (index < numSrcVertices && ((flags & ClothingConstants::ImmediateClothingInSkinFlag)) == 0)
+ {
+ destPositionsLocal[j] = *((PxVec3*)(void*)&srcPositions[index]);
+ PX_ASSERT(destPositionsLocal[j].isFinite());
+ }
+ }
+ }
+}
+
+
+
+void ClothingActorData::skinToImmediateMap(const uint32_t* immediateClothMap_, uint32_t numGraphicalVertices_, uint32_t numSrcVertices_,
+ const PxVec3* srcPositions_, const PxVec3* srcNormals_)
+{
+ const uint32_t* PX_RESTRICT immediateClothMap = immediateClothMap_;
+
+ const PxVec3* PX_RESTRICT srcPositions = srcPositions_;
+ const PxVec3* PX_RESTRICT srcNormals = srcNormals_;
+
+ PxVec3* PX_RESTRICT destPositions = mRenderingDataPosition;
+ PxVec3* PX_RESTRICT destNormals = mRenderingDataNormal;
+
+ const uint32_t numGraphicalVertices = numGraphicalVertices_;
+ const uint32_t numSrcVertices = numSrcVertices_;
+
+ const uint32_t WorkSize = 160;
+
+ //__builtin_snpause();
+
+ const uint32_t numIterations = (numGraphicalVertices + WorkSize - 1) / WorkSize;
+
+ for (uint32_t a = 0; a < numIterations; ++a)
+ {
+ const uint32_t numToProcess = PxMin(numGraphicalVertices - (a * WorkSize), WorkSize);
+
+ const uint32_t* PX_RESTRICT immediateClothMapLocal = (const uint32_t * PX_RESTRICT)(void*)&immediateClothMap[a * WorkSize];
+ PxVec3* PX_RESTRICT destPositionsLocal = (PxVec3 * PX_RESTRICT)(void*)&destPositions[a * WorkSize];
+ PxVec3* PX_RESTRICT destNormalsLocal = (PxVec3 * PX_RESTRICT)(void*)&destNormals[a * WorkSize];
+
+ for (uint32_t j = 0; j < numToProcess; ++j)
+ {
+ const uint32_t mapEntry = immediateClothMapLocal[j];
+ const uint32_t index = mapEntry & ClothingConstants::ImmediateClothingReadMask;
+ const uint32_t flags = mapEntry & ~ClothingConstants::ImmediateClothingReadMask;
+
+ if (index < numSrcVertices && ((flags & ClothingConstants::ImmediateClothingInSkinFlag)) == 0)
+ {
+ destPositionsLocal[j] = *((PxVec3*)(void*)&srcPositions[index]);
+ PX_ASSERT(destPositionsLocal[j].isFinite());
+
+ const PxVec3 destNormal = *((PxVec3*)(void*)&srcNormals[index]);
+ destNormalsLocal[j] = (flags & ClothingConstants::ImmediateClothingInvertNormal) ? -destNormal : destNormal;
+ PX_ASSERT(destNormalsLocal[j].isFinite());
+ }
+ }
+ }
+}
+
+
+
+void ClothingActorData::skinToPhysicalMesh_NoPhysX(bool fromFetchResults)
+{
+ // This optimization only works if the render data from last frame is still there.
+ // So this can only be used if we're using the same ClothingRenderProxy again.
+ //if (!bIsSimulationMeshDirty)
+ //{
+ // return;
+ //}
+
+ PX_PROFILE_ZONE("ClothingActorImpl::meshMesh-Skinning", GetInternalApexSDK()->getContextId());
+
+ const ClothingMeshAssetData& graphicalLod = *mAsset.GetLod(mCurrentGraphicalLodId);
+
+ const ClothingPhysicalMeshData* physicalMesh = mAsset.GetPhysicalMeshFromLod(mCurrentGraphicalLodId);
+
+ AbstractMeshDescription pcm;
+ pcm.numVertices = mSdkDeformableVerticesCount;
+ pcm.numIndices = mSdkDeformableIndicesCount;
+ pcm.pPosition = mSdkWritebackPositions;
+ pcm.pNormal = mSdkWritebackNormal;
+ pcm.pIndices = physicalMesh->mIndices;
+ pcm.avgEdgeLength = graphicalLod.mSkinClothMapThickness;
+
+ const bool skinNormals = !bRecomputeNormals;
+
+ if (!fromFetchResults)
+ {
+ renderDataLock();
+ }
+
+ uint32_t activeCount = 0;
+
+ for (uint32_t i = 0; i < mAsset.mGraphicalLodsCount; i++)
+ {
+ const ClothingMeshAssetData& lod = *mAsset.GetLod(i);
+ if (!lod.bActive)
+ {
+ continue;
+ }
+ activeCount++;
+
+ bool skinTangents = !bRecomputeTangents;
+
+ uint32_t graphicalVerticesCount = 0;
+ for (uint32_t j = 0; j < lod.mSubMeshCount; j++)
+ {
+ ClothingAssetSubMesh* subMesh = mAsset.GetSubmesh(&lod, j);
+ graphicalVerticesCount += subMesh->mVertexCount; // only 1 part is supported
+
+ if (subMesh->mTangents == NULL)
+ {
+ skinTangents = false;
+ }
+ }
+
+ //__builtin_snpause();
+ //RenderMeshAssetIntl* renderMeshAsset = mAsset->getGraphicalMesh(i);
+ //PX_ASSERT(renderMeshAsset != NULL);
+
+ // Do mesh-to-mesh skinning here
+ if (graphicalLod.mSkinClothMapB != NULL)
+ {
+ mAsset.skinClothMapB(mRenderingDataPosition, mRenderingDataNormal, graphicalVerticesCount, pcm,
+ graphicalLod.mSkinClothMapB, graphicalLod.mSkinClothMapBCount, skinNormals);
+ }
+ else if (graphicalLod.mSkinClothMap != NULL)
+ {
+ PxVec4* tangents = skinTangents ? mRenderingDataTangent : NULL;
+ if (skinNormals)
+ mAsset.skinClothMap<true>(mRenderingDataPosition, mRenderingDataNormal, tangents, graphicalVerticesCount, pcm,
+ graphicalLod.mSkinClothMap, graphicalLod.mSkinClothMapCount, graphicalLod.mSkinClothMapOffset, mActorScale);
+ else
+ mAsset.skinClothMap<false>(mRenderingDataPosition, mRenderingDataNormal, tangents, graphicalVerticesCount, pcm,
+ graphicalLod.mSkinClothMap, graphicalLod.mSkinClothMapCount, graphicalLod.mSkinClothMapOffset, mActorScale);
+
+ }
+ else if (graphicalLod.mTetraMap != NULL)
+ {
+ AbstractMeshDescription destMesh;
+ destMesh.pPosition = mRenderingDataPosition;
+ if (skinNormals)
+ {
+ destMesh.pNormal = mRenderingDataNormal;
+ }
+ destMesh.numVertices = graphicalVerticesCount;
+ mAsset.skinToTetraMesh(destMesh, pcm, graphicalLod);
+ }
+
+ if (graphicalLod.mImmediateClothMap != NULL)
+ {
+ if (skinNormals)
+ {
+ skinToImmediateMap(graphicalLod.mImmediateClothMap, graphicalVerticesCount, pcm.numVertices, pcm.pPosition, pcm.pNormal);
+ }
+ else
+ {
+ skinToImmediateMap(graphicalLod.mImmediateClothMap, graphicalVerticesCount, pcm.numVertices, pcm.pPosition);
+ }
+ }
+ }
+
+ PX_ASSERT(activeCount < 2);
+
+ if (!fromFetchResults)
+ {
+ renderDataUnLock();
+ }
+}
+
+
+
+
+
+
+void ClothingActorData::finalizeSkinning_NoPhysX(bool fromFetchResults)
+{
+ // PH: If fromFetchResults is true, renderLock does not need to be aquired as it is already aquired by ApexScene::fetchResults()
+ if (!fromFetchResults)
+ {
+ renderDataLock();
+ }
+
+ mNewBounds.setEmpty();
+
+ for (uint32_t graphicalLod = 0; graphicalLod < mAsset.mGraphicalLodsCount; graphicalLod++)
+ {
+ ClothingMeshAssetData& renderMeshAsset = *mAsset.GetLod(graphicalLod);
+ if (!renderMeshAsset.bActive)
+ {
+ continue;
+ }
+
+ const uint32_t submeshCount = renderMeshAsset.mSubMeshCount;
+
+ uint32_t submeshVertexOffset = 0;
+ for (uint32_t submeshIndex = 0; submeshIndex < submeshCount; submeshIndex++)
+ {
+ AbstractMeshDescription renderData;
+
+ ClothingAssetSubMesh* pSubmesh = mAsset.GetSubmesh(&renderMeshAsset, submeshIndex);
+
+ renderData.numVertices = pSubmesh->mVertexCount;
+
+ renderData.pPosition = mRenderingDataPosition + submeshVertexOffset;
+
+ bool recomputeTangents = bRecomputeTangents && renderMeshAsset.bNeedsTangents;
+ if (bRecomputeNormals || recomputeTangents)
+ {
+ renderData.pNormal = mRenderingDataNormal + submeshVertexOffset;
+
+ const uint32_t* compressedTangentW = NULL;
+
+ if (recomputeTangents)
+ {
+ renderData.pTangent4 = mRenderingDataTangent + submeshVertexOffset;
+ uint32_t mapSize = 0;
+ compressedTangentW = mAsset.getCompressedTangentW(graphicalLod, submeshIndex, mapSize);
+ }
+ if (bRecomputeNormals && recomputeTangents)
+ {
+ PX_PROFILE_ZONE("ClothingActorImpl::recomupteNormalAndTangent", GetInternalApexSDK()->getContextId());
+ computeTangentSpaceUpdate<true, true>(renderData, renderMeshAsset, submeshIndex, compressedTangentW);
+ }
+ else if (bRecomputeNormals)
+ {
+ PX_PROFILE_ZONE("ClothingActorImpl::recomupteNormal", GetInternalApexSDK()->getContextId());
+ computeTangentSpaceUpdate<true, false>(renderData, renderMeshAsset, submeshIndex, compressedTangentW);
+ }
+ else
+ {
+ PX_PROFILE_ZONE("ClothingActorImpl::recomupteTangent", GetInternalApexSDK()->getContextId());
+ computeTangentSpaceUpdate<false, true>(renderData, renderMeshAsset, submeshIndex, compressedTangentW);
+ }
+ }
+
+ const uint32_t unrollCount = 1024;
+ const uint32_t numIterations = (renderData.numVertices + unrollCount - 1) / unrollCount;
+
+ for (uint32_t a = 0; a < numIterations; ++a)
+ {
+ const uint32_t numToProcess = PxMin(unrollCount, renderData.numVertices - (a * unrollCount));
+ const PxVec3* PX_RESTRICT positions = (const PxVec3 * PX_RESTRICT)(renderData.pPosition + (a * unrollCount));
+ for (uint32_t b = 0; b < numToProcess; ++b)
+ {
+ mNewBounds.include(positions[b]);
+ }
+ }
+
+ submeshVertexOffset += renderData.numVertices;
+ }
+ }
+
+ if (!fromFetchResults)
+ {
+ renderDataUnLock();
+ }
+}
+
+#define FLOAT_TANGENT_UPDATE 0
+
+
+template <bool withNormals, bool withTangents>
+void ClothingActorData::computeTangentSpaceUpdate(AbstractMeshDescription& destMesh,
+ const ClothingMeshAssetData& rendermesh, uint32_t submeshIndex, const uint32_t* compressedTangentW)
+{
+ //__builtin_snpause();
+ ClothingAssetSubMesh* pSubMesh = mAsset.GetSubmesh(&rendermesh, submeshIndex);
+
+ if (withNormals && withTangents)
+ {
+ computeTangentSpaceUpdate<true, false>(destMesh, rendermesh, submeshIndex, compressedTangentW);
+ computeTangentSpaceUpdate<false, true>(destMesh, rendermesh, submeshIndex, compressedTangentW);
+ }
+ else
+ {
+ const RenderDataFormat::Enum uvFormat = pSubMesh->mUvFormat;
+
+ if (uvFormat != RenderDataFormat::FLOAT2)
+ {
+ if (withNormals)
+ {
+ computeTangentSpaceUpdate<true, false>(destMesh, rendermesh, submeshIndex, compressedTangentW);
+ }
+
+ return;
+ }
+
+ PX_ASSERT(pSubMesh->mCurrentMaxIndexSimulation <= pSubMesh->mIndicesCount);
+ const uint32_t numGraphicalVertexIndices = pSubMesh->mCurrentMaxIndexSimulation;
+ const uint32_t* indices = pSubMesh->mIndices;
+
+ const VertexUVLocal* PX_RESTRICT uvs = pSubMesh->mUvs;
+ PX_ASSERT(uvs != NULL);
+
+ const uint32_t numVertices = pSubMesh->mCurrentMaxVertexAdditionalSimulation;
+ const uint32_t numZeroVertices = pSubMesh->mCurrentMaxVertexSimulation;
+ PX_ASSERT(numVertices <= destMesh.numVertices);
+
+ PX_ASSERT(pSubMesh->mVertexCount == destMesh.numVertices);
+ PX_ASSERT(destMesh.pPosition != NULL);
+ PX_ASSERT(destMesh.pNormal != NULL);
+ PX_ASSERT(destMesh.pTangent4 != NULL || !withTangents);
+ PX_ASSERT(destMesh.pTangent == NULL);
+ PX_ASSERT(destMesh.pBitangent == NULL);
+
+ const Simd4f vZero = gSimd4fZero;
+
+ //All indices read in in blocks of 3...hence need to fetch in an exact multiple of 3...
+
+ const uint32_t UnrollSize = 192; //exactly divisible by 16 AND 3 :-)
+
+ const uint32_t numIterations = (numGraphicalVertexIndices + UnrollSize - 1) / UnrollSize;
+
+ const PxVec3* PX_RESTRICT destPositions = (const PxVec3 * PX_RESTRICT)(destMesh.pPosition);
+
+ if (withNormals)
+ {
+ //__builtin_snpause();
+ PxVec3* PX_RESTRICT destNormals = destMesh.pNormal;
+ for (uint32_t a = 0; a < numZeroVertices; ++a)
+ {
+ destNormals[a] = PxVec3(0.0f);
+ }
+
+ for (uint32_t a = 0; a < numIterations; ++a)
+ {
+ //__builtin_snpause();
+ const uint32_t numToProcess = PxMin(numGraphicalVertexIndices - (a * UnrollSize), UnrollSize);
+ const uint32_t* localIndices = (const uint32_t*)((void*)(indices + (a * UnrollSize)));
+
+ for (uint32_t i = 0; i < numToProcess; i += 3)
+ {
+ const uint32_t i0 = localIndices[i + 0];
+ const uint32_t i1 = localIndices[i + 1];
+ const uint32_t i2 = localIndices[i + 2];
+
+ const Simd4f P0 = createSimd3f(destPositions[i0]);
+ const Simd4f P1 = createSimd3f(destPositions[i1]);
+ const Simd4f P2 = createSimd3f(destPositions[i2]);
+
+ const Simd4f X1 = P1 - P0;
+ const Simd4f X2 = P2 - P0;
+
+ Simd4f FACENORMAL = cross3(X1, X2);
+
+ PxVec3* PX_RESTRICT nor1 = &destNormals[i0];
+ Simd4f n1 = createSimd3f(*nor1);
+ n1 = n1 + FACENORMAL;
+ store3(&nor1->x, n1);
+
+ PxVec3* PX_RESTRICT nor2 = &destNormals[i1];
+ Simd4f n2 = createSimd3f(*nor2);
+ n2 = n2 + FACENORMAL;
+ store3(&nor2->x, n2);
+
+ PxVec3* PX_RESTRICT nor3 = &destNormals[i2];
+ Simd4f n3 = createSimd3f(*nor3);
+ n3 = n3 + FACENORMAL;
+ store3(&nor3->x, n3);
+
+ }
+ }
+ }
+ if (withTangents)
+ {
+ const VertexUVLocal* PX_RESTRICT uvLocal = (const VertexUVLocal * PX_RESTRICT)(void*)uvs;
+
+ PxVec4* PX_RESTRICT tangents = destMesh.pTangent4;
+ for (uint32_t a = 0; a < numZeroVertices; ++a)
+ {
+ tangents[a] = PxVec4(0.f);
+ }
+
+
+ for (uint32_t a = 0; a < numIterations; ++a)
+ {
+ //__builtin_snpause();
+ const uint32_t numToProcess = PxMin(numGraphicalVertexIndices - (a * UnrollSize), UnrollSize);
+ const uint32_t* localIndices = (const uint32_t*)(void*)(indices + (a * UnrollSize));
+
+ for (uint32_t i = 0; i < numToProcess; i += 3)
+ {
+ const uint32_t i0 = localIndices[i + 0];
+ const uint32_t i1 = localIndices[i + 1];
+ const uint32_t i2 = localIndices[i + 2];
+
+ const Simd4f P0 = createSimd3f(destPositions[i0]);
+ const Simd4f P1 = createSimd3f(destPositions[i1]);
+ const Simd4f P2 = createSimd3f(destPositions[i2]);
+
+ const Simd4f X1 = P1 - P0;
+ const Simd4f X2 = P2 - P0;
+
+ const VertexUVLocal& w0 = uvLocal[i0];
+ const VertexUVLocal& w1 = uvLocal[i1];
+ const VertexUVLocal& w2 = uvLocal[i2];
+
+ const Simd4f W0U = Simd4fScalarFactory(w0.u);
+ const Simd4f W1U = Simd4fScalarFactory(w1.u);
+ const Simd4f W2U = Simd4fScalarFactory(w2.u);
+ const Simd4f W0V = Simd4fScalarFactory(w0.v);
+ const Simd4f W1V = Simd4fScalarFactory(w1.v);
+ const Simd4f W2V = Simd4fScalarFactory(w2.v);
+
+ //This could be just 1 sub...
+
+ const Simd4f S1 = W1U - W0U;
+ const Simd4f S2 = W2U - W0U;
+ const Simd4f T1 = W1V - W0V;
+ const Simd4f T2 = W2V - W0V;
+
+ // invH = (s1 * t2 - s2 * t1);
+ const Simd4f S1T2 = S1 * T2;
+ const Simd4f invHR = S1T2 - S2 * T1;
+ const Simd4f HR = recip(invHR);
+ const Simd4f T2X1 = X1 * T2;
+ //const Vec3V S1X2 = V3Scale(X2, S1);
+ const Simd4f invHREqZero = (invHR == vZero);
+
+ const Simd4f T1X2MT2X1 = T2X1 - X2 * T1;
+ //const Simd4f S2X1MS1X2 = S1X2 - X1 * X2;
+
+ const Simd4f scale = select(invHREqZero, vZero, HR);
+
+ const Simd4f SDIR = T1X2MT2X1 * scale; // .w gets overwritten later on
+ //const Simd4f TDIR = S2X1MS1X2 * scale;
+
+ PxVec4* PX_RESTRICT tangent0 = tangents + i0;
+ PxVec4* PX_RESTRICT tangent1 = tangents + i1;
+ PxVec4* PX_RESTRICT tangent2 = tangents + i2;
+ Simd4f t0 = Simd4fAlignedLoadFactory((float*)tangent0);
+ Simd4f t1 = Simd4fAlignedLoadFactory((float*)tangent1);
+ Simd4f t2 = Simd4fAlignedLoadFactory((float*)tangent2);
+
+ t0 = t0 + SDIR;
+ t1 = t1 + SDIR;
+ t2 = t2 + SDIR;
+
+ storeAligned((float*)tangent0, t0);
+ storeAligned((float*)tangent1, t1);
+ storeAligned((float*)tangent2, t2);
+ }
+ }
+
+ uint32_t tangentW = 0;
+
+ int32_t j = 0;
+#if 1
+ // This makes it quite a bit faster, but it also works without it.
+ for (; j < (int32_t)numVertices - 4; j += 4)
+ {
+ if ((j & 0x1f) == 0)
+ {
+ tangentW = compressedTangentW[j >> 5];
+ }
+
+ tangents[j].w = (tangentW & 0x1) ? 1.0f : -1.0f;
+ tangents[j + 1].w = (tangentW & 0x2) ? 1.0f : -1.0f;
+ tangents[j + 2].w = (tangentW & 0x4) ? 1.0f : -1.0f;
+ tangents[j + 3].w = (tangentW & 0x8) ? 1.0f : -1.0f;
+ tangentW >>= 4;
+ }
+#endif
+
+ // We need this loop to handle last vertices in tangents[], it shares the same j as previous loop
+ for (; j < (int32_t)numVertices; j++)
+ {
+ if ((j & 0x1f) == 0)
+ {
+ tangentW = compressedTangentW[j >> 5];
+ }
+
+ tangents[j].w = (tangentW & 0x1) ? 1.0f : -1.0f;
+ tangentW >>= 1;
+ }
+ }
+ }
+}
+
+
+PxBounds3 ClothingActorData::getRenderMeshAssetBoundsTransformed()
+{
+ PxBounds3 newBounds = mAsset.GetLod(mCurrentGraphicalLodId)->mBounds;
+
+ PxMat44 transformation;
+ if (mInternalBoneMatricesCur != NULL)
+ {
+ transformation = mInternalBoneMatricesCur[mAsset.mRootBoneIndex];
+ }
+ else
+ {
+ //transformation = mActorDesc->globalPose;
+ transformation = mGlobalPose;
+ }
+
+ if (!newBounds.isEmpty())
+ {
+ PxVec3 center = transformation.transform(newBounds.getCenter());
+ PxVec3 extent = newBounds.getExtents();
+
+ // extended basis vectors
+ PxVec3 c0 = transformation.column0.getXYZ() * extent.x;
+ PxVec3 c1 = transformation.column1.getXYZ() * extent.y;
+ PxVec3 c2 = transformation.column2.getXYZ() * extent.z;
+
+ // find combination of base vectors that produces max. distance for each component = sum of PxAbs()
+ extent.x = PxAbs(c0.x) + PxAbs(c1.x) + PxAbs(c2.x);
+ extent.y = PxAbs(c0.y) + PxAbs(c1.y) + PxAbs(c2.y);
+ extent.z = PxAbs(c0.z) + PxAbs(c1.z) + PxAbs(c2.z);
+
+ return PxBounds3::centerExtents(center, extent);
+ }
+ else
+ {
+ return newBounds;
+ }
+}
+
+
+void ClothingActorData::tickSynchAfterFetchResults_LocksPhysX()
+{
+ if (bIsInitialized && !bIsClothingSimulationNull && bShouldComputeRenderData /*&& !bInternalFrozen*/)
+ {
+ // overwrite a few writeback normals!
+
+ if (bCorrectSimulationNormals)
+ {
+ skinPhysicsMaxDist0Normals_NoPhysx();
+ }
+
+ //// perform mesh-to-mesh skinning if using skin cloth
+
+ if (!bParallelCpuSkinning)
+ {
+ skinToAnimation_NoPhysX(true);
+ }
+
+ skinToPhysicalMesh_NoPhysX(true);
+
+ finalizeSkinning_NoPhysX(true);
+
+ PX_ASSERT(!mNewBounds.isEmpty());
+ PX_ASSERT(mNewBounds.isFinite());
+ }
+}
+
+
+bool ClothingActorData::calcIfSimplePhysicsMesh() const
+{
+ // this number is the blocksize in SPU_ClothSkinPhysicsSimple.spu.cpp
+ return skinPhysicsSimpleMem() < BLOCK_SIZE_SKIN_PHYSICS;
+
+ // with
+ // BLOCK_SIZE_SKIN_PHYSICS (32768*6)
+ // 100 bones
+ // 4 bone indices per vertex
+ // => simple mesh is vertexCount < 3336
+}
+
+
+uint32_t ClothingActorData::skinPhysicsSimpleMem() const
+{
+ PX_ASSERT(bIsInitialized);
+
+ const ClothingPhysicalMeshData* physicalMesh = mAsset.GetPhysicalMeshFromLod(mCurrentGraphicalLodId);
+ PX_ASSERT(physicalMesh != NULL);
+
+ const uint32_t numVertices = physicalMesh->mSimulatedVertexCount;
+ const uint32_t numBoneIndicesPerVertex = physicalMesh->mNumBonesPerVertex;
+
+ uint32_t srcPositionMem = numVertices * sizeof(PxVec3);
+ uint32_t srcNormalMem = numVertices * sizeof(PxVec3);
+
+ uint32_t simBoneIndicesMem = numBoneIndicesPerVertex * numVertices * sizeof(uint16_t);
+ uint32_t simBoneWeightsMem = numBoneIndicesPerVertex * numVertices * sizeof(float);
+
+ uint32_t matricesMem = mInternalMatricesCount * sizeof(PxMat44);
+
+ uint32_t optimizationDataMem = physicalMesh->mOptimizationDataCount * sizeof(uint8_t); // mOptimizationDataCount ~ numVertices
+
+ uint32_t mem = srcPositionMem + srcNormalMem + simBoneIndicesMem + simBoneWeightsMem + matricesMem + optimizationDataMem;
+ // numVertices * (33 + (6*numBonesPerVert)) + 64*numBones
+
+ return mem;
+}
+
+
+void ClothingActorData::skinPhysicsMeshSimple()
+{
+ if (!bIsInitialized)
+ {
+ return;
+ }
+
+ // with bones, no interpolated matrices, no backstop?
+
+ // data
+ const ClothingPhysicalMeshData* physicalMesh = mAsset.GetPhysicalMeshFromLod(mCurrentGraphicalLodId);
+ PX_ASSERT(physicalMesh != NULL);
+
+ const uint32_t numVertices = physicalMesh->mSimulatedVertexCount;
+ const uint32_t numBoneIndicesPerVertex = physicalMesh->mNumBonesPerVertex;
+
+ PxVec3* const PX_RESTRICT eaPositions = physicalMesh->mVertices;
+ PxVec3* const PX_RESTRICT positions = (PxVec3*)eaPositions;
+
+ PxVec3* const PX_RESTRICT eaNormals = physicalMesh->mNormals;
+ PxVec3* const PX_RESTRICT normals = (PxVec3*)eaNormals;
+
+ PxVec3* const PX_RESTRICT targetPositions = mSkinnedPhysicsPositions;
+ PxVec3* const PX_RESTRICT targetNormals = mSkinnedPhysicsNormals;
+
+ uint16_t* const PX_RESTRICT eaSimBoneIndices = physicalMesh->mBoneIndices;
+ const uint16_t* const PX_RESTRICT simBoneIndices = (uint16_t*)eaSimBoneIndices;
+
+ float* const PX_RESTRICT eaSimBoneWeights = physicalMesh->mBoneWeights;
+ const float* const PX_RESTRICT simBoneWeights = (float*)eaSimBoneWeights;
+
+ PxMat44* eaMatrices = mInternalBoneMatricesCur; // TODO interpolated matrices?
+ const PxMat44* matrices = (PxMat44*)eaMatrices;
+
+ uint8_t* const PX_RESTRICT eaOptimizationData = physicalMesh->mOptimizationData;
+ const uint8_t* const PX_RESTRICT optimizationData = (uint8_t*)eaOptimizationData;
+
+ PX_ASSERT(optimizationData != NULL);
+
+ for (uint32_t vertexIndex = 0; vertexIndex < numVertices; ++vertexIndex)
+ {
+ Simd4f positionV = gSimd4fZero;
+ Simd4f normalV = gSimd4fZero;
+
+ const uint8_t shift = 4 * (vertexIndex % 2);
+ const uint8_t numBones = uint8_t((optimizationData[vertexIndex / 2] >> shift) & 0x7);
+ for (uint32_t k = 0; k < numBones; k++)
+ {
+ const float weight = simBoneWeights[vertexIndex * numBoneIndicesPerVertex + k];
+
+ PX_ASSERT(weight <= 1.0f);
+
+ //sumWeights += weight;
+ Simd4f weightV = Simd4fScalarFactory(weight);
+
+ const uint32_t index = simBoneIndices[vertexIndex * numBoneIndicesPerVertex + k];
+ PX_ASSERT(index < mInternalMatricesCount);
+
+ /// PH: This might be faster without the reference, but on PC I can't tell
+ /// HL: Now with SIMD it's significantly faster as reference
+ const PxMat44& bone = (PxMat44&)matrices[index];
+
+ Simd4f pV = applyAffineTransform(bone, createSimd3f(positions[vertexIndex]));
+ pV = pV * weightV;
+ positionV = positionV + pV;
+
+ ///todo There are probably cases where we don't need the normal on the physics mesh
+ Simd4f nV = applyLinearTransform(bone, createSimd3f(normals[vertexIndex]));
+ nV = nV * weightV;
+ normalV = normalV + nV;
+ }
+
+ normalV = normalizeSimd3f(normalV);
+ store3(&targetNormals[vertexIndex].x, normalV);
+ store3(&targetPositions[vertexIndex].x, positionV);
+ }
+}
+
+
+}
+} // namespace nvidia
diff --git a/APEX_1.4/module/clothing/src/ClothingActorImpl.cpp b/APEX_1.4/module/clothing/src/ClothingActorImpl.cpp
new file mode 100644
index 00000000..06956ddd
--- /dev/null
+++ b/APEX_1.4/module/clothing/src/ClothingActorImpl.cpp
@@ -0,0 +1,4852 @@
+/*
+ * 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 "ApexSimdMath.h"
+#include "ApexDefs.h"
+
+#include "PsIntrinsics.h"
+
+#include "ClothingActorImpl.h"
+#include "ClothingActorProxy.h"
+#include "ClothingCooking.h"
+#include "ClothingPhysicalMesh.h"
+#include "ClothingPreviewProxy.h"
+#include "ClothingScene.h"
+#include "CookingPhysX.h"
+#include "ModuleClothing.h"
+#include "ModulePerfScope.h"
+#include "ClothingVelocityCallback.h"
+#include "RenderMeshActorDesc.h"
+#include "SimulationAbstract.h"
+
+#include "ClothingGraphicalLodParameters.h"
+#include "DebugRenderParams.h"
+
+#include "SceneIntl.h"
+#include "ApexSDKIntl.h"
+#include "ApexUsingNamespace.h"
+#include "PsAtomic.h"
+
+#include "ApexMath.h"
+
+#if PX_PHYSICS_VERSION_MAJOR == 3
+#include "PxScene.h"
+//#include "ApexReadWriteLock.h"
+#endif
+
+#include "PsVecMath.h"
+
+#include "PxStrideIterator.h"
+
+#include "Simulation.h"
+
+#include "ApexPvdClient.h"
+
+namespace nvidia
+{
+namespace clothing
+{
+
+ClothingActorImpl::ClothingActorImpl(const NvParameterized::Interface& descriptor, ClothingActorProxy* actorProxy,
+ ClothingPreviewProxy* previewProxy, ClothingAssetImpl* asset, ClothingScene* scene) :
+ mActorProxy(actorProxy),
+ mPreviewProxy(previewProxy),
+ mAsset(asset),
+ mClothingScene(scene),
+#if PX_PHYSICS_VERSION_MAJOR == 3
+ mPhysXScene(NULL),
+#endif
+ mActorDesc(NULL),
+ mBackendName(NULL),
+ mInternalGlobalPose(PxVec4(1.0f)),
+ mOldInternalGlobalPose(PxVec4(0.0f)),
+ mInternalInterpolatedGlobalPose(PxVec4(1.0f)),
+ mInternalInterpolatedBoneMatrices(NULL),
+ mCurrentSolverIterations(0),
+ mInternalScaledGravity(0.0f, 0.0f, 0.0f),
+ mInternalMaxDistanceBlendTime(0.0f),
+ mMaxDistReduction(0.0f),
+ mBufferedGraphicalLod(0),
+ mCurrentGraphicalLodId(0),
+ mRenderProxyReady(NULL),
+ mRenderProxyURR(NULL),
+ mClothingSimulation(NULL),
+ mCurrentMaxDistanceBias(0.0f),
+ bIsSimulationOn(false),
+ mForceSimulation(-1),
+ mLodCentroid(0.0f, 0.0f, 0.0f),
+ mLodRadiusSquared(0.0f),
+ mVelocityCallback(NULL),
+ mInterCollisionChannels(0),
+ mIsAllowedHalfPrecisionSolver(false),
+ mBeforeTickTask(this),
+ mDuringTickTask(this),
+ mFetchResultsTask(this),
+ mActiveCookingTask(NULL),
+ mFetchResultsRunning(false),
+ bGlobalPoseChanged(1),
+ bBoneMatricesChanged(1),
+ bBoneBufferDirty(0),
+ bMaxDistanceScaleChanged(0),
+ bBlendingAllowed(1),
+ bDirtyActorTemplate(0),
+ bDirtyShapeTemplate(0),
+ bDirtyClothingTemplate(0),
+ bBufferedVisible(1),
+ bInternalVisible(1),
+ bUpdateFrozenFlag(0),
+ bBufferedFrozen(0),
+ bInternalFrozen(0),
+ bPressureWarning(0),
+ bUnsucessfullCreation(0),
+ bInternalTeleportDue(ClothingTeleportMode::Continuous),
+ bInternalScaledGravityChanged(1),
+ bReinitActorData(0),
+ bInternalLocalSpaceSim(0),
+ bActorCollisionChanged(0)
+{
+ //mBufferedBoneMatrices = NULL;
+
+ if ((((size_t)this) & 0xf) != 0)
+ {
+ APEX_INTERNAL_ERROR("ClothingActorImpl is not 16 byte aligned");
+ }
+ // make sure the alignment is ok
+ if ((((size_t)&mInternalGlobalPose) & 0xf) != 0)
+ {
+ APEX_INTERNAL_ERROR("Matrix ClothingActorImpl::mInternalGlobalPose is not 16 byte aligned");
+ }
+ if ((((size_t)&mOldInternalGlobalPose) & 0xf) != 0)
+ {
+ APEX_INTERNAL_ERROR("Matrix ClothingActorImpl::mOldInternalGlobalPose is not 16 byte aligned");
+ }
+ if ((((size_t)&mInternalInterpolatedGlobalPose) & 0xf) != 0)
+ {
+ APEX_INTERNAL_ERROR("Matrix ClothingActorImpl::mInternalInterpolatedGlobalPose is not 16 byte aligned");
+ }
+
+ if (::strcmp(descriptor.className(), ClothingActorParam::staticClassName()) == 0)
+ {
+ PX_ASSERT(mActorProxy != NULL);
+
+ mActorDesc = static_cast<ClothingActorParam*>(GetInternalApexSDK()->getParameterizedTraits()->createNvParameterized(ClothingActorParam::staticClassName()));
+ PX_ASSERT(mActorDesc != NULL);
+ mActorDesc->copy(descriptor);
+ PX_ASSERT(mActorDesc->equals(descriptor, NULL, 0));
+
+ const ClothingActorParamNS::ParametersStruct& actorDesc = static_cast<const ClothingActorParamNS::ParametersStruct&>(*mActorDesc);
+
+ // initialize these too
+ mInternalWindParams = mActorDesc->windParams;
+ mInternalMaxDistanceScale = mActorDesc->maxDistanceScale;
+ mInternalFlags = mActorDesc->flags;
+ bInternalLocalSpaceSim = mActorDesc->localSpaceSim ? 1u : 0u;
+
+ mInterCollisionChannels = mAsset->getInterCollisionChannels();
+
+ // Physics is turned off initially
+ mCurrentSolverIterations = 0;
+
+ if (actorDesc.slowStart)
+ {
+ mMaxDistReduction = mAsset->getBiggestMaxDistance();
+ }
+
+
+ mNewBounds.setEmpty();
+
+ // prepare some runtime data for each graphical mesh
+ mGraphicalMeshes.reserve(mAsset->getNumGraphicalMeshes());
+ uint32_t vertexOffset = 0;
+ for (uint32_t i = 0; i < mAsset->getNumGraphicalMeshes(); i++)
+ {
+ ClothingGraphicalMeshActor actor;
+
+ RenderMeshAssetIntl* renderMeshAsset = mAsset->getGraphicalMesh(i);
+ // it can be NULL if ClothingAsset::releaseGraphicalData has beend called to do skinning externally
+ if (renderMeshAsset != NULL)
+ {
+ const uint32_t numSubmeshes = renderMeshAsset->getSubmeshCount();
+
+ for (uint32_t si = 0; si < numSubmeshes; ++si)
+ {
+ actor.morphTargetVertexOffsets.pushBack(vertexOffset);
+ vertexOffset += renderMeshAsset->getSubmesh(si).getVertexCount(0);
+ }
+ }
+ else
+ {
+ actor.morphTargetVertexOffsets.pushBack(0);
+ }
+
+ actor.active = i == 0;
+ mGraphicalMeshes.pushBack(actor);
+ }
+
+ // When we add ourselves to the ApexScene, it will call us back with setPhysXScene
+ addSelfToContext(*mClothingScene->mApexScene->getApexContext());
+
+ // Add ourself to our ClothingScene
+ addSelfToContext(*static_cast<ApexContext*>(mClothingScene));
+
+ // make sure the clothing material gets initialized when
+ // applyClothingMaterial is called the first time
+ mClothingMaterial.solverIterations = uint32_t(-1);
+
+ if (::strcmp(mActorDesc->simulationBackend, "Default") == 0)
+ {
+ mBackendName = "Embedded";
+ }
+ else if (::strcmp(mActorDesc->simulationBackend, "ForceEmbedded") == 0)
+ {
+ mBackendName = "Embedded";
+ }
+ else
+ {
+ mBackendName = "Native";
+ }
+
+ if (mActorDesc->morphDisplacements.arraySizes[0] > 0)
+ {
+ PX_PROFILE_ZONE("ClothingActorImpl::morphTarget", GetInternalApexSDK()->getContextId());
+
+ if (mActorDesc->morphPhysicalMeshNewPositions.buf == NULL)
+ {
+ ParamArray<PxVec3> morphPhysicalNewPos(mActorDesc, "morphPhysicalMeshNewPositions", reinterpret_cast<ParamDynamicArrayStruct*>(&mActorDesc->morphPhysicalMeshNewPositions));
+ mAsset->getDisplacedPhysicalMeshPositions(mActorDesc->morphDisplacements.buf, morphPhysicalNewPos);
+
+ CookingAbstract* cookingJob = mAsset->getModuleClothing()->getBackendFactory(mBackendName)->createCookingJob();
+ PX_ASSERT(cookingJob != NULL);
+
+ if (cookingJob != NULL)
+ {
+ PxVec3 gravity = scene->mApexScene->getGravity();
+ gravity = mActorDesc->globalPose.inverseRT().rotate(gravity);
+ mAsset->prepareCookingJob(*cookingJob, mActorDesc->actorScale, &gravity, morphPhysicalNewPos.begin());
+
+ if (cookingJob->isValid())
+ {
+ if (mAsset->getModuleClothing()->allowAsyncCooking())
+ {
+ mActiveCookingTask = PX_NEW(ClothingCookingTask)(mClothingScene, *cookingJob);
+ mActiveCookingTask->lockObject(mAsset);
+ mClothingScene->submitCookingTask(mActiveCookingTask);
+ }
+ else
+ {
+ mActorDesc->runtimeCooked = cookingJob->execute();
+ PX_DELETE_AND_RESET(cookingJob);
+ }
+ }
+ else
+ {
+ PX_DELETE_AND_RESET(cookingJob);
+ }
+ }
+ }
+
+ if (mActorDesc->morphGraphicalMeshNewPositions.buf == NULL)
+ {
+ ParamArray<PxVec3> morphGraphicalNewPos(mActorDesc, "morphGraphicalMeshNewPositions", reinterpret_cast<ParamDynamicArrayStruct*>(&mActorDesc->morphGraphicalMeshNewPositions));
+
+ uint32_t graphicalVertexCount = 0;
+ for (uint32_t gi = 0; gi < mGraphicalMeshes.size(); ++gi)
+ {
+ RenderMeshAssetIntl* renderMeshAsset = mAsset->getGraphicalMesh(gi);
+
+ const ClothingGraphicalMeshAssetWrapper meshAsset(renderMeshAsset);
+ graphicalVertexCount += meshAsset.getNumTotalVertices();
+ }
+
+ morphGraphicalNewPos.resize(graphicalVertexCount);
+
+ uint32_t vertexOffset = 0;
+ for (uint32_t gi = 0; gi < mGraphicalMeshes.size(); ++gi)
+ {
+ RenderMeshAssetIntl* renderMeshAsset = mAsset->getGraphicalMesh(gi);
+ if (renderMeshAsset == NULL)
+ continue;
+
+ const uint32_t numSubmeshes = renderMeshAsset->getSubmeshCount();
+ for (uint32_t si = 0; si < numSubmeshes; ++si)
+ {
+ const RenderSubmesh& submesh = renderMeshAsset->getSubmesh(si);
+ const VertexFormat& format = submesh.getVertexBuffer().getFormat();
+
+ uint32_t* morphMapping = mAsset->getMorphMapping(gi, si);
+
+ const int32_t positionIndex = format.getBufferIndexFromID(format.getSemanticID(RenderVertexSemantic::POSITION));
+ if (positionIndex != -1)
+ {
+ RenderDataFormat::Enum bufferFormat = RenderDataFormat::UNSPECIFIED;
+ const PxVec3* positions = reinterpret_cast<const PxVec3*>(submesh.getVertexBuffer().getBufferAndFormat(bufferFormat, (uint32_t)positionIndex));
+ PX_ASSERT(bufferFormat == RenderDataFormat::FLOAT3);
+ if (bufferFormat == RenderDataFormat::FLOAT3)
+ {
+ const uint32_t vertexCount = submesh.getVertexCount(0);
+ for (uint32_t i = 0; i < vertexCount; i++)
+ {
+ const PxVec3 disp = morphMapping != NULL ? mActorDesc->morphDisplacements.buf[morphMapping[i]] : PxVec3(0.0f);
+ morphGraphicalNewPos[i + vertexOffset] = positions[i] + disp;
+ }
+ }
+ }
+
+ vertexOffset += submesh.getVertexCount(0);
+ }
+ }
+ }
+ }
+
+ // default render proxy to handle pre simulate case
+ mRenderProxyReady = mClothingScene->getRenderProxy(mAsset->getGraphicalMesh(0), mActorDesc->fallbackSkinning, false, mOverrideMaterials, mActorDesc->morphPhysicalMeshNewPositions.buf, &mGraphicalMeshes[0].morphTargetVertexOffsets[0]);
+
+ if (getRuntimeCookedDataPhysX() != NULL && mActorDesc->actorScale != getRuntimeCookedDataPhysX()->actorScale)
+ {
+ mActorDesc->runtimeCooked->destroy();
+ mActorDesc->runtimeCooked = NULL;
+ }
+
+ // PH: So if backend name is 'embedded', i won't get an asset cooked data ever, so it also won't complain about the cooked version, good
+ // if backend is native, it might, but that's only when you force native with the 2.8.x sdk on a 3.2 asset
+ // const char* cookingDataType = mAsset->getModuleClothing()->getBackendFactory(mBackendName)->getCookingJobType();
+ NvParameterized::Interface* assetCookedData = mAsset->getCookedData(mActorDesc->actorScale);
+ NvParameterized::Interface* actorCookedData = mActorDesc->runtimeCooked;
+
+ BackendFactory* factory = mAsset->getModuleClothing()->getBackendFactory(mBackendName);
+
+ uint32_t assetCookedDataVersion = factory->getCookedDataVersion(assetCookedData);
+ uint32_t actorCookedDataVersion = factory->getCookedDataVersion(actorCookedData);
+
+ if (assetCookedData != NULL && !factory->isMatch(assetCookedData->className()))
+ {
+ APEX_DEBUG_WARNING("Asset (%s) cooked data type (%s) does not match the current backend (%s). Recooking.",
+ mAsset->getName(), assetCookedData->className(), mBackendName);
+ assetCookedData = NULL;
+ }
+ // If the PhysX3 cooking format changes from 3.0 to 3.x, then APEX needs to store something other than the
+ // _SDK_VERSION_NUMBER. Perhaps _PHYSICS_SDK_VERSION (which is something like 0x03010000 or 0x02080400).
+ // Currently, _SDK_VERSION_NUMBER does not change for P3, it is fixed at 300. The PhysX2 path will continue to use
+ // _SDK_VERSION_NUMBER so existing assets cooked with PhysX2 data aren't recooked by default.
+
+ else if (assetCookedData && assetCookedDataVersion != factory->getCookingVersion())
+ {
+ APEX_DEBUG_WARNING("Asset (%s) cooked data version (%d/0x%08x) does not match the current sdk version. Recooking.",
+ mAsset->getName(),
+ assetCookedDataVersion,
+ assetCookedDataVersion);
+ assetCookedData = NULL;
+ }
+
+ if (actorCookedData != NULL && !factory->isMatch(actorCookedData->className()))
+ {
+ APEX_DEBUG_WARNING("Asset (%s) cooked data type (%s) does not match the current backend (%s). Recooking.",
+ mAsset->getName(), assetCookedData->className(), mBackendName);
+ actorCookedData = NULL;
+ }
+
+ if (actorCookedData && actorCookedDataVersion != factory->getCookingVersion())
+ {
+ APEX_DEBUG_WARNING("Actor (%s) cooked data version (%d/0x%08x) does not match the current sdk version. Recooking.",
+ mAsset->getName(),
+ actorCookedDataVersion,
+ actorCookedDataVersion);
+ actorCookedData = NULL;
+ }
+
+ if (assetCookedData == NULL && actorCookedData == NULL && mActiveCookingTask == NULL)
+ {
+ CookingAbstract* cookingJob = mAsset->getModuleClothing()->getBackendFactory(mBackendName)->createCookingJob();
+ PX_ASSERT(cookingJob != NULL);
+
+ if (cookingJob != NULL)
+ {
+ PxVec3 gravity = scene->mApexScene->getGravity();
+ gravity = mActorDesc->globalPose.inverseRT().rotate(gravity);
+ mAsset->prepareCookingJob(*cookingJob, mActorDesc->actorScale, &gravity, NULL);
+
+ if (cookingJob->isValid())
+ {
+ if (mAsset->getModuleClothing()->allowAsyncCooking())
+ {
+ mActiveCookingTask = PX_NEW(ClothingCookingTask)(mClothingScene, *cookingJob);
+ mActiveCookingTask->lockObject(mAsset);
+ mClothingScene->submitCookingTask(mActiveCookingTask);
+ }
+ else
+ {
+ mActorDesc->runtimeCooked = cookingJob->execute();
+ PX_DELETE_AND_RESET(cookingJob);
+ }
+ }
+ else
+ {
+ PX_DELETE_AND_RESET(cookingJob);
+ }
+ }
+
+ }
+
+ mActorProxy->userData = reinterpret_cast<void*>(mActorDesc->userData);
+ }
+ else if (::strcmp(descriptor.className(), ClothingPreviewParam::staticClassName()) == 0)
+ {
+ PX_ASSERT(mPreviewProxy != NULL);
+
+ const ClothingPreviewParam& previewDesc = static_cast<const ClothingPreviewParam&>(descriptor);
+ mActorDesc = static_cast<ClothingActorParam*>(GetInternalApexSDK()->getParameterizedTraits()->createNvParameterized(ClothingActorParam::staticClassName()));
+ PX_ASSERT(mActorDesc != NULL);
+ mActorDesc->globalPose = previewDesc.globalPose;
+ {
+ NvParameterized::Handle handle(mActorDesc);
+ handle.getParameter("boneMatrices");
+ handle.resizeArray(previewDesc.boneMatrices.arraySizes[0]);
+ for (int32_t i = 0; i < previewDesc.boneMatrices.arraySizes[0]; i++)
+ {
+ mActorDesc->boneMatrices.buf[i] = previewDesc.boneMatrices.buf[i];
+ }
+ }
+ mActorDesc->useInternalBoneOrder = previewDesc.useInternalBoneOrder;
+ mActorDesc->updateStateWithGlobalMatrices = previewDesc.updateStateWithGlobalMatrices;
+ mActorDesc->fallbackSkinning = previewDesc.fallbackSkinning;
+
+ //mActorDesc->copy(descriptor);
+ //PX_ASSERT(mActorDesc->equals(descriptor, NULL, 0));
+
+ // prepare some runtime data for each graphical mesh
+ mGraphicalMeshes.reserve(mAsset->getNumGraphicalMeshes());
+ for (uint32_t i = 0; i < mAsset->getNumGraphicalMeshes(); i++)
+ {
+ ClothingGraphicalMeshActor actor;
+ RenderMeshAssetIntl* renderMeshAsset = mAsset->getGraphicalMesh(i);
+ if (renderMeshAsset == NULL)
+ continue;
+
+ actor.active = i == 0;
+ actor.morphTargetVertexOffsets.pushBack(0);
+ mGraphicalMeshes.pushBack(actor);
+ }
+ // default render proxy to handle pre simulate case
+ mRenderProxyReady = PX_NEW(ClothingRenderProxyImpl)(mAsset->getGraphicalMesh(0), mActorDesc->fallbackSkinning, false, mOverrideMaterials, mActorDesc->morphPhysicalMeshNewPositions.buf, &mGraphicalMeshes[0].morphTargetVertexOffsets[0], NULL);
+
+ mPreviewProxy->userData = reinterpret_cast<void*>(mActorDesc->userData);
+ }
+ else
+ {
+ APEX_INVALID_PARAMETER("%s is not a valid descriptor class", descriptor.className());
+
+ PX_ASSERT(mActorProxy == NULL);
+ PX_ASSERT(mPreviewProxy == NULL);
+ }
+
+ if (mActorDesc != NULL)
+ {
+ // initialize overrideMaterialMap with data from actor desc
+ for (uint32_t i = 0; i < (uint32_t)mActorDesc->overrideMaterialNames.arraySizes[0]; ++i)
+ {
+ mOverrideMaterials[i] = mActorDesc->overrideMaterialNames.buf[i];
+ }
+
+ if (mActorDesc->updateStateWithGlobalMatrices)
+ {
+ mAsset->setupInvBindMatrices();
+ }
+
+ uint32_t numMeshesWithTangents = 0;
+ uint32_t maxVertexCount = 0;
+
+ for (uint32_t i = 0; i < mGraphicalMeshes.size(); i++)
+ {
+ RenderMeshAssetIntl* renderMeshAsset = mAsset->getGraphicalMesh(i);
+
+ const ClothingGraphicalMeshAssetWrapper meshAsset(renderMeshAsset);
+
+ if (meshAsset.hasChannel(NULL, RenderVertexSemantic::TANGENT) && meshAsset.hasChannel(NULL, RenderVertexSemantic::BINORMAL))
+ {
+ PX_ALWAYS_ASSERT();
+ // need to compress them into one semantic
+ //APEX_INVALID_PARAMETER("RenderMeshAsset must have either TANGENT and BINORMAL semantics, or none. But not only one!");
+ }
+
+ if (meshAsset.hasChannel(NULL, RenderVertexSemantic::TANGENT) && meshAsset.hasChannel(NULL, RenderVertexSemantic::TEXCOORD0))
+ {
+ numMeshesWithTangents++;
+ mGraphicalMeshes[i].needsTangents = true;
+ }
+ maxVertexCount = PxMax(maxVertexCount, meshAsset.getNumTotalVertices());
+ }
+
+ const uint32_t numBones = mActorDesc->useInternalBoneOrder ? mAsset->getNumUsedBones() : mActorDesc->boneMatrices.arraySizes[0];
+ updateState(mActorDesc->globalPose, mActorDesc->boneMatrices.buf, sizeof(PxMat44), numBones, ClothingTeleportMode::Continuous);
+ updateStateInternal_NoPhysX(false);
+ updateBoneBuffer(mRenderProxyReady);
+ }
+
+ mRenderBounds = getRenderMeshAssetBoundsTransformed();
+ bool bHasBones = mActorDesc->boneMatrices.arraySizes[0] > 0 || mAsset->getNumBones() > 0;
+ if (bHasBones && bInternalLocalSpaceSim == 1)
+ {
+ PX_ASSERT(!mRenderBounds.isEmpty());
+ mRenderBounds = PxBounds3::transformFast(PxTransform(mInternalGlobalPose), mRenderBounds);
+ }
+
+ PX_ASSERT(mRenderBounds.isFinite());
+ PX_ASSERT(!mRenderBounds.isEmpty());
+}
+
+
+
+void ClothingActorImpl::release()
+{
+ if (mInRelease)
+ {
+ return;
+ }
+
+ if (isSimulationRunning())
+ {
+ APEX_INVALID_OPERATION("Cannot release ClothingActorImpl while simulation is still running");
+ return;
+ }
+
+ waitForFetchResults();
+
+ mInRelease = true;
+
+ if (mActorProxy != NULL)
+ {
+ mAsset->releaseClothingActor(*mActorProxy);
+ }
+ else
+ {
+ PX_ASSERT(mPreviewProxy != NULL);
+ mAsset->releaseClothingPreview(*mPreviewProxy);
+ }
+}
+
+
+
+Renderable* ClothingActorImpl::getRenderable()
+{
+ // make sure the result is ready
+ // this is mainly for legacy kind of rendering
+ // with the renderable iterator. note that the
+ // user does not acquire the render proxy here
+ waitForFetchResults();
+
+ return mRenderProxyReady;
+}
+
+
+
+void ClothingActorImpl::dispatchRenderResources(UserRenderer& api)
+{
+ mRenderProxyMutex.lock();
+ if (mRenderProxyURR != NULL)
+ {
+ mRenderProxyURR->dispatchRenderResources(api);
+ }
+ mRenderProxyMutex.unlock();
+}
+
+
+
+void ClothingActorImpl::updateRenderResources(bool rewriteBuffers, void* userRenderData)
+{
+ waitForFetchResults();
+
+ ClothingRenderProxyImpl* newRenderProxy = static_cast<ClothingRenderProxyImpl*>(acquireRenderProxy());
+ if (newRenderProxy != NULL)
+ {
+ if (mRenderProxyURR != NULL)
+ {
+ mRenderProxyURR->release();
+ mRenderProxyURR = NULL;
+ }
+ mRenderProxyURR = newRenderProxy;
+ }
+ if (mRenderProxyURR != NULL)
+ {
+ mRenderProxyURR->updateRenderResources(rewriteBuffers, userRenderData);
+ }
+}
+
+
+
+NvParameterized::Interface* ClothingActorImpl::getActorDesc()
+{
+ if (mActorDesc != NULL && isValidDesc(*mActorDesc))
+ {
+ return mActorDesc;
+ }
+
+ return NULL;
+}
+
+
+
+void ClothingActorImpl::updateState(const PxMat44& globalPose, const PxMat44* newBoneMatrices, uint32_t boneMatricesByteStride, uint32_t numBoneMatrices, ClothingTeleportMode::Enum teleportMode)
+{
+ PX_PROFILE_ZONE("ClothingActorImpl::updateState", GetInternalApexSDK()->getContextId());
+
+ PX_ASSERT(mActorDesc);
+ const bool useInternalBoneOrder = mActorDesc->useInternalBoneOrder;
+
+ uint32_t numElements = useInternalBoneOrder ? mAsset->getNumUsedBones() : mAsset->getNumBones();
+ if (useInternalBoneOrder && (numBoneMatrices > numElements))
+ {
+ APEX_DEBUG_WARNING("numMatrices too big.");
+ return;
+ }
+
+ mActorDesc->globalPose = globalPose;
+ if (!PxEquals(globalPose.column0.magnitude(), mActorDesc->actorScale, 1e-5))
+ {
+ APEX_DEBUG_WARNING("Actor Scale wasn't set properly, it doesn't equal to the Global Pose scale: %f != %f",
+ mActorDesc->actorScale,
+ globalPose.column0.magnitude());
+ }
+
+ PX_ASSERT(newBoneMatrices == NULL || boneMatricesByteStride >= sizeof(PxMat44));
+ if (boneMatricesByteStride >= sizeof(PxMat44) && newBoneMatrices != NULL)
+ {
+ if (mActorDesc->boneMatrices.arraySizes[0] != (int32_t)numBoneMatrices)
+ {
+ // PH: aligned alloc?
+ NvParameterized::Handle handle(mActorDesc);
+ handle.getParameter("boneMatrices");
+ handle.resizeArray((int32_t)numBoneMatrices);
+ }
+
+ for (uint32_t i = 0; i < numBoneMatrices; i++)
+ {
+ const PxMat44* source = (const PxMat44*)(((const uint8_t*)newBoneMatrices) + boneMatricesByteStride * i);
+ mActorDesc->boneMatrices.buf[i] = *source;
+ }
+ }
+ else
+ {
+ NvParameterized::Handle handle(mActorDesc);
+ handle.getParameter("boneMatrices");
+ handle.resizeArray(0);
+ }
+
+ mActorDesc->teleportMode = teleportMode;
+
+ if (mClothingScene == NULL)
+ {
+ // In Preview mode!
+ updateStateInternal_NoPhysX(false);
+ updateBoneBuffer(mRenderProxyReady);
+ }
+}
+
+
+
+void ClothingActorImpl::updateMaxDistanceScale(float scale, bool multipliable)
+{
+ PX_ASSERT(mActorDesc != NULL);
+ mActorDesc->maxDistanceScale.Scale = PxClamp(scale, 0.0f, 1.0f);
+ mActorDesc->maxDistanceScale.Multipliable = multipliable;
+}
+
+
+
+const PxMat44& ClothingActorImpl::getGlobalPose() const
+{
+ PX_ASSERT(mActorDesc != NULL);
+ return mActorDesc->globalPose;
+}
+
+
+
+void ClothingActorImpl::setWind(float windAdaption, const PxVec3& windVelocity)
+{
+ if (windAdaption < 0.0f)
+ {
+ APEX_INVALID_PARAMETER("windAdaption must be bigger or equal than 0.0 (is %f)", windAdaption);
+ windAdaption = 0.0f;
+ }
+
+ PX_ASSERT(mActorDesc);
+ mActorDesc->windParams.Adaption = windAdaption;
+ mActorDesc->windParams.Velocity = windVelocity;
+}
+
+
+
+void ClothingActorImpl::setMaxDistanceBlendTime(float blendTime)
+{
+ PX_ASSERT(mActorDesc);
+ mActorDesc->maxDistanceBlendTime = blendTime;
+}
+
+
+
+
+float ClothingActorImpl::getMaxDistanceBlendTime() const
+{
+ PX_ASSERT(mActorDesc);
+ return mActorDesc->maxDistanceBlendTime;
+}
+
+
+
+void ClothingActorImpl::setVisible(bool enable)
+{
+ // buffer enable
+ bBufferedVisible = enable ? 1u : 0u;
+
+ // disable immediately
+ if (!enable)
+ {
+ bInternalVisible = 0;
+ }
+}
+
+
+
+bool ClothingActorImpl::isVisibleBuffered() const
+{
+ return bBufferedVisible == 1;
+}
+
+
+
+bool ClothingActorImpl::isVisible() const
+{
+ return bInternalVisible == 1;
+}
+
+
+
+bool ClothingActorImpl::shouldComputeRenderData() const
+{
+ return mInternalFlags.ComputeRenderData && bInternalVisible == 1 && mGraphicalMeshes[mCurrentGraphicalLodId].renderProxy != NULL;
+}
+
+
+
+void ClothingActorImpl::setFrozen(bool enable)
+{
+ bUpdateFrozenFlag = 1;
+ bBufferedFrozen = enable ? 1u : 0u;
+}
+
+
+
+bool ClothingActorImpl::isFrozenBuffered() const
+{
+ return bBufferedFrozen == 1;
+}
+
+
+
+ClothSolverMode::Enum ClothingActorImpl::getClothSolverMode() const
+{
+ return ClothSolverMode::v3;
+}
+
+
+
+void ClothingActorImpl::freeze_LocksPhysX(bool on)
+{
+ if (mClothingSimulation != NULL)
+ {
+ mClothingSimulation->setStatic(on);
+ }
+}
+
+
+
+void ClothingActorImpl::setGraphicalLOD(uint32_t lod)
+{
+ mBufferedGraphicalLod = PxMin(lod, mAsset->getNumGraphicalLodLevels()-1);
+}
+
+
+
+uint32_t ClothingActorImpl::getGraphicalLod()
+{
+ return mBufferedGraphicalLod;
+}
+
+
+
+bool ClothingActorImpl::rayCast(const PxVec3& worldOrigin, const PxVec3& worldDirection, float& time, PxVec3& normal, uint32_t& vertexIndex)
+{
+ if (mClothingSimulation != NULL)
+ {
+ PxVec3 origin(worldOrigin);
+ PxVec3 dir(worldDirection);
+ if (bInternalLocalSpaceSim == 1)
+ {
+#if _DEBUG
+ bool ok = true;
+ ok &= mInternalGlobalPose.column0.isNormalized();
+ ok &= mInternalGlobalPose.column1.isNormalized();
+ ok &= mInternalGlobalPose.column2.isNormalized();
+ if (!ok)
+ {
+ APEX_DEBUG_WARNING("Internal Global Pose is not normalized (Scale: %f %f %f). Raycast could be wrong.", mInternalGlobalPose.column0.magnitude(), mInternalGlobalPose.column1.magnitude(), mInternalGlobalPose.column2.magnitude());
+ }
+#endif
+ PxMat44 invGlobalPose = mInternalGlobalPose.inverseRT();
+ origin = invGlobalPose.transform(worldOrigin);
+ dir = invGlobalPose.rotate(worldDirection);
+ }
+
+ bool hit = mClothingSimulation->raycast(origin, dir, time, normal, vertexIndex);
+
+ if (hit && bInternalLocalSpaceSim == 1)
+ {
+ mInternalGlobalPose.rotate(normal);
+ }
+ return hit;
+
+ }
+
+ return false;
+}
+
+
+
+void ClothingActorImpl::attachVertexToGlobalPosition(uint32_t vertexIndex, const PxVec3& worldPosition)
+{
+ if (mClothingSimulation != NULL)
+ {
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type* physicalMesh = mAsset->getPhysicalMeshFromLod(mCurrentGraphicalLodId);
+ const ClothingPhysicalMeshParametersNS::ConstrainCoefficient_Type* const PX_RESTRICT coeffs = physicalMesh->constrainCoefficients.buf;
+ PX_ASSERT((int32_t)vertexIndex < physicalMesh->constrainCoefficients.arraySizes[0]);
+
+ const float linearScale = (mInternalMaxDistanceScale.Multipliable ? mInternalMaxDistanceScale.Scale : 1.0f) * mActorDesc->actorScale;
+ const float absoluteScale = mInternalMaxDistanceScale.Multipliable ? 0.0f : (physicalMesh->maximumMaxDistance * (1.0f - mInternalMaxDistanceScale.Scale));
+ const float reduceMaxDistance = mMaxDistReduction + absoluteScale;
+
+ const float maxDistance = PxMax(0.0f, coeffs[vertexIndex].maxDistance - reduceMaxDistance) * linearScale;
+ const PxVec3 skinnedPosition = mClothingSimulation->skinnedPhysicsPositions[vertexIndex];
+
+ PxVec3 restrictedWorldPosition = worldPosition;
+ if (bInternalLocalSpaceSim == 1)
+ {
+#if _DEBUG
+ bool ok = true;
+ ok &= mInternalGlobalPose.column0.isNormalized();
+ ok &= mInternalGlobalPose.column1.isNormalized();
+ ok &= mInternalGlobalPose.column2.isNormalized();
+ if (!ok)
+ {
+ APEX_DEBUG_WARNING("Internal Global Pose is not normalized (Scale: %f %f %f). attachVertexToGlobalPosition could be wrong.", mInternalGlobalPose.column0.magnitude(), mInternalGlobalPose.column1.magnitude(), mInternalGlobalPose.column2.magnitude());
+ }
+#endif
+ restrictedWorldPosition = mInternalGlobalPose.inverseRT().transform(restrictedWorldPosition);
+ }
+
+ PxVec3 dir = restrictedWorldPosition - skinnedPosition;
+ if (dir.magnitude() > maxDistance)
+ {
+ dir.normalize();
+ restrictedWorldPosition = skinnedPosition + dir * maxDistance;
+ }
+
+ mClothingSimulation->attachVertexToGlobalPosition(vertexIndex, restrictedWorldPosition);
+ }
+}
+
+
+
+void ClothingActorImpl::freeVertex(uint32_t vertexIndex)
+{
+ if (mClothingSimulation != NULL)
+ {
+ mClothingSimulation->freeVertex(vertexIndex);
+ }
+}
+
+
+
+uint32_t ClothingActorImpl::getClothingMaterial() const
+{
+ const ClothingAssetParameters* clothingAsset = static_cast<const ClothingAssetParameters*>(mAsset->getAssetNvParameterized());
+ ClothingMaterialLibraryParameters* materialLib = static_cast<ClothingMaterialLibraryParameters*>(clothingAsset->materialLibrary);
+
+ PX_ASSERT(materialLib != NULL);
+ if (materialLib == NULL)
+ {
+ return 0;
+ }
+
+ PX_ASSERT(materialLib->materials.buf != NULL);
+ PX_ASSERT(materialLib->materials.arraySizes[0] > 0);
+
+ PX_ASSERT(mActorDesc->clothingMaterialIndex < (uint32_t)materialLib->materials.arraySizes[0]);
+
+ return mActorDesc->clothingMaterialIndex;
+}
+
+
+
+void ClothingActorImpl::setClothingMaterial(uint32_t index)
+{
+ mActorDesc->clothingMaterialIndex = index;
+}
+
+
+
+void ClothingActorImpl::setOverrideMaterial(uint32_t submeshIndex, const char* overrideMaterialName)
+{
+ mOverrideMaterials[submeshIndex] = ApexSimpleString(overrideMaterialName);
+
+ for (uint32_t i = 0; i < mGraphicalMeshes.size(); ++i)
+ {
+ ClothingRenderProxyImpl* renderProxy = mGraphicalMeshes[i].renderProxy;
+ if (renderProxy != NULL)
+ {
+ renderProxy->setOverrideMaterial(i, overrideMaterialName);
+ }
+ }
+}
+
+
+
+void ClothingActorImpl::getLodRange(float& min, float& max, bool& intOnly) const
+{
+ min = 0.f;
+ max = 1.f;
+ intOnly = true;
+}
+
+
+
+float ClothingActorImpl::getActiveLod() const
+{
+ return bIsSimulationOn ? 0.f : 1.f;
+}
+
+
+
+void ClothingActorImpl::forceLod(float lod)
+{
+ if (lod < 0.0f)
+ {
+ mForceSimulation = -1;
+ }
+ else if (lod >= 1.f)
+ {
+ mForceSimulation = 1;
+ }
+ else
+ {
+ mForceSimulation = (int32_t)(lod + 0.5f);
+ }
+
+ if (mClothingSimulation == NULL && mForceSimulation > 0)
+ {
+ mMaxDistReduction = mAsset->getBiggestMaxDistance();
+ }
+}
+
+
+
+void ClothingActorImpl::getPhysicalMeshPositions(void* buffer, uint32_t byteStride)
+{
+ if (isSimulationRunning())
+ {
+ APEX_INTERNAL_ERROR("Cannot be called while the scene is running");
+ return;
+ }
+
+ PX_ASSERT(buffer != NULL);
+ if (byteStride == 0)
+ {
+ byteStride = sizeof(PxVec3);
+ }
+
+ if (byteStride < sizeof(PxVec3))
+ {
+ APEX_INTERNAL_ERROR("Bytestride is too small (%d, but must be >= %d)", byteStride, sizeof(PxVec3));
+ return;
+ }
+
+ uint32_t numSimulatedVertices = (mClothingSimulation == NULL) ? 0 : mClothingSimulation->sdkNumDeformableVertices;
+ PxStrideIterator<PxVec3> it((PxVec3*)buffer, byteStride);
+ for (uint32_t i = 0; i < numSimulatedVertices; i++, ++it)
+ {
+ *it = mClothingSimulation->sdkWritebackPosition[i];
+ }
+
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type* pmesh = mAsset->getPhysicalMeshFromLod(mCurrentGraphicalLodId);
+ const PxVec3* skinPosePosition = pmesh->vertices.buf;
+ const PxMat44* matrices = mData.mInternalBoneMatricesCur;
+
+ const uint8_t* const PX_RESTRICT optimizationData = pmesh->optimizationData.buf;
+ PX_ASSERT(optimizationData != NULL);
+
+ if (matrices != NULL)
+ {
+ const uint16_t* boneIndices = pmesh->boneIndices.buf;
+ const float* boneWeights = pmesh->boneWeights.buf;
+ const uint32_t numBonesPerVertex = pmesh->numBonesPerVertex;
+ const uint32_t numVertices = pmesh->numVertices;
+ for (uint32_t vertexIndex = numSimulatedVertices; vertexIndex < numVertices; ++vertexIndex, ++it)
+ {
+ const uint8_t shift = 4 * (vertexIndex % 2);
+ const uint8_t numBones = uint8_t((optimizationData[vertexIndex / 2] >> shift) & 0x7);
+
+ Simd4f temp = gSimd4fZero;
+ for (uint32_t j = 0; j < numBones; j++)
+ {
+ const Simd4f boneWeightV = Simd4fScalarFactory(boneWeights[vertexIndex * numBonesPerVertex + j]);
+ const uint32_t boneIndex = boneIndices[vertexIndex * numBonesPerVertex + j];
+ const PxMat44& mat = (PxMat44&)(matrices[boneIndex]);
+
+ Simd4f transformedPosV = applyAffineTransform(mat, createSimd3f(skinPosePosition[vertexIndex]));
+ transformedPosV = transformedPosV * boneWeightV;
+ temp = temp + transformedPosV;
+ }
+ store3(&(*it).x, temp);
+ }
+ }
+ else
+ {
+ const uint32_t numVertices = pmesh->numVertices;
+ const PxMat44& mat = (PxMat44&)(mInternalGlobalPose);
+ for (uint32_t vertexIndex = numSimulatedVertices; vertexIndex < numVertices; ++vertexIndex, ++it)
+ {
+ Simd4f transformedPosV = applyAffineTransform(mat, createSimd3f(skinPosePosition[vertexIndex]));
+ store3(&(*it).x, transformedPosV);
+ }
+ }
+}
+
+
+
+void ClothingActorImpl::getPhysicalMeshNormals(void* buffer, uint32_t byteStride)
+{
+ if (isSimulationRunning())
+ {
+ APEX_INTERNAL_ERROR("Cannot be called while the scene is running");
+ return;
+ }
+
+ PX_ASSERT(buffer != NULL);
+ if (byteStride == 0)
+ {
+ byteStride = sizeof(PxVec3);
+ }
+
+ if (byteStride < sizeof(PxVec3))
+ {
+ APEX_INTERNAL_ERROR("Bytestride is too small (%d, but must be >= %d)", byteStride, sizeof(PxVec3));
+ return;
+ }
+
+ if (mClothingSimulation == NULL)
+ {
+ APEX_INTERNAL_ERROR("No simulation data available");
+ return;
+ }
+
+ if (mClothingSimulation->sdkWritebackNormal == NULL)
+ {
+ APEX_INTERNAL_ERROR("No simulation normals for softbodies");
+ return;
+ }
+
+ PxStrideIterator<PxVec3> it((PxVec3*)buffer, byteStride);
+ for (uint32_t i = 0; i < mClothingSimulation->sdkNumDeformableVertices; i++, ++it)
+ {
+ *it = mClothingSimulation->sdkWritebackNormal[i];
+ }
+
+
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type* pmesh = mAsset->getPhysicalMeshFromLod(mCurrentGraphicalLodId);
+ const PxVec3* skinPoseNormal = pmesh->normals.buf;
+ const PxMat44* matrices = mData.mInternalBoneMatricesCur;
+ const uint32_t numVertices = pmesh->numVertices;
+
+ const uint8_t* const PX_RESTRICT optimizationData = pmesh->optimizationData.buf;
+ PX_ASSERT(optimizationData != NULL);
+
+ if (matrices != NULL)
+ {
+ const uint16_t* boneIndices = pmesh->boneIndices.buf;
+ const float* boneWeights = pmesh->boneWeights.buf;
+ const uint32_t numBonesPerVertex = pmesh->numBonesPerVertex;
+ for (uint32_t vertexIndex = mClothingSimulation->sdkNumDeformableVertices; vertexIndex < numVertices; ++vertexIndex, ++it)
+ {
+ const uint8_t shift = 4 * (vertexIndex % 2);
+ const uint8_t numBones = uint8_t((optimizationData[vertexIndex / 2] >> shift) & 0x7);
+
+ Simd4f temp = gSimd4fZero;
+ for (uint32_t j = 0; j < numBones; j++)
+ {
+ const Simd4f boneWeightV = Simd4fScalarFactory(boneWeights[vertexIndex * numBonesPerVertex + j]);
+ const uint32_t boneIndex = boneIndices[vertexIndex * numBonesPerVertex + j];
+ const PxMat44& mat = (PxMat44&)(matrices[boneIndex]);
+
+ Simd4f transformedNormalV = applyAffineTransform(mat, createSimd3f(skinPoseNormal[vertexIndex]));
+ transformedNormalV = transformedNormalV * boneWeightV;
+ temp = temp + transformedNormalV;
+ }
+ store3(&(*it).x, temp);
+ }
+ }
+ else
+ {
+ const PxMat44& mat = (PxMat44&)(mInternalGlobalPose);
+ for (uint32_t vertexIndex = mClothingSimulation->sdkNumDeformableVertices; vertexIndex < numVertices; ++vertexIndex, ++it)
+ {
+ Simd4f transformedNormalV = applyLinearTransform(mat, createSimd3f(skinPoseNormal[vertexIndex]));
+ store3(&(*it).x, transformedNormalV);
+ }
+ }
+}
+
+
+
+float ClothingActorImpl::getMaximumSimulationBudget() const
+{
+ uint32_t solverIterations = 5;
+
+ ClothingMaterialLibraryParametersNS::ClothingMaterial_Type* clothingMaterial = getCurrentClothingMaterial();
+ if (clothingMaterial != NULL)
+ {
+ solverIterations = clothingMaterial->solverIterations;
+ }
+
+ return mAsset->getMaximumSimulationBudget(solverIterations);
+}
+
+
+
+uint32_t ClothingActorImpl::getNumSimulationVertices() const
+{
+ uint32_t numVerts = 0;
+ if (mClothingSimulation != NULL)
+ {
+ numVerts = mClothingSimulation->sdkNumDeformableVertices;
+ }
+ return numVerts;
+}
+
+
+
+const PxVec3* ClothingActorImpl::getSimulationPositions()
+{
+ if (mClothingSimulation == NULL)
+ return NULL;
+
+ waitForFetchResults();
+
+ return mClothingSimulation->sdkWritebackPosition;
+}
+
+
+
+const PxVec3* ClothingActorImpl::getSimulationNormals()
+{
+ if (mClothingSimulation == NULL)
+ return NULL;
+
+ waitForFetchResults();
+
+ return mClothingSimulation->sdkWritebackNormal;
+}
+
+
+
+bool ClothingActorImpl::getSimulationVelocities(PxVec3* velocities)
+{
+ if (mClothingSimulation == NULL)
+ return false;
+
+ waitForFetchResults();
+
+ mClothingSimulation->getVelocities(velocities);
+ return true;
+}
+
+
+
+uint32_t ClothingActorImpl::getNumGraphicalVerticesActive(uint32_t submeshIndex) const
+{
+ if (mClothingSimulation == NULL)
+ return 0;
+
+ uint32_t numVertices = 0;
+
+ const ClothingGraphicalLodParameters* graphicalLod = mAsset->getGraphicalLod(mCurrentGraphicalLodId);
+
+ const uint32_t numParts = (uint32_t)graphicalLod->physicsMeshPartitioning.arraySizes[0];
+ ClothingGraphicalLodParametersNS::PhysicsMeshPartitioning_Type* parts = graphicalLod->physicsMeshPartitioning.buf;
+
+#if PX_DEBUG || PX_CHECKED
+ bool found = false;
+#endif
+ for (uint32_t c = 0; c < numParts; c++)
+ {
+ if (parts[c].graphicalSubmesh == submeshIndex)
+ {
+ numVertices = parts[c].numSimulatedVertices;
+#if defined _DEBUG || PX_CHECKED
+ found = true;
+#endif
+ break;
+ }
+ }
+#if PX_DEBUG || PX_CHECKED
+ PX_ASSERT(found);
+#endif
+
+ return numVertices;
+}
+
+
+
+PxMat44 ClothingActorImpl::getRenderGlobalPose() const
+{
+ return (bInternalLocalSpaceSim == 1) ? mInternalGlobalPose : PxMat44(PxIdentity);
+}
+
+
+
+const PxMat44* ClothingActorImpl::getCurrentBoneSkinningMatrices() const
+{
+ return mData.mInternalBoneMatricesCur;
+}
+
+
+#if PX_PHYSICS_VERSION_MAJOR == 3
+void ClothingActorImpl::setPhysXScene(PxScene* physXscene)
+{
+ if (isSimulationRunning())
+ {
+ APEX_INTERNAL_ERROR("Cannot change the physics scene while the simulation is running");
+ return;
+ }
+
+ if (mPhysXScene != NULL && mPhysXScene != physXscene)
+ {
+ removePhysX_LocksPhysX();
+ }
+
+ mPhysXScene = physXscene;
+
+ if (mPhysXScene != NULL)
+ {
+ if (isCookedDataReady())
+ {
+ createPhysX_LocksPhysX(0.0f);
+ }
+ }
+}
+
+PxScene* ClothingActorImpl::getPhysXScene() const
+{
+ return mPhysXScene;
+}
+#endif
+
+
+// this is 2.8.x only
+void ClothingActorImpl::updateScaledGravity(float substepSize)
+{
+ if (mClothingScene != NULL && mClothingScene->mApexScene != NULL)
+ {
+ PxVec3 oldInternalScaledGravity = mInternalScaledGravity;
+ mInternalScaledGravity = mClothingScene->mApexScene->getGravity();
+
+ if (mActorDesc->allowAdaptiveTargetFrequency)
+ {
+ // disable adaptive frequency if the simulation doesn't require it
+ if (mClothingSimulation && !mClothingSimulation->needsAdaptiveTargetFrequency())
+ {
+ substepSize = 0.0f;
+ }
+
+ const float targetFrequency = mClothingScene->getAverageSimulationFrequency(); // will return 0 if the module is not set to compute it!
+ if (targetFrequency > 0.0f && substepSize > 0.0f)
+ {
+ // PH: This will scale the gravity to result in fixed velocity deltas (in Cloth/SoftBody)
+ const float targetScale = 1.0f / (targetFrequency * substepSize);
+ mInternalScaledGravity *= targetScale * targetScale; // need to square this to achieve constant behavior.
+ }
+ }
+
+ bInternalScaledGravityChanged = (oldInternalScaledGravity != mInternalScaledGravity) ? 1u : 0u;
+ }
+}
+
+
+
+void ClothingActorImpl::tickSynchBeforeSimulate_LocksPhysX(float simulationDelta, float substepSize, uint32_t substepNumber, uint32_t numSubSteps)
+{
+ PX_PROFILE_ZONE("ClothingActorImpl::beforeSimulate", GetInternalApexSDK()->getContextId());
+
+ // PH: simulationDelta can be 0 for subsequent substeps (substepNumber > 0 and numSubSteps > 1
+
+ if (mClothingSimulation != NULL && simulationDelta > 0.0f)
+ {
+ mClothingSimulation->verifyTimeStep(substepSize);
+ }
+
+ if (substepNumber == 0)
+ {
+ PX_PROFILE_ZONE("ClothingActorImpl::updateStateInternal", GetInternalApexSDK()->getContextId());
+
+ updateStateInternal_NoPhysX(numSubSteps > 1);
+ updateScaledGravity(substepSize); // moved after updateStateInternal, cause it reads the localSpace state
+ freeze_LocksPhysX(bInternalFrozen == 1);
+ }
+
+ /// interpolate matrices
+ if (numSubSteps > 1)
+ {
+ PX_PROFILE_ZONE("ClothingActorImpl::interpolateMatrices", GetInternalApexSDK()->getContextId());
+
+ const uint32_t numBones = mActorDesc->useInternalBoneOrder ? mAsset->getNumUsedBones() : mAsset->getNumBones();
+ PX_ASSERT((numBones != 0) == (mInternalInterpolatedBoneMatrices != NULL));
+ PX_ASSERT((numBones != 0) == (mData.mInternalBoneMatricesPrev != NULL));
+ if (substepNumber == (numSubSteps - 1))
+ {
+ bool matrixChanged = false;
+ for (uint32_t i = 0; i < numBones; i++)
+ {
+ mInternalInterpolatedBoneMatrices[i] = mData.mInternalBoneMatricesCur[i];
+ matrixChanged |= mData.mInternalBoneMatricesCur[i] != mData.mInternalBoneMatricesPrev[i];
+ }
+
+ mInternalInterpolatedGlobalPose = mInternalGlobalPose;
+ bGlobalPoseChanged |= mOldInternalGlobalPose != mInternalGlobalPose ? 1 : 0;
+ bBoneMatricesChanged |= matrixChanged ? 1 : 0;
+ }
+ else
+ {
+ const float ratio = bInternalTeleportDue == ClothingTeleportMode::TeleportAndReset ? 0.0f : (1.0f - float(substepNumber + 1) / float(numSubSteps));
+
+ bool matrixChanged = false;
+ for (uint32_t i = 0; i < numBones; i++)
+ {
+ mInternalInterpolatedBoneMatrices[i] = interpolateMatrix(ratio, mData.mInternalBoneMatricesPrev[i], mData.mInternalBoneMatricesCur[i]);
+ matrixChanged |= mData.mInternalBoneMatricesCur[i] != mData.mInternalBoneMatricesPrev[i];
+ }
+ mInternalInterpolatedGlobalPose = interpolateMatrix(ratio, mOldInternalGlobalPose, mInternalGlobalPose);
+ bGlobalPoseChanged |= mOldInternalGlobalPose != mInternalGlobalPose ? 1 : 0;
+ bBoneMatricesChanged |= matrixChanged ? 1 : 0;
+ }
+ }
+
+ if (mClothingSimulation != NULL)
+ {
+ mClothingSimulation->setGlobalPose(substepNumber == 0 ? mInternalGlobalPose : mInternalInterpolatedGlobalPose);
+ }
+
+ // PH: this is done before createPhysX mesh is called to make sure it's not executed on the freshly generated skeleton
+ // see ClothignAsset::createCollisionBulk for more info
+ {
+ PX_PROFILE_ZONE("ClothingActorImpl::updateCollision", GetInternalApexSDK()->getContextId());
+ updateCollision_LocksPhysX(numSubSteps > 1);
+ }
+
+ // PH: Done before skinPhysicsMesh to use the same buffers
+ if (mClothingSimulation != NULL && substepNumber == 0 && (bInternalFrozen == 0))
+ {
+ PX_PROFILE_ZONE("ClothingActorImpl::applyVelocityChanges", GetInternalApexSDK()->getContextId());
+ applyVelocityChanges_LocksPhysX(simulationDelta);
+ }
+
+ if (substepNumber == 0)
+ {
+ lodTick_LocksPhysX(simulationDelta);
+ }
+
+ if (mCurrentSolverIterations > 0)
+ {
+ PX_ASSERT(mClothingSimulation != NULL); // after lodTick there should be a simulation mesh
+
+ applyTeleport(false, substepNumber);
+
+ if (bDirtyClothingTemplate == 1)
+ {
+ bDirtyClothingTemplate = 0;
+ mClothingSimulation->applyClothingDesc(mActorDesc->clothDescTemplate);
+ }
+ }
+
+ initializeActorData();
+ if (mClothingSimulation != NULL)
+ {
+ skinPhysicsMesh(numSubSteps > 1, (float)(substepNumber + 1) / (float)numSubSteps);
+
+ applyLockingTasks();
+
+ mClothingSimulation->setInterCollisionChannels(mInterCollisionChannels);
+
+ mClothingSimulation->setHalfPrecisionOption(mIsAllowedHalfPrecisionSolver);
+ }
+}
+
+
+
+void ClothingActorImpl::applyLockingTasks()
+{
+ if (mClothingSimulation != NULL)
+ {
+ // depends on nothing
+ applyClothingMaterial_LocksPhysX();
+
+ // depends on skinning
+ applyTeleport(true, 0);
+
+ // depends on applyTeleport
+ applyGlobalPose_LocksPhysX();
+
+ // depends on skinning and applyTeleport
+ updateConstrainPositions_LocksPhysX();
+
+ // depends on lod tick (and maybe applyTeleport eventually)
+ applyCollision_LocksPhysX();
+ }
+}
+
+
+
+bool ClothingActorImpl::isSkinningDirty()
+{
+ return bBoneMatricesChanged == 1 || ((!bInternalLocalSpaceSim) == 1 && bGlobalPoseChanged == 1);
+}
+
+
+
+void ClothingActorImpl::skinPhysicsMesh(bool useInterpolatedMatrices, float substepFraction)
+{
+ if (mClothingSimulation == NULL || mClothingSimulation->skinnedPhysicsPositions == NULL)
+ {
+ return;
+ }
+
+ const bool skinningDirty = isSkinningDirty();
+ if (skinningDirty)
+ {
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type* physicalMesh = mAsset->getPhysicalMeshFromLod(mCurrentGraphicalLodId);
+
+ if (physicalMesh->hasNegativeBackstop)
+ {
+ skinPhysicsMeshInternal<true>(useInterpolatedMatrices, substepFraction);
+ }
+ else
+ {
+ skinPhysicsMeshInternal<false>(useInterpolatedMatrices, substepFraction);
+ }
+ }
+}
+
+
+
+void ClothingActorImpl::updateConstrainPositions_LocksPhysX()
+{
+ PX_PROFILE_ZONE("ClothingActorImpl::updateConstrainPositions", GetInternalApexSDK()->getContextId());
+
+ if (mClothingSimulation == NULL || mClothingSimulation->skinnedPhysicsPositions == NULL)
+ {
+ return;
+ }
+
+ const bool skinningDirty = isSkinningDirty();
+ mClothingSimulation->updateConstrainPositions(skinningDirty);
+
+ bBoneMatricesChanged = 0;
+ bGlobalPoseChanged = 0;
+}
+
+
+
+void ClothingActorImpl::applyCollision_LocksPhysX()
+{
+ PX_PROFILE_ZONE("ClothingActorImpl::applyCollision", GetInternalApexSDK()->getContextId());
+
+ if (mClothingSimulation != NULL)
+ {
+ mClothingSimulation->applyCollision();
+ }
+}
+
+
+
+ClothingMaterialLibraryParametersNS::ClothingMaterial_Type* ClothingActorImpl::getCurrentClothingMaterial() const
+{
+ const ClothingAssetParameters* clothingAsset = static_cast<const ClothingAssetParameters*>(mAsset->getAssetNvParameterized());
+ const ClothingMaterialLibraryParameters* materialLib = static_cast<const ClothingMaterialLibraryParameters*>(clothingAsset->materialLibrary);
+ if (materialLib == NULL)
+ {
+ APEX_DEBUG_WARNING("No Clothing Material Library present in asset");
+ return NULL;
+ }
+
+ PX_ASSERT(materialLib->materials.buf != NULL);
+ PX_ASSERT(materialLib->materials.arraySizes[0] > 0);
+
+ uint32_t index = mActorDesc->clothingMaterialIndex;
+ if (index >= (uint32_t)materialLib->materials.arraySizes[0])
+ {
+ APEX_INVALID_PARAMETER("Index must be smaller than materials array: %d < %d", index, materialLib->materials.arraySizes[0]);
+
+ PX_ASSERT(nvidia::strcmp(clothingAsset->className(), ClothingAssetParameters::staticClassName()) == 0);
+ index = clothingAsset->materialIndex;
+ mActorDesc->clothingMaterialIndex = index;
+ }
+
+ return &materialLib->materials.buf[index];
+}
+
+
+bool ClothingActorImpl::clothingMaterialsEqual(ClothingMaterialLibraryParametersNS::ClothingMaterial_Type& a, ClothingMaterialLibraryParametersNS::ClothingMaterial_Type& b)
+{
+ // update this compare function in case the struct has changed
+ // PH: Let's hope that we bump the version number when modifying the materials in the .pl
+ PX_COMPILE_TIME_ASSERT(ClothingMaterialLibraryParameters::ClassVersion == 14);
+
+ return
+ a.verticalStretchingStiffness == b.verticalStretchingStiffness &&
+ a.horizontalStretchingStiffness == b.horizontalStretchingStiffness &&
+ a.bendingStiffness == b.bendingStiffness &&
+ a.shearingStiffness == b.shearingStiffness &&
+ a.tetherStiffness == b.tetherStiffness &&
+ a.tetherLimit == b.tetherLimit &&
+ a.orthoBending == b.orthoBending &&
+ a.verticalStiffnessScaling.compressionRange == b.verticalStiffnessScaling.compressionRange &&
+ a.verticalStiffnessScaling.stretchRange == b.verticalStiffnessScaling.stretchRange &&
+ a.verticalStiffnessScaling.scale == b.verticalStiffnessScaling.scale &&
+ a.horizontalStiffnessScaling.compressionRange == b.horizontalStiffnessScaling.compressionRange &&
+ a.horizontalStiffnessScaling.stretchRange == b.horizontalStiffnessScaling.stretchRange &&
+ a.horizontalStiffnessScaling.scale == b.horizontalStiffnessScaling.scale &&
+ a.bendingStiffnessScaling.compressionRange == b.bendingStiffnessScaling.compressionRange &&
+ a.bendingStiffnessScaling.stretchRange == b.bendingStiffnessScaling.stretchRange &&
+ a.bendingStiffnessScaling.scale == b.bendingStiffnessScaling.scale &&
+ a.shearingStiffnessScaling.compressionRange == b.shearingStiffnessScaling.compressionRange &&
+ a.shearingStiffnessScaling.stretchRange == b.shearingStiffnessScaling.stretchRange &&
+ a.shearingStiffnessScaling.scale == b.shearingStiffnessScaling.scale &&
+ a.damping == b.damping &&
+ a.stiffnessFrequency == b.stiffnessFrequency &&
+ a.drag == b.drag &&
+ a.comDamping == b.comDamping &&
+ a.friction == b.friction &&
+ a.massScale == b.massScale &&
+ a.solverIterations == b.solverIterations &&
+ a.solverFrequency == b.solverFrequency &&
+ a.gravityScale == b.gravityScale &&
+ a.inertiaScale == b.inertiaScale &&
+ a.hardStretchLimitation == b.hardStretchLimitation &&
+ a.maxDistanceBias == b.maxDistanceBias &&
+ a.hierarchicalSolverIterations == b.hierarchicalSolverIterations &&
+ a.selfcollisionThickness == b.selfcollisionThickness &&
+ a.selfcollisionSquashScale == b.selfcollisionSquashScale &&
+ a.selfcollisionStiffness == b.selfcollisionStiffness;
+}
+
+
+
+void ClothingActorImpl::applyClothingMaterial_LocksPhysX()
+{
+ PX_PROFILE_ZONE("ClothingActorImpl::applyClothingMaterial", GetInternalApexSDK()->getContextId());
+
+ ClothingMaterialLibraryParametersNS::ClothingMaterial_Type* currentMaterial = getCurrentClothingMaterial();
+ bool clothingMaterialDirty = !clothingMaterialsEqual(*currentMaterial, mClothingMaterial) || (bInternalScaledGravityChanged == 1);
+
+ if (mClothingSimulation != NULL && clothingMaterialDirty)
+ {
+ if (mClothingSimulation->applyClothingMaterial(currentMaterial, mInternalScaledGravity))
+ {
+ mClothingMaterial = *currentMaterial;
+ bInternalScaledGravityChanged = 0;
+ }
+ }
+}
+
+
+
+void ClothingActorImpl::tickAsynch_NoPhysX()
+{
+ if (mClothingSimulation != NULL)
+ {
+ if (shouldComputeRenderData() /*&& bInternalFrozen == 0*/)
+ {
+ // perform mesh-to-mesh skinning if using skin cloth
+ if (mInternalFlags.ParallelCpuSkinning)
+ {
+ mData.skinToAnimation_NoPhysX(false);
+ }
+ }
+ }
+}
+
+
+
+bool ClothingActorImpl::needsManualSubstepping()
+{
+ return mClothingSimulation != NULL && mClothingSimulation->needsManualSubstepping();
+}
+
+
+#ifndef WITHOUT_PVD
+void ClothingActorImpl::initPvdInstances(pvdsdk::PvdDataStream& pvdStream)
+{
+ ApexResourceInterface* pvdInstance = static_cast<ApexResourceInterface*>(mActorProxy);
+
+ // Actor Params
+ pvdStream.createInstance(pvdsdk::NamespacedName(APEX_PVD_NAMESPACE, "ClothingActorParam"), mActorDesc);
+ pvdStream.setPropertyValue(pvdInstance, "ActorParams", pvdsdk::DataRef<const uint8_t>((const uint8_t*)&mActorDesc, sizeof(ClothingActorParam*)), pvdsdk::getPvdNamespacedNameForType<pvdsdk::ObjectRef>());
+
+ pvdsdk::ApexPvdClient* client = GetInternalApexSDK()->getApexPvdClient();
+ PX_ASSERT(client != NULL);
+ client->updatePvd(mActorDesc, *mActorDesc);
+}
+
+
+void ClothingActorImpl::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(mActorDesc, *mActorDesc, pvdsdk::PvdAction::DESTROY);
+ pvdStream->destroyInstance(mActorDesc);
+ // the actor instance is destroyed in ResourceList::remove
+ }
+ }
+ }
+ }
+}
+
+
+void ClothingActorImpl::updatePvd()
+{
+ // update pvd
+ pvdsdk::ApexPvdClient* client = GetInternalApexSDK()->getApexPvdClient();
+ if (client != NULL)
+ {
+ if (client->isConnected() && client->getPxPvd().getInstrumentationFlags() & PxPvdInstrumentationFlag::eDEBUG)
+ {
+ pvdsdk::PvdDataStream* pvdStream = client->getDataStream();
+ pvdsdk::PvdUserRenderer* pvdRenderer = client->getUserRender();
+
+ if (pvdStream != NULL && pvdRenderer != NULL)
+ {
+ ApexResourceInterface* pvdInstance = static_cast<ApexResourceInterface*>(mActorProxy);
+
+ client->updatePvd(mActorDesc, *mActorDesc);
+
+ if (mClothingSimulation)
+ {
+ mClothingSimulation->updatePvd(*pvdStream, *pvdRenderer, pvdInstance, bInternalLocalSpaceSim == 1);
+ }
+ }
+ }
+ }
+}
+#endif
+
+
+void ClothingActorImpl::visualize()
+{
+#ifdef WITHOUT_DEBUG_VISUALIZE
+#else
+
+ using RENDER_DEBUG::DebugColors;
+ using RENDER_DEBUG::DebugRenderState;
+
+ if (mClothingScene == NULL || mClothingScene->mRenderDebug == NULL)
+ {
+ return;
+ }
+ if ( !mEnableDebugVisualization ) return;
+
+ RenderDebugInterface& renderDebug = *mClothingScene->mRenderDebug;
+ const physx::PxMat44& savedPose = *RENDER_DEBUG_IFACE(&renderDebug)->getPoseTyped();
+ RENDER_DEBUG_IFACE(&renderDebug)->setIdentityPose();
+
+ const float visualizationScale = mClothingScene->mDebugRenderParams->Scale;
+
+ PX_ASSERT(mActorDesc != NULL);
+
+ if (visualizationScale == 0.0f || !mActorDesc->flags.Visualize)
+ {
+ return;
+ }
+
+ if (mClothingScene->mClothingDebugRenderParams->GlobalPose)
+ {
+#if 1
+ // PH: This uses only lines, not triangles, hence wider engine support
+ const uint32_t colorRed = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Red);
+ const uint32_t colorGreen = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Green);
+ const uint32_t colorBlue = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Blue);
+ PxMat44 absPose(mInternalGlobalPose);
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorRed);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(absPose.getPosition(), absPose.getPosition() + absPose.column0.getXYZ() * visualizationScale);
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorGreen);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(absPose.getPosition(), absPose.getPosition() + absPose.column1.getXYZ() * visualizationScale);
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorBlue);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(absPose.getPosition(), absPose.getPosition() + absPose.column2.getXYZ() * visualizationScale);
+#else
+ // PH: But this one looks a bit nicer
+ RENDER_DEBUG_IFACE(&renderDebug)->debugAxes(mInternalGlobalPose, visualizationScale);
+#endif
+ }
+
+ // transform debug rendering to global space
+ if (bInternalLocalSpaceSim == 1 && !mClothingScene->mClothingDebugRenderParams->ShowInLocalSpace)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->setPose(mInternalGlobalPose);
+ }
+
+ const uint32_t colorRed = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Red);
+ const uint32_t colorBlue = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Blue);
+ const uint32_t colorWhite = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::White);
+
+ renderDataLock();
+
+#if 0
+ static bool turnOn = true;
+ if (turnOn)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->pushRenderState();
+
+ RenderMeshAssetIntl* rma = mAsset->getGraphicalMesh(mCurrentGraphicalLodId);
+ if (false && mActorDesc->morphDisplacements.arraySizes[0] > 0 && rma != NULL)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorBlue);
+
+ uint32_t* morphMap = mAsset->getMorphMapping(mCurrentGraphicalLodId);
+
+ for (uint32_t s = 0; s < rma->getSubmeshCount(); s++)
+ {
+ const uint32_t numVertices = rma->getSubmesh(s).getVertexCount(0);
+ const VertexFormat& format = rma->getSubmesh(s).getVertexBuffer().getFormat();
+ const uint32_t positionIndex = format.getBufferIndexFromID(format.getSemanticID(RenderVertexSemantic::POSITION));
+ if (format.getBufferFormat(positionIndex) == RenderDataFormat::FLOAT3)
+ {
+ PxVec3* positions = (PxVec3*)rma->getSubmesh(s).getVertexBuffer().getBuffer(positionIndex);
+ for (uint32_t v = 0; v < numVertices; v++)
+ {
+ PxVec3 from = positions[v];
+ PX_ASSERT((int)morphMap[v] < mActorDesc->morphDisplacements.arraySizes[0]);
+ PxVec3 to = from + mActorDesc->morphDisplacements.buf[morphMap[v]];
+
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(from, to);
+ }
+ }
+ }
+
+ }
+
+ if (mActorDesc->morphPhysicalMeshNewPositions.buf != NULL)
+ {
+ mClothingScene-> mRENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorRed);
+
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type* physicalMesh = mAsset->getPhysicalMeshFromLod(mCurrentGraphicalLodId);
+ uint32_t offset = mAsset->getPhysicalMeshOffset(mAsset->getPhysicalMeshID(mCurrentGraphicalLodId));
+ PX_ASSERT((int32_t)(offset + physicalMesh->numVertices) <= mActorDesc->morphPhysicalMeshNewPositions.arraySizes[0]);
+ for (uint32_t p = 0; p < physicalMesh->numVertices; p++)
+ {
+ const PxVec3 renderDisp(0.0f, 0.0f, 0.001f);
+ PxVec3 from = physicalMesh->vertices.buf[p] + renderDisp;
+ PxVec3 to = mActorDesc->morphPhysicalMeshNewPositions.buf[offset + p] + renderDisp;
+
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(from, to);
+ }
+ }
+
+ RENDER_DEBUG_IFACE(&renderDebug)->popRenderState();
+ }
+#endif
+
+ // save the rendering state.
+ RENDER_DEBUG_IFACE(&renderDebug)->pushRenderState();
+
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorRed);
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentState(DebugRenderState::SolidShaded);
+
+
+ // visualize velocities
+ const float velocityScale = mClothingScene->mClothingDebugRenderParams->Velocities * visualizationScale;
+ if (velocityScale > 0.0f && mClothingSimulation != NULL)
+ {
+ PxVec3* velocities = (PxVec3*)GetInternalApexSDK()->getTempMemory(sizeof(PxVec3) * mClothingSimulation->sdkNumDeformableVertices);
+ if (velocities != NULL)
+ {
+ mClothingSimulation->getVelocities(velocities);
+
+ const bool useVelocityClamp = mActorDesc->useVelocityClamping;
+ PxBounds3 velocityClamp(mActorDesc->vertexVelocityClamp);
+
+ for (uint32_t i = 0; i < mClothingSimulation->sdkNumDeformableVertices; i++)
+ {
+ const PxVec3 pos = mClothingSimulation->sdkWritebackPosition[i];
+ const PxVec3 vel = velocities[i];
+ bool clamped = false;
+ if (useVelocityClamp)
+ {
+ clamped = (vel.x < velocityClamp.minimum.x) || (vel.x > velocityClamp.maximum.x);
+ clamped |= (vel.y < velocityClamp.minimum.y) || (vel.y > velocityClamp.maximum.y);
+ clamped |= (vel.z < velocityClamp.minimum.z) || (vel.z > velocityClamp.maximum.z);
+ }
+ const PxVec3 dest = pos + vel * velocityScale;
+ RENDER_DEBUG_IFACE(&renderDebug)->debugGradientLine(pos, dest, clamped ? colorRed : colorBlue, colorWhite);
+ }
+
+ GetInternalApexSDK()->releaseTempMemory(velocities);
+ }
+ }
+
+ // visualize Skeleton
+ const bool skeleton = mClothingScene->mClothingDebugRenderParams->Skeleton;
+ const float boneFramesScale = mClothingScene->mClothingDebugRenderParams->BoneFrames;
+ const float boneNamesScale = mClothingScene->mClothingDebugRenderParams->BoneNames;
+ if (skeleton || boneFramesScale + boneNamesScale > 0.0f)
+ {
+ const PxMat44* matrices = mData.mInternalBoneMatricesCur;
+
+ if (matrices != NULL)
+ {
+ mAsset->visualizeBones(renderDebug, matrices, skeleton, boneFramesScale, boneNamesScale);
+ }
+ }
+
+ // visualization of the physical mesh
+ if (mClothingScene->mClothingDebugRenderParams->Backstop)
+ {
+ visualizeBackstop(renderDebug);
+ }
+
+ const float backstopPrecise = mClothingScene->mClothingDebugRenderParams->BackstopPrecise;
+ if (backstopPrecise > 0.0f)
+ {
+ visualizeBackstopPrecise(renderDebug, backstopPrecise);
+ }
+
+ const float skinnedPositionsScale = mClothingScene->mClothingDebugRenderParams->SkinnedPositions;
+ const bool drawMaxDistance = mClothingScene->mClothingDebugRenderParams->MaxDistance;
+ const bool drawMaxDistanceIn = mClothingScene->mClothingDebugRenderParams->MaxDistanceInwards;
+ if (skinnedPositionsScale > 0.0f || drawMaxDistance || drawMaxDistanceIn)
+ {
+ visualizeSkinnedPositions(renderDebug, skinnedPositionsScale, drawMaxDistance, drawMaxDistanceIn);
+ }
+
+ // visualize vertex - bone connections for skinning
+ for (uint32_t g = 0; g < mGraphicalMeshes.size(); g++)
+ {
+ if (!mGraphicalMeshes[g].active)
+ {
+ continue;
+ }
+
+ //const ClothingGraphicalLodParameters* graphicalLod = mAsset->getGraphicalLod(g);
+ ClothingGraphicalMeshAssetWrapper meshAsset(mAsset->getRenderMeshAsset(g));
+
+ const float graphicalVertexBonesScale = mClothingScene->mClothingDebugRenderParams->GraphicalVertexBones;
+ if (graphicalVertexBonesScale > 0.0f)
+ {
+ for (uint32_t submeshIndex = 0; submeshIndex < meshAsset.getSubmeshCount(); submeshIndex++)
+ {
+ RenderDataFormat::Enum outFormat;
+ const PxVec3* positions = (const PxVec3*)meshAsset.getVertexBuffer(submeshIndex, RenderVertexSemantic::POSITION, outFormat);
+ PX_ASSERT(outFormat == RenderDataFormat::FLOAT3);
+ const uint16_t* boneIndices = (const uint16_t*)meshAsset.getVertexBuffer(submeshIndex, RenderVertexSemantic::BONE_INDEX, outFormat);
+ const float* boneWeights = (const float*)meshAsset.getVertexBuffer(submeshIndex, RenderVertexSemantic::BONE_WEIGHT, outFormat);
+ visualizeBoneConnections(renderDebug, positions, boneIndices, boneWeights,
+ meshAsset.getNumBonesPerVertex(submeshIndex), meshAsset.getNumVertices(submeshIndex));
+ }
+ }
+
+ const float physicalVertexBonesScale = mClothingScene->mClothingDebugRenderParams->PhysicalVertexBones;
+ if (physicalVertexBonesScale > 0.0f)
+ {
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type* physicalMesh = mAsset->getPhysicalMeshFromLod(g);
+ visualizeBoneConnections(renderDebug, physicalMesh->vertices.buf, physicalMesh->boneIndices.buf,
+ physicalMesh->boneWeights.buf, physicalMesh->numBonesPerVertex, physicalMesh->numVertices);
+ }
+ }
+
+ if (mClothingSimulation != NULL)
+ {
+ // visualization of the physical mesh
+ const float physicsMeshWireScale = mClothingScene->mClothingDebugRenderParams->PhysicsMeshWire;
+ const float physicsMeshSolidScale = mClothingScene->mClothingDebugRenderParams->PhysicsMeshSolid;
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type* physicalMesh = mAsset->getPhysicalMeshFromLod(mCurrentGraphicalLodId);
+
+ const float physicsMeshNormalScale = mClothingScene->mClothingDebugRenderParams->PhysicsMeshNormals;
+ if (physicsMeshNormalScale > 0.0f)
+ {
+ const PxVec3* positions = mClothingSimulation->sdkWritebackPosition;
+ const PxVec3* normals = mClothingSimulation->sdkWritebackNormal;
+
+ RENDER_DEBUG_IFACE(&renderDebug)->pushRenderState();
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Blue));
+
+ const uint32_t numVertices = mClothingSimulation->sdkNumDeformableVertices;
+ for (uint32_t i = 0; i < numVertices; i++)
+ {
+ const PxVec3 dest = positions[i] + normals[i] * physicsMeshNormalScale;
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(positions[i], dest);
+ }
+
+ RENDER_DEBUG_IFACE(&renderDebug)->popRenderState();
+ }
+
+ if (mClothingScene->mClothingDebugRenderParams->PhysicsMeshIndices)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->pushRenderState();
+ const PxVec3 upAxis = -mInternalScaledGravity.getNormalized();
+ const float avgEdgeLength = mAsset->getPhysicalMeshFromLod(mCurrentGraphicalLodId)->averageEdgeLength;
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentTextScale(avgEdgeLength);
+ RENDER_DEBUG_IFACE(&renderDebug)->addToCurrentState(RENDER_DEBUG::DebugRenderState::CameraFacing);
+
+ const uint32_t numVertices = mClothingSimulation->sdkNumDeformableVertices;
+ const PxVec3* const positions = mClothingSimulation->sdkWritebackPosition;
+ const PxVec3* const normals = mClothingSimulation->sdkWritebackNormal;
+ for (uint32_t i = 0; i < numVertices; ++i)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(0xFFFFFFFF);
+ const PxVec3 pos = positions[i];
+ const PxVec3 normal = normals[i].getNormalized();
+ PxVec3 rightAxis = upAxis.cross(normal).getNormalized();
+ PxVec3 realUpAxis = normal.cross(rightAxis).getNormalized();
+
+ RENDER_DEBUG_IFACE(&renderDebug)->debugText(pos + normal * (avgEdgeLength * 0.1f), "%d", i);
+ }
+ RENDER_DEBUG_IFACE(&renderDebug)->popRenderState();
+ }
+
+ if (physicsMeshWireScale > 0.0f || physicsMeshSolidScale > 0.0f)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->pushRenderState();
+ RENDER_DEBUG_IFACE(&renderDebug)->setIdentityPose();
+ const float actorScale = mActorDesc->actorScale;
+
+ const float linearScale = (mInternalMaxDistanceScale.Multipliable ? mInternalMaxDistanceScale.Scale : 1.0f) * actorScale;
+ const float absoluteScale = mInternalMaxDistanceScale.Multipliable ? 0.0f : (physicalMesh->maximumMaxDistance * (1.0f - mInternalMaxDistanceScale.Scale));
+
+ const float reduceMaxDistance = mMaxDistReduction + absoluteScale;
+
+ const uint32_t numIndices = mClothingSimulation->sdkNumDeformableIndices;
+ const uint32_t* const indices = physicalMesh->indices.buf;
+ const PxVec3* const positions = mClothingSimulation->sdkWritebackPosition;
+ const PxVec3* const skinnedPositions = mClothingSimulation->skinnedPhysicsPositions;
+
+ const ClothingPhysicalMeshParametersNS::ConstrainCoefficient_Type* const PX_RESTRICT coeffs = physicalMesh->constrainCoefficients.buf;
+
+ RENDER_DEBUG_IFACE(&renderDebug)->removeFromCurrentState(DebugRenderState::SolidWireShaded);
+
+ union BlendColors
+ {
+ unsigned char chars[4];
+ uint32_t color;
+ } blendColors[3];
+
+ blendColors[0].color = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Yellow);
+ blendColors[1].color = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Gold);
+ blendColors[2].color = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Red);
+ const uint32_t lightBlue = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::LightBlue);
+ const uint32_t darkBlue = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Blue);
+
+ if (bInternalFrozen)
+ {
+ blendColors[0].color = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Purple);
+ blendColors[1].color = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::DarkPurple);
+ }
+ else if (bInternalTeleportDue == ClothingTeleportMode::TeleportAndReset)
+ {
+ blendColors[0].color = darkBlue;
+ blendColors[1].color = darkBlue;
+ blendColors[2].color = darkBlue;
+ }
+ else if (bInternalTeleportDue == ClothingTeleportMode::Teleport)
+ {
+ blendColors[0].color = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Red);
+ blendColors[1].color = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Red);
+ blendColors[2].color = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Red);
+ }
+
+ const uint8_t sides[4][3] = {{2, 1, 0}, {0, 1, 3}, {1, 2, 3}, {2, 0, 3}};
+
+ const uint32_t numIndicesPerPrim = physicalMesh->isTetrahedralMesh ? 4u : 3u;
+ const float numindicesPerPrimF = (float)numIndicesPerPrim;
+
+ for (uint32_t i = 0; i < numIndices; i += numIndicesPerPrim)
+ {
+ PxVec3 vecs[8];
+ PxVec3 center(0.0f, 0.0f, 0.0f);
+ uint32_t colors[8];
+ for (uint32_t j = 0; j < numIndicesPerPrim; j++)
+ {
+ const uint32_t index = indices[i + j];
+ vecs[j] = positions[index];
+ center += vecs[j];
+ const float maxDistance = (coeffs[index].maxDistance - reduceMaxDistance) * linearScale;
+ if (maxDistance <= 0.0f)
+ {
+ colors[j ] = lightBlue;
+ colors[j + numIndicesPerPrim] = darkBlue;
+ }
+ else
+ {
+ const float distance = (positions[index] - skinnedPositions[index]).magnitude() / maxDistance;
+
+ union
+ {
+ unsigned char tempChars[8];
+ uint32_t tempColor[2];
+ };
+
+ if (distance > 1.0f)
+ {
+ colors[j ] = blendColors[2].color;
+ colors[j + numIndicesPerPrim] = blendColors[2].color;
+ }
+ else
+ {
+ for (uint32_t k = 0; k < 4; k++)
+ {
+ tempChars[k ] = (unsigned char)(blendColors[2].chars[k] * distance + blendColors[0].chars[k] * (1.0f - distance));
+ tempChars[k + 4] = (unsigned char)(blendColors[2].chars[k] * distance + blendColors[1].chars[k] * (1.0f - distance));
+ }
+ colors[j ] = tempColor[0];
+ colors[j + numIndicesPerPrim] = tempColor[1];
+ }
+ }
+ }
+
+ center /= numindicesPerPrimF;
+
+ for (uint32_t j = 0; j < numIndicesPerPrim; j++)
+ {
+ vecs[j + numIndicesPerPrim] = vecs[j] * physicsMeshSolidScale + center * (1.0f - physicsMeshSolidScale);
+ vecs[j] = vecs[j] * physicsMeshWireScale + center * (1.0f - physicsMeshWireScale);
+ }
+
+ if (physicsMeshWireScale > 0.0f)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->removeFromCurrentState(DebugRenderState::SolidShaded);
+
+ if (numIndicesPerPrim == 3)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->debugGradientLine(vecs[0], vecs[1], colors[0], colors[1]);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugGradientLine(vecs[1], vecs[2], colors[1], colors[2]);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugGradientLine(vecs[2], vecs[0], colors[2], colors[0]);
+ }
+ else
+ {
+ for (uint32_t j = 0; j < 4; j++)
+ {
+ uint32_t triIndices[3] = { sides[j][0], sides[j][1], sides[j][2] };
+ RENDER_DEBUG_IFACE(&renderDebug)->debugGradientLine(vecs[triIndices[0]], vecs[triIndices[2]], colors[triIndices[0]], colors[triIndices[2]]);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugGradientLine(vecs[triIndices[2]], vecs[triIndices[1]], colors[triIndices[2]], colors[triIndices[1]]);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugGradientLine(vecs[triIndices[1]], vecs[triIndices[0]], colors[triIndices[1]], colors[triIndices[0]]);
+ }
+ }
+ }
+ if (physicsMeshSolidScale > 0.0f)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->addToCurrentState(DebugRenderState::SolidShaded);
+
+ if (numIndicesPerPrim == 3)
+ {
+ // culling is active for these, so we need both of them
+ RENDER_DEBUG_IFACE(&renderDebug)->debugGradientTri(vecs[3], vecs[4], vecs[5], colors[3], colors[4], colors[5]);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugGradientTri(vecs[3], vecs[5], vecs[4], colors[3], colors[5], colors[4]);
+ }
+ else
+ {
+ for (uint32_t j = 0; j < 4; j++)
+ {
+ uint32_t triIndices[3] = { (uint32_t)sides[j][0] + 4, (uint32_t)sides[j][1] + 4, (uint32_t)sides[j][2] + 4 };
+ RENDER_DEBUG_IFACE(&renderDebug)->debugGradientTri(
+ vecs[triIndices[0]], vecs[triIndices[2]], vecs[triIndices[1]],
+ colors[triIndices[0]], colors[triIndices[2]], colors[triIndices[1]]);
+ }
+ }
+ }
+ }
+ RENDER_DEBUG_IFACE(&renderDebug)->popRenderState();
+ }
+
+ // self collision visualization
+ if ( (mClothingScene->mClothingDebugRenderParams->SelfCollision || mClothingScene->mClothingDebugRenderParams->SelfCollisionWire)
+ && (!mAsset->getModuleClothing()->useSparseSelfCollision() || mClothingSimulation->getType() != SimulationType::CLOTH3x))
+ {
+ const PxVec3* const positions = mClothingSimulation->sdkWritebackPosition;
+ ClothingMaterialLibraryParametersNS::ClothingMaterial_Type* material = getCurrentClothingMaterial();
+
+ if (material->selfcollisionThickness > 0.0f && material->selfcollisionStiffness > 0.0f)
+ {
+ visualizeSpheres(renderDebug, positions, mClothingSimulation->sdkNumDeformableVertices, 0.5f*material->selfcollisionThickness*mActorDesc->actorScale, colorRed, mClothingScene->mClothingDebugRenderParams->SelfCollisionWire);
+ }
+ }
+ /*
+ // inter collision visualization
+ if ( (mClothingScene->mClothingDebugRenderParams->InterCollision || mClothingScene->mClothingDebugRenderParams->InterCollisionWire)
+ && mClothingSimulation->getType() == SimulationType::CLOTH3x)
+ {
+ const PxVec3* const positions = mClothingSimulation->sdkWritebackPosition;
+ float distance = mAsset->getModuleClothing()->getInterCollisionDistance();
+ float stiffness = mAsset->getModuleClothing()->getInterCollisionStiffness();
+ if (distance > 0.0f && stiffness > 0.0f)
+ {
+ visualizeSpheres(renderDebug, positions, mClothingSimulation->sdkNumDeformableVertices, 0.5f*distance, colorBlue, mClothingScene->mClothingDebugRenderParams->InterCollisionWire);
+ }
+ }
+ */
+ // visualization of the graphical mesh
+ for (uint32_t g = 0; g < mGraphicalMeshes.size(); g++)
+ {
+ if (!mGraphicalMeshes[g].active)
+ {
+ continue;
+ }
+
+ const ClothingGraphicalLodParameters* graphicalLod = mAsset->getGraphicalLod(g);
+
+ if (graphicalLod != NULL && (graphicalLod->skinClothMapB.buf != NULL || graphicalLod->skinClothMap.buf != NULL))
+ {
+ AbstractMeshDescription pcm;
+ pcm.numVertices = mClothingSimulation->sdkNumDeformableVertices;
+ pcm.numIndices = mClothingSimulation->sdkNumDeformableIndices;
+ pcm.pPosition = mClothingSimulation->sdkWritebackPosition;
+ pcm.pNormal = mClothingSimulation->sdkWritebackNormal;
+ pcm.pIndices = physicalMesh->indices.buf;
+ pcm.avgEdgeLength = graphicalLod->skinClothMapThickness;
+
+ if (mClothingScene->mClothingDebugRenderParams->SkinMapAll)
+ {
+ mAsset->visualizeSkinCloth(renderDebug, pcm, graphicalLod->skinClothMapB.buf != NULL, mActorDesc->actorScale);
+ }
+ if (mClothingScene->mClothingDebugRenderParams->SkinMapBad)
+ {
+ mAsset->visualizeSkinClothMap(renderDebug, pcm,
+ graphicalLod->skinClothMapB.buf, (uint32_t)graphicalLod->skinClothMapB.arraySizes[0],
+ graphicalLod->skinClothMap.buf, (uint32_t)graphicalLod->skinClothMap.arraySizes[0], mActorDesc->actorScale, true, false);
+ }
+ if (mClothingScene->mClothingDebugRenderParams->SkinMapActual)
+ {
+ mAsset->visualizeSkinClothMap(renderDebug, pcm,
+ graphicalLod->skinClothMapB.buf, (uint32_t)graphicalLod->skinClothMapB.arraySizes[0],
+ graphicalLod->skinClothMap.buf, (uint32_t)graphicalLod->skinClothMap.arraySizes[0], mActorDesc->actorScale, false, false);
+ }
+ if (mClothingScene->mClothingDebugRenderParams->SkinMapInvalidBary)
+ {
+ mAsset->visualizeSkinClothMap(renderDebug, pcm,
+ graphicalLod->skinClothMapB.buf, (uint32_t)graphicalLod->skinClothMapB.arraySizes[0],
+ graphicalLod->skinClothMap.buf, (uint32_t)graphicalLod->skinClothMap.arraySizes[0], mActorDesc->actorScale, false, true);
+ }
+
+ }
+
+ RENDER_DEBUG_IFACE(&renderDebug)->pushRenderState();
+
+ RENDER_DEBUG_IFACE(&renderDebug)->addToCurrentState(RENDER_DEBUG::DebugRenderState::CenterText);
+ RENDER_DEBUG_IFACE(&renderDebug)->addToCurrentState(RENDER_DEBUG::DebugRenderState::CameraFacing);
+
+ // Probably should be removed
+ if (graphicalLod != NULL && mClothingScene->mClothingDebugRenderParams->RecomputeSubmeshes)
+ {
+ const RenderMeshAsset* rma = mAsset->getRenderMeshAsset(mCurrentGraphicalLodId);
+
+ RENDER_DEBUG_IFACE(&renderDebug)->addToCurrentState(DebugRenderState::SolidShaded);
+
+ uint32_t submeshVertexOffset = 0;
+ for (uint32_t s = 0; s < rma->getSubmeshCount(); s++)
+ {
+ const RenderSubmesh& submesh = rma->getSubmesh(s);
+ const uint32_t vertexCount = submesh.getVertexCount(0);
+ const uint32_t* indices = submesh.getIndexBuffer(0);
+ const uint32_t numIndices = submesh.getIndexCount(0);
+
+ if(mGraphicalMeshes[mCurrentGraphicalLodId].renderProxy == NULL)
+ continue;
+ const PxVec3* positions = mGraphicalMeshes[mCurrentGraphicalLodId].renderProxy->renderingDataPosition + submeshVertexOffset;
+
+
+ uint32_t maxForColor = (uint32_t)graphicalLod->physicsMeshPartitioning.arraySizes[0] + 2;
+ {
+ const uint8_t colorPart = (uint8_t)((255 / maxForColor) & 0xff);
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(uint32_t(colorPart | colorPart << 8 | colorPart << 16));
+ }
+
+ for (uint32_t i = 0; i < numIndices; i += 3)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->debugTri(positions[indices[i]], positions[indices[i + 1]], positions[indices[i + 2]]);
+ }
+ const uint8_t colorPart = (uint8_t)((2 * 255 / maxForColor) & 0xff);
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(uint32_t(colorPart | colorPart << 8 | colorPart << 16));
+
+ submeshVertexOffset += vertexCount;
+ }
+ }
+ if (graphicalLod != NULL && mClothingScene->mClothingDebugRenderParams->RecomputeVertices)
+ {
+ uint32_t color1 = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Orange);
+ uint32_t color2 = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Purple);
+
+ const PxVec3 upAxis = -mInternalScaledGravity.getNormalized();
+ PX_UNUSED(upAxis);
+
+ const float avgEdgeLength = mAsset->getPhysicalMeshFromLod(mCurrentGraphicalLodId)->averageEdgeLength;
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentTextScale(0.2f * avgEdgeLength);
+
+ const RenderMeshAsset* rma = mAsset->getRenderMeshAsset(mCurrentGraphicalLodId);
+
+ uint32_t submeshVertexOffset = 0;
+ for (uint32_t s = 0; s < rma->getSubmeshCount(); s++)
+ {
+ const RenderSubmesh& submesh = rma->getSubmesh(s);
+ const uint32_t vertexCount = submesh.getVertexCount(0);
+
+ ClothingRenderProxyImpl* renderProxy = mGraphicalMeshes[mCurrentGraphicalLodId].renderProxy;
+
+ if (renderProxy == NULL)
+ {
+ renderProxy = mRenderProxyReady;
+ }
+
+ if (renderProxy == NULL)
+ {
+ renderProxy = mRenderProxyURR;
+ }
+
+ if(renderProxy == NULL)
+ continue;
+
+ const PxVec3* positions = renderProxy->renderingDataPosition + submeshVertexOffset;
+
+ uint32_t simulatedVertices = graphicalLod->physicsMeshPartitioning.buf[s].numSimulatedVertices;
+ uint32_t simulatedVerticesAdditional = graphicalLod->physicsMeshPartitioning.buf[s].numSimulatedVerticesAdditional;
+
+ for (uint32_t i = 0; i < simulatedVerticesAdditional && i < vertexCount; i++)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(i < simulatedVertices ? color1 : color2);
+ const PxVec3 pos = positions[i];
+
+ RENDER_DEBUG_IFACE(&renderDebug)->debugText(pos, "%d", submeshVertexOffset + i);
+ }
+
+ submeshVertexOffset += vertexCount;
+ }
+ }
+
+ RENDER_DEBUG_IFACE(&renderDebug)->popRenderState();
+ }
+ }
+
+ if (mClothingSimulation != NULL)
+ {
+ mClothingSimulation->visualize(renderDebug, *mClothingScene->mClothingDebugRenderParams);
+ }
+
+ // restore the rendering state.
+ RENDER_DEBUG_IFACE(&renderDebug)->popRenderState();
+
+ const float windScale = mClothingScene->mClothingDebugRenderParams->Wind;
+ if (mClothingSimulation != NULL && windScale != 0.0f)
+ {
+ //PX_ASSERT(mWindDebugRendering.size() == mClothingSimulation->sdkNumDeformableVertices);
+ const uint32_t numVertices = PxMin(mClothingSimulation->sdkNumDeformableVertices, mWindDebugRendering.size());
+ const PxVec3* positions = mClothingSimulation->sdkWritebackPosition;
+ const uint32_t red = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Red);
+ const uint32_t white = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::White);
+ for (uint32_t i = 0; i < numVertices; i++)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->debugGradientLine(positions[i], positions[i] + mWindDebugRendering[i] * windScale, red, white);
+ }
+ }
+
+ // fetchresults must be completed before Normal/Tangent debug rendering
+ waitForFetchResults();
+
+ // render mesh actor debug rendering
+ for (uint32_t i = 0; i < mGraphicalMeshes.size(); i++)
+ {
+ if (mGraphicalMeshes[i].active && mGraphicalMeshes[i].renderProxy != NULL)
+ {
+ mGraphicalMeshes[i].renderProxy->getRenderMeshActor()->visualize(renderDebug, mClothingScene->mDebugRenderParams);
+ }
+ }
+ if (mRenderProxyReady != NULL)
+ {
+ mRenderProxyReady->getRenderMeshActor()->visualize(renderDebug, mClothingScene->mDebugRenderParams);
+ }
+ else if (mRenderProxyURR != NULL)
+ {
+ mRenderProxyURR->getRenderMeshActor()->visualize(renderDebug, mClothingScene->mDebugRenderParams);
+ }
+
+ // transform debug rendering to global space
+ if (bInternalLocalSpaceSim == 1)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->setPose(PxMat44(PxIdentity));
+ }
+
+
+ if (mClothingScene->mClothingDebugRenderParams->Wind != 0.0f && mActorDesc->windParams.Adaption > 0.0f)
+ {
+ const PxVec3 center = mRenderBounds.getCenter();
+ const float radius = mRenderBounds.getExtents().magnitude() * 0.02f;
+ RENDER_DEBUG_IFACE(&renderDebug)->debugThickRay(center, center + mActorDesc->windParams.Velocity * mClothingScene->mClothingDebugRenderParams->Wind, radius);
+ }
+
+ if (mClothingScene->mClothingDebugRenderParams->SolverMode)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->pushRenderState();
+ RENDER_DEBUG_IFACE(&renderDebug)->addToCurrentState(RENDER_DEBUG::DebugRenderState::CenterText);
+ RENDER_DEBUG_IFACE(&renderDebug)->addToCurrentState(RENDER_DEBUG::DebugRenderState::CameraFacing);
+
+ ApexSimpleString solverString;
+
+ if (mClothingSimulation != NULL)
+ {
+ solverString = (mClothingSimulation->getType() == SimulationType::CLOTH3x) ? "3.x" : "2.x";
+#if APEX_CUDA_SUPPORT
+ ApexSimpleString gpu(mClothingSimulation->isGpuSim() ? " GPU" : " CPU");
+
+ if (mClothingSimulation->getGpuSimMemType() == GpuSimMemType::GLOBAL)
+ {
+ gpu += ApexSimpleString(", Global");
+ }
+ else if(mClothingSimulation->getGpuSimMemType() == GpuSimMemType::MIXED)
+ {
+ gpu += ApexSimpleString(", Mixed");
+ }
+ else if (mClothingSimulation->getGpuSimMemType() == GpuSimMemType::SHARED)
+ {
+ gpu += ApexSimpleString(", Shared");
+ }
+
+ solverString += gpu;
+#endif
+ solverString += ApexSimpleString(", ");
+ ApexSimpleString solverCount;
+ ApexSimpleString::itoa(mClothingSimulation->getNumSolverIterations(), solverCount);
+ solverString += solverCount;
+ }
+ else
+ {
+ solverString = "Disabled";
+ }
+
+ PxVec3 up(0.0f, 1.0f, 0.0f);
+ up = mData.mInternalGlobalPose.transform(up) - mClothingScene->getApexScene()->getGravity();
+ up.normalize();
+
+ const uint32_t white = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::White);
+ const uint32_t gray = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::DarkGray);
+ up = mRenderBounds.getDimensions().multiply(up) * 1.1f;
+ const PxVec3 center = mRenderBounds.getCenter();
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentTextScale(mRenderBounds.getDimensions().magnitude());
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(gray);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugText(center + up * 1.1f, solverString.c_str());
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(white);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugText(center + up * 1.12f, solverString.c_str());
+
+ RENDER_DEBUG_IFACE(&renderDebug)->popRenderState();
+ }
+
+
+ RENDER_DEBUG_IFACE(&renderDebug)->setPose(savedPose);
+ renderDataUnLock();
+#endif
+}
+
+
+
+void ClothingActorImpl::destroy()
+{
+ PX_ASSERT(!isSimulationRunning());
+ if (mActiveCookingTask != NULL)
+ {
+ mActiveCookingTask->abort();
+ PX_ASSERT(mActorDesc->runtimeCooked == NULL);
+ mActiveCookingTask = NULL;
+ }
+
+ ApexActor::destroy(); // remove self from contexts, prevent re-release()
+
+ removePhysX_LocksPhysX();
+
+ if (mData.mInternalBoneMatricesCur != NULL)
+ {
+ PX_FREE(mData.mInternalBoneMatricesCur);
+ mData.mInternalBoneMatricesCur = NULL;
+ }
+ if (mData.mInternalBoneMatricesPrev != NULL)
+ {
+ PX_FREE(mData.mInternalBoneMatricesPrev);
+ mData.mInternalBoneMatricesPrev = NULL;
+ }
+
+ if (mInternalInterpolatedBoneMatrices != NULL)
+ {
+ PX_FREE(mInternalInterpolatedBoneMatrices);
+ mInternalInterpolatedBoneMatrices = NULL;
+ }
+
+ PX_ASSERT(mActorDesc != NULL); // This is a requirement!
+
+
+#ifndef WITHOUT_PVD
+ destroyPvdInstances();
+#endif
+ if (mActorDesc != NULL)
+ {
+ if (mActorDesc->runtimeCooked != NULL)
+ {
+ mAsset->getModuleClothing()->getBackendFactory(mActorDesc->runtimeCooked->className())->releaseCookedInstances(mActorDesc->runtimeCooked);
+ }
+ mActorDesc->destroy();
+ mActorDesc = NULL;
+ }
+
+ for (uint32_t i = 0; i < mGraphicalMeshes.size(); i++)
+ {
+ if (mGraphicalMeshes[i].renderProxy != NULL)
+ {
+ mGraphicalMeshes[i].renderProxy->release();
+ mGraphicalMeshes[i].renderProxy = NULL;
+ }
+ }
+ mGraphicalMeshes.clear();
+
+ mRenderProxyMutex.lock();
+ if (mRenderProxyURR != NULL)
+ {
+ mRenderProxyURR->release();
+ mRenderProxyURR = NULL;
+ }
+ if (mRenderProxyReady != NULL)
+ {
+ mRenderProxyReady->release();
+ mRenderProxyReady = NULL;
+ }
+ mRenderProxyMutex.unlock();
+}
+
+
+#if APEX_UE4
+void ClothingActorImpl::initBeforeTickTasks(PxF32 deltaTime, PxF32 substepSize, PxU32 numSubSteps, PxTaskManager* taskManager, PxTaskID before, PxTaskID after)
+#else
+void ClothingActorImpl::initBeforeTickTasks(float deltaTime, float substepSize, uint32_t numSubSteps)
+#endif
+{
+#if APEX_UE4
+ PX_UNUSED(before);
+ PX_UNUSED(after);
+ PX_UNUSED(taskManager);
+#endif
+ mBeforeTickTask.setDeltaTime(deltaTime, substepSize, numSubSteps);
+}
+
+
+
+void ClothingActorImpl::submitTasksDuring(PxTaskManager* taskManager)
+{
+ taskManager->submitUnnamedTask(mDuringTickTask);
+}
+
+
+
+void ClothingActorImpl::setTaskDependenciesBefore(PxBaseTask* after)
+{
+ mBeforeTickTask.setContinuation(after);
+}
+
+
+void ClothingActorImpl::startBeforeTickTask()
+{
+ mBeforeTickTask.removeReference();
+}
+
+
+
+PxTaskID ClothingActorImpl::setTaskDependenciesDuring(PxTaskID before, PxTaskID after)
+{
+ mDuringTickTask.startAfter(before);
+ mDuringTickTask.finishBefore(after);
+
+ return mDuringTickTask.getTaskID();
+}
+
+
+#if !APEX_UE4
+void ClothingActorImpl::setFetchContinuation()
+{
+ PxTaskManager* taskManager = mClothingScene->getApexScene()->getTaskManager();
+ taskManager->submitUnnamedTask(mWaitForFetchTask);
+
+ mFetchResultsTask.setContinuation(&mWaitForFetchTask);
+
+ // reduce refcount to 1
+ mWaitForFetchTask.removeReference();
+}
+#endif
+
+
+void ClothingActorImpl::startFetchTasks()
+{
+ mFetchResultsRunningMutex.lock();
+ mFetchResultsRunning = true;
+#if APEX_UE4
+ mFetchResultsSync.reset();
+#else
+ mWaitForFetchTask.mWaiting.reset();
+#endif
+ mFetchResultsRunningMutex.unlock();
+
+#if APEX_UE4
+ PxTaskManager* taskManager = mClothingScene->getApexScene()->getTaskManager();
+ taskManager->submitUnnamedTask(mFetchResultsTask);
+#else
+ setFetchContinuation();
+#endif
+
+ mFetchResultsTask.removeReference();
+}
+
+
+
+void ClothingActorImpl::waitForFetchResults()
+{
+ mFetchResultsRunningMutex.lock();
+ if (mFetchResultsRunning)
+ {
+ PX_PROFILE_ZONE("ClothingActorImpl::waitForFetchResults", GetInternalApexSDK()->getContextId());
+#if APEX_UE4
+ mFetchResultsSync.wait();
+#else
+ mWaitForFetchTask.mWaiting.wait();
+#endif
+ syncActorData();
+ mFetchResultsRunning = false;
+
+#ifndef WITHOUT_PVD
+ updatePvd();
+#endif
+ }
+ mFetchResultsRunningMutex.unlock();
+}
+
+
+
+#if !APEX_UE4
+void ClothingWaitForFetchTask::run()
+{
+}
+
+
+
+void ClothingWaitForFetchTask::release()
+{
+ PxTask::release();
+
+ mWaiting.set();
+}
+
+
+
+const char* ClothingWaitForFetchTask::getName() const
+{
+ return "ClothingWaitForFetchTask";
+}
+#endif
+
+
+
+void ClothingActorImpl::applyTeleport(bool skinningReady, uint32_t substepNumber)
+{
+ const float teleportWeight = (bInternalTeleportDue != ClothingTeleportMode::Continuous && substepNumber == 0) ? 1.0f : 0.0f;
+ const bool teleportReset = bInternalTeleportDue == ClothingTeleportMode::TeleportAndReset;
+
+ // skinninReady is required when the teleportWeight is > 0.0
+ // != is the same as XOR, it prevents calling setTeleportWeights twice when using a normal or (||)
+ if ((mClothingSimulation != NULL) && ((teleportWeight == 0.0f) != skinningReady))
+ {
+ mClothingSimulation->setTeleportWeight(teleportWeight, teleportReset, bInternalLocalSpaceSim == 1);
+ }
+}
+
+
+
+void ClothingActorImpl::applyGlobalPose_LocksPhysX()
+{
+ if (mClothingSimulation)
+ {
+ mClothingSimulation->applyGlobalPose();
+ }
+}
+
+
+
+bool ClothingActorImpl::isValidDesc(const NvParameterized::Interface& params)
+{
+ // make this verbose!!!!
+ if (::strcmp(params.className(), ClothingActorParam::staticClassName()) == 0)
+ {
+ const ClothingActorParam& actorDescGeneric = static_cast<const ClothingActorParam&>(params);
+ const ClothingActorParamNS::ParametersStruct& actorDesc = static_cast<const ClothingActorParamNS::ParametersStruct&>(actorDescGeneric);
+
+ // commented variables don't need validation.
+ // actorDesc.actorDescTemplate
+ for (int32_t i = 0; i < actorDesc.boneMatrices.arraySizes[0]; i++)
+ {
+ if (!actorDesc.boneMatrices.buf[i].isFinite())
+ {
+ APEX_INVALID_PARAMETER("boneMatrices[%d] is not finite!", i);
+ return false;
+ }
+ }
+ // actorDesc.clothDescTemplate
+ // actorDesc.fallbackSkinning
+ // actorDesc.flags.ParallelCpuSkinning
+ // actorDesc.flags.ParallelMeshMeshSkinning
+ // actorDesc.flags.ParallelPhysxMeshSkinning
+ // actorDesc.flags.RecomputeNormals
+ // actorDesc.flags.Visualize
+ if (!actorDesc.globalPose.isFinite())
+ {
+ APEX_INVALID_PARAMETER("globalPose is not finite!");
+ return false;
+ }
+
+ if (actorDesc.maxDistanceBlendTime < 0.0f)
+ {
+ APEX_INVALID_PARAMETER("maxDistanceBlendTime must be positive");
+ return false;
+ }
+
+ if (actorDesc.maxDistanceScale.Scale < 0.0f || actorDesc.maxDistanceScale.Scale > 1.0f)
+ {
+ APEX_INVALID_PARAMETER("maxDistanceScale.Scale must be in the [0.0, 1.0] interval (is %f)",
+ actorDesc.maxDistanceScale.Scale);
+ return false;
+ }
+
+ // actorDesc.shapeDescTemplate
+ // actorDesc.slowStart
+ // actorDesc.updateStateWithGlobalMatrices
+ // actorDesc.useHardwareCloth
+ // actorDesc.useInternalBoneOrder
+ // actorDesc.userData
+ // actorDesc.uvChannelForTangentUpdate
+ if (actorDesc.windParams.Adaption < 0.0f)
+ {
+ APEX_INVALID_PARAMETER("windParams.Adaption must be positive or zero");
+ return false;
+ }
+ // actorDesc.windParams.Velocity
+
+ if (actorDesc.actorScale <= 0.0f)
+ {
+ APEX_INVALID_PARAMETER("ClothingActorParam::actorScale must be bigger than 0 (is %f)", actorDesc.actorScale);
+ return false;
+ }
+
+ return true;
+ }
+ else if (::strcmp(params.className(), ClothingPreviewParam::staticClassName()) == 0)
+ {
+ const ClothingPreviewParam& previewDescGeneric = static_cast<const ClothingPreviewParam&>(params);
+ const ClothingPreviewParamNS::ParametersStruct& previewDesc = static_cast<const ClothingPreviewParamNS::ParametersStruct&>(previewDescGeneric);
+
+
+ for (int32_t i = 0; i < previewDesc.boneMatrices.arraySizes[0]; i++)
+ {
+ if (!previewDesc.boneMatrices.buf[i].isFinite())
+ {
+ APEX_INVALID_PARAMETER("boneMatrices[%d] is not finite!", i);
+ return false;
+ }
+ }
+
+ if (!previewDesc.globalPose.isFinite())
+ {
+ APEX_INVALID_PARAMETER("globalPose is not finite!");
+ return false;
+ }
+
+ return true;
+ }
+ return false;
+}
+
+
+
+ClothingCookedParam* ClothingActorImpl::getRuntimeCookedDataPhysX()
+{
+ if (mActorDesc->runtimeCooked != NULL && ::strcmp(mActorDesc->runtimeCooked->className(), ClothingCookedParam::staticClassName()) == 0)
+ {
+ return static_cast<ClothingCookedParam*>(mActorDesc->runtimeCooked);
+ }
+
+ return NULL;
+}
+
+
+
+// ------ private methods -------
+
+
+void ClothingActorImpl::updateBoneBuffer(ClothingRenderProxyImpl* renderProxy)
+{
+ if (renderProxy == NULL)
+ return;
+
+ renderProxy->setPose(getRenderGlobalPose());
+
+ RenderMeshActor* meshActor = renderProxy->getRenderMeshActor();
+ if (meshActor == NULL)
+ return;
+
+ if (mData.mInternalBoneMatricesCur == NULL)
+ {
+ // no bones
+ PxMat44 pose = PxMat44(PxIdentity);
+ if (mClothingSimulation == NULL)
+ {
+ // no sim
+ if (bInternalLocalSpaceSim == 1)
+ {
+ pose = PxMat44(PxIdentity) * mActorDesc->actorScale;
+ }
+ else
+ {
+ pose = mInternalGlobalPose;
+ }
+ }
+
+ meshActor->setTM(pose, 0);
+ }
+ else /*if (bBoneBufferDirty)*/ // this dirty flag can only be used if we know that the
+ // render mesh asset stays with the clothing actor
+ // reactivate when APEX-43 is fixed. Note that currently
+ // the flag is set every frame in removePhysX_LocksPhysX
+ // when simulation is disabled, so the flag is
+ // currently not too useful
+ {
+ // bones or simulation have changed
+ PxMat44* buffer = mData.mInternalBoneMatricesCur;
+ PX_ASSERT(buffer != NULL);
+
+ if (mAsset->getNumUsedBonesForMesh() == 1 && mClothingSimulation != NULL)
+ {
+ meshActor->setTM(PxMat44(PxIdentity), 0);
+ }
+ else
+ {
+ const uint32_t numBones = PxMin(mAsset->getNumUsedBonesForMesh(), meshActor->getBoneCount());
+ for (uint32_t i = 0; i < numBones; i++)
+ {
+ meshActor->setTM(buffer[i], i);
+ }
+ }
+ }
+
+ bBoneBufferDirty = 0;
+}
+
+
+
+PxBounds3 ClothingActorImpl::getRenderMeshAssetBoundsTransformed()
+{
+ PxBounds3 newBounds = mAsset->getBoundingBox();
+
+ PxMat44 transformation;
+ if (mData.mInternalBoneMatricesCur != NULL)
+ {
+ transformation = mData.mInternalBoneMatricesCur[mAsset->getRootBoneIndex()];
+ }
+ else
+ {
+ transformation = mActorDesc->globalPose;
+ }
+
+ if (!newBounds.isEmpty())
+ {
+ const PxVec3 center = transformation.transform(newBounds.getCenter());
+ const PxVec3 extent = newBounds.getExtents();
+ const PxMat33 basis(transformation.column0.getXYZ(), transformation.column1.getXYZ(), transformation.column2.getXYZ());
+
+ return PxBounds3::basisExtent(center, basis, extent);
+ }
+ else
+ {
+ return newBounds;
+ }
+}
+
+
+
+bool ClothingActorImpl::allocateEnoughBoneBuffers_NoPhysX(bool prepareForSubstepping)
+{
+ PX_ASSERT(mActorDesc != NULL);
+ const uint32_t numBones = mActorDesc->useInternalBoneOrder ? mAsset->getNumUsedBones() : mAsset->getNumBones();
+
+ if (prepareForSubstepping && mInternalInterpolatedBoneMatrices == NULL)
+ {
+ mInternalInterpolatedBoneMatrices = (PxMat44*)PX_ALLOC(sizeof(PxMat44) * numBones, "mInternalInterpolatedBoneMatrices");
+ }
+
+ if (mData.mInternalBoneMatricesCur == NULL)
+ {
+ mData.mInternalBoneMatricesCur = (PxMat44*)PX_ALLOC(sizeof(PxMat44) * numBones, "mInternalBoneMatrices");
+ mData.mInternalBoneMatricesPrev = (PxMat44*)PX_ALLOC(sizeof(PxMat44) * numBones, "mInternalBoneMatrices2");
+ intrinsics::memSet(mData.mInternalBoneMatricesCur, 0, sizeof(PxMat44) * numBones);
+ intrinsics::memSet(mData.mInternalBoneMatricesPrev, 0, sizeof(PxMat44) * numBones);
+ return true;
+ }
+
+ return false;
+}
+
+
+
+bool ClothingActorImpl::isSimulationRunning() const
+{
+ if (mClothingScene != NULL)
+ {
+ return mClothingScene->isSimulating(); // virtual call
+ }
+
+ return false;
+}
+
+
+
+void ClothingActorImpl::updateStateInternal_NoPhysX(bool prepareForSubstepping)
+{
+ PX_ASSERT(mActorDesc);
+ mInternalFlags = mActorDesc->flags;
+
+ mInternalMaxDistanceBlendTime = (mActorDesc->freezeByLOD) ? 0.0f : mActorDesc->maxDistanceBlendTime;
+
+ mInternalWindParams = mActorDesc->windParams;
+
+ bInternalVisible = bBufferedVisible;
+ if (bUpdateFrozenFlag == 1)
+ {
+ bInternalFrozen = bBufferedFrozen;
+ bUpdateFrozenFlag = 0;
+ }
+
+ // update teleportation from double buffering
+ bInternalTeleportDue = (ClothingTeleportMode::Enum)mActorDesc->teleportMode;
+ mActorDesc->teleportMode = ClothingTeleportMode::Continuous;
+
+ if (mActorDesc->localSpaceSim != (bInternalLocalSpaceSim == 1))
+ {
+ bInternalTeleportDue = ClothingTeleportMode::TeleportAndReset;
+ }
+ bInternalLocalSpaceSim = mActorDesc->localSpaceSim ? 1u : 0u;
+
+ bMaxDistanceScaleChanged =
+ (mInternalMaxDistanceScale.Scale != mActorDesc->maxDistanceScale.Scale ||
+ mInternalMaxDistanceScale.Multipliable != mActorDesc->maxDistanceScale.Multipliable)
+ ? 1u : 0u;
+
+ mInternalMaxDistanceScale = mActorDesc->maxDistanceScale;
+
+ lockRenderResources();
+
+ PxMat44 globalPose = mActorDesc->globalPose;
+
+ PxMat44 rootBoneTransform = PxMat44(PxIdentity);
+ const float invActorScale = 1.0f / mActorDesc->actorScale;
+ bool bHasBones = mActorDesc->boneMatrices.arraySizes[0] > 0 || mAsset->getNumBones() > 0;
+ bool bMultiplyGlobalPoseIntoBones = mActorDesc->multiplyGlobalPoseIntoBones || mActorDesc->boneMatrices.arraySizes[0] == 0;
+ if (bHasBones)
+ {
+ bool newBuffers = allocateEnoughBoneBuffers_NoPhysX(prepareForSubstepping);
+
+ nvidia::swap(mData.mInternalBoneMatricesCur, mData.mInternalBoneMatricesPrev);
+
+ const uint32_t numBones = (mActorDesc->useInternalBoneOrder) ? mAsset->getNumUsedBones() : mAsset-> getNumBones();
+
+ uint32_t rootNodeExternalIndex = mActorDesc->useInternalBoneOrder ? mAsset->getRootBoneIndex() : mAsset->getBoneExternalIndex(mAsset->getRootBoneIndex());
+ if (rootNodeExternalIndex < (uint32_t)mActorDesc->boneMatrices.arraySizes[0])
+ {
+ // new pose of root bone available
+ rootBoneTransform = mActorDesc->boneMatrices.buf[rootNodeExternalIndex];
+ }
+ else if (mActorDesc->updateStateWithGlobalMatrices)
+ {
+ // no pose for root bone available, use bind pose
+ mAsset->getBoneBasePose(mAsset->getRootBoneIndex(), rootBoneTransform);
+ }
+
+ PxMat44 pose = PxMat44(PxIdentity);
+ if (bInternalLocalSpaceSim == 1)
+ {
+ // consider the root bone as local space reference
+ // PH: Note that inverseRT does not invert the scale, but preserve it
+
+ // normalize (dividing by actorscale is not precise enough)
+ if (!bMultiplyGlobalPoseIntoBones)
+ {
+ rootBoneTransform.column0.normalize();
+ rootBoneTransform.column1.normalize();
+ rootBoneTransform.column2.normalize();
+ }
+
+ // this transforms the skeleton into origin, and keeps the scale
+ PxMat44 invRootBoneTransformTimesScale = rootBoneTransform.inverseRT();
+
+ if (bMultiplyGlobalPoseIntoBones)
+ {
+ invRootBoneTransformTimesScale *= mActorDesc->actorScale;
+ }
+
+ // the result will be transformed back to global space in rendering
+ pose = invRootBoneTransformTimesScale;
+ }
+ else if (bMultiplyGlobalPoseIntoBones)
+ {
+ pose = globalPose;
+ }
+
+ if (mActorDesc->boneMatrices.arraySizes[0] >= (int32_t)numBones)
+ {
+ // TODO when no globalPose is set and the bones are given internal, there could be a memcpy
+ if (mAsset->writeBoneMatrices(pose, mActorDesc->boneMatrices.buf, sizeof(PxMat44), (uint32_t)mActorDesc->boneMatrices.arraySizes[0],
+ mData.mInternalBoneMatricesCur, mActorDesc->useInternalBoneOrder, mActorDesc->updateStateWithGlobalMatrices))
+ {
+ bBoneMatricesChanged = 1;
+ }
+ }
+ else
+ {
+ // no matrices provided. mInternalBoneMatrices (skinningMatrices) should just reflect the
+ // the global pose transform
+
+ for (uint32_t i = 0; i < numBones; i++)
+ {
+ mData.mInternalBoneMatricesCur[i] = pose;
+ }
+ }
+
+ if (newBuffers)
+ {
+ memcpy(mData.mInternalBoneMatricesPrev, mData.mInternalBoneMatricesCur, sizeof(PxMat44) * numBones);
+ }
+ }
+ else if (mData.mInternalBoneMatricesCur != NULL)
+ {
+ PX_FREE(mData.mInternalBoneMatricesCur);
+ PX_FREE(mData.mInternalBoneMatricesPrev);
+ mData.mInternalBoneMatricesCur = mData.mInternalBoneMatricesPrev = NULL;
+ }
+
+ unlockRenderResources();
+
+ PxMat44 newInternalGlobalPose;
+ if (bInternalLocalSpaceSim == 1)
+ {
+ // transform back into global space:
+ if (bMultiplyGlobalPoseIntoBones || !bHasBones)
+ {
+ // we need to remove the scale when transforming back, as we keep the scale in local space
+ // hmm, not sure why the adjustments on the translation parts are necessary, but they are..
+ globalPose *= invActorScale;
+ rootBoneTransform.scale(PxVec4(1.0f, 1.0f, 1.0f, mActorDesc->actorScale));
+ newInternalGlobalPose = globalPose * rootBoneTransform;
+ }
+ else
+ {
+ newInternalGlobalPose = rootBoneTransform;
+ }
+ }
+ else
+ {
+ newInternalGlobalPose = globalPose;
+ }
+
+ mOldInternalGlobalPose = mOldInternalGlobalPose.column0.isZero() ? newInternalGlobalPose : mInternalGlobalPose;
+ mInternalGlobalPose = newInternalGlobalPose;
+
+ bGlobalPoseChanged = (mInternalGlobalPose != mOldInternalGlobalPose) ? 1u : 0u;
+
+ // set bBoneBufferDirty to 1 if any matrices have changed
+ bBoneBufferDirty = (bGlobalPoseChanged == 1) || (bBoneMatricesChanged == 1) || (bBoneBufferDirty == 1) ? 1u : 0u;
+}
+
+
+
+#define RENDER_DEBUG_INTERMEDIATE_STEPS 0
+
+template<bool withBackstop>
+void ClothingActorImpl::skinPhysicsMeshInternal(bool useInterpolatedMatrices, float substepFraction)
+{
+#if RENDER_DEBUG_INTERMEDIATE_STEPS
+ const float RenderDebugIntermediateRadius = 0.8f;
+ mClothingScene->mRenderDebug->setCurrentDisplayTime(0.1);
+ const uint8_t yellowColor = 255 - (uint8_t)(255.0f * substepFraction);
+ const uint32_t color = 0xff0000 | yellowColor << 8;
+ mClothingScene->mRenderDebug->setCurrentColor(color);
+#else
+ PX_UNUSED(substepFraction);
+#endif
+
+ uint32_t morphOffset = mAsset->getPhysicalMeshOffset(mAsset->getPhysicalMeshID(mCurrentGraphicalLodId));
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type* physicalMesh = mAsset->getPhysicalMeshFromLod(mCurrentGraphicalLodId);
+ PxVec3* morphedPositions = mActorDesc->morphPhysicalMeshNewPositions.buf;
+ const PxVec3* const PX_RESTRICT positions = morphedPositions != NULL ? morphedPositions + morphOffset : physicalMesh->vertices.buf;
+ const PxVec3* const PX_RESTRICT normals = physicalMesh->normals.buf;
+ const ClothingPhysicalMeshParametersNS::ConstrainCoefficient_Type* const PX_RESTRICT coeffs = physicalMesh->constrainCoefficients.buf;
+ const float actorScale = mActorDesc->actorScale;
+
+ const uint32_t numVertices = physicalMesh->numSimulatedVertices;
+ const uint32_t numBoneIndicesPerVertex = physicalMesh->numBonesPerVertex;
+
+ PxVec3* const PX_RESTRICT targetPositions = mClothingSimulation->skinnedPhysicsPositions;
+ PxVec3* const PX_RESTRICT targetNormals = mClothingSimulation->skinnedPhysicsNormals;
+
+ const uint32_t numPrefetches = ((numVertices + NUM_VERTICES_PER_CACHE_BLOCK - 1) / NUM_VERTICES_PER_CACHE_BLOCK);
+
+ if (mData.mInternalBoneMatricesCur == NULL || numBoneIndicesPerVertex == 0)
+ {
+ PxMat44 matrix = PxMat44(PxIdentity);
+ if (bInternalLocalSpaceSim == 1)
+ {
+ matrix *= actorScale;
+ }
+ else
+ {
+ // PH: maybe we can skip the matrix multiplication altogether when using local space sim?
+ matrix = useInterpolatedMatrices ? mInternalInterpolatedGlobalPose : mInternalGlobalPose;
+ }
+ for (uint32_t i = 0; i < numVertices; i++)
+ {
+ //const PxVec3 untransformedPosition = positions[index] + morphReordering == NULL ? PxVec3(0.0f) : morphDisplacements[morphReordering[index]];
+ targetPositions[i] = matrix.transform(positions[i]);
+ targetNormals[i] = matrix.rotate(normals[i]);
+
+ if (withBackstop)
+ {
+ if (coeffs[i].collisionSphereDistance < 0.0f)
+ {
+ targetPositions[i] -= (coeffs[i].collisionSphereDistance * actorScale) * targetNormals[i];
+ }
+ }
+#if RENDER_DEBUG_INTERMEDIATE_STEPS
+ if (RenderDebugIntermediateRadius > 0.0f)
+ {
+ mClothingScene->mRenderDebug->debugPoint(targetPositions[i], RenderDebugIntermediateRadius);
+ }
+#endif
+ }
+ }
+ else
+ {
+ const uint16_t* const PX_RESTRICT simBoneIndices = physicalMesh->boneIndices.buf;
+ const float* const PX_RESTRICT simBoneWeights = physicalMesh->boneWeights.buf;
+ const PxMat44* matrices = useInterpolatedMatrices ? mInternalInterpolatedBoneMatrices : mData.mInternalBoneMatricesCur;
+
+ const uint8_t* const PX_RESTRICT optimizationData = physicalMesh->optimizationData.buf;
+ PX_ASSERT(optimizationData != NULL);
+ PX_ASSERT((int32_t)(numPrefetches * NUM_VERTICES_PER_CACHE_BLOCK) / 2 <= physicalMesh->optimizationData.arraySizes[0]);
+
+ uint32_t vertexIndex = 0;
+ for (uint32_t i = 0; i < numPrefetches; ++i)
+ {
+ // HL: i tried to put positions and normals into a 16 byte aligned struct
+ // but there was no significant perf benefit, and it caused a lot of adaptations
+ // in the code because of the introduction of strides. Had to use
+ // a stride iterators in AbstractMeshDescription, which made
+ // its usage slower on xbox
+
+ uint8_t* cache = (uint8_t*)((((size_t)(positions + vertexIndex + NUM_VERTICES_PER_CACHE_BLOCK)) >> 7) << 7);
+ prefetchLine(cache);
+ //prefetchLine(cache + 128);
+
+ cache = (uint8_t*)((((size_t)(normals + vertexIndex + NUM_VERTICES_PER_CACHE_BLOCK)) >> 7) << 7);
+ prefetchLine(cache);
+ //prefetchLine(cache + 128);
+
+ cache = (uint8_t*)((((size_t)(&simBoneWeights[(vertexIndex + NUM_VERTICES_PER_CACHE_BLOCK) * numBoneIndicesPerVertex])) >> 7) << 7);
+ prefetchLine(cache);
+ prefetchLine(cache + 128);
+
+ cache = (uint8_t*)((((size_t)(&simBoneIndices[(vertexIndex + NUM_VERTICES_PER_CACHE_BLOCK) * numBoneIndicesPerVertex])) >> 7) << 7);
+ prefetchLine(cache);
+ //prefetchLine(cache + 128);
+
+
+ if (withBackstop)
+ {
+ prefetchLine(&coeffs[vertexIndex + NUM_VERTICES_PER_CACHE_BLOCK]);
+ }
+
+ for (uint32_t j = 0; j < NUM_VERTICES_PER_CACHE_BLOCK; ++j)
+ {
+ //float sumWeights = 0.0f; // this is just for sanity
+
+ Simd4f positionV = gSimd4fZero;
+ Simd4f normalV = gSimd4fZero;
+
+ const uint8_t shift = 4 * (vertexIndex % 2);
+ const uint8_t numBones = uint8_t((optimizationData[vertexIndex / 2] >> shift) & 0x7);
+ for (uint32_t k = 0; k < numBones; k++)
+ {
+ const float weight = simBoneWeights[vertexIndex * numBoneIndicesPerVertex + k];
+
+ PX_ASSERT(weight <= 1.0f);
+
+ //sumWeights += weight;
+ Simd4f weightV = Simd4fScalarFactory(weight);
+
+ const uint32_t index = simBoneIndices[vertexIndex * numBoneIndicesPerVertex + k];
+ PX_ASSERT(index < mAsset->getNumUsedBones());
+
+ /// PH: This might be faster without the reference, but on PC I can't tell
+ /// HL: Now with SIMD it's significantly faster as reference
+ const PxMat44& bone = (PxMat44&)matrices[index];
+
+ Simd4f pV = applyAffineTransform(bone, createSimd3f(positions[vertexIndex]));
+ pV = pV * weightV;
+ positionV = positionV + pV;
+
+ ///todo There are probably cases where we don't need the normal on the physics mesh
+ Simd4f nV = applyLinearTransform(bone, createSimd3f(normals[vertexIndex]));
+ nV = nV * weightV;
+ normalV = normalV + nV;
+ }
+
+ // PH: Sanity test. if this is not fulfilled, skinning went awfully wrong anyways
+ // TODO do this check only once somewhere at initialization
+ //PX_ASSERT(sumWeights == 0.0f || (sumWeights > 0.9999f && sumWeights < 1.0001f));
+
+ normalV = normalV * rsqrt(dot3(normalV, normalV));
+ store3(&targetNormals[vertexIndex].x, normalV);
+ PX_ASSERT(numBones == 0 || targetNormals[vertexIndex].isFinite());
+
+ // We disabled this in skinToBones as well, cause it's not really a valid case
+ //if (sumWeights == 0)
+ // positionV = V3LoadU(positions[vertexIndex]);
+
+ // in case of a negative collision sphere distance we move the animated position upwards
+ // along the normal and set the collision sphere distance to zero.
+ if (withBackstop)
+ {
+ if ((optimizationData[vertexIndex / 2] >> shift) & 0x8)
+ {
+ const float collisionSphereDistance = coeffs[vertexIndex].collisionSphereDistance;
+ Simd4f dV = normalV * Simd4fScalarFactory(collisionSphereDistance * actorScale);
+ positionV = positionV - dV;
+ }
+ }
+
+ store3(&targetPositions[vertexIndex].x, positionV);
+ PX_ASSERT(targetPositions[vertexIndex].isFinite());
+
+#if RENDER_DEBUG_INTERMEDIATE_STEPS
+ if (RenderDebugIntermediateRadius > 0.0f)
+ {
+ mClothingScene->mRenderDebug->debugPoint(targetPositions[vertexIndex], RenderDebugIntermediateRadius);
+ }
+#endif
+
+ ++vertexIndex;
+ }
+ }
+ }
+#if RENDER_DEBUG_INTERMEDIATE_STEPS
+ mClothingScene->mRenderDebug->setCurrentDisplayTime();
+#endif
+}
+
+
+
+void ClothingActorImpl::fetchResults()
+{
+ PX_PROFILE_ZONE("ClothingActorImpl::fetchResults", GetInternalApexSDK()->getContextId());
+ if (isVisible() && mClothingSimulation != NULL && bInternalFrozen == 0)
+ {
+ mClothingSimulation->fetchResults(mInternalFlags.ComputePhysicsMeshNormals);
+ }
+}
+
+
+
+ClothingActorData& ClothingActorImpl::getActorData()
+{
+ return mData;
+}
+
+
+
+void ClothingActorImpl::initializeActorData()
+{
+ PX_PROFILE_ZONE("ClothingActorImpl::initializeActorData", GetInternalApexSDK()->getContextId());
+
+ mData.bIsClothingSimulationNull = mClothingSimulation == NULL;
+ const bool bUninit = mData.bIsInitialized && mClothingSimulation == NULL;
+ if (bReinitActorData == 1 || bUninit)
+ {
+ //We need to uninitialize ourselves
+ PX_FREE(mData.mAsset.mData);
+ mData.mAsset.mData = NULL;
+ mData.bIsInitialized = false;
+ bReinitActorData = 0;
+
+ if (bUninit)
+ {
+ return;
+ }
+ }
+
+ if(mGraphicalMeshes[mCurrentGraphicalLodId].renderProxy != NULL)
+ {
+ mData.mRenderingDataPosition = mGraphicalMeshes[mCurrentGraphicalLodId].renderProxy->renderingDataPosition;
+ mData.mRenderingDataNormal = mGraphicalMeshes[mCurrentGraphicalLodId].renderProxy->renderingDataNormal;
+ mData.mRenderingDataTangent = mGraphicalMeshes[mCurrentGraphicalLodId].renderProxy->renderingDataTangent;
+ }
+
+ if (!mData.bIsInitialized && mClothingSimulation != NULL)
+ {
+ mData.bIsInitialized = true;
+ //Initialize
+ mData.mRenderLock = mRenderDataLock;
+
+ mData.mSdkDeformableVerticesCount = mClothingSimulation->sdkNumDeformableVertices;
+ mData.mSdkDeformableIndicesCount = mClothingSimulation->sdkNumDeformableIndices;
+ mData.mSdkWritebackPositions = mClothingSimulation->sdkWritebackPosition;
+ mData.mSdkWritebackNormal = mClothingSimulation->sdkWritebackNormal;
+
+ mData.mSkinnedPhysicsPositions = mClothingSimulation->skinnedPhysicsPositions;
+ mData.mSkinnedPhysicsNormals = mClothingSimulation->skinnedPhysicsNormals;
+
+ //Allocate the clothing asset now...
+
+ mAsset->initializeAssetData(mData.mAsset, mActorDesc->uvChannelForTangentUpdate);
+
+ mData.mMorphDisplacementBuffer = mActorDesc->morphDisplacements.buf;
+ mData.mMorphDisplacementBufferCount = (uint32_t)mActorDesc->morphDisplacements.arraySizes[0];
+ }
+
+ uint32_t largestSubmesh = 0;
+ if (mData.bIsInitialized && mClothingSimulation != NULL)
+ {
+ mData.bRecomputeNormals = mInternalFlags.RecomputeNormals;
+ mData.bRecomputeTangents = mInternalFlags.RecomputeTangents;
+ mData.bIsSimulationMeshDirty = mClothingSimulation->isSimulationMeshDirty();
+
+ // this updates per-frame so I need to sync it every frame
+ mData.mInternalGlobalPose = mInternalGlobalPose;
+ mData.mCurrentGraphicalLodId = mCurrentGraphicalLodId;
+
+ for (uint32_t a = 0; a < mData.mAsset.mGraphicalLodsCount; ++a)
+ {
+ ClothingMeshAssetData* pLod = mData.mAsset.GetLod(a);
+ pLod->bActive = mGraphicalMeshes[a].active;
+ pLod->bNeedsTangents = mGraphicalMeshes[a].needsTangents;
+
+ // check if map contains tangent values, otherwise print out warning
+ if (!mData.bRecomputeTangents && mGraphicalMeshes[a].needsTangents && pLod->mImmediateClothMap != NULL)
+ {
+ // tangentBary has been marked invalid during asset update, or asset has immediate map (without tangent info)
+ mData.bRecomputeTangents = true;
+ mInternalFlags.RecomputeTangents = true;
+ mActorDesc->flags.RecomputeTangents = true;
+
+ // hm, let's not spam the user, as RecomputeTangents is off by default
+ //APEX_DEBUG_INFO("Asset (%s) does not support tangent skinning. Resetting RecomputeTangents to true.", mAsset->getName());
+ }
+
+ //Copy to...
+
+ for (uint32_t b = 0; b < pLod->mSubMeshCount; b++)
+ {
+ ClothingAssetSubMesh* submesh = mData.mAsset.GetSubmesh(a, b);
+
+ const uint32_t numParts = (uint32_t)mAsset->getGraphicalLod(a)->physicsMeshPartitioning.arraySizes[0];
+ ClothingGraphicalLodParametersNS::PhysicsMeshPartitioning_Type* parts = mAsset->getGraphicalLod(a)->physicsMeshPartitioning.buf;
+
+#if defined _DEBUG || PX_CHECKED
+ bool found = false;
+#endif
+ for (uint32_t c = 0; c < numParts; c++)
+ {
+ if (parts[c].graphicalSubmesh == b)
+ {
+ submesh->mCurrentMaxVertexSimulation = parts[c].numSimulatedVertices;
+ submesh->mCurrentMaxVertexAdditionalSimulation = parts[c].numSimulatedVerticesAdditional;
+ submesh->mCurrentMaxIndexSimulation = parts[c].numSimulatedIndices;
+
+ largestSubmesh = PxMax(largestSubmesh, parts[c].numSimulatedVerticesAdditional);
+#if defined _DEBUG || PX_CHECKED
+ found = true;
+#endif
+ break;
+ }
+ }
+#if defined _DEBUG || PX_CHECKED
+ PX_ASSERT(found);
+#endif
+ }
+ }
+ mData.mActorScale = mActorDesc->actorScale;
+
+ mData.bShouldComputeRenderData = shouldComputeRenderData();
+ mData.bInternalFrozen = bInternalFrozen;
+ mData.bCorrectSimulationNormals = mInternalFlags.CorrectSimulationNormals;
+ mData.bParallelCpuSkinning = mInternalFlags.ParallelCpuSkinning;
+ mData.mGlobalPose = mActorDesc->globalPose;
+
+ mData.mInternalMatricesCount = mActorDesc->useInternalBoneOrder ? mAsset->getNumUsedBones() : mAsset->getNumBones();
+ }
+
+}
+
+void ClothingActorImpl::syncActorData()
+{
+ PX_PROFILE_ZONE("ClothingActorImpl::syncActorData", GetInternalApexSDK()->getContextId());
+
+ if (mData.bIsInitialized && mData.bShouldComputeRenderData && mClothingSimulation != NULL /*&& bInternalFrozen == 0*/)
+ {
+ PX_ASSERT(!mData.mNewBounds.isEmpty());
+ PX_ASSERT(mData.mNewBounds.isFinite());
+
+ //Write back all the modified variables so that the simulation is consistent
+ mNewBounds = mData.mNewBounds;
+ }
+ else
+ {
+ mNewBounds = getRenderMeshAssetBoundsTransformed();
+ }
+
+ if (bInternalLocalSpaceSim == 1)
+ {
+#if _DEBUG
+ bool ok = true;
+ ok &= mInternalGlobalPose.column0.isNormalized();
+ ok &= mInternalGlobalPose.column1.isNormalized();
+ ok &= mInternalGlobalPose.column2.isNormalized();
+ if (!ok)
+ {
+ APEX_DEBUG_WARNING("Internal Global Pose is not normalized (Scale: %f %f %f). Bounds could be wrong.", mInternalGlobalPose.column0.magnitude(), mInternalGlobalPose.column1.magnitude(), mInternalGlobalPose.column2.magnitude());
+ }
+#endif
+ PX_ASSERT(!mNewBounds.isEmpty());
+ mRenderBounds = PxBounds3::transformFast(PxTransform(mInternalGlobalPose), mNewBounds);
+ }
+ else
+ {
+ mRenderBounds = mNewBounds;
+ }
+
+ markRenderProxyReady();
+}
+
+
+
+void ClothingActorImpl::markRenderProxyReady()
+{
+ PX_PROFILE_ZONE("ClothingActorImpl::markRenderProxyReady", GetInternalApexSDK()->getContextId());
+ mRenderProxyMutex.lock();
+ if (mRenderProxyReady != NULL)
+ {
+ // user didn't request the renderable after fetchResults,
+ // let's release it, so it can be reused
+ mRenderProxyReady->release();
+ }
+
+ ClothingRenderProxyImpl* renderProxy = mGraphicalMeshes[mCurrentGraphicalLodId].renderProxy;
+ if (renderProxy != NULL)
+ {
+ updateBoneBuffer(renderProxy);
+ mGraphicalMeshes[mCurrentGraphicalLodId].renderProxy = NULL;
+ renderProxy->setBounds(mRenderBounds);
+ }
+
+ mRenderProxyReady = renderProxy;
+ mRenderProxyMutex.unlock();
+}
+
+
+
+void ClothingActorImpl::fillWritebackData_LocksPhysX(const WriteBackInfo& writeBackInfo)
+{
+ PX_ASSERT(mClothingSimulation != NULL);
+ PX_ASSERT(mClothingSimulation->physicalMeshId != 0xffffffff);
+ PX_ASSERT(writeBackInfo.simulationDelta >= 0.0f);
+
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type* destPhysicalMesh = mAsset->getPhysicalMeshFromLod(mCurrentGraphicalLodId);
+
+ // copy the data from the old mesh
+ // use bigger position buffer as temp buffer
+ uint32_t numCopyVertices = 0;
+ PxVec3* velocities = NULL;
+
+ float transitionMapThickness = 0.0f;
+ float transitionMapOffset = 0.0f;
+ const ClothingPhysicalMeshParametersNS::SkinClothMapB_Type* pTCMB = NULL;
+ const ClothingPhysicalMeshParametersNS::SkinClothMapD_Type* pTCM = NULL;
+ if (writeBackInfo.oldSimulation)
+ {
+ PX_ASSERT(writeBackInfo.oldSimulation->physicalMeshId != 0xffffffff);
+ pTCMB = mAsset->getTransitionMapB(mClothingSimulation->physicalMeshId, writeBackInfo.oldSimulation->physicalMeshId, transitionMapThickness, transitionMapOffset);
+ pTCM = mAsset->getTransitionMap(mClothingSimulation->physicalMeshId, writeBackInfo.oldSimulation->physicalMeshId, transitionMapThickness, transitionMapOffset);
+ }
+
+ if (pTCMB != NULL || pTCM != NULL)
+ {
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type* srcPhysicalMesh = mAsset->getPhysicalMeshFromLod(writeBackInfo.oldGraphicalLodId);
+ PX_ASSERT(srcPhysicalMesh != NULL);
+
+ AbstractMeshDescription srcPM;
+ srcPM.numIndices = writeBackInfo.oldSimulation->sdkNumDeformableIndices;
+ srcPM.numVertices = writeBackInfo.oldSimulation->sdkNumDeformableVertices;
+ srcPM.pIndices = srcPhysicalMesh->indices.buf;
+ srcPM.pNormal = writeBackInfo.oldSimulation->sdkWritebackNormal;
+ srcPM.pPosition = writeBackInfo.oldSimulation->sdkWritebackPosition;
+ srcPM.avgEdgeLength = transitionMapThickness;
+
+ // new position and normal buffer will be initialized afterwards, buffer can be used here
+ if (mClothingSimulation->sdkNumDeformableVertices > writeBackInfo.oldSimulation->sdkNumDeformableVertices)
+ {
+ transferVelocities_LocksPhysX(*writeBackInfo.oldSimulation, pTCMB, pTCM, destPhysicalMesh->numVertices, srcPM.pIndices, srcPM.numIndices, srcPM.numVertices,
+ mClothingSimulation->sdkWritebackPosition, mClothingSimulation->sdkWritebackNormal, writeBackInfo.simulationDelta);
+ }
+
+ // PH: sdkWritebackPosition will contain qnans for the values that have not been written.
+ intrinsics::memSet(mClothingSimulation->sdkWritebackPosition, 0xff, sizeof(PxVec3) * mClothingSimulation->sdkNumDeformableVertices);
+
+ if (pTCMB != NULL)
+ {
+ numCopyVertices = mData.mAsset.skinClothMapB(mClothingSimulation->sdkWritebackPosition, mClothingSimulation->sdkWritebackNormal,
+ mClothingSimulation->sdkNumDeformableVertices, srcPM, (ClothingGraphicalLodParametersNS::SkinClothMapB_Type*)pTCMB, destPhysicalMesh->numVertices, true);
+ }
+ else
+ {
+ numCopyVertices = mData.mAsset.skinClothMap<true>(mClothingSimulation->sdkWritebackPosition, mClothingSimulation->sdkWritebackNormal, NULL, mClothingSimulation->sdkNumDeformableVertices,
+ srcPM, (ClothingGraphicalLodParametersNS::SkinClothMapD_Type*)pTCM, destPhysicalMesh->numVertices, transitionMapOffset, mActorDesc->actorScale);
+ }
+
+ // don't need old positions and normals anymore
+ if (writeBackInfo.oldSimulation->sdkNumDeformableVertices >= mClothingSimulation->sdkNumDeformableVertices)
+ {
+ transferVelocities_LocksPhysX(*writeBackInfo.oldSimulation, pTCMB, pTCM, destPhysicalMesh->numVertices, srcPM.pIndices, srcPM.numIndices, srcPM.numVertices,
+ writeBackInfo.oldSimulation->sdkWritebackPosition, writeBackInfo.oldSimulation->sdkWritebackNormal, writeBackInfo.simulationDelta);
+ }
+ }
+ else if (writeBackInfo.oldSimulation != NULL && writeBackInfo.oldSimulation->physicalMeshId == mClothingSimulation->physicalMeshId)
+ {
+ if (writeBackInfo.oldSimulation->sdkNumDeformableVertices < mClothingSimulation->sdkNumDeformableVertices)
+ {
+ // old is smaller
+ numCopyVertices = writeBackInfo.oldSimulation->sdkNumDeformableVertices;
+ velocities = mClothingSimulation->sdkWritebackPosition;
+ copyAndComputeVelocities_LocksPhysX(numCopyVertices, writeBackInfo.oldSimulation, velocities, writeBackInfo.simulationDelta);
+
+ // PH: sdkWritebackPosition will contain qnans for the values that have not been written.
+ intrinsics::memSet(mClothingSimulation->sdkWritebackPosition, 0xff, sizeof(PxVec3) * mClothingSimulation->sdkNumDeformableVertices);
+
+ copyPositionAndNormal_NoPhysX(numCopyVertices, writeBackInfo.oldSimulation);
+ }
+ else
+ {
+ // new is smaller
+ numCopyVertices = mClothingSimulation->sdkNumDeformableVertices;
+ velocities = writeBackInfo.oldSimulation->sdkWritebackPosition;
+
+ // PH: sdkWritebackPosition will contain qnans for the values that have not been written.
+ intrinsics::memSet(mClothingSimulation->sdkWritebackPosition, 0xff, sizeof(PxVec3) * mClothingSimulation->sdkNumDeformableVertices);
+
+ copyPositionAndNormal_NoPhysX(numCopyVertices, writeBackInfo.oldSimulation);
+ copyAndComputeVelocities_LocksPhysX(numCopyVertices, writeBackInfo.oldSimulation, velocities, writeBackInfo.simulationDelta);
+ }
+ }
+ else
+ {
+ velocities = mClothingSimulation->sdkWritebackPosition;
+ copyAndComputeVelocities_LocksPhysX(0, writeBackInfo.oldSimulation, velocities, writeBackInfo.simulationDelta);
+
+ // PH: sdkWritebackPosition will contain qnans for the values that have not been written.
+ intrinsics::memSet(mClothingSimulation->sdkWritebackPosition, 0xff, sizeof(PxVec3) * mClothingSimulation->sdkNumDeformableVertices);
+ }
+
+
+ const PxVec3* positions = destPhysicalMesh->vertices.buf;
+ const PxVec3* normals = destPhysicalMesh->normals.buf;
+ const uint32_t numBoneIndicesPerVertex = destPhysicalMesh->numBonesPerVertex;
+ const uint16_t* simBoneIndices = destPhysicalMesh->boneIndices.buf;
+ const float* simBoneWeights = destPhysicalMesh->boneWeights.buf;
+
+ // apply an initial skinning on the physical mesh
+ // ASSUMPTION: when allocated, mSdkWriteback* buffers will always contain meaningful data, so initialize correctly!
+ // All data that is not skinned from the old to the new mesh will have non-finite values (qnan)
+
+ const uint8_t* const PX_RESTRICT optimizationData = destPhysicalMesh->optimizationData.buf;
+ PX_ASSERT(optimizationData != NULL);
+
+ const PxMat44* matrices = mData.mInternalBoneMatricesCur;
+ if (matrices != NULL)
+ {
+ // one pass of cpu skinning on the physical mesh
+ const bool useNormals = mClothingSimulation->sdkWritebackNormal != NULL;
+
+ const uint32_t numVertices = destPhysicalMesh->numVertices;
+ for (uint32_t i = numCopyVertices; i < numVertices; i++)
+ {
+ const uint8_t shift = 4 * (i % 2);
+ const uint8_t numBones = uint8_t((optimizationData[i / 2] >> shift) & 0x7);
+
+ const uint32_t vertexIndex = (pTCMB == NULL) ? i : pTCMB[i].vertexIndexPlusOffset;
+
+ if (vertexIndex >= mClothingSimulation->sdkNumDeformableVertices)
+ {
+ continue;
+ }
+
+ if (PxIsFinite(mClothingSimulation->sdkWritebackPosition[vertexIndex].x))
+ {
+ continue;
+ }
+
+ Simd4f positionV = gSimd4fZero;
+ Simd4f normalV = gSimd4fZero;
+
+ const uint32_t numUsedBones = mAsset->getNumUsedBones();
+ PX_UNUSED(numUsedBones);
+
+ for (uint32_t j = 0; j < numBones; j++)
+ {
+
+ Simd4f weightV = Simd4fScalarFactory(simBoneWeights[vertexIndex * numBoneIndicesPerVertex + j]);
+ uint16_t index = simBoneIndices[vertexIndex * numBoneIndicesPerVertex + j];
+ PX_ASSERT(index < numUsedBones);
+
+ const PxMat44& bone = (PxMat44&)matrices[index];
+
+ Simd4f pV = applyAffineTransform(bone, createSimd3f(positions[vertexIndex]));
+ pV = pV * weightV;
+ positionV = positionV + pV;
+
+ if (useNormals)
+ {
+ Simd4f nV = applyLinearTransform(bone, createSimd3f(normals[vertexIndex]));
+ nV = nV * weightV;
+ normalV = normalV + nV;
+ }
+
+ }
+
+ if (useNormals)
+ {
+ normalV = normalV * rsqrt(dot3(normalV, normalV));
+ store3(&mClothingSimulation->sdkWritebackNormal[vertexIndex].x, normalV);
+ }
+ store3(&mClothingSimulation->sdkWritebackPosition[vertexIndex].x, positionV);
+ }
+ }
+ else
+ {
+ // no bone matrices, just move into world space
+ const uint32_t numVertices = destPhysicalMesh->numVertices;
+ PxMat44 TM = bInternalLocalSpaceSim == 1 ? PxMat44(PxIdentity) * mActorDesc->actorScale : mInternalGlobalPose;
+ for (uint32_t i = numCopyVertices; i < numVertices; i++)
+ {
+ const uint32_t vertexIndex = (pTCMB == NULL) ? i : pTCMB[i].vertexIndexPlusOffset;
+ if (vertexIndex >= mClothingSimulation->sdkNumDeformableVertices)
+ {
+ continue;
+ }
+
+ if (PxIsFinite(mClothingSimulation->sdkWritebackPosition[vertexIndex].x))
+ {
+ continue;
+ }
+
+ mClothingSimulation->sdkWritebackPosition[vertexIndex] = TM.transform(positions[vertexIndex]);
+ if (mClothingSimulation->sdkWritebackNormal != NULL)
+ {
+ mClothingSimulation->sdkWritebackNormal[vertexIndex] = TM.rotate(normals[vertexIndex]);
+ }
+ }
+ }
+}
+
+
+
+/// todo simdify?
+void ClothingActorImpl::applyVelocityChanges_LocksPhysX(float simulationDelta)
+{
+ if (mClothingSimulation == NULL)
+ {
+ return;
+ }
+
+ float pressure = mActorDesc->pressure;
+ if (pressure >= 0.0f)
+ {
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type* mesh = mAsset->getPhysicalMeshFromLod(mCurrentGraphicalLodId);
+ if (!mesh->isClosed)
+ {
+ pressure = -1.0f;
+
+ if (bPressureWarning == 0)
+ {
+ bPressureWarning = 1;
+ if (!mesh->isClosed)
+ {
+ APEX_INTERNAL_ERROR("Pressure requires a closed mesh!\n");
+ }
+ else
+ {
+ APEX_INTERNAL_ERROR("Pressure only works on Physics LODs where all vertices are active!\n");
+ }
+ }
+ }
+ }
+
+ // did the simulation handle pressure already?
+ const bool needsPressure = !mClothingSimulation->applyPressure(pressure) && (pressure > 0.0f);
+
+ if (mInternalWindParams.Adaption > 0.0f || mVelocityCallback != NULL || mActorDesc->useVelocityClamping || needsPressure)
+ {
+ PX_ASSERT(mClothingScene);
+ PX_PROFILE_ZONE("ClothingActorImpl::applyVelocityChanges", GetInternalApexSDK()->getContextId());
+
+ const uint32_t numVertices = mClothingSimulation->sdkNumDeformableVertices;
+
+ // copy velocities to temp array
+ PxVec3* velocities = mClothingSimulation->skinnedPhysicsNormals;
+
+ // use the skinnedPhysics* buffers when possible
+ const bool doNotUseWritebackMemory = (bBoneMatricesChanged == 0 && bGlobalPoseChanged == 0);
+
+ if (doNotUseWritebackMemory)
+ {
+ velocities = (PxVec3*)GetInternalApexSDK()->getTempMemory(sizeof(PxVec3) * numVertices);
+ }
+
+ if (velocities == NULL)
+ {
+ return;
+ }
+
+ mClothingSimulation->getVelocities(velocities);
+ // positions never need to be read!
+
+ bool writeVelocities = false;
+
+ // get pointers
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type* physicalMesh = mAsset->getPhysicalMeshFromLod(mCurrentGraphicalLodId);
+ const PxVec3* assetNormals = physicalMesh->normals.buf;
+ const ClothingPhysicalMeshParametersNS::ConstrainCoefficient_Type* coeffs = physicalMesh->constrainCoefficients.buf;
+ const PxVec3* normals = (mClothingSimulation->sdkWritebackNormal != NULL) ? mClothingSimulation->sdkWritebackNormal : assetNormals;
+
+ PxVec3 windVelocity = mInternalWindParams.Velocity;
+ if (windVelocity.magnitudeSquared() > 0.0f && bInternalLocalSpaceSim == 1)
+ {
+#if _DEBUG
+ bool ok = true;
+ ok &= mInternalGlobalPose.column0.isNormalized();
+ ok &= mInternalGlobalPose.column1.isNormalized();
+ ok &= mInternalGlobalPose.column2.isNormalized();
+ if (!ok)
+ {
+ APEX_DEBUG_WARNING("Internal Global Pose is not normalized (Scale: %f %f %f). Velocities could be wrong.", mInternalGlobalPose.column0.magnitude(), mInternalGlobalPose.column1.magnitude(), mInternalGlobalPose.column2.magnitude());
+ }
+#endif
+ PxMat44 invGlobalPose = mInternalGlobalPose.inverseRT();
+ windVelocity = invGlobalPose.rotate(windVelocity);
+ }
+
+ // modify velocities (2.8.x) or set acceleration (3.x) based on wind
+ writeVelocities |= mClothingSimulation->applyWind(velocities, normals, coeffs, windVelocity, mInternalWindParams.Adaption, simulationDelta);
+
+ // clamp velocities
+ if (mActorDesc->useVelocityClamping)
+ {
+ PxBounds3 velocityClamp(mActorDesc->vertexVelocityClamp);
+ for (uint32_t i = 0; i < numVertices; i++)
+ {
+ PxVec3 velocity = velocities[i];
+ velocity.x = PxClamp(velocity.x, velocityClamp.minimum.x, velocityClamp.maximum.x);
+ velocity.y = PxClamp(velocity.y, velocityClamp.minimum.y, velocityClamp.maximum.y);
+ velocity.z = PxClamp(velocity.z, velocityClamp.minimum.z, velocityClamp.maximum.z);
+ velocities[i] = velocity;
+ }
+ writeVelocities = true;
+ }
+
+ if (needsPressure)
+ {
+ PX_ALWAYS_ASSERT();
+ //writeVelocities = true;
+ }
+
+ if (mVelocityCallback != NULL)
+ {
+ PX_PROFILE_ZONE("ClothingActorImpl::velocityShader", GetInternalApexSDK()->getContextId());
+ writeVelocities |= mVelocityCallback->velocityShader(velocities, mClothingSimulation->sdkWritebackPosition, mClothingSimulation->sdkNumDeformableVertices);
+ }
+
+ if (writeVelocities)
+ {
+ if (mClothingScene->mClothingDebugRenderParams->Wind != 0.0f)
+ {
+ mWindDebugRendering.clear(); // no memory operation!
+
+ PxVec3* oldVelocities = (PxVec3*)GetInternalApexSDK()->getTempMemory(sizeof(PxVec3) * numVertices);
+ mClothingSimulation->getVelocities(oldVelocities);
+
+ for (uint32_t i = 0; i < numVertices; i++)
+ {
+ mWindDebugRendering.pushBack(velocities[i] - oldVelocities[i]);
+ }
+
+ GetInternalApexSDK()->releaseTempMemory(oldVelocities);
+ }
+ else if (mWindDebugRendering.capacity() > 0)
+ {
+ mWindDebugRendering.reset();
+ }
+ mClothingSimulation->setVelocities(velocities);
+ }
+
+ if (doNotUseWritebackMemory)
+ {
+ GetInternalApexSDK()->releaseTempMemory(velocities);
+ }
+ }
+}
+
+
+
+// update the renderproxy to which the data of this frame is written
+void ClothingActorImpl::updateRenderProxy()
+{
+ PX_PROFILE_ZONE("ClothingActorImpl::updateRenderProxy", GetInternalApexSDK()->getContextId());
+ PX_ASSERT(mGraphicalMeshes[mCurrentGraphicalLodId].renderProxy == NULL);
+
+ // get a new render proxy from the pool
+ RenderMeshAssetIntl* renderMeshAsset = mAsset->getGraphicalMesh(mCurrentGraphicalLodId);
+ ClothingRenderProxyImpl* renderProxy = mClothingScene->getRenderProxy(renderMeshAsset, mActorDesc->fallbackSkinning, mClothingSimulation != NULL,
+ mOverrideMaterials, mActorDesc->morphGraphicalMeshNewPositions.buf,
+ &mGraphicalMeshes[mCurrentGraphicalLodId].morphTargetVertexOffsets[0]);
+
+ mGraphicalMeshes[mCurrentGraphicalLodId].renderProxy = renderProxy;
+}
+
+
+
+ClothingRenderProxy* ClothingActorImpl::acquireRenderProxy()
+{
+ PX_PROFILE_ZONE("ClothingActorImpl::acquireRenderProxy", GetInternalApexSDK()->getContextId());
+ if (!mClothingScene->isSimulating()) // after fetchResults
+ {
+ // For consistency, only return the new result after fetchResults.
+ // During simulation always return the old result
+ // even if the new result might be ready
+ waitForFetchResults();
+ }
+
+ mRenderProxyMutex.lock();
+ ClothingRenderProxyImpl* renderProxy = mRenderProxyReady;
+ mRenderProxyReady = NULL;
+ mRenderProxyMutex.unlock();
+
+ return renderProxy;
+}
+
+
+
+void ClothingActorImpl::getSimulation(const WriteBackInfo& writeBackInfo)
+{
+ const uint32_t physicalMeshId = mAsset->getGraphicalLod(mCurrentGraphicalLodId)->physicalMeshId;
+
+#if defined _DEBUG || PX_CHECKED
+ BackendFactory* factory = mAsset->getModuleClothing()->getBackendFactory(mBackendName);
+ PX_UNUSED(factory); // Strange warning fix
+#endif
+
+ NvParameterized::Interface* cookingInterface = mActorDesc->runtimeCooked;
+
+ if (cookingInterface != NULL)
+ {
+#if defined _DEBUG || PX_CHECKED
+ PX_ASSERT(factory->isMatch(cookingInterface->className()));
+#endif
+ }
+ else
+ {
+ cookingInterface = mAsset->getCookedData(mActorDesc->actorScale);
+#if defined _DEBUG || PX_CHECKED
+ PX_ASSERT(factory->isMatch(cookingInterface->className()));
+#endif
+ }
+
+ mClothingSimulation = mAsset->getSimulation(physicalMeshId, cookingInterface, mClothingScene);
+ if (mClothingSimulation != NULL)
+ {
+ mClothingSimulation->reenablePhysX(mActorProxy, mInternalGlobalPose);
+
+ mAsset->updateCollision(mClothingSimulation, mData.mInternalBoneMatricesCur, mCollisionPlanes, mCollisionConvexes, mCollisionSpheres, mCollisionCapsules, mCollisionTriangleMeshes, true);
+ mClothingSimulation->updateCollisionDescs(mActorDesc->actorDescTemplate, mActorDesc->shapeDescTemplate);
+
+ fillWritebackData_LocksPhysX(writeBackInfo);
+
+ mClothingSimulation->setPositions(mClothingSimulation->sdkWritebackPosition);
+
+ PX_ASSERT(mClothingSimulation->physicalMeshId != 0xffffffff);
+ PX_ASSERT(mClothingSimulation->submeshId != 0xffffffff);
+ }
+ else if (cookingInterface != NULL)
+ {
+ // will call fillWritebackData_LocksPhysX
+ createSimulation(physicalMeshId, cookingInterface, writeBackInfo);
+ }
+
+ bDirtyClothingTemplate = 1; // updates the clothing desc
+
+ if (mClothingSimulation != NULL)
+ {
+ // make sure skinPhysicalMesh does something
+ bBoneMatricesChanged = 1;
+ }
+}
+
+
+
+bool ClothingActorImpl::isCookedDataReady()
+{
+ // Move getResult of the Cooking Task outside because it would block the other cooking tasks when the actor stopped the simulation.
+ if (mActiveCookingTask == NULL)
+ {
+ return true;
+ }
+
+ PX_ASSERT(mActorDesc->runtimeCooked == NULL);
+ mActorDesc->runtimeCooked = mActiveCookingTask->getResult();
+ if (mActorDesc->runtimeCooked != NULL)
+ {
+ mActiveCookingTask = NULL; // will be deleted by the scene
+ return true;
+ }
+
+ if(mAsset->getModuleClothing()->allowAsyncCooking())
+ {
+ mClothingScene->submitCookingTask(NULL); //trigger tasks to be submitted
+ }
+
+ return false;
+}
+
+
+
+void ClothingActorImpl::createPhysX_LocksPhysX(float simulationDelta)
+{
+#if PX_PHYSICS_VERSION_MAJOR == 3
+ if (mPhysXScene == NULL)
+ {
+ return;
+ }
+#endif
+ if (mCurrentSolverIterations == 0)
+ {
+ return;
+ }
+
+ if (mClothingSimulation != NULL)
+ {
+ APEX_INTERNAL_ERROR("Physics mesh already created!");
+ return;
+ }
+
+ PX_PROFILE_ZONE("ClothingActorImpl::createPhysX", GetInternalApexSDK()->getContextId());
+
+ WriteBackInfo writeBackInfo;
+ writeBackInfo.simulationDelta = simulationDelta;
+
+ getSimulation(writeBackInfo);
+
+ if (mClothingSimulation == NULL)
+ {
+ mCurrentSolverIterations = 0;
+ }
+
+ updateConstraintCoefficients_LocksPhysX();
+
+ bBoneBufferDirty = 1;
+}
+
+
+
+void ClothingActorImpl::removePhysX_LocksPhysX()
+{
+ if (mClothingScene != NULL)
+ {
+ if (mClothingSimulation != NULL)
+ {
+ mAsset->returnSimulation(mClothingSimulation);
+ mClothingSimulation = NULL;
+ }
+ }
+ else
+ {
+ PX_ASSERT(mClothingSimulation == NULL);
+ }
+
+ bBoneBufferDirty = 1;
+}
+
+
+
+void ClothingActorImpl::changePhysicsMesh_LocksPhysX(uint32_t oldGraphicalLodId, float simulationDelta)
+{
+ PX_ASSERT(mClothingSimulation != NULL);
+ PX_ASSERT(mClothingScene != NULL);
+
+ WriteBackInfo writeBackInfo;
+ writeBackInfo.oldSimulation = mClothingSimulation;
+ writeBackInfo.oldGraphicalLodId = oldGraphicalLodId;
+ writeBackInfo.simulationDelta = simulationDelta;
+
+ getSimulation(writeBackInfo); // sets mClothingSimulation & will register the sim buffers
+ writeBackInfo.oldSimulation->swapCollision(mClothingSimulation);
+
+ mAsset->returnSimulation(writeBackInfo.oldSimulation);
+ writeBackInfo.oldSimulation = NULL;
+
+ updateConstraintCoefficients_LocksPhysX();
+
+ // make sure skinPhysicalMesh does something
+ bBoneMatricesChanged = 1;
+
+ // make sure actorData gets updated
+ reinitActorData();
+}
+
+
+
+void ClothingActorImpl::updateCollision_LocksPhysX(bool useInterpolatedMatrices)
+{
+ if (mClothingSimulation == NULL || (bBoneMatricesChanged == 0 && bGlobalPoseChanged == 0 && bActorCollisionChanged == 0))
+ {
+ return;
+ }
+
+ PX_ASSERT(mClothingScene != NULL);
+
+ const PxMat44* matrices = useInterpolatedMatrices ? mInternalInterpolatedBoneMatrices : mData.mInternalBoneMatricesCur;
+ mAsset->updateCollision(mClothingSimulation, matrices, mCollisionPlanes, mCollisionConvexes, mCollisionSpheres, mCollisionCapsules, mCollisionTriangleMeshes, bInternalTeleportDue != ClothingTeleportMode::Continuous);
+ bActorCollisionChanged = 0;
+
+ if (bDirtyActorTemplate == 1 || bDirtyShapeTemplate == 1)
+ {
+ mClothingSimulation->updateCollisionDescs(mActorDesc->actorDescTemplate, mActorDesc->shapeDescTemplate);
+
+ bDirtyActorTemplate = 0;
+ bDirtyShapeTemplate = 0;
+ }
+}
+
+
+
+void ClothingActorImpl::updateConstraintCoefficients_LocksPhysX()
+{
+ if (mClothingSimulation == NULL)
+ {
+ return;
+ }
+
+ const ClothingPhysicalMeshParametersNS::PhysicalMesh_Type* physicalMesh = mAsset->getPhysicalMeshFromLod(mCurrentGraphicalLodId);
+ const ClothingPhysicalMeshParametersNS::ConstrainCoefficient_Type* assetCoeffs = physicalMesh->constrainCoefficients.buf;
+
+ const float actorScale = mActorDesc->actorScale;
+
+ const float linearScale = (mInternalMaxDistanceScale.Multipliable ? mInternalMaxDistanceScale.Scale : 1.0f) * actorScale;
+ const float absoluteScale = mInternalMaxDistanceScale.Multipliable ? 0.0f : (physicalMesh->maximumMaxDistance * (1.0f - mInternalMaxDistanceScale.Scale));
+
+ const float reduceMaxDistance = mMaxDistReduction + absoluteScale;
+
+ mCurrentMaxDistanceBias = 0.0f;
+ ClothingMaterialLibraryParametersNS::ClothingMaterial_Type* clothingMaterial = getCurrentClothingMaterial();
+ if (clothingMaterial != NULL)
+ {
+ mCurrentMaxDistanceBias = clothingMaterial->maxDistanceBias;
+ }
+
+ mClothingSimulation->setConstrainCoefficients(assetCoeffs, reduceMaxDistance, linearScale, mCurrentMaxDistanceBias, actorScale);
+
+ // change is applied now
+ bMaxDistanceScaleChanged = 0;
+}
+
+
+
+void ClothingActorImpl::copyPositionAndNormal_NoPhysX(uint32_t numCopyVertices, SimulationAbstract* oldClothingSimulation)
+{
+ if (oldClothingSimulation == NULL)
+ {
+ return;
+ }
+
+ PX_ASSERT(numCopyVertices <= mClothingSimulation->sdkNumDeformableVertices && numCopyVertices <= oldClothingSimulation->sdkNumDeformableVertices);
+
+ memcpy(mClothingSimulation->sdkWritebackPosition, oldClothingSimulation->sdkWritebackPosition, sizeof(PxVec3) * numCopyVertices);
+
+ if (mClothingSimulation->sdkWritebackNormal != NULL)
+ {
+ memcpy(mClothingSimulation->sdkWritebackNormal, oldClothingSimulation->sdkWritebackNormal, sizeof(PxVec3) * numCopyVertices);
+ }
+}
+
+
+
+void ClothingActorImpl::copyAndComputeVelocities_LocksPhysX(uint32_t numCopyVertices, SimulationAbstract* oldClothingSimulation, PxVec3* velocities, float simulationDelta) const
+{
+ PX_ASSERT(mClothingScene != NULL);
+
+ // copy
+ if (oldClothingSimulation != NULL && numCopyVertices > 0)
+ {
+ oldClothingSimulation->getVelocities(velocities);
+ }
+
+ // compute velocity from old and current skinned pos
+ // TODO only skin when bone matrices have changed -> how to use bBoneMatricesChanged in a safe way?
+ const ClothingPhysicalMeshParametersNS::PhysicalMesh_Type* physicalMesh = mAsset->getPhysicalMeshFromLod(mCurrentGraphicalLodId);
+ PX_ASSERT(physicalMesh != NULL);
+
+ const uint32_t numVertices = physicalMesh->numSimulatedVertices;
+ PX_ASSERT(numVertices == mClothingSimulation->sdkNumDeformableVertices);
+ if (mData.mInternalBoneMatricesCur != NULL && mData.mInternalBoneMatricesPrev != NULL && simulationDelta > 0 && bBoneMatricesChanged == 1)
+ {
+ // cpu skinning on the physical mesh
+ for (uint32_t i = numCopyVertices; i < numVertices; i++)
+ {
+ velocities[i] = computeVertexVelFromAnim(i, physicalMesh, simulationDelta);
+ }
+ }
+ else
+ {
+ // no bone matrices, just set 0 velocities
+ memset(velocities + numCopyVertices, 0, sizeof(PxVec3) * (numVertices - numCopyVertices));
+ }
+
+ // set the velocities
+ mClothingSimulation->setVelocities(velocities);
+}
+
+
+
+void ClothingActorImpl::transferVelocities_LocksPhysX(const SimulationAbstract& oldClothingSimulation,
+ const ClothingPhysicalMeshParametersNS::SkinClothMapB_Type* pTCMB,
+ const ClothingPhysicalMeshParametersNS::SkinClothMapD_Type* pTCM,
+ uint32_t numVerticesInMap, const uint32_t* srcIndices, uint32_t numSrcIndices, uint32_t numSrcVertices,
+ PxVec3* oldVelocities, PxVec3* newVelocities, float simulationDelta)
+{
+ oldClothingSimulation.getVelocities(oldVelocities);
+
+ // data for skinning
+ const ClothingPhysicalMeshParametersNS::PhysicalMesh_Type* physicalMesh = mAsset->getPhysicalMeshFromLod(mCurrentGraphicalLodId);
+
+ // copy velocities
+ uint32_t vertexIndex = (uint32_t) - 1;
+ uint32_t idx[3] =
+ {
+ (uint32_t) - 1,
+ (uint32_t) - 1,
+ (uint32_t) - 1,
+ };
+ for (uint32_t i = 0; i < numVerticesInMap; ++i)
+ {
+ if (pTCMB)
+ {
+ uint32_t faceIndex = pTCMB[i].faceIndex0;
+ idx[0] = (faceIndex >= numSrcIndices) ? srcIndices[faceIndex + 0] : (uint32_t) - 1;
+ idx[1] = (faceIndex >= numSrcIndices) ? srcIndices[faceIndex + 1] : (uint32_t) - 1;
+ idx[2] = (faceIndex >= numSrcIndices) ? srcIndices[faceIndex + 2] : (uint32_t) - 1;
+
+ vertexIndex = pTCMB[i].vertexIndexPlusOffset;
+ }
+ else if (pTCM)
+ {
+ idx[0] = pTCM[i].vertexIndex0;
+ idx[1] = pTCM[i].vertexIndex1;
+ idx[2] = pTCM[i].vertexIndex2;
+ vertexIndex = pTCM[i].vertexIndexPlusOffset;
+ //PX_ASSERT(i == pTCM[i].vertexIndexPlusOffset);
+ }
+ else
+ {
+ PX_ALWAYS_ASSERT();
+ }
+
+ if (vertexIndex >= mClothingSimulation->sdkNumDeformableVertices)
+ {
+ continue;
+ }
+
+ if (idx[0] >= numSrcVertices || idx[1] >= numSrcVertices || idx[2] >= numSrcVertices)
+ {
+ // compute from anim
+ if (mData.mInternalBoneMatricesPrev == NULL || simulationDelta == 0.0f)
+ {
+ newVelocities[vertexIndex] = PxVec3(0.0f);
+ }
+ else
+ {
+ newVelocities[vertexIndex] = computeVertexVelFromAnim(vertexIndex, physicalMesh, simulationDelta);
+ }
+ }
+ else
+ {
+ // transfer from old mesh
+ newVelocities[vertexIndex] = (oldVelocities[idx[0]] + oldVelocities[idx[1]] + oldVelocities[idx[2]]) / 3.0f;
+ }
+ }
+
+ mClothingSimulation->setVelocities(newVelocities);
+}
+
+
+
+PxVec3 ClothingActorImpl::computeVertexVelFromAnim(uint32_t vertexIndex, const ClothingPhysicalMeshParametersNS::PhysicalMesh_Type* physicalMesh, float simulationDelta) const
+{
+ PX_ASSERT(simulationDelta > 0);
+ PX_ASSERT(mData.mInternalBoneMatricesCur != NULL);
+ PX_ASSERT(mData.mInternalBoneMatricesPrev != NULL);
+
+ const PxVec3* positions = physicalMesh->vertices.buf;
+ Simd4f simulationDeltaV = Simd4fScalarFactory(simulationDelta);
+
+ uint32_t numBoneIndicesPerVertex = physicalMesh->numBonesPerVertex;
+ const uint16_t* simBoneIndices = physicalMesh->boneIndices.buf;
+ const float* simBoneWeights = physicalMesh->boneWeights.buf;
+
+ const uint8_t* const optimizationData = physicalMesh->optimizationData.buf;
+ PX_ASSERT(optimizationData != NULL);
+
+ const uint8_t shift = 4 * (vertexIndex % 2);
+ const uint8_t numBones = uint8_t((optimizationData[vertexIndex / 2] >> shift) & 0x7);
+
+ Simd4f oldPosV = gSimd4fZero;
+ Simd4f newPosV = gSimd4fZero;
+ for (uint32_t j = 0; j < numBones; j++)
+ {
+ const Simd4f weightV = Simd4fScalarFactory(simBoneWeights[vertexIndex * numBoneIndicesPerVertex + j]);
+
+ const uint16_t index = simBoneIndices[vertexIndex * numBoneIndicesPerVertex + j];
+ PX_ASSERT(index < mAsset->getNumUsedBones());
+ const PxMat44& oldBoneV = (PxMat44&)mData.mInternalBoneMatricesPrev[index];
+ const PxMat44& boneV = (PxMat44&)mData.mInternalBoneMatricesCur[index];
+
+
+ //oldPos += oldBone * positions[vertexIndex] * weight;
+ Simd4f pV = applyAffineTransform(oldBoneV, createSimd3f(positions[vertexIndex]));
+ pV = pV * weightV;
+ oldPosV = oldPosV + pV;
+
+ //newPos += bone * positions[vertexIndex] * weight;
+ pV = applyAffineTransform(boneV, createSimd3f(positions[vertexIndex]));
+ pV = pV * weightV;
+ newPosV = newPosV + pV;
+
+ }
+
+ Simd4f velV = newPosV - oldPosV;
+ velV = velV / simulationDeltaV;
+
+ PxVec3 vel;
+ store3(&vel.x, velV);
+ return vel;
+}
+
+
+
+void ClothingActorImpl::createSimulation(uint32_t physicalMeshId, NvParameterized::Interface* cookedData, const WriteBackInfo& writeBackInfo)
+{
+ PX_ASSERT(mClothingSimulation == NULL);
+#if PX_PHYSICS_VERSION_MAJOR == 3
+ if (mPhysXScene == NULL)
+ {
+ return;
+ }
+#endif
+ if (bUnsucessfullCreation == 1)
+ {
+ return;
+ }
+
+ PX_PROFILE_ZONE("ClothingActorImpl::SDKCreateClothSoftbody", GetInternalApexSDK()->getContextId());
+
+ mClothingSimulation = mAsset->getModuleClothing()->getBackendFactory(mBackendName)->createSimulation(mClothingScene, mActorDesc->useHardwareCloth);
+
+ bool success = false;
+
+ if (mClothingSimulation != NULL)
+ {
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type* physicalMesh = mAsset->getPhysicalMeshFromLod(mCurrentGraphicalLodId);
+ const uint32_t numVertices = physicalMesh->numSimulatedVertices;
+ const uint32_t numIndices = physicalMesh->numSimulatedIndices;
+
+ mClothingSimulation->init(numVertices, numIndices, true);
+
+ PX_ASSERT(nvidia::strcmp(mAsset->getAssetNvParameterized()->className(), ClothingAssetParameters::staticClassName()) == 0);
+ const ClothingAssetParameters* assetParams = static_cast<const ClothingAssetParameters*>(mAsset->getAssetNvParameterized());
+ mClothingSimulation->initSimulation(assetParams->simulation);
+
+ mClothingSimulation->physicalMeshId = physicalMeshId;
+ fillWritebackData_LocksPhysX(writeBackInfo);
+
+ uint32_t* indices = NULL;
+ PxVec3* vertices = NULL;
+ if (physicalMesh != NULL)
+ {
+ indices = physicalMesh->indices.buf;
+ vertices = physicalMesh->vertices.buf;
+ }
+
+ success = mClothingSimulation->setCookedData(cookedData, mActorDesc->actorScale);
+
+ mAsset->initCollision(mClothingSimulation, mData.mInternalBoneMatricesCur, mCollisionPlanes, mCollisionConvexes, mCollisionSpheres, mCollisionCapsules, mCollisionTriangleMeshes, mActorDesc, mInternalGlobalPose, bInternalLocalSpaceSim == 1);
+
+ // sets positions to sdkWritebackPosition
+ ClothingMaterialLibraryParametersNS::ClothingMaterial_Type* clothingMaterial = getCurrentClothingMaterial();
+ success &= mClothingSimulation->initPhysics(physicalMeshId, indices, vertices, clothingMaterial, mInternalGlobalPose, mInternalScaledGravity, bInternalLocalSpaceSim == 1);
+
+ if (success)
+ {
+ mClothingSimulation->registerPhysX(mActorProxy);
+ }
+
+ mClothingScene->registerAsset(mAsset);
+ }
+
+ if (!success)
+ {
+ bUnsucessfullCreation = 1;
+
+ if (mClothingSimulation != NULL)
+ {
+ PX_DELETE_AND_RESET(mClothingSimulation);
+ }
+ }
+}
+
+
+
+float ClothingActorImpl::getCost() const
+{
+ ClothingMaterialLibraryParametersNS::ClothingMaterial_Type* clothingMaterial = getCurrentClothingMaterial();
+ const uint32_t solverIterations = clothingMaterial != NULL ? clothingMaterial->solverIterations : 5;
+
+ float cost = 0.0f;
+ if (mClothingSimulation != NULL)
+ {
+ cost = static_cast<float>(solverIterations * mAsset->getPhysicalMeshFromLod(mCurrentGraphicalLodId)->numSimulatedVertices);
+ }
+ return cost;
+}
+
+
+
+uint32_t ClothingActorImpl::getGraphicalMeshIndex(uint32_t lod) const
+{
+ for (uint32_t i = 1; i < mAsset->getNumGraphicalMeshes(); i++)
+ {
+ if (mAsset->getGraphicalLod(i)->lod > lod)
+ {
+ return i - 1;
+ }
+ }
+
+ // not found, return last index
+ return mAsset->getNumGraphicalMeshes() - 1;
+}
+
+
+
+void ClothingActorImpl::lodTick_LocksPhysX(float simulationDelta)
+{
+ PX_PROFILE_ZONE("ClothingActorImpl::lodTick", GetInternalApexSDK()->getContextId());
+
+ bool actorCooked = isCookedDataReady();
+
+ // update graphics lod
+ // hlanker: active needs a lock if parallel active checks are allowed (like parallel updateRenderResource)
+ for (uint32_t i = 0; i < mGraphicalMeshes.size(); i++)
+ {
+ mGraphicalMeshes[i].active = false;
+ }
+
+ const uint32_t newGraphicalLodId = getGraphicalMeshIndex(mBufferedGraphicalLod);
+
+ if (newGraphicalLodId >= mGraphicalMeshes.size())
+ {
+ return;
+ }
+
+ mGraphicalMeshes[newGraphicalLodId].active = true;
+
+ uint32_t oldPhysicalMeshId = mAsset->getGraphicalLod(mCurrentGraphicalLodId)->physicalMeshId;
+ const bool physicalMeshChanged = oldPhysicalMeshId != mAsset->getGraphicalLod(newGraphicalLodId)->physicalMeshId;
+ if (physicalMeshChanged)
+ {
+ bInternalScaledGravityChanged = 1;
+ }
+
+ const bool graphicalLodChanged = newGraphicalLodId != mCurrentGraphicalLodId;
+ const uint32_t oldGraphicalLodId = mCurrentGraphicalLodId;
+ mCurrentGraphicalLodId = newGraphicalLodId;
+
+ if (mForceSimulation < 0)
+ {
+ mForceSimulation = 1;
+ }
+ bIsSimulationOn = mForceSimulation > 0? false : true;
+
+ float maxDistReductionTarget = 0.f;
+ if (graphicalLodChanged)
+ {
+ // interrupt blending when switching graphical lod
+ mMaxDistReduction = maxDistReductionTarget;
+ }
+
+ // must not enter here if graphical lod changed. otherwise we'll assert in updateConstraintCoefficients because of a pointer mismatch
+ if (mAsset->getGraphicalLod(mCurrentGraphicalLodId)->physicalMeshId != uint32_t(-1) && !graphicalLodChanged)
+ {
+ const ClothingPhysicalMeshParametersNS::PhysicalMesh_Type* physicalMesh = mAsset->getPhysicalMeshFromLod(mCurrentGraphicalLodId);
+
+ // update maxDistReductionTarget
+ // if there is no simulation bulk, wait with reducing the maxDistReductionTarget
+ if (mMaxDistReduction != maxDistReductionTarget && mClothingSimulation != NULL)
+ {
+ const float maxBlendDistance = physicalMesh->maximumMaxDistance * (mInternalMaxDistanceBlendTime > 0 ? (simulationDelta / mInternalMaxDistanceBlendTime) : 1.0f);
+ if (mMaxDistReduction == -1.0f)
+ {
+ // initialization
+ mMaxDistReduction = maxDistReductionTarget;
+ }
+ else if (PxAbs(maxDistReductionTarget - mMaxDistReduction) < maxBlendDistance)
+ {
+ // distance multiplier target reached
+ mMaxDistReduction = maxDistReductionTarget;
+ }
+ else if (bBlendingAllowed == 0)
+ {
+ // No blending
+ mMaxDistReduction = maxDistReductionTarget;
+ }
+ else
+ {
+ // move towards distance multiplier target
+ mMaxDistReduction += PxSign(maxDistReductionTarget - mMaxDistReduction) * maxBlendDistance;
+ }
+ updateConstraintCoefficients_LocksPhysX();
+ }
+ else if (mCurrentMaxDistanceBias != mClothingMaterial.maxDistanceBias)
+ {
+ // update them if the max distance bias changes
+ updateConstraintCoefficients_LocksPhysX();
+ }
+ else if (bMaxDistanceScaleChanged == 1)
+ {
+ updateConstraintCoefficients_LocksPhysX();
+ }
+ }
+
+
+ // switch immediately when simulation was switched off or when graphical lod has changed, otherwise wait until finished blending
+ if (mMaxDistReduction >= maxDistReductionTarget)
+ {
+ ClothingMaterialLibraryParametersNS::ClothingMaterial_Type* clothingMaterial = getCurrentClothingMaterial();
+ const uint32_t solverIterations = clothingMaterial != NULL ? clothingMaterial->solverIterations : 5;
+
+ uint32_t solverIterationsTarget = solverIterations;
+
+ bool solverIterChanged = (mCurrentSolverIterations != solverIterationsTarget);
+ mCurrentSolverIterations = solverIterationsTarget;
+ if (actorCooked && mCurrentSolverIterations > 0)
+ {
+ if (mClothingSimulation == NULL)
+ {
+ createPhysX_LocksPhysX(simulationDelta);
+ }
+ else if (graphicalLodChanged)
+ {
+ PX_ASSERT(!physicalMeshChanged || mCurrentGraphicalLodId != oldGraphicalLodId);
+ changePhysicsMesh_LocksPhysX(oldGraphicalLodId, simulationDelta);
+ }
+
+ if (solverIterChanged && mClothingSimulation != NULL)
+ {
+ mClothingSimulation->setSolverIterations(mCurrentSolverIterations);
+ }
+
+ bInternalFrozen = bBufferedFrozen;
+ freeze_LocksPhysX(bInternalFrozen == 1);
+ bUpdateFrozenFlag = 0;
+ }
+ else
+ {
+ mCurrentSolverIterations = 0;
+
+ if (!mActorDesc->freezeByLOD)
+ {
+ removePhysX_LocksPhysX();
+ }
+ else
+ {
+ freeze_LocksPhysX(true);
+ bInternalFrozen = 1;
+ bUpdateFrozenFlag = 0;
+ }
+ }
+ }
+
+ // get render proxy for this simulate call
+ updateRenderProxy();
+}
+
+
+
+void ClothingActorImpl::visualizeSkinnedPositions(RenderDebugInterface& renderDebug, float positionRadius, bool maxDistanceOut, bool maxDistanceIn) const
+{
+#ifdef WITHOUT_DEBUG_VISUALIZE
+ PX_UNUSED(renderDebug);
+ PX_UNUSED(positionRadius);
+ PX_UNUSED(maxDistanceOut);
+ PX_UNUSED(maxDistanceIn);
+#else
+ using RENDER_DEBUG::DebugColors;
+ using RENDER_DEBUG::DebugRenderState;
+
+ if (mClothingSimulation != NULL)
+ {
+ const float pointRadius = positionRadius * 0.1f;
+ PX_ASSERT(mClothingSimulation->skinnedPhysicsPositions != NULL);
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type* physicalMesh = mAsset->getPhysicalMeshFromLod(mCurrentGraphicalLodId);
+ ClothingPhysicalMeshParametersNS::ConstrainCoefficient_Type* coeffs = physicalMesh->constrainCoefficients.buf;
+
+
+ const float actorScale = mActorDesc->actorScale;
+
+ const float linearScale = (mInternalMaxDistanceScale.Multipliable ? mInternalMaxDistanceScale.Scale : 1.0f) * actorScale;
+ const float absoluteScale = mInternalMaxDistanceScale.Multipliable ? 0.0f : (physicalMesh->maximumMaxDistance * (1.0f - mInternalMaxDistanceScale.Scale));
+
+ const float reduceMaxDistance = mMaxDistReduction + absoluteScale;
+
+ const float maxMotionRadius = (physicalMesh->maximumMaxDistance - reduceMaxDistance) * linearScale;
+
+ const uint32_t colorGreen = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Green);
+ const uint32_t colorBlue = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Blue);
+
+ const uint32_t numVertices = physicalMesh->numSimulatedVertices;
+ for (uint32_t i = 0; i < numVertices; i++)
+ {
+ const float maxDistance = PxMax(0.0f, coeffs[i].maxDistance - reduceMaxDistance) * linearScale;
+ uint32_t color;
+ if (maxDistance < 0.0f)
+ {
+ color = colorGreen;
+ }
+ else if (maxDistance == 0.0f)
+ {
+ color = colorBlue;
+ }
+ else
+ {
+ uint32_t b = (uint32_t)(255 * maxDistance / maxMotionRadius);
+ color = (b << 16) + (b << 8) + b;
+ }
+
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(color);
+ //RENDER_DEBUG_IFACE(&renderDebug)->setCurrentDisplayTime(0.1f);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugPoint(mClothingSimulation->skinnedPhysicsPositions[i], pointRadius);
+ //RENDER_DEBUG_IFACE(&renderDebug)->setCurrentDisplayTime();
+
+ if (maxDistanceOut)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(
+ mClothingSimulation->skinnedPhysicsPositions[i],
+ mClothingSimulation->skinnedPhysicsPositions[i] + mClothingSimulation->skinnedPhysicsNormals[i] * maxDistance
+ );
+ }
+ if (maxDistanceIn)
+ {
+ float collDist = PxMax(0.0f, coeffs[i].collisionSphereDistance * actorScale);
+ //float scaledMaxDist = PxMax(0.0f, maxDistance - reduceMaxDistance);
+ if (coeffs[i].collisionSphereRadius > 0.0f && collDist < maxDistance)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(
+ mClothingSimulation->skinnedPhysicsPositions[i] - mClothingSimulation->skinnedPhysicsNormals[i] * collDist,
+ mClothingSimulation->skinnedPhysicsPositions[i]
+ );
+ }
+ else
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(
+ mClothingSimulation->skinnedPhysicsPositions[i] - mClothingSimulation->skinnedPhysicsNormals[i] * maxDistance,
+ mClothingSimulation->skinnedPhysicsPositions[i]
+ );
+ }
+ }
+ }
+ }
+#endif
+}
+
+
+
+void ClothingActorImpl::visualizeSpheres(RenderDebugInterface& renderDebug, const PxVec3* positions, uint32_t numPositions, float radius, uint32_t color, bool wire) const
+{
+#ifdef WITHOUT_DEBUG_VISUALIZE
+ PX_UNUSED(renderDebug);
+ PX_UNUSED(positions);
+ PX_UNUSED(numPositions);
+ PX_UNUSED(radius);
+ PX_UNUSED(color);
+ PX_UNUSED(wire);
+#else
+ RENDER_DEBUG_IFACE(&renderDebug)->pushRenderState();
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(color);
+
+ if (wire)
+ {
+ PxMat44 cameraPose = mClothingScene->mApexScene->getViewMatrix(0).inverseRT();
+ cameraPose = mInternalGlobalPose.inverseRT() * cameraPose;
+ PxVec3 cameraPos = cameraPose.getPosition();
+ for (uint32_t i = 0; i < numPositions; ++i)
+ {
+ // face camera
+ PxVec3 y = positions[i] - cameraPos;
+ y.normalize();
+ PxPlane p(y, 0.0f);
+ PxVec3 x = p.project(cameraPose.column0.getXYZ());
+ x.normalize();
+ PxMat44 pose(x, y, x.cross(y), positions[i]);
+
+ RENDER_DEBUG_IFACE(&renderDebug)->setPose(pose);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugCircle(PxVec3(0.0f), radius, 2);
+ }
+ }
+ else
+ {
+ PxMat44 pose(PxIdentity);
+ for (uint32_t i = 0; i < numPositions; ++i)
+ {
+ pose.setPosition(positions[i]);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugSphere(pose.getPosition(), radius, 0);
+ }
+ }
+ RENDER_DEBUG_IFACE(&renderDebug)->popRenderState();
+#endif
+}
+
+
+
+void ClothingActorImpl::visualizeBackstop(RenderDebugInterface& renderDebug) const
+{
+#ifdef WITHOUT_DEBUG_VISUALIZE
+ PX_UNUSED(renderDebug);
+#else
+ using RENDER_DEBUG::DebugColors;
+ using RENDER_DEBUG::DebugRenderState;
+
+ if (mClothingSimulation != NULL)
+ {
+ PX_ASSERT(mClothingSimulation->skinnedPhysicsPositions != NULL);
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type* physicalMesh = mAsset->getPhysicalMeshFromLod(mCurrentGraphicalLodId);
+ ClothingPhysicalMeshParametersNS::ConstrainCoefficient_Type* coeffs = physicalMesh->constrainCoefficients.buf;
+ uint32_t* indices = physicalMesh->indices.buf;
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Red));
+
+ const float actorScale = mActorDesc->actorScale;
+
+ if (!physicalMesh->isTetrahedralMesh)
+ {
+ // render collision surface as triangle-mesh
+ const uint32_t colorDarkRed = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::DarkRed);
+ const uint32_t colorDarkBlue = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::DarkBlue);
+
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentState(DebugRenderState::SolidShaded);
+ for (uint32_t i = 0; i < physicalMesh->numSimulatedIndices; i += 3)
+ {
+ PxVec3 p[3];
+
+ bool show = true;
+
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ const uint32_t index = indices[i + j];
+ if (coeffs[index].collisionSphereRadius <= 0.0f)
+ {
+ show = false;
+ break;
+ }
+
+ const float collisionSphereDistance = coeffs[index].collisionSphereDistance * actorScale;
+ if (collisionSphereDistance < 0.0f)
+ {
+ p[j] = mClothingSimulation->skinnedPhysicsPositions[index];
+ }
+ else
+ {
+ p[j] = mClothingSimulation->skinnedPhysicsPositions[index]
+ - (mClothingSimulation->skinnedPhysicsNormals[index] * collisionSphereDistance);
+ }
+ }
+
+ if (show)
+ {
+ // frontface
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorDarkRed);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugTri(p[0], p[2], p[1]);
+
+ // backface
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorDarkBlue);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugTri(p[0], p[1], p[2]);
+ }
+ }
+ }
+ }
+#endif
+}
+
+
+
+void ClothingActorImpl::visualizeBackstopPrecise(RenderDebugInterface& renderDebug, float scale) const
+{
+#ifdef WITHOUT_DEBUG_VISUALIZE
+ PX_UNUSED(renderDebug);
+ PX_UNUSED(scale);
+#else
+ using RENDER_DEBUG::DebugColors;
+ using RENDER_DEBUG::DebugRenderState;
+
+ if (mClothingSimulation != NULL)
+ {
+ PX_ASSERT(mClothingSimulation->skinnedPhysicsPositions != NULL);
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type* physicalMesh = mAsset->getPhysicalMeshFromLod(mCurrentGraphicalLodId);
+ ClothingPhysicalMeshParametersNS::ConstrainCoefficient_Type* coeffs = physicalMesh->constrainCoefficients.buf;
+
+ const float shortestEdgeLength = physicalMesh->averageEdgeLength * 0.5f * scale;
+
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentState(DebugRenderState::SolidShaded);
+
+ const uint32_t colorRed = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Red);
+ const uint32_t colorBlue = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Blue);
+
+ const float actorScale = mActorDesc->actorScale;
+
+ for (uint32_t i = 0; i < mClothingSimulation->sdkNumDeformableVertices; i++)
+ {
+ if (coeffs[i].collisionSphereRadius <= 0.0f)
+ {
+ continue;
+ }
+
+ PxVec3 skinnedPosition = mClothingSimulation->skinnedPhysicsPositions[i];
+ if (coeffs[i].collisionSphereDistance > 0.0f)
+ {
+ skinnedPosition -= mClothingSimulation->skinnedPhysicsNormals[i] * (coeffs[i].collisionSphereDistance * actorScale);
+ }
+
+ const float collisionSphereRadius = coeffs[i].collisionSphereRadius * actorScale;
+
+ const PxVec3 sphereCenter = skinnedPosition - mClothingSimulation->skinnedPhysicsNormals[i] * collisionSphereRadius;
+
+ PxVec3 centerToSim = mClothingSimulation->sdkWritebackPosition[i] - sphereCenter;
+ centerToSim.normalize();
+ PxVec3 right = centerToSim.cross(PxVec3(0.0f, 1.0f, 0.0f));
+ PxVec3 up = right.cross(centerToSim);
+ PxVec3 target = sphereCenter + centerToSim * collisionSphereRadius;
+
+ right *= shortestEdgeLength;
+ up *= shortestEdgeLength;
+
+ const float r = collisionSphereRadius;
+ const float back = r - sqrtf(r * r - shortestEdgeLength * shortestEdgeLength);
+
+ // move the verts a bit back such that they are on the sphere
+ centerToSim *= back;
+
+ PxVec3 l1 = target + right - centerToSim;
+ PxVec3 l2 = target + up - centerToSim;
+ PxVec3 l3 = target - right - centerToSim;
+ PxVec3 l4 = target - up - centerToSim;
+
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorRed);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugTri(target, l1, l2);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugTri(target, l2, l3);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugTri(target, l3, l4);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugTri(target, l4, l1);
+#if 1
+ // PH: also render backfaces, in blue
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorBlue);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugTri(target, l1, l4);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugTri(target, l4, l3);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugTri(target, l3, l2);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugTri(target, l2, l1);
+#endif
+ }
+ }
+#endif
+}
+
+
+
+void ClothingActorImpl::visualizeBoneConnections(RenderDebugInterface& renderDebug, const PxVec3* positions, const uint16_t* boneIndices,
+ const float* boneWeights, uint32_t numBonesPerVertex, uint32_t numVertices) const
+{
+#ifdef WITHOUT_DEBUG_VISUALIZE
+ PX_UNUSED(renderDebug);
+ PX_UNUSED(positions);
+ PX_UNUSED(boneIndices);
+ PX_UNUSED(boneWeights);
+ PX_UNUSED(numBonesPerVertex);
+ PX_UNUSED(numVertices);
+#else
+ const PxMat44* matrices = mData.mInternalBoneMatricesCur;
+ if (matrices == NULL)
+ {
+ return;
+ }
+
+ for (uint32_t i = 0; i < numVertices; i++)
+ {
+ // skin the vertex
+ PxVec3 pos(0.0f);
+ for (uint32_t j = 0; j < numBonesPerVertex; j++)
+ {
+ float boneWeight = (boneWeights == NULL) ? 1.0f : boneWeights[i * numBonesPerVertex + j];
+ if (boneWeight > 0.0f)
+ {
+ uint32_t boneIndex = boneIndices[i * numBonesPerVertex + j];
+ pos += matrices[boneIndex].transform(positions[i]) * boneWeight;
+ }
+ }
+
+ // draw the lines to the bones
+ for (uint32_t j = 0; j < numBonesPerVertex; j++)
+ {
+ float boneWeight = (boneWeights == NULL) ? 1.0f : boneWeights[i * numBonesPerVertex + j];
+ if (boneWeight > 0.0f)
+ {
+ uint32_t boneIndex = boneIndices[i * numBonesPerVertex + j];
+ uint32_t b = (uint32_t)(255 * boneWeight);
+ uint32_t color = (b << 16) + (b << 8) + b;
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(color);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(pos, matrices[boneIndex].transform(mAsset->getBoneBindPose(boneIndex).getPosition()));
+ }
+ }
+ }
+#endif
+}
+
+
+
+// collision functions
+ClothingPlane* ClothingActorImpl::createCollisionPlane(const PxPlane& plane)
+{
+ ClothingPlane* actorPlane = NULL;
+ actorPlane = PX_NEW(ClothingPlaneImpl)(mCollisionPlanes, *this, plane);
+ PX_ASSERT(actorPlane != NULL);
+ bActorCollisionChanged = true;
+ return actorPlane;
+}
+
+ClothingConvex* ClothingActorImpl::createCollisionConvex(ClothingPlane** planes, uint32_t numPlanes)
+{
+ if (numPlanes < 3)
+ return NULL;
+
+ ClothingConvex* convex = NULL;
+ convex = PX_NEW(ClothingConvexImpl)(mCollisionConvexes, *this, planes, numPlanes);
+ PX_ASSERT(convex != NULL);
+ bActorCollisionChanged = true;
+
+ return convex;
+}
+
+ClothingSphere* ClothingActorImpl::createCollisionSphere(const PxVec3& position, float radius)
+{
+
+ ClothingSphere* actorSphere = NULL;
+ actorSphere = PX_NEW(ClothingSphereImpl)(mCollisionSpheres, *this, position, radius);
+ PX_ASSERT(actorSphere != NULL);
+ bActorCollisionChanged = true;
+ return actorSphere;
+}
+
+ClothingCapsule* ClothingActorImpl::createCollisionCapsule(ClothingSphere& sphere1, ClothingSphere& sphere2)
+{
+ ClothingCapsule* actorCapsule = NULL;
+ actorCapsule = PX_NEW(ClothingCapsuleImpl)(mCollisionCapsules, *this, sphere1, sphere2);
+ PX_ASSERT(actorCapsule != NULL);
+ bActorCollisionChanged = true;
+ return actorCapsule;
+}
+
+ClothingTriangleMesh* ClothingActorImpl::createCollisionTriangleMesh()
+{
+ ClothingTriangleMesh* triMesh = NULL;
+ triMesh = PX_NEW(ClothingTriangleMeshImpl)(mCollisionTriangleMeshes, *this);
+ PX_ASSERT(triMesh != NULL);
+ bActorCollisionChanged = true;
+ return triMesh;
+}
+
+
+void ClothingActorImpl::releaseCollision(ClothingCollisionImpl& collision)
+{
+ bActorCollisionChanged = 1;
+ if (mClothingSimulation != NULL)
+ {
+ mClothingSimulation->releaseCollision(collision);
+ }
+ collision.destroy();
+}
+
+#if APEX_UE4
+void ClothingActorImpl::simulate(PxF32 dt)
+{
+ // before tick task
+ tickSynchBeforeSimulate_LocksPhysX(dt, dt, 0, 1);
+
+ if (mClothingSimulation != NULL)
+ mClothingSimulation->simulate(dt);
+
+ // during tick task
+ tickAsynch_NoPhysX(); // this is a no-op
+
+ // start fetch result task
+ mFetchResultsRunningMutex.lock();
+ mFetchResultsRunning = true;
+ mFetchResultsSync.reset();
+ mFetchResultsRunningMutex.unlock();
+
+ // fetch result task
+ fetchResults();
+ getActorData().tickSynchAfterFetchResults_LocksPhysX(); // this is a no-op
+ setFetchResultsSync();
+}
+#endif
+
+}
+} // namespace nvidia
+
diff --git a/APEX_1.4/module/clothing/src/ClothingActorTasks.cpp b/APEX_1.4/module/clothing/src/ClothingActorTasks.cpp
new file mode 100644
index 00000000..31407a78
--- /dev/null
+++ b/APEX_1.4/module/clothing/src/ClothingActorTasks.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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 "ClothingActorTasks.h"
+#include "ClothingActorImpl.h"
+#include "ModulePerfScope.h"
+
+
+namespace nvidia
+{
+namespace clothing
+{
+
+void ClothingActorBeforeTickTask::run()
+{
+#if APEX_UE4 // SHORTCUT_CLOTH_TASKS
+ mActor->simulate(mDeltaTime);
+#else
+#ifdef PROFILE
+ PIXBeginNamedEvent(0, "ClothingActorBeforeTickTask");
+#endif
+ //PX_ASSERT(mDeltaTime > 0.0f); // need to allow simulate(0) calls
+ mActor->tickSynchBeforeSimulate_LocksPhysX(mDeltaTime, mSubstepSize, 0, mNumSubSteps);
+#ifdef PROFILE
+ PIXEndNamedEvent();
+#endif
+#endif // SHORTCUT_CLOTH_TASKS
+}
+
+
+
+const char* ClothingActorBeforeTickTask::getName() const
+{
+ return "ClothingActorImpl::BeforeTickTask";
+}
+
+
+// --------------------------------------------------------------------
+
+
+void ClothingActorDuringTickTask::run()
+{
+ mActor->tickAsynch_NoPhysX();
+}
+
+
+
+const char* ClothingActorDuringTickTask::getName() const
+{
+ return "ClothingActorImpl::DuringTickTask";
+}
+
+// --------------------------------------------------------------------
+
+void ClothingActorFetchResultsTask::run()
+{
+#ifdef PROFILE
+ PIXBeginNamedEvent(0, "ClothingActorFetchResultsTask");
+#endif
+ mActor->fetchResults();
+ ClothingActorData& actorData = mActor->getActorData();
+
+ actorData.tickSynchAfterFetchResults_LocksPhysX();
+#ifdef PROFILE
+ PIXEndNamedEvent();
+#endif
+#if APEX_UE4
+ mActor->setFetchResultsSync();
+#endif
+}
+
+
+#if APEX_UE4
+void ClothingActorFetchResultsTask::release()
+{
+ PxTask::release();
+}
+#endif
+
+
+const char* ClothingActorFetchResultsTask::getName() const
+{
+ return "ClothingActorImpl::FetchResultsTask";
+}
+
+
+}
+}
+
+
diff --git a/APEX_1.4/module/clothing/src/ClothingAssetAuthoringImpl.cpp b/APEX_1.4/module/clothing/src/ClothingAssetAuthoringImpl.cpp
new file mode 100644
index 00000000..cd7d83aa
--- /dev/null
+++ b/APEX_1.4/module/clothing/src/ClothingAssetAuthoringImpl.cpp
@@ -0,0 +1,3931 @@
+/*
+ * 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 "ApexUsingNamespace.h"
+
+#ifndef WITHOUT_APEX_AUTHORING
+
+#include "ClothingAssetAuthoringImpl.h"
+#include "ApexMeshHash.h"
+#include "PsSort.h"
+#include "ApexPermute.h"
+#include "CookingPhysX.h"
+#include "ClothingGlobals.h"
+#include "ClothingPhysicalMeshImpl.h"
+
+#define MAX_DISTANCE_NAME "MAX_DISTANCE"
+#define COLLISION_SPHERE_DISTANCE_NAME "COLLISION_SPHERE_DISTANCE"
+#define COLLISION_SPHERE_RADIUS_NAME "COLLISION_SPHERE_RADIUS"
+#define USED_FOR_PHYSICS_NAME "USED_FOR_PHYSICS"
+
+#define LATCH_TO_NEAREST_SLAVE_NAME "LATCH_TO_NEAREST_SLAVE"
+#define LATCH_TO_NEAREST_MASTER_NAME "LATCH_TO_NEAREST_MASTER"
+
+#include "AbstractMeshDescription.h"
+#include "RenderMesh.h"
+
+#include "ApexSDKIntl.h"
+#include "AuthorableObjectIntl.h"
+
+#include "PsMathUtils.h"
+
+
+namespace nvidia
+{
+namespace clothing
+{
+
+struct uint32_t_3
+{
+ uint32_t indices[3];
+};
+
+
+
+class TriangleGreater_3
+{
+public:
+ TriangleGreater_3() {}
+
+ TriangleGreater_3(uint32_t* deformableIndices, ClothingConstrainCoefficients* constrainCoeffs) :
+ mDeformableIndices(deformableIndices),
+ mConstrainCoeffs(constrainCoeffs)
+ {}
+
+ inline bool operator()(uint32_t_3 a, uint32_t_3 b) const
+ {
+ float maxDistA = mConstrainCoeffs[mDeformableIndices[a.indices[0]]].maxDistance;
+ float maxDistB = mConstrainCoeffs[mDeformableIndices[b.indices[0]]].maxDistance;
+ bool aHasEqualMaxDistances = (maxDistA == mConstrainCoeffs[mDeformableIndices[a.indices[1]]].maxDistance);
+ bool bHasEqualMaxDistances = (maxDistB == mConstrainCoeffs[mDeformableIndices[b.indices[1]]].maxDistance);
+ for (uint32_t i = 1; i < 3; i++)
+ {
+ if (aHasEqualMaxDistances)
+ {
+ aHasEqualMaxDistances = (mConstrainCoeffs[mDeformableIndices[a.indices[i - 1]]].maxDistance == mConstrainCoeffs[mDeformableIndices[a.indices[i]]].maxDistance);
+ }
+ if (bHasEqualMaxDistances)
+ {
+ bHasEqualMaxDistances = (mConstrainCoeffs[mDeformableIndices[b.indices[i - 1]]].maxDistance == mConstrainCoeffs[mDeformableIndices[b.indices[i]]].maxDistance);
+ }
+ maxDistA = PxMax(maxDistA, mConstrainCoeffs[mDeformableIndices[a.indices[i]]].maxDistance);
+ maxDistB = PxMax(maxDistB, mConstrainCoeffs[mDeformableIndices[b.indices[i]]].maxDistance);
+ }
+
+ if (maxDistA == maxDistB)
+ {
+ return aHasEqualMaxDistances && !bHasEqualMaxDistances;
+ }
+
+ return maxDistA > maxDistB;
+ }
+
+private:
+ uint32_t* mDeformableIndices;
+ ClothingConstrainCoefficients* mConstrainCoeffs;
+};
+
+
+
+struct uint32_t_4
+{
+ uint32_t indices[4];
+};
+
+
+
+class TriangleGreater_4
+{
+public:
+ TriangleGreater_4() {}
+
+ TriangleGreater_4(uint32_t* deformableIndices, ClothingConstrainCoefficients* constrainCoeffs) :
+ mDeformableIndices(deformableIndices),
+ mConstrainCoeffs(constrainCoeffs)
+ {}
+
+ inline bool operator()(uint32_t_4 a, uint32_t_4 b) const
+ {
+ float maxDistA = mConstrainCoeffs[mDeformableIndices[a.indices[0]]].maxDistance;
+ float maxDistB = mConstrainCoeffs[mDeformableIndices[b.indices[0]]].maxDistance;
+ bool aHasEqualMaxDistances = (maxDistA == mConstrainCoeffs[mDeformableIndices[a.indices[1]]].maxDistance);
+ bool bHasEqualMaxDistances = (maxDistB == mConstrainCoeffs[mDeformableIndices[b.indices[1]]].maxDistance);
+ for (uint32_t i = 1; i < 4; i++)
+ {
+ if (aHasEqualMaxDistances)
+ {
+ aHasEqualMaxDistances = (mConstrainCoeffs[mDeformableIndices[a.indices[i - 1]]].maxDistance == mConstrainCoeffs[mDeformableIndices[a.indices[i]]].maxDistance);
+ }
+ if (bHasEqualMaxDistances)
+ {
+ bHasEqualMaxDistances = (mConstrainCoeffs[mDeformableIndices[b.indices[i - 1]]].maxDistance == mConstrainCoeffs[mDeformableIndices[b.indices[i]]].maxDistance);
+ }
+ maxDistA = PxMax(maxDistA, mConstrainCoeffs[mDeformableIndices[a.indices[i]]].maxDistance);
+ maxDistB = PxMax(maxDistB, mConstrainCoeffs[mDeformableIndices[b.indices[i]]].maxDistance);
+ }
+
+ if (maxDistA == maxDistB)
+ {
+ return aHasEqualMaxDistances && !bHasEqualMaxDistances;
+ }
+
+ return maxDistA > maxDistB;
+ }
+
+private:
+ uint32_t* mDeformableIndices;
+ ClothingConstrainCoefficients* mConstrainCoeffs;
+};
+
+
+
+class BoneEntryPredicate
+{
+public:
+ bool operator()(const ClothingAssetParametersNS::BoneEntry_Type& a, const ClothingAssetParametersNS::BoneEntry_Type& b) const
+ {
+ // mesh referenced bones first
+ if (a.numMeshReferenced == 0 && b.numMeshReferenced > 0)
+ {
+ return false;
+ }
+ if (a.numMeshReferenced > 0 && b.numMeshReferenced == 0)
+ {
+ return true;
+ }
+
+ if (a.numMeshReferenced == 0) // both are 0 as they have to be equal here
+ {
+ PX_ASSERT(b.numMeshReferenced == 0);
+
+ // RB referenced bones next, this will leave non referenced bones at the end
+ if (a.numRigidBodiesReferenced != b.numRigidBodiesReferenced)
+ {
+ return a.numRigidBodiesReferenced > b.numRigidBodiesReferenced;
+ }
+ else
+ {
+ return a.externalIndex < b.externalIndex;
+ }
+ }
+
+ return a.externalIndex < b.externalIndex;
+ }
+};
+
+
+
+class ActorEntryPredicate
+{
+public:
+ bool operator()(const ClothingAssetParametersNS::ActorEntry_Type& a, const ClothingAssetParametersNS::ActorEntry_Type& b) const
+ {
+ if (a.boneIndex < b.boneIndex)
+ {
+ return true;
+ }
+ else if (a.boneIndex > b.boneIndex)
+ {
+ return false;
+ }
+ return a.convexVerticesCount < b.convexVerticesCount;
+ }
+};
+
+
+
+static bool getClosestVertex(RenderMeshAssetAuthoringIntl* renderMeshAsset, const PxVec3& position, uint32_t& resultSubmeshIndex,
+ uint32_t& resultGraphicalVertexIndex, const char* bufferName, bool ignoreUnused)
+{
+ resultSubmeshIndex = 0;
+ resultGraphicalVertexIndex = 0;
+
+ bool found = false;
+
+ if (renderMeshAsset != NULL)
+ {
+ float closestDistanceSquared = FLT_MAX;
+
+ for (uint32_t submeshIndex = 0; submeshIndex < renderMeshAsset->getSubmeshCount(); submeshIndex++)
+ {
+ RenderDataFormat::Enum outFormat = RenderDataFormat::UNSPECIFIED;
+ const VertexBuffer& vb = renderMeshAsset->getSubmesh(submeshIndex).getVertexBuffer();
+ const VertexFormat& vf = vb.getFormat();
+ if (bufferName != NULL)
+ {
+ VertexFormat::BufferID id = ::strcmp(bufferName, "NORMAL") == 0 ? vf.getSemanticID(RenderVertexSemantic::NORMAL) : vf.getID(bufferName);
+ outFormat = vf.getBufferFormat((uint32_t)vf.getBufferIndexFromID(id));
+ if (outFormat == RenderDataFormat::UNSPECIFIED)
+ {
+ continue;
+ }
+ }
+
+ const uint8_t* usedForPhysics = NULL;
+ if (ignoreUnused)
+ {
+ uint32_t usedForPhysicsIndex = (uint32_t)vf.getBufferIndexFromID(vf.getID(USED_FOR_PHYSICS_NAME));
+ outFormat = vf.getBufferFormat(usedForPhysicsIndex);
+ if (outFormat == RenderDataFormat::UBYTE1)
+ {
+ usedForPhysics = (const uint8_t*)vb.getBuffer(usedForPhysicsIndex);
+ }
+ }
+
+ const uint32_t* slave = NULL;
+ if (ignoreUnused)
+ {
+ uint32_t slaveIndex = (uint32_t)vf.getBufferIndexFromID(vf.getID(LATCH_TO_NEAREST_SLAVE_NAME));
+ outFormat = vf.getBufferFormat(slaveIndex);
+ if (outFormat == RenderDataFormat::UINT1)
+ {
+ slave = (const uint32_t*)vb.getBuffer(slaveIndex);
+ }
+ }
+
+ const uint32_t vertexCount = renderMeshAsset->getSubmesh(submeshIndex).getVertexCount(0); // only 1 part supported
+ RenderDataFormat::Enum format;
+ uint32_t bufferIndex = (uint32_t)vf.getBufferIndexFromID(vf.getSemanticID(RenderVertexSemantic::POSITION));
+ const PxVec3* positions = (const PxVec3*)vb.getBufferAndFormat(format, bufferIndex);
+ if (format != RenderDataFormat::FLOAT3)
+ {
+ PX_ALWAYS_ASSERT();
+ positions = NULL;
+ }
+ for (uint32_t vertexIndex = 0; vertexIndex < vertexCount; vertexIndex++)
+ {
+ if (usedForPhysics != NULL && usedForPhysics[vertexIndex] == 0)
+ {
+ continue;
+ }
+
+ if (slave != NULL && slave[vertexIndex] != 0)
+ {
+ continue;
+ }
+
+ const float distSquared = (position - positions[vertexIndex]).magnitudeSquared();
+ if (distSquared < closestDistanceSquared)
+ {
+ closestDistanceSquared = distSquared;
+ resultSubmeshIndex = submeshIndex;
+ resultGraphicalVertexIndex = vertexIndex;
+ found = true;
+ }
+ }
+ }
+ }
+
+ return found;
+}
+
+
+
+
+ClothingAssetAuthoringImpl::ClothingAssetAuthoringImpl(ModuleClothingImpl* module, ResourceList& list) :
+ ClothingAssetImpl(module, list, "ClothingAuthoring"),
+ mExportScale(1.0f),
+ mDeriveNormalsFromBones(false),
+ mOwnsMaterialLibrary(true),
+ mPreviousCookedType("Embedded")
+{
+ mInvalidConstrainCoefficients.maxDistance = -1.0f;
+ mInvalidConstrainCoefficients.collisionSphereDistance = -FLT_MAX;
+ mInvalidConstrainCoefficients.collisionSphereRadius = -1.0f;
+
+ initParams();
+}
+
+ClothingAssetAuthoringImpl::ClothingAssetAuthoringImpl(ModuleClothingImpl* module, ResourceList& list, const char* name) :
+ ClothingAssetImpl(module, list, name),
+ mExportScale(1.0f),
+ mDeriveNormalsFromBones(false),
+ mOwnsMaterialLibrary(true),
+ mPreviousCookedType("Embedded")
+{
+ mInvalidConstrainCoefficients.maxDistance = -1.0f;
+ mInvalidConstrainCoefficients.collisionSphereDistance = -FLT_MAX;
+ mInvalidConstrainCoefficients.collisionSphereRadius = -1.0f;
+
+ initParams();
+}
+
+ClothingAssetAuthoringImpl::ClothingAssetAuthoringImpl(ModuleClothingImpl* module, ResourceList& list, NvParameterized::Interface* params, const char* name) :
+ ClothingAssetImpl(module, list, params, name),
+ mExportScale(1.0f),
+ mDeriveNormalsFromBones(false),
+ mOwnsMaterialLibrary(true),
+ mPreviousCookedType("Embedded")
+{
+ mDefaultConstrainCoefficients.maxDistance = 0.0f;
+ mDefaultConstrainCoefficients.collisionSphereDistance = 0.0f;
+ mDefaultConstrainCoefficients.collisionSphereRadius = 0.0f;
+
+ mInvalidConstrainCoefficients.maxDistance = -1.0f;
+ mInvalidConstrainCoefficients.collisionSphereDistance = -FLT_MAX;
+ mInvalidConstrainCoefficients.collisionSphereRadius = -1.0f;
+
+ initParams();
+
+ if (mParams->rootBoneIndex < (uint32_t)mParams->bones.arraySizes[0])
+ {
+ mRootBoneName = mParams->bones.buf[mParams->rootBoneIndex].name;
+ }
+}
+
+
+
+void ClothingAssetAuthoringImpl::release()
+{
+ mModule->mSdk->releaseAssetAuthoring(*this);
+}
+
+
+
+bool ClothingAssetAuthoringImpl::checkSetMeshesInput(uint32_t lod, ClothingPhysicalMesh* nxPhysicalMesh, uint32_t& graphicalLodIndex)
+{
+ // index where it will be inserted
+ for (graphicalLodIndex = 0; graphicalLodIndex < mGraphicalLods.size(); ++graphicalLodIndex)
+ {
+ if (mGraphicalLods[graphicalLodIndex]->lod >= lod)
+ {
+ break;
+ }
+ }
+
+
+ if (nxPhysicalMesh != NULL)
+ {
+ if (mPhysicalMeshesInput.size() != mPhysicalMeshes.size())
+ {
+ APEX_INVALID_PARAMETER("Trying to operate add a physical mesh to an authoring object that has been deserialized. This is not suppored.");
+ return false;
+ }
+
+ // check that shared physics meshes are only in subsequent lods
+ int32_t i = (int32_t)graphicalLodIndex - 1;
+ uint32_t physMeshId = (uint32_t) - 1;
+ while (i >= 0)
+ {
+ physMeshId = mGraphicalLods[(uint32_t)i]->physicalMeshId;
+ if (physMeshId != (uint32_t) - 1 && mPhysicalMeshesInput[physMeshId] != nxPhysicalMesh)
+ {
+ break;
+ }
+ --i;
+ }
+
+ while (i >= 0)
+ {
+ physMeshId = mGraphicalLods[(uint32_t)i]->physicalMeshId;
+ if (physMeshId != (uint32_t) - 1 && mPhysicalMeshesInput[physMeshId] == nxPhysicalMesh)
+ {
+ APEX_INVALID_PARAMETER("Only subsequent graphical lods can share a physical mesh.");
+ return false;
+ }
+ --i;
+ }
+
+ i = (int32_t)graphicalLodIndex + 1;
+ physMeshId = (uint32_t) - 1;
+ while (i < (int32_t)mGraphicalLods.size())
+ {
+ physMeshId = mGraphicalLods[(uint32_t)i]->physicalMeshId;
+ if (physMeshId != (uint32_t) - 1 && mPhysicalMeshesInput[physMeshId] != nxPhysicalMesh)
+ {
+ break;
+ }
+ ++i;
+ }
+
+ while (i < (int32_t)mGraphicalLods.size())
+ {
+ physMeshId = mGraphicalLods[(uint32_t)i]->physicalMeshId;
+ if (physMeshId != (uint32_t) - 1 && mPhysicalMeshesInput[physMeshId] == nxPhysicalMesh)
+ {
+ APEX_INVALID_PARAMETER("Only subsequent graphical lods can share a physical mesh.");
+ return false;
+ }
+ ++i;
+ }
+ }
+ return true;
+}
+
+
+
+void ClothingAssetAuthoringImpl::sortPhysicalMeshes()
+{
+ if (mPhysicalMeshes.size() == 0)
+ {
+ return;
+ }
+
+ // sort physical lods according to references in graphical lods
+ Array<uint32_t> new2old(mPhysicalMeshes.size(), (uint32_t) - 1);
+ Array<uint32_t> old2new(mPhysicalMeshes.size(), (uint32_t) - 1);
+ bool reorderFailed = false;
+
+ uint32_t nextId = 0;
+ for (uint32_t i = 0; i < mGraphicalLods.size(); i++)
+ {
+ uint32_t physMeshId = mGraphicalLods[i]->physicalMeshId;
+ if (physMeshId == (uint32_t) - 1)
+ {
+ continue;
+ }
+
+ if (nextId == 0 || new2old[nextId - 1] != physMeshId) // if there's a new ID
+ {
+ // the new ID already appeared before, we can't sort
+ if (old2new[physMeshId] != (uint32_t) - 1)
+ {
+ PX_ALWAYS_ASSERT();
+ APEX_INTERNAL_ERROR("The assignment of graphics and physics mesh in the asset does not allow ordering of the physical meshes. Reuse of physical mesh is only allowed on subsequend graphical lods.");
+ reorderFailed = true;
+ break;
+ }
+
+ new2old[nextId] = physMeshId;
+ old2new[physMeshId] = nextId;
+ ++nextId;
+ }
+ }
+
+ if (!reorderFailed)
+ {
+ // reorder
+ ApexPermute<ClothingPhysicalMeshParameters*>(&mPhysicalMeshes[0], &new2old[0], mPhysicalMeshes.size());
+
+ // update references
+ for (uint32_t i = 0; i < mGraphicalLods.size(); i++)
+ {
+ mGraphicalLods[i]->physicalMeshId = old2new[mGraphicalLods[i]->physicalMeshId];
+ }
+
+ // clear transition maps
+ for (uint32_t i = 0; i < mPhysicalMeshes.size(); i++)
+ {
+ ParamArray<SkinClothMapB> transitionDownB(mPhysicalMeshes[i], "transitionDownB", reinterpret_cast<ParamDynamicArrayStruct*>(&mPhysicalMeshes[i]->transitionDownB));
+ transitionDownB.clear();
+ ParamArray<SkinClothMapB> transitionUpB(mPhysicalMeshes[i], "transitionUpB", reinterpret_cast<ParamDynamicArrayStruct*>(&mPhysicalMeshes[i]->transitionUpB));
+ transitionUpB.clear();
+
+ ParamArray<SkinClothMap> transitionDown(mPhysicalMeshes[i], "transitionDown", reinterpret_cast<ParamDynamicArrayStruct*>(&mPhysicalMeshes[i]->transitionDown));
+ transitionDown.clear();
+ ParamArray<SkinClothMap> transitionUp(mPhysicalMeshes[i], "transitionUp", reinterpret_cast<ParamDynamicArrayStruct*>(&mPhysicalMeshes[i]->transitionUp));
+ transitionUp.clear();
+ }
+ }
+}
+
+
+void ClothingAssetAuthoringImpl::setMeshes(uint32_t lod, RenderMeshAssetAuthoring* renderMeshAssetDontReference,
+ ClothingPhysicalMesh* nxPhysicalMesh,
+ float normalResemblance, bool ignoreUnusedVertices,
+ IProgressListener* progress)
+{
+ WRITE_ZONE();
+ // check input
+ uint32_t graphicalLodIndexTest = (uint32_t) - 1;
+ if (!checkSetMeshesInput(lod, nxPhysicalMesh, graphicalLodIndexTest))
+ {
+ return;
+ }
+
+ // get index and add lod if necessary, only adds if lod doesn't exist already
+ const uint32_t graphicalLodIndex = addGraphicalLod(lod);
+ PX_ASSERT(graphicalLodIndex == graphicalLodIndexTest);
+ PX_ASSERT(lod == mGraphicalLods[graphicalLodIndex]->lod);
+
+ clearMapping(graphicalLodIndex);
+
+ // reset counters to 0
+ for (uint32_t i = 0; i < mBones.size(); i++)
+ {
+ mBones[i].numMeshReferenced = mBones[i].numRigidBodiesReferenced = 0;
+ }
+
+ // remove existing physical of this lod mesh if it is not used by other lod
+ const uint32_t oldPhysicalMeshId = mGraphicalLods[graphicalLodIndex]->physicalMeshId;
+ if (oldPhysicalMeshId != (uint32_t) - 1)
+ {
+ // check if it's referenced by someone else
+ bool removePhysicalMesh = true;
+ for (uint32_t i = 0; i < mGraphicalLods.size(); i++)
+ {
+ // don't consider the current graphical lod
+ if (mGraphicalLods[i]->lod == lod)
+ {
+ continue;
+ }
+
+ if (mGraphicalLods[i]->physicalMeshId == oldPhysicalMeshId)
+ {
+ removePhysicalMesh = false;
+ break;
+ }
+ }
+
+ // if it's not referenced, remove it
+ if (removePhysicalMesh)
+ {
+ if (mPhysicalMeshesInput.size() == mPhysicalMeshes.size()) // mPhysicalMeshesInput is not set if the authoring is created from an existing params object
+ {
+ mPhysicalMeshesInput.replaceWithLast(oldPhysicalMeshId);
+ }
+
+ // replace with last and update the references to the last
+ mPhysicalMeshes.replaceWithLast(oldPhysicalMeshId);
+ for (uint32_t i = 0; i < mGraphicalLods.size(); i++)
+ {
+ if (mGraphicalLods[i]->physicalMeshId == mPhysicalMeshes.size())
+ {
+ mGraphicalLods[i]->physicalMeshId = oldPhysicalMeshId;
+ }
+ }
+ }
+ }
+
+ // copy physical mesh if we don't already have it
+ bool newPhysicalMesh = false;
+ ClothingPhysicalMeshParameters* physicalMesh = NULL;
+
+ if (nxPhysicalMesh != NULL)
+ {
+ ClothingPhysicalMeshImpl* physicalMeshInput = DYNAMIC_CAST(ClothingPhysicalMeshImpl*)(nxPhysicalMesh);
+ PX_ASSERT(physicalMeshInput != NULL);
+
+ PX_ASSERT(mPhysicalMeshes.size() == mPhysicalMeshesInput.size());
+ for (uint32_t i = 0; i < mPhysicalMeshesInput.size(); i++)
+ {
+ if (physicalMeshInput == mPhysicalMeshesInput[i]) // TODO check some more stuff in case it has been released and a new one was created at the same address
+ {
+ physicalMesh = mPhysicalMeshes[i];
+ PX_ASSERT(physicalMesh != NULL);
+ mGraphicalLods[graphicalLodIndex]->physicalMeshId = i;
+ break;
+ }
+ }
+ if (physicalMesh == NULL)
+ {
+ physicalMesh = DYNAMIC_CAST(ClothingPhysicalMeshParameters*)(GetInternalApexSDK()->getParameterizedTraits()->createNvParameterized(ClothingPhysicalMeshParameters::staticClassName()));
+ physicalMeshInput->makeCopy(physicalMesh);
+ physicalMesh->referenceCount = 1;
+ mPhysicalMeshes.pushBack(physicalMesh);
+ mPhysicalMeshesInput.pushBack(physicalMeshInput);
+
+ ClothingPhysicalMeshImpl* mesh = mModule->createPhysicalMeshInternal(physicalMesh);
+ mesh->updateSkinningNormals();
+ mesh->release();
+
+ newPhysicalMesh = true;
+ PX_ASSERT(physicalMesh != NULL);
+ mGraphicalLods[graphicalLodIndex]->physicalMeshId = mPhysicalMeshes.size() - 1;
+ }
+ }
+
+ bool hasLod = addGraphicalMesh(renderMeshAssetDontReference, graphicalLodIndex);
+ if (hasLod && physicalMesh)
+ {
+ PX_ASSERT(mGraphicalLods[graphicalLodIndex] != NULL);
+ RenderMeshAssetIntl* renderMeshAssetCopy = reinterpret_cast<RenderMeshAssetIntl*>(mGraphicalLods[graphicalLodIndex]->renderMeshAssetPointer);
+
+ // update mapping
+ updateMappingAuthoring(*mGraphicalLods[graphicalLodIndex], renderMeshAssetCopy, static_cast<RenderMeshAssetAuthoringIntl*>(renderMeshAssetDontReference),
+ normalResemblance, ignoreUnusedVertices, progress);
+
+ // sort physics mesh triangles and vertices
+ ClothingPhysicalMeshImpl* mesh = mModule->createPhysicalMeshInternal(physicalMesh);
+ sortDeformableIndices(*mesh);
+
+ // calculate and setup number of simulated vertices and indices
+ setupPhysicalMesh(*physicalMesh);
+
+ // "reordering has to be done after creating the submeshes because the vertices must be sorted per submesh" - not valid anymore
+ reorderDeformableVertices(*mesh);
+
+ // re-order vertices in graphical mesh to make tangent recompute faster
+ reorderGraphicsVertices(graphicalLodIndex, false);
+ removeMaxDistance0Mapping(*mGraphicalLods[graphicalLodIndex], renderMeshAssetCopy);
+
+ mesh->release();
+ mesh = NULL;
+
+ // conditionally drop the immediate map (perf optimization)
+ conditionalMergeMapping(*renderMeshAssetCopy, *mGraphicalLods[graphicalLodIndex]);
+ }
+
+ // keep physical meshes sorted such that the transition maps are correct
+ // (needs to be called after 'addGraphicalMesh', so a graphicalLOD deletion is not missed)
+ sortPhysicalMeshes();
+
+ bool isIdentity = true;
+ Array<int32_t> old2new(mBones.size(), -1);
+ for (uint32_t i = 0; i < mBones.size(); i++)
+ {
+ old2new[(uint32_t)mBones[i].externalIndex] = mBones[i].internalIndex;
+ isIdentity &= mBones[i].externalIndex == mBones[i].internalIndex;
+ }
+
+ if (!isIdentity && hasLod)
+ {
+ reinterpret_cast<RenderMeshAssetIntl*>(mGraphicalLods[graphicalLodIndex]->renderMeshAssetPointer)->permuteBoneIndices(old2new);
+
+ if (newPhysicalMesh)
+ {
+ const uint32_t physicalMeshId = mGraphicalLods[graphicalLodIndex]->physicalMeshId;
+ ClothingPhysicalMeshImpl* mesh = mModule->createPhysicalMeshInternal(mPhysicalMeshes[physicalMeshId]);
+ mesh->permuteBoneIndices(old2new);
+ mesh->release();
+ }
+ }
+}
+
+
+
+bool ClothingAssetAuthoringImpl::addPlatformToGraphicalLod(uint32_t lod, PlatformTag platform)
+{
+ WRITE_ZONE();
+ uint32_t index;
+ if (!getGraphicalLodIndex(lod, index))
+ {
+ return false;
+ }
+
+ ClothingGraphicalLodParameters* graphicalLod = mGraphicalLods[index];
+
+ // pushback to an array of strings
+ NvParameterized::Handle handle(*graphicalLod);
+ if (graphicalLod->getParameterHandle("platforms", handle) != NvParameterized::ERROR_NONE)
+ {
+ return false;
+ }
+
+ int32_t numPlatforms = 0;
+ graphicalLod->getArraySize(handle, numPlatforms);
+ graphicalLod->resizeArray(handle, numPlatforms + 1);
+ NvParameterized::Handle elementHandle(*graphicalLod);
+ handle.getChildHandle(numPlatforms, elementHandle);
+ graphicalLod->setParamString(elementHandle, platform);
+
+ return true;
+}
+
+
+bool ClothingAssetAuthoringImpl::removePlatform(uint32_t lod, PlatformTag platform)
+{
+ WRITE_ZONE();
+ uint32_t index;
+ if (!getGraphicalLodIndex(lod, index))
+ {
+ return false;
+ }
+
+ ClothingGraphicalLodParameters* graphicalLod = mGraphicalLods[index];
+
+ ParamArray<NvParameterized::DummyStringStruct> platforms(graphicalLod, "platforms", reinterpret_cast<ParamDynamicArrayStruct*>(&graphicalLod->platforms));
+
+ bool removed = false;
+ for (int32_t i = (int32_t)platforms.size() - 1; i >= 0 ; --i)
+ {
+ if (::strcmp(platforms[(uint32_t)i], platform) == 0)
+ {
+ platforms.replaceWithLast((uint32_t)i);
+ removed = true;
+ }
+ }
+
+ return removed;
+}
+
+
+uint32_t ClothingAssetAuthoringImpl::getNumPlatforms(uint32_t lod) const
+{
+ uint32_t index;
+ if (!getGraphicalLodIndex(lod, index))
+ {
+ return 0;
+ }
+
+ ClothingGraphicalLodParameters* graphicalLod = mGraphicalLods[index];
+
+ ParamArray<NvParameterized::DummyStringStruct> platforms(graphicalLod, "platforms", reinterpret_cast<ParamDynamicArrayStruct*>(&graphicalLod->platforms));
+ return platforms.size();
+}
+
+
+PlatformTag ClothingAssetAuthoringImpl::getPlatform(uint32_t lod, uint32_t i) const
+{
+ READ_ZONE();
+ uint32_t index;
+ if (!getGraphicalLodIndex(lod, index))
+ {
+ return 0;
+ }
+
+ ClothingGraphicalLodParameters* graphicalLod = mGraphicalLods[index];
+
+ ParamArray<NvParameterized::DummyStringStruct> platforms(graphicalLod, "platforms", reinterpret_cast<ParamDynamicArrayStruct*>(&graphicalLod->platforms));
+
+ if (i >= platforms.size())
+ {
+ return 0;
+ }
+
+ return platforms[i];
+}
+
+
+bool ClothingAssetAuthoringImpl::prepareForPlatform(PlatformTag platform)
+{
+ bool retVal = false;
+
+ // go through graphical lods and remove the ones that are not tagged with "platform"
+ for (int32_t i = (int32_t)mGraphicalLods.size() - 1; i >= 0; --i)
+ {
+ ClothingGraphicalLodParameters* graphicalLod = mGraphicalLods[(uint32_t)i];
+ ParamArray<NvParameterized::DummyStringStruct> platforms(graphicalLod, "platforms", reinterpret_cast<ParamDynamicArrayStruct*>(&graphicalLod->platforms));
+
+ bool keep = platforms.size() == 0; // keep it if it has no platforms at all
+ for (uint32_t j = 0; j < platforms.size(); j++)
+ {
+ const char* storedPlatform = platforms[j].buf;
+ if (::strcmp(platform, storedPlatform) == 0)
+ {
+ keep = true;
+ }
+ }
+
+ if (!keep)
+ {
+ setMeshes(graphicalLod->lod, NULL, NULL); // remove
+ }
+ else
+ {
+ retVal = true; // keep
+ }
+ }
+
+ return retVal;
+}
+
+
+
+uint32_t ClothingAssetAuthoringImpl::getNumLods() const
+{
+ READ_ZONE();
+ return mGraphicalLods.size();
+}
+
+
+
+int32_t ClothingAssetAuthoringImpl::getLodValue(uint32_t lod) const
+{
+ READ_ZONE();
+ if (lod < mGraphicalLods.size())
+ {
+ return (int32_t)mGraphicalLods[lod]->lod;
+ }
+
+ return -1;
+}
+
+
+
+void ClothingAssetAuthoringImpl::clearMeshes()
+{
+ WRITE_ZONE();
+ for (int32_t i = (int32_t)mGraphicalLods.size() - 1; i >= 0; i--)
+ {
+ setMeshes(mGraphicalLods[(uint32_t)i]->lod, NULL, NULL);
+ }
+ PX_ASSERT(mGraphicalLods.isEmpty());
+
+ PX_ASSERT(mPhysicalMeshes.size() == mPhysicalMeshesInput.size());
+ for (uint32_t i = 0; i < mPhysicalMeshes.size(); i++)
+ {
+ mPhysicalMeshes[i]->destroy();
+ }
+ mPhysicalMeshes.clear();
+ mPhysicalMeshesInput.clear();
+}
+
+
+
+ClothingPhysicalMesh* ClothingAssetAuthoringImpl::getClothingPhysicalMesh(uint32_t graphicalLod) const
+{
+ READ_ZONE();
+ uint32_t graphicalLodIndex = 0;
+ if (!getGraphicalLodIndex(graphicalLod, graphicalLodIndex))
+ {
+ return NULL;
+ }
+
+ uint32_t physicalMeshId = mGraphicalLods[graphicalLodIndex]->physicalMeshId;
+
+ if (physicalMeshId == (uint32_t) - 1)
+ {
+ return NULL;
+ }
+
+ return mModule->createPhysicalMeshInternal(mPhysicalMeshes[physicalMeshId]);
+}
+
+
+
+bool ClothingAssetAuthoringImpl::getBoneBindPose(uint32_t boneIndex, PxMat44& bindPose) const
+{
+ READ_ZONE();
+ bool ret = false;
+ if (boneIndex < mBones.size())
+ {
+ bindPose = mBones[boneIndex].bindPose;
+ ret = true;
+ }
+ return ret;
+}
+
+bool ClothingAssetAuthoringImpl::setBoneBindPose(uint32_t boneIndex, const PxMat44& bindPose)
+{
+ WRITE_ZONE();
+ bool ret = false;
+ if (boneIndex < mBones.size())
+ {
+ mBones[boneIndex].bindPose = bindPose;
+ ret = true;
+ }
+ return ret;
+}
+
+void ClothingAssetAuthoringImpl::setBoneInfo(uint32_t boneIndex, const char* boneName, const PxMat44& bindPose, int32_t parentIndex)
+{
+ WRITE_ZONE();
+ for (uint32_t i = 0; i < mBones.size(); i++)
+ {
+ if (mBones[i].externalIndex == (int32_t)boneIndex)
+ {
+ if (mBones[i].name == NULL || ::strcmp(mBones[i].name, boneName) != 0)
+ {
+ setBoneName(i, boneName);
+ }
+
+ mBones[i].bindPose = bindPose;
+
+ // parentIndex should be an internal index, so let's see
+ int32_t oldInternalParent = mBones[i].parentIndex;
+ int32_t newInternalParent = oldInternalParent;
+ PX_ASSERT((oldInternalParent == -1) == (parentIndex == -1)); // both are -1 or valid
+ if (oldInternalParent >= 0)
+ {
+ PX_ASSERT(parentIndex >= 0);
+ PX_ASSERT((uint32_t)oldInternalParent < mBones.size());
+ if ((uint32_t)oldInternalParent < mBones.size())
+ {
+ PX_ASSERT(mBones[(uint32_t)oldInternalParent].internalIndex == oldInternalParent); // just some sanity
+ if (mBones[(uint32_t)oldInternalParent].externalIndex != parentIndex)
+ {
+ // it seems the parent changed, let's hope this doesn't kill us
+ for (uint32_t b = 0; b < mBones.size(); b++)
+ {
+ if (mBones[b].externalIndex == parentIndex)
+ {
+ newInternalParent = (int32_t)b;
+ break;
+ }
+ }
+ }
+ }
+ }
+ mBones[i].parentIndex = newInternalParent;
+ return;
+ }
+ }
+
+ ClothingAssetParametersNS::BoneEntry_Type& bm = mBones.pushBack();
+ bm.internalIndex = (int32_t)boneIndex;
+ bm.externalIndex = (int32_t)boneIndex;
+ bm.numMeshReferenced = 0;
+ bm.numRigidBodiesReferenced = 0;
+ bm.parentIndex = parentIndex;
+ bm.bindPose = bindPose;
+ setBoneName(mBones.size() - 1, boneName);
+}
+
+
+
+void ClothingAssetAuthoringImpl::setRootBone(const char* boneName)
+{
+ WRITE_ZONE();
+ mRootBoneName = boneName;
+}
+
+
+
+uint32_t ClothingAssetAuthoringImpl::addBoneConvex(const char* boneName, const PxVec3* positions, uint32_t numPositions)
+{
+ WRITE_ZONE();
+ int32_t internalBoneIndex = getBoneInternalIndex(boneName);
+
+ if (internalBoneIndex == -1)
+ {
+ return 0;
+ }
+
+ return addBoneConvexInternal((uint32_t)internalBoneIndex , positions, numPositions);
+}
+
+uint32_t ClothingAssetAuthoringImpl::addBoneConvex(uint32_t boneIndex, const PxVec3* positions, uint32_t numPositions)
+{
+ WRITE_ZONE();
+ int32_t internalBoneIndex = getBoneInternalIndex(boneIndex);
+
+ if (internalBoneIndex == -1)
+ {
+ return 0;
+ }
+
+ return addBoneConvexInternal((uint32_t)internalBoneIndex , positions, numPositions);
+
+}
+
+
+
+void ClothingAssetAuthoringImpl::addBoneCapsule(const char* boneName, float capsuleRadius, float capsuleHeight, const PxMat44& localPose)
+{
+ WRITE_ZONE();
+ int32_t internalBoneIndex = getBoneInternalIndex(boneName);
+
+ if (internalBoneIndex == -1)
+ {
+ return;
+ }
+
+ addBoneCapsuleInternal((uint32_t)internalBoneIndex, capsuleRadius, capsuleHeight, localPose);
+}
+
+
+
+void ClothingAssetAuthoringImpl::addBoneCapsule(uint32_t boneIndex, float capsuleRadius, float capsuleHeight, const PxMat44& localPose)
+{
+ WRITE_ZONE();
+ int32_t internalBoneIndex = getBoneInternalIndex(boneIndex);
+
+ if (internalBoneIndex == -1)
+ {
+ return;
+ }
+
+ addBoneCapsuleInternal((uint32_t)internalBoneIndex, capsuleRadius, capsuleHeight, localPose);
+}
+
+
+
+void ClothingAssetAuthoringImpl::clearBoneActors(const char* boneName)
+{
+ WRITE_ZONE();
+ int32_t internalBoneIndex = getBoneInternalIndex(boneName);
+
+ if (internalBoneIndex == -1)
+ {
+ return;
+ }
+
+ clearBoneActorsInternal(internalBoneIndex);
+}
+
+
+
+void ClothingAssetAuthoringImpl::clearBoneActors(uint32_t boneIndex)
+{
+ WRITE_ZONE();
+ int32_t internalBoneIndex = getBoneInternalIndex(boneIndex);
+
+ if (internalBoneIndex == -1)
+ {
+ return;
+ }
+
+ clearBoneActorsInternal(internalBoneIndex);
+}
+
+
+
+void ClothingAssetAuthoringImpl::clearAllBoneActors()
+{
+ WRITE_ZONE();
+ mBoneActors.clear();
+ mBoneVertices.clear();
+ mBonePlanes.clear();
+ clearCooked();
+}
+
+
+
+void ClothingAssetAuthoringImpl::setCollision(const char** boneNames, float* radii, PxVec3* localPositions, uint32_t numSpheres, uint16_t* pairs, uint32_t numPairs)
+{
+ WRITE_ZONE();
+ nvidia::Array<uint32_t> boneIndices(numSpheres, 0);
+ for (uint32_t i = 0; i < numSpheres; ++i)
+ {
+ int32_t internalBoneIndex = getBoneInternalIndex(boneNames[i]);
+ if (internalBoneIndex < 0 || internalBoneIndex >= (int32_t)mBones.size())
+ {
+ APEX_INVALID_PARAMETER("Bone \'%s\' not found, setting to root", boneNames[i]);
+ boneIndices[i] = 0;
+ }
+ else
+ {
+ boneIndices[i] = (uint32_t)mBones[i].externalIndex;
+ }
+ }
+
+ setCollision(boneIndices.begin(), radii, localPositions, numSpheres, pairs, numPairs);
+}
+
+
+
+void ClothingAssetAuthoringImpl::setCollision(uint32_t* boneIndices, float* radii, PxVec3* localPositions, uint32_t numSpheres, uint16_t* pairs, uint32_t numPairs)
+{
+ WRITE_ZONE();
+ if (numPairs & 0x1)
+ {
+ APEX_INVALID_PARAMETER("numPairs must be a multiple of 2");
+ return;
+ }
+
+ mBoneSpheres.clear();
+ for (uint32_t i = 0; i < numSpheres; ++i)
+ {
+ int32_t internalBoneIndex = getBoneInternalIndex(boneIndices[i]);
+
+ PX_ASSERT(internalBoneIndex < (int32_t)mBones.size());
+ internalBoneIndex = PxClamp(internalBoneIndex, 0, (int32_t)mBones.size() - 1);
+ float radius = radii[i];
+ if (radius <= 0.0f)
+ {
+ APEX_INVALID_PARAMETER("Sphere radius must be bigger than 0.0 (sphere %d has radius %f)", i, radius);
+ radius = 0.0f;
+ }
+ ClothingAssetParametersNS::BoneSphere_Type& newEntry = mBoneSpheres.pushBack();
+ memset(&newEntry, 0, sizeof(ClothingAssetParametersNS::BoneSphere_Type));
+ newEntry.boneIndex = internalBoneIndex;
+ newEntry.radius = radius;
+ newEntry.localPos = localPositions[i];
+ }
+
+ mSpherePairs.clear();
+ for (uint32_t i = 0; i < numPairs; i += 2)
+ {
+ const uint16_t p1 = PxMin(pairs[i + 0], pairs[i + 1]);
+ const uint16_t p2 = PxMax(pairs[i + 0], pairs[i + 1]);
+ if (p1 == p2)
+ {
+ APEX_INVALID_PARAMETER("pairs[%d] and pairs[%d] are identical (%d), skipping", i, i + 1, p1);
+ continue;
+ }
+ else if (p1 >= mBoneSpheres.size() || p2 >= mBoneSpheres.size())
+ {
+ APEX_INVALID_PARAMETER("pairs[%d] = %d and pairs[%d] = %d are overflowing bone spheres, skipping", i, pairs[i], i + 1, pairs[i + 1]);
+ }
+ else
+ {
+ bool skip = false;
+ for (uint32_t j = 0; j < mSpherePairs.size(); j += 2)
+ {
+ if (mSpherePairs[j] == p1 && mSpherePairs[j + 1] == p2)
+ {
+ APEX_INVALID_PARAMETER("pairs[%d] = %d and pairs[%d] = %d are a duplicate, skipping", i, pairs[i], i + 1, pairs[i + 1]);
+ skip = true;
+ break;
+ }
+ }
+ if (!skip)
+ {
+ mSpherePairs.pushBack(p1);
+ mSpherePairs.pushBack(p2);
+ }
+ }
+ }
+}
+
+
+
+void ClothingAssetAuthoringImpl::clearCollision()
+{
+ WRITE_ZONE();
+ mBoneSpheres.clear();
+ mSpherePairs.clear();
+}
+
+
+
+NvParameterized::Interface* ClothingAssetAuthoringImpl::getMaterialLibrary()
+{
+ READ_ZONE();
+ PX_ASSERT(mParams->materialLibrary != NULL);
+ return mParams->materialLibrary;
+}
+
+
+
+bool ClothingAssetAuthoringImpl::setMaterialLibrary(NvParameterized::Interface* materialLibrary, uint32_t materialIndex, bool transferOwnership)
+{
+ WRITE_ZONE();
+ if (::strcmp(materialLibrary->className(), ClothingMaterialLibraryParameters::staticClassName()) == 0)
+ {
+ if (mParams->materialLibrary != NULL && mOwnsMaterialLibrary)
+ {
+ mParams->materialLibrary->destroy();
+ }
+
+ mParams->materialLibrary = materialLibrary;
+ mParams->materialIndex = materialIndex;
+ mOwnsMaterialLibrary = transferOwnership;
+
+ return true;
+ }
+
+ return false;
+}
+
+
+
+NvParameterized::Interface* ClothingAssetAuthoringImpl::getRenderMeshAssetAuthoring(uint32_t lodLevel) const
+{
+ READ_ZONE();
+ NvParameterized::Interface* ret = NULL;
+
+ if (lodLevel < mGraphicalLods.size())
+ {
+ ret = mGraphicalLods[lodLevel]->renderMeshAsset;
+ }
+
+ return ret;
+}
+
+
+
+NvParameterized::Interface* ClothingAssetAuthoringImpl::releaseAndReturnNvParameterizedInterface()
+{
+ // this is important for destroy() !
+ if (!mOwnsMaterialLibrary && mParams->materialLibrary != NULL)
+ {
+ NvParameterized::Interface* foreignMatLib = mParams->materialLibrary;
+
+ // clone the mat lib
+ mParams->materialLibrary = mParams->getTraits()->createNvParameterized(foreignMatLib->className());
+ mParams->materialLibrary->copy(*foreignMatLib);
+ }
+ mOwnsMaterialLibrary = true;
+
+ if (NvParameterized::ERROR_NONE != mParams->callPreSerializeCallback())
+ {
+ return NULL;
+ }
+
+ mParams->setSerializationCallback(NULL, NULL);
+
+ // release the object without mParams
+ NvParameterized::Interface* ret = mParams;
+ mParams = NULL;
+
+ release();
+ return ret;
+}
+
+
+
+void ClothingAssetAuthoringImpl::preSerialize(void* userData)
+{
+ PX_ASSERT(userData == NULL);
+ PX_UNUSED(userData);
+
+
+ ParamArray<ClothingAssetParametersNS::CookedEntry_Type> cookedEntries(mParams, "cookedData", reinterpret_cast<ParamDynamicArrayStruct*>(&mParams->cookedData));
+ if (cookedEntries.isEmpty())
+ {
+ ClothingAssetParametersNS::CookedEntry_Type entry;
+ entry.cookedData = NULL;
+ entry.scale = 1.0f;
+ cookedEntries.pushBack(entry);
+ }
+
+ for (uint32_t i = 0; i < cookedEntries.size(); i++)
+ {
+ if (cookedEntries[i].cookedData != NULL)
+ {
+ mPreviousCookedType = cookedEntries[i].cookedData->className();
+ cookedEntries[i].cookedData->destroy();
+ cookedEntries[i].cookedData = NULL;
+ }
+
+ PX_ASSERT(mPreviousCookedType != NULL);
+ BackendFactory* cookingFactory = mModule->getBackendFactory(mPreviousCookedType);
+ PX_ASSERT(cookingFactory != NULL);
+ if (cookingFactory != NULL)
+ {
+ CookingAbstract* cookingJob = cookingFactory->createCookingJob();
+ PX_ASSERT(cookingJob != NULL);
+ if (cookingJob)
+ {
+ prepareCookingJob(*cookingJob, cookedEntries[i].scale, NULL, NULL);
+
+ if (cookingJob->isValid())
+ {
+ cookedEntries[i].cookedData = cookingJob->execute();
+ }
+ PX_DELETE_AND_RESET(cookingJob);
+ }
+ }
+ }
+
+ compressBones();
+
+ for (uint32_t graphicalMeshId = 0; graphicalMeshId < mGraphicalLods.size(); graphicalMeshId++)
+ {
+ RenderMeshAssetIntl* renderMeshAsset = reinterpret_cast<RenderMeshAssetIntl*>(mGraphicalLods[graphicalMeshId]->renderMeshAssetPointer);
+ for (uint32_t submeshIndex = 0; submeshIndex < renderMeshAsset->getSubmeshCount(); submeshIndex++)
+ {
+ VertexFormat& format = renderMeshAsset->getInternalSubmesh(submeshIndex).getVertexBufferWritable().getFormatWritable();
+ format.setBufferAccess((uint32_t)format.getBufferIndexFromID(format.getSemanticID(RenderVertexSemantic::POSITION)), RenderDataAccess::DYNAMIC);
+ format.setBufferAccess((uint32_t)format.getBufferIndexFromID(format.getSemanticID(RenderVertexSemantic::NORMAL)), RenderDataAccess::DYNAMIC);
+ if (format.getBufferFormat((uint32_t)format.getBufferIndexFromID(format.getSemanticID(RenderVertexSemantic::TANGENT))) != RenderDataFormat::UNSPECIFIED)
+ {
+ format.setBufferAccess((uint32_t)format.getBufferIndexFromID(format.getSemanticID(RenderVertexSemantic::TANGENT)), RenderDataAccess::DYNAMIC);
+ format.setBufferAccess((uint32_t)format.getBufferIndexFromID(format.getSemanticID(RenderVertexSemantic::BINORMAL)), RenderDataAccess::DYNAMIC);
+ }
+ format.setHasSeparateBoneBuffer(true);
+ }
+ }
+
+ // create lod transition maps
+ for (uint32_t i = 0; i < mPhysicalMeshes.size(); i++)
+ {
+ AbstractMeshDescription other;
+ other.pPosition = mPhysicalMeshes[i]->physicalMesh.vertices.buf;
+ other.pNormal = mPhysicalMeshes[i]->physicalMesh.normals.buf;
+ other.numVertices = mPhysicalMeshes[i]->physicalMesh.numVertices;
+
+ if (i > 0)
+ {
+ ParamArray<SkinClothMap> transitionDown(mPhysicalMeshes[i], "transitionDown",
+ reinterpret_cast<ParamDynamicArrayStruct*>(&mPhysicalMeshes[i]->transitionDown));
+ if (transitionDown.isEmpty())
+ {
+ generateSkinClothMap(&other, 1, mPhysicalMeshes[i - 1]->physicalMesh, NULL, NULL, 0, transitionDown,
+ mPhysicalMeshes[i]->transitionDownOffset, false, NULL);
+
+ mPhysicalMeshes[i]->transitionDownThickness = 1.0f;
+ }
+ }
+ if (i + 1 < mPhysicalMeshes.size())
+ {
+
+ ParamArray<SkinClothMap> transitionUp(mPhysicalMeshes[i], "transitionUp",
+ reinterpret_cast<ParamDynamicArrayStruct*>(&mPhysicalMeshes[i]->transitionUp));
+ if (transitionUp.isEmpty())
+ {
+ generateSkinClothMap(&other, 1, mPhysicalMeshes[i + 1]->physicalMesh, NULL, NULL, 0, transitionUp,
+ mPhysicalMeshes[i]->transitionUpOffset, false, NULL);
+
+ mPhysicalMeshes[i]->transitionUpThickness = 1.0f;
+ }
+ }
+ }
+
+ updateBoundingBox();
+
+ ClothingAssetImpl::preSerialize(userData);
+}
+
+
+
+void ClothingAssetAuthoringImpl::setToolString(const char* toolString)
+{
+ if (mParams != NULL)
+ {
+ NvParameterized::Handle handle(*mParams, "toolString");
+ PX_ASSERT(handle.isValid());
+ if (handle.isValid())
+ {
+ PX_ASSERT(handle.parameterDefinition()->type() == NvParameterized::TYPE_STRING);
+ handle.setParamString(toolString);
+ }
+ }
+}
+
+
+
+void ClothingAssetAuthoringImpl::applyTransformation(const PxMat44& transformation, float scale, bool applyToGraphics, bool applyToPhysics)
+{
+ WRITE_ZONE();
+ if (applyToPhysics)
+ {
+ clearCooked();
+
+ for (uint32_t i = 0; i < mPhysicalMeshes.size(); i++)
+ {
+ ClothingPhysicalMeshImpl* mesh = mModule->createPhysicalMeshInternal(mPhysicalMeshes[i]);
+ mesh->applyTransformation(transformation, scale);
+ mesh->release();
+ }
+
+ for (uint32_t i = 0; i < mBones.size(); i++)
+ {
+ mBones[i].bindPose = transformation * mBones[i].bindPose;
+ mBones[i].bindPose.setPosition(mBones[i].bindPose.getPosition() * scale);
+ }
+
+ for (uint32_t i = 0; i < mBoneVertices.size(); i++)
+ {
+ // PH: Do not apply transformation, bindpose was already adapted!
+ //mBoneVertices[i] = transformation * mBoneVertices[i];
+ mBoneVertices[i] *= scale;
+ }
+
+ for(uint32_t i = 0; i < mBonePlanes.size(); i++)
+ {
+ mBonePlanes[i].d *= scale;
+ }
+
+ for (uint32_t i = 0; i < mBoneActors.size(); i++)
+ {
+ mBoneActors[i].capsuleRadius *= scale;
+ mBoneActors[i].capsuleHeight *= scale;
+ mBoneActors[i].localPose.setPosition(mBoneActors[i].localPose.getPosition() * scale);
+ }
+
+ for (uint32_t i = 0; i < mBoneSpheres.size(); i++)
+ {
+ mBoneSpheres[i].radius *= scale;
+ mBoneSpheres[i].localPos *= scale;
+ }
+
+ mParams->simulation.thickness *= scale;
+
+ ClothingMaterialLibraryParameters* materialLib = static_cast<ClothingMaterialLibraryParameters*>(mParams->materialLibrary);
+ for (int32_t i = 0; i < materialLib->materials.arraySizes[0]; ++i)
+ {
+ materialLib->materials.buf[i].selfcollisionThickness *= scale;
+ }
+ }
+
+ for (uint32_t i = 0; i < mGraphicalLods.size(); i++)
+ {
+ if (applyToGraphics)
+ {
+ reinterpret_cast<RenderMeshAssetIntl*>(mGraphicalLods[i]->renderMeshAssetPointer)->applyTransformation(transformation, scale);
+ }
+
+ if (applyToPhysics)
+ {
+ const uint32_t numSkinClothMap = (uint32_t)mGraphicalLods[i]->skinClothMap.arraySizes[0];
+ SkinClothMap* skinClothMap = mGraphicalLods[i]->skinClothMap.buf;
+
+ mGraphicalLods[i]->skinClothMapThickness *= scale;
+
+ for (uint32_t j = 0; j < numSkinClothMap; j++)
+ {
+ // make sure no INF is created
+ if (skinClothMap[j].vertexBary.z != PX_MAX_F32) skinClothMap[j].vertexBary.z *= scale;
+ if (skinClothMap[j].normalBary.z != PX_MAX_F32) skinClothMap[j].normalBary.z *= scale;
+ if (skinClothMap[j].tangentBary.z != PX_MAX_F32) skinClothMap[j].tangentBary.z *= scale;
+ }
+ const PxMat33 t(transformation.column0.getXYZ(), transformation.column1.getXYZ(), transformation.column2.getXYZ());
+
+ if (t.getDeterminant() * scale < 0.0f)
+ {
+ const uint32_t numTetraMap = (uint32_t)mGraphicalLods[i]->tetraMap.arraySizes[0];
+ ClothingGraphicalLodParametersNS::TetraLink_Type* tetraMap = mGraphicalLods[i]->tetraMap.buf;
+
+ for (uint32_t j = 0; j < numTetraMap; j++)
+ {
+ PxVec3 bary = tetraMap[j].vertexBary;
+ bary.z = 1.0f - bary.x - bary.y - bary.z;
+ tetraMap[j].vertexBary = bary;
+
+ bary = tetraMap[j].normalBary;
+ bary.z = 1.0f - bary.x - bary.y - bary.z;
+ tetraMap[j].normalBary = bary;
+ }
+ }
+ }
+ }
+}
+
+
+
+void ClothingAssetAuthoringImpl::updateBindPoses(const PxMat44* newBindPoses, uint32_t newBindPosesCount, bool isInternalOrder, bool collisionMaintainWorldPose)
+{
+ WRITE_ZONE();
+ Array<PxMat44> transformation(mBones.size());
+
+ bool hasSkew = false;
+ for (uint32_t i = 0; i < mBones.size(); i++)
+ {
+ PX_ASSERT(mBones[i].internalIndex == (int32_t)i);
+ const uint32_t externalIndex = isInternalOrder ? i : mBones[i].externalIndex;
+
+ if (externalIndex >= newBindPosesCount)
+ {
+ transformation[i] = PxMat44(PxIdentity);
+ }
+ else
+ {
+ PxMat44 temp;
+ temp = mBones[i].bindPose.inverseRT();
+ mBones[i].bindPose = newBindPoses[externalIndex];
+ transformation[i] = temp * mBones[i].bindPose;
+
+ PxMat33 m(transformation[i].column0.getXYZ(), transformation[i].column1.getXYZ(), transformation[i].column2.getXYZ());
+ float det = m.getDeterminant();
+
+ if (PxAbs(det) < 0.99f)
+ {
+ hasSkew = true;
+ }
+ }
+ }
+
+ if (hasSkew)
+ {
+ APEX_INVALID_PARAMETER("Skew on matrices is not allowed, aborting");
+ return;
+ }
+
+ int32_t errorInSize = -1;
+
+ if (collisionMaintainWorldPose)
+ {
+ for (uint32_t i = 0; i < mBoneActors.size(); i++)
+ {
+ const uint32_t boneIndex = (uint32_t)mBoneActors[i].boneIndex;
+ if (transformation[boneIndex].transform(PxVec3(1.f)) != PxVec3(1.f))
+ {
+ if (mBoneActors[i].convexVerticesCount == 0)
+ {
+ // capsule
+ PxMat33 m33(transformation[boneIndex].column0.getXYZ(), transformation[boneIndex].column1.getXYZ(), transformation[boneIndex].column2.getXYZ());
+ PxMat44 invTransformation(m33.getInverse(), m33.transform(-transformation[boneIndex].getPosition()));
+ mBoneActors[i].localPose = invTransformation * mBoneActors[i].localPose;
+ }
+ else
+ {
+ // convex
+ const uint32_t start = mBoneActors[i].convexVerticesStart;
+ const uint32_t end = start + mBoneActors[i].convexVerticesCount;
+ for (uint32_t j = start; j < end; j++)
+ {
+ PX_ASSERT(j < mBoneVertices.size());
+ mBoneVertices[j] = transformation[boneIndex].transform(mBoneVertices[j]);
+ }
+ }
+ }
+ else
+ {
+ const uint32_t boneIdx = (uint32_t)mBoneActors[i].boneIndex;
+ const int32_t externalIndex = isInternalOrder ? (int32_t)boneIdx : mBones[boneIdx].externalIndex;
+
+ errorInSize = PxMax(errorInSize, externalIndex);
+ }
+ }
+ for (uint32_t i = 0; i < mBoneSpheres.size(); i++)
+ {
+ const uint32_t boneIndex = (uint32_t)mBoneSpheres[i].boneIndex;
+ if (transformation[boneIndex].transform(PxVec3(1.f)) != PxVec3(1.f))
+ {
+ PxMat33 invTransformation(transformation[boneIndex].column0.getXYZ(), transformation[boneIndex].column1.getXYZ(), transformation[boneIndex].column2.getXYZ());
+ invTransformation = invTransformation.getInverse();
+ mBoneSpheres[i].localPos = invTransformation.transform(mBoneSpheres[i].localPos)
+ + invTransformation.transform(-transformation[boneIndex].getPosition());
+ }
+ else
+ {
+ const int32_t externalIndex = isInternalOrder ? (int32_t)boneIndex : mBones[boneIndex].externalIndex;
+ errorInSize = PxMax(errorInSize, externalIndex);
+ }
+ }
+ }
+
+#if 0
+ // PH: This proved to be actually wrong. We should just adapt the bind pose without moving
+ // the meshes AT ALL.
+ for (uint32_t physicalMeshIndex = 0; physicalMeshIndex < mPhysicalMeshes.size(); physicalMeshIndex++)
+ {
+
+ const uint32_t numBonesPerVertex = mPhysicalMeshes[physicalMeshIndex]->physicalMesh.numBonesPerVertex;
+ if (numBonesPerVertex > 0)
+ {
+ const uint32_t numVertices = mPhysicalMeshes[physicalMeshIndex]->physicalMesh.numVertices;
+ PxVec3* positions = mPhysicalMeshes[physicalMeshIndex]->physicalMesh.vertices.buf;
+ PxVec3* normals = mPhysicalMeshes[physicalMeshIndex]->physicalMesh.normals.buf;
+ uint16_t* boneIndices = mPhysicalMeshes[physicalMeshIndex]->physicalMesh.boneIndices.buf;
+ float* boneWeights = mPhysicalMeshes[physicalMeshIndex]->physicalMesh.boneWeights.buf;
+ PX_ASSERT(positions != NULL);
+ PX_ASSERT(normals != NULL);
+ PX_ASSERT(numBonesPerVertex == 1 || boneWeights != NULL);
+
+ for (uint32_t vertexID = 0; vertexID < numVertices; vertexID++)
+ {
+ PxVec3 position(0.0f, 0.0f, 0.0f);
+ PxVec3 normal(0.0f, 0.0f, 0.0f);
+ float sumWeight = 0.0f;
+ for (uint32_t k = 0; k < numBonesPerVertex; k++)
+ {
+ const float weight = numBonesPerVertex > 1 ? boneWeights[vertexID * numBonesPerVertex + k] : 1.0f;
+ if (weight > 0.0f)
+ {
+ const PxMat44 matrix = transformation[boneIndices[vertexID * numBonesPerVertex + k]];
+ sumWeight += weight;
+ position += matrix.transform(positions[vertexID]) * weight;
+ normal += matrix.rotate(normals[vertexID]) * weight;
+ }
+ }
+ if (sumWeight > 0.0f)
+ {
+ PX_ASSERT(sumWeight >= 0.9999f);
+ PX_ASSERT(sumWeight <= 1.0001f);
+
+ positions[vertexID] = position;
+ normals[vertexID] = normal;
+ }
+ }
+ }
+ }
+
+ PX_ASSERT(mGraphicalLods.size() == mGraphicalMeshesRuntime.size());
+ for (uint32_t graphicalMeshIndex = 0; graphicalMeshIndex < mGraphicalLods.size(); graphicalMeshIndex++)
+ {
+ ClothingGraphicalMeshAsset meshAsset(*mGraphicalMeshesRuntime[graphicalMeshIndex]);
+ const uint32_t submeshCount = meshAsset.getSubmeshCount();
+
+ for (uint32_t submeshIndex = 0; submeshIndex < submeshCount; submeshIndex++)
+ {
+ const uint32_t numBonesPerVertex = meshAsset.getNumBonesPerVertex(submeshIndex);
+ const uint32_t numVertices = meshAsset.getNumVertices(submeshIndex);
+
+ if (numBonesPerVertex > 0 && numVertices > 0)
+ {
+ RenderDataFormat::Enum outFormat;
+ const uint16_t* boneIndices = (const uint16_t*)meshAsset.getVertexBuffer(submeshIndex, RenderVertexSemantic::BONE_INDEX, outFormat);
+ const float* boneWeights = (const float*)meshAsset.getVertexBuffer(submeshIndex, RenderVertexSemantic::BONE_WEIGHT, outFormat);
+
+ PxVec3* positions = (PxVec3*)meshAsset.getVertexBuffer(submeshIndex, RenderVertexSemantic::POSITION, outFormat);
+ PxVec3* normals = (PxVec3*)meshAsset.getVertexBuffer(submeshIndex, RenderVertexSemantic::NORMAL, outFormat);
+ PxVec3* tangents = (PxVec3*)meshAsset.getVertexBuffer(submeshIndex, RenderVertexSemantic::TANGENT, outFormat);
+ PxVec3* bitangents = (PxVec3*)meshAsset.getVertexBuffer(submeshIndex, RenderVertexSemantic::BINORMAL, outFormat);
+
+ if (boneWeights != NULL || numBonesPerVertex == 1)
+ {
+ for (uint32_t vertexID = 0; vertexID < numVertices; vertexID++)
+ {
+ PxVec3 position(0.0f, 0.0f, 0.0f);
+ PxVec3 normal(0.0f, 0.0f, 0.0f);
+ PxVec3 tangent(0.0f, 0.0f, 0.0f);
+ PxVec3 bitangent(0.0f, 0.0f, 0.0f);
+ float sumWeight = 0.0f;
+
+ for (uint32_t k = 0; k < numBonesPerVertex; k++)
+ {
+ const float weight = (boneWeights == NULL) ? 1.0f : boneWeights[vertexID * numBonesPerVertex + k];
+ if (weight > 0.0f)
+ {
+ const PxMat44 matrix = transformation[boneIndices[vertexID * numBonesPerVertex + k]];
+
+ if (positions != NULL)
+ {
+ position += matrix.transform(positions[vertexID]) * weight;
+ }
+ if (normals != NULL)
+ {
+ normal += matrix.rotate(normals[vertexID]) * weight;
+ }
+ if (tangents != NULL)
+ {
+ tangent += matrix.rotate(tangents[vertexID]) * weight;
+ }
+ if (bitangents != NULL)
+ {
+ bitangent += matrix.rotate(bitangents[vertexID]) * weight;
+ }
+ }
+ }
+
+ if (sumWeight != 0.0f)
+ {
+ PX_ASSERT(sumWeight > 0.9999f);
+ PX_ASSERT(sumWeight < 1.0001f);
+
+ // copy back
+ if (positions != NULL)
+ {
+ positions[vertexID] = position;
+ }
+ if (normals != NULL)
+ {
+ normals[vertexID] = normal * ClothingUserRecompute::invSqrt(normal.magnitudeSquared());
+ }
+ if (tangents != NULL)
+ {
+ tangents[vertexID] = tangent * ClothingUserRecompute::invSqrt(tangent.magnitudeSquared());
+ }
+ if (bitangents != NULL)
+ {
+ bitangents[vertexID] = bitangent * ClothingUserRecompute::invSqrt(bitangent.magnitudeSquared());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+#endif
+
+ if (errorInSize > -1)
+ {
+ APEX_INVALID_PARAMETER("newBindPosesCount must be bigger than %d (is %d)", errorInSize, newBindPosesCount);
+ }
+}
+
+
+void ClothingAssetAuthoringImpl::destroy()
+{
+ if (!mOwnsMaterialLibrary)
+ {
+ PX_ASSERT(mParams != NULL);
+ mParams->materialLibrary = NULL;
+ }
+
+ ClothingAssetImpl::destroy(); // delete gets called in here
+}
+
+
+
+// ----- protected methods ----------------
+
+
+uint32_t ClothingAssetAuthoringImpl::addBoneConvexInternal(uint32_t boneIndex, const PxVec3* positions, uint32_t numPositions)
+{
+ // compute average
+ PxVec3 average(0.0f, 0.0f, 0.0f);
+
+ uint32_t maxNumberPositions = PxMin(20u, numPositions);
+ uint32_t newNumPositions = 0;
+
+ Array<PxVec3> newPositions(numPositions);
+ Array<float> minDist(numPositions, PX_MAX_F32);
+
+ if (numPositions > 0)
+ {
+ for (uint32_t i = 0; i < numPositions; i++)
+ {
+ average += positions[i];
+ }
+ average /= (float)numPositions;
+
+ float squaredDistFromAverage = (average - positions[0]).magnitudeSquared();
+ uint32_t startVertex = 0;
+ for (uint32_t i = 1; i < numPositions; i++)
+ {
+ float squaredDist = (average - positions[i]).magnitudeSquared();
+ if (squaredDist > squaredDistFromAverage)
+ {
+ squaredDistFromAverage = squaredDist;
+ startVertex = i;
+ }
+ }
+
+ for (uint32_t i = 0; i < numPositions; i++)
+ {
+ newPositions[i] = positions[i];
+ }
+
+ if (startVertex != 0)
+ {
+ newPositions[0] = positions[startVertex];
+ newPositions[startVertex] = positions[0];
+ }
+
+
+ for (uint32_t i = 1; i < maxNumberPositions; i++)
+ {
+ float max = 0.0f;
+ int32_t maxj = -1;
+ for (uint32_t j = i; j < numPositions; j++)
+ {
+ const float distSquared = (newPositions[j] - newPositions[i - 1]).magnitudeSquared();
+ if (distSquared < minDist[j])
+ {
+ minDist[j] = distSquared;
+ }
+
+ if (minDist[j] > max)
+ {
+ max = minDist[j];
+ maxj = (int32_t)j;
+ }
+ }
+
+ if (maxj < 0)
+ {
+ break;
+ }
+
+ const PxVec3 v = newPositions[i];
+ newPositions[i] = newPositions[(uint32_t)maxj];
+ newPositions[(uint32_t)maxj] = v;
+
+ const float dist = minDist[i];
+ minDist[i] = minDist[(uint32_t)maxj];
+ minDist[(uint32_t)maxj] = dist;
+ newNumPositions = i + 1;
+ }
+
+ ClothingAssetParametersNS::ActorEntry_Type& newEntry = mBoneActors.pushBack();
+ memset(&newEntry, 0, sizeof(ClothingAssetParametersNS::ActorEntry_Type));
+ newEntry.boneIndex = (int32_t)boneIndex;
+ newEntry.convexVerticesStart = mBoneVertices.size();
+ newEntry.convexVerticesCount = newNumPositions;
+ for (uint32_t i = 0; i < newNumPositions; i++)
+ {
+ mBoneVertices.pushBack(newPositions[i]);
+ }
+ compressBoneCollision();
+ }
+ clearCooked();
+
+
+ // extract planes from points
+ ConvexHullImpl convexHull;
+ convexHull.init();
+ Array<PxPlane> planes;
+
+ convexHull.buildFromPoints(&newPositions[0], newNumPositions, sizeof(PxVec3));
+
+ uint32_t planeCount = convexHull.getPlaneCount();
+ if (planeCount + mBonePlanes.size() > 32)
+ {
+ APEX_DEBUG_WARNING("The asset is trying to use more than 32 planes for convexes. The collision convex will not be simulated with 3.x cloth.");
+ }
+ else
+ {
+ uint32_t convex = 0; // each bit references a plane
+ for (uint32_t i = 0; i < planeCount; ++i)
+ {
+ PxPlane plane = convexHull.getPlane(i);
+ convex |= 1 << mBonePlanes.size();
+
+ ClothingAssetParametersNS::BonePlane_Type& newEntry = mBonePlanes.pushBack();
+ memset(&newEntry, 0, sizeof(ClothingAssetParametersNS::BonePlane_Type));
+ newEntry.boneIndex = (int32_t)boneIndex;
+ newEntry.n = plane.n;
+ newEntry.d = plane.d;
+ }
+
+ mCollisionConvexes.pushBack(convex);
+ }
+
+
+ return newNumPositions;
+}
+
+
+
+void ClothingAssetAuthoringImpl::addBoneCapsuleInternal(uint32_t boneIndex, float capsuleRadius, float capsuleHeight, const PxMat44& localPose)
+{
+ PX_ASSERT(boneIndex < mBones.size());
+ if (capsuleRadius > 0)
+ {
+ ClothingAssetParametersNS::ActorEntry_Type& newEntry = mBoneActors.pushBack();
+ memset(&newEntry, 0, sizeof(ClothingAssetParametersNS::ActorEntry_Type));
+ newEntry.boneIndex = (int32_t)boneIndex;
+ newEntry.capsuleRadius = capsuleRadius;
+ newEntry.capsuleHeight = capsuleHeight;
+ newEntry.localPose = localPose;
+ }
+}
+
+
+
+void ClothingAssetAuthoringImpl::clearBoneActorsInternal(int32_t internalBoneIndex)
+{
+ PX_ASSERT(internalBoneIndex >= 0);
+ for (uint32_t i = 0; i < mBoneActors.size(); i++)
+ {
+ if (mBoneActors[i].boneIndex == internalBoneIndex)
+ {
+ mBoneActors[i].boneIndex = -1;
+ }
+ }
+
+ compressBoneCollision();
+}
+
+
+
+void ClothingAssetAuthoringImpl::compressBones() const
+{
+ if (mBones.isEmpty())
+ {
+ return;
+ }
+
+ // reset counters
+ mParams->rootBoneIndex = uint32_t(-1);
+ for (uint32_t i = 0; i < mBones.size(); i++)
+ {
+ mBones[i].numMeshReferenced = 0;
+ mBones[i].numRigidBodiesReferenced = 0;
+
+ if (::strcmp(mBones[i].name, mRootBoneName.c_str()) == 0)
+ {
+ // set root bone index
+ mParams->rootBoneIndex = i;
+
+ // declare bone as referenced
+ mBones[i].numRigidBodiesReferenced++;
+ }
+ }
+
+ // update bone reference count from graphics mesh
+ for (uint32_t i = 0; i < mGraphicalLods.size(); i++)
+ {
+ ClothingGraphicalMeshAssetWrapper meshAsset(reinterpret_cast<RenderMeshAssetIntl*>(mGraphicalLods[i]->renderMeshAssetPointer));
+
+ for (uint32_t submeshIndex = 0; submeshIndex < meshAsset.getSubmeshCount(); submeshIndex++)
+ {
+ RenderDataFormat::Enum outFormat;
+ const uint16_t* boneIndices = (const uint16_t*)meshAsset.getVertexBuffer(submeshIndex, RenderVertexSemantic::BONE_INDEX, outFormat);
+ if (outFormat != RenderDataFormat::USHORT1 && outFormat != RenderDataFormat::USHORT2 &&
+ outFormat != RenderDataFormat::USHORT3 && outFormat != RenderDataFormat::USHORT4)
+ {
+ boneIndices = NULL;
+ }
+
+ const float* boneWeights = (const float*)meshAsset.getVertexBuffer(submeshIndex, RenderVertexSemantic::BONE_WEIGHT, outFormat);
+ if (outFormat != RenderDataFormat::FLOAT1 && outFormat != RenderDataFormat::FLOAT2 &&
+ outFormat != RenderDataFormat::FLOAT3 && outFormat != RenderDataFormat::FLOAT4)
+ {
+ boneWeights = NULL;
+ }
+
+ collectBoneIndices(meshAsset.getNumVertices(submeshIndex), boneIndices, boneWeights, meshAsset.getNumBonesPerVertex(submeshIndex));
+ }
+ }
+
+ // update bone reference count from physics mesh
+ for (uint32_t i = 0; i < mPhysicalMeshes.size(); i++)
+ {
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type& physicalMesh = mPhysicalMeshes[i]->physicalMesh;
+ collectBoneIndices(physicalMesh.numVertices, physicalMesh.boneIndices.buf, physicalMesh.boneWeights.buf, physicalMesh.numBonesPerVertex);
+ }
+
+ // update bone reference count from bone actors
+ for (uint32_t i = 0; i < mBoneActors.size(); i++)
+ {
+ mBones[(uint32_t)mBoneActors[i].boneIndex].numRigidBodiesReferenced++;
+ }
+
+ // update bone reference count from spheres
+ for (uint32_t i = 0; i < mBoneSpheres.size(); i++)
+ {
+ mBones[(uint32_t)mBoneSpheres[i].boneIndex].numRigidBodiesReferenced++;
+ }
+
+ // update bone reference count from spheres
+ for (uint32_t i = 0; i < mBonePlanes.size(); i++)
+ {
+ mBones[(uint32_t)mBonePlanes[i].boneIndex].numRigidBodiesReferenced++;
+ }
+
+ // sort the bones to the following structure:
+ // |-- bones referenced by mesh --|-- bones referenced by collision RBs, but not mesh --|-- unreferenced bones --|
+ {
+ BoneEntryPredicate predicate;
+ sort(mBones.begin(), mBones.size(), predicate);
+ }
+
+
+ // create map from old indices to new ones and store the number of used bones
+ Array<int32_t> old2new(mBones.size(), -1);
+ mParams->bonesReferenced = 0;
+ mParams->bonesReferencedByMesh = 0;
+ for (uint32_t i = 0; i < mBones.size(); i++)
+ {
+ if (mBones[i].numMeshReferenced > 0)
+ {
+ mParams->bonesReferencedByMesh++;
+ }
+
+ if (mBones[i].numMeshReferenced > 0 || mBones[i].numRigidBodiesReferenced > 0)
+ {
+ mParams->bonesReferenced++;
+ }
+
+ old2new[(uint32_t)mBones[i].internalIndex] = (int32_t)i;
+ mBones[i].internalIndex = (int32_t)i;
+ }
+
+ // update bone indices in parent
+ for (uint32_t i = 0; i < mBones.size(); i++)
+ {
+ if (mBones[i].parentIndex != -1)
+ {
+ mBones[i].parentIndex = old2new[(uint32_t)mBones[i].parentIndex];
+ }
+ }
+
+ // update bone indices in bone actors
+ for (uint32_t i = 0; i < mBoneActors.size(); i++)
+ {
+ PX_ASSERT(mBoneActors[i].boneIndex != -1);
+ mBoneActors[i].boneIndex = old2new[(uint32_t)mBoneActors[i].boneIndex];
+ }
+
+ // update bone indices in bone spheres
+ for (uint32_t i = 0; i < mBoneSpheres.size(); i++)
+ {
+ PX_ASSERT(mBoneSpheres[i].boneIndex != -1);
+ mBoneSpheres[i].boneIndex = old2new[(uint32_t)mBoneSpheres[i].boneIndex];
+ }
+
+ // update bone indices in bone planes
+ for (uint32_t i = 0; i < mBonePlanes.size(); i++)
+ {
+ PX_ASSERT(mBonePlanes[i].boneIndex != -1);
+ mBonePlanes[i].boneIndex = old2new[(uint32_t)mBonePlanes[i].boneIndex];
+ }
+
+ for (uint32_t i = 0; i < mGraphicalLods.size(); i++)
+ {
+ reinterpret_cast<RenderMeshAssetIntl*>(mGraphicalLods[i]->renderMeshAssetPointer)->permuteBoneIndices(old2new);
+ }
+
+ for (uint32_t i = 0; i < mPhysicalMeshes.size(); i++)
+ {
+ ClothingPhysicalMeshImpl* mesh = mModule->createPhysicalMeshInternal(mPhysicalMeshes[i]);
+ mesh->permuteBoneIndices(old2new);
+ mesh->release();
+ }
+
+ if (mParams->rootBoneIndex == uint32_t(-1))
+ {
+ // no root bone defined, find one within referenced bones
+ mParams->rootBoneIndex = 0;
+ uint32_t minDepth = mBones.size();
+ for (uint32_t i = 0; i < mParams->bonesReferenced; i++)
+ {
+ uint32_t depth = 0;
+ int32_t parent = mBones[i].parentIndex;
+ while (parent != -1 && depth < mBones.size())
+ {
+ parent = mBones[(uint32_t)parent].parentIndex;
+ depth++;
+ }
+
+ if (depth < minDepth)
+ {
+ minDepth = depth;
+ mParams->rootBoneIndex = i;
+ }
+ }
+ }
+ else
+ {
+ // update root bone index
+ mParams->rootBoneIndex = (uint32_t)old2new[mParams->rootBoneIndex];
+ }
+ PX_ASSERT(mParams->rootBoneIndex < mParams->bonesReferenced);
+}
+
+
+
+void ClothingAssetAuthoringImpl::compressBoneCollision()
+{
+ const PxVec3* oldBoneVertices = (const PxVec3*)GetInternalApexSDK()->getTempMemory(sizeof(PxVec3) * mBoneVertices.size());
+ if (oldBoneVertices == NULL)
+ {
+ return;
+ }
+
+ memcpy(const_cast<PxVec3*>(oldBoneVertices), mBoneVertices.begin(), sizeof(PxVec3) * mBoneVertices.size());
+
+ // clean out all unused actors
+ for (int32_t i = (int32_t)mBoneActors.size() - 1; i >= 0; i--)
+ {
+ if (mBoneActors[(uint32_t)i].boneIndex < 0)
+ {
+ mBoneActors.replaceWithLast((uint32_t)i);
+ }
+ }
+ if (!mBoneActors.isEmpty())
+ {
+ nvidia::sort(mBoneActors.begin(), mBoneActors.size(), ActorEntryPredicate());
+ }
+
+ uint32_t boneVerticesWritten = 0;
+ for (uint32_t i = 0; i < mBoneActors.size(); i++)
+ {
+ if (mBoneActors[i].convexVerticesCount == 0)
+ {
+ mBoneActors[i].convexVerticesStart = 0;
+ }
+ else
+ {
+ const uint32_t oldStart = mBoneActors[i].convexVerticesStart;
+ const uint32_t count = mBoneActors[i].convexVerticesCount;
+ mBoneActors[i].convexVerticesStart = boneVerticesWritten;
+ for (uint32_t j = 0; j < count; j++)
+ {
+ mBoneVertices[boneVerticesWritten++] = oldBoneVertices[oldStart + j];
+ }
+ }
+ }
+ mBoneVertices.resize(boneVerticesWritten);
+
+ GetInternalApexSDK()->releaseTempMemory(const_cast<PxVec3*>(oldBoneVertices));
+ clearCooked();
+}
+
+
+
+void ClothingAssetAuthoringImpl::collectBoneIndices(uint32_t numVertices, const uint16_t* boneIndices, const float* boneWeights, uint32_t numBonesPerVertex) const
+{
+ for (uint32_t i = 0; i < numVertices; i++)
+ {
+ for (uint32_t j = 0; j < numBonesPerVertex; j++)
+ {
+ uint16_t index = boneIndices[i * numBonesPerVertex + j];
+ float weight = (boneWeights == NULL) ? 1.0f : boneWeights[i * numBonesPerVertex + j];
+ if (weight > 0.0f)
+ {
+ PX_ASSERT(index < mBones.size());
+ PX_ASSERT(mBones[index].internalIndex == (int32_t)index);
+ mBones[index].numMeshReferenced++;
+ }
+ }
+ }
+}
+
+
+
+struct Confidentially
+{
+ Confidentially() : maxDistConfidence(0.0f), collisionDistConfidence(0.0f), collisionRadiusConfidence(0.0f), normalConfidence(0.0f) {}
+ float maxDistConfidence;
+ float collisionDistConfidence;
+ float collisionRadiusConfidence;
+ float normalConfidence;
+};
+
+
+
+void ClothingAssetAuthoringImpl::updateMappingAuthoring(ClothingGraphicalLodParameters& graphicalLod, RenderMeshAssetIntl* renderMeshAssetCopy,
+ RenderMeshAssetAuthoringIntl* renderMeshAssetOrig, float normalResemblance, bool ignoreUnusedVertices, IProgressListener* progressListener)
+{
+ if (graphicalLod.physicalMeshId == (uint32_t) - 1 || renderMeshAssetCopy == NULL)
+ {
+ return;
+ }
+
+ const uint32_t physicalMeshId = graphicalLod.physicalMeshId;
+
+ if (normalResemblance < 0)
+ {
+ APEX_DEBUG_WARNING("A normal resemblance of %f not allowed, must be positive.", normalResemblance);
+ normalResemblance = 90.0f;
+ }
+ else if (normalResemblance < 5)
+ {
+ APEX_DEBUG_WARNING("A physicalNormal resemblance of %f is very small, it might discard too many values", normalResemblance);
+ }
+ else if (normalResemblance > 90.0f)
+ {
+ normalResemblance = 90.0f;
+ }
+
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type& physicalMesh = mPhysicalMeshes[physicalMeshId]->physicalMesh;
+ uint32_t* masterFlags = mPhysicalMeshesInput[physicalMeshId]->getMasterFlagsBuffer();
+
+ bool skipConstraints = false;
+ if (physicalMesh.constrainCoefficients.arraySizes[0] != 0)
+ {
+ skipConstraints = true;
+ }
+
+ PX_ASSERT(graphicalLod.immediateClothMap.buf == NULL);
+ PX_ASSERT(graphicalLod.skinClothMapB.buf == NULL);
+ PX_ASSERT(graphicalLod.tetraMap.buf == NULL);
+
+ HierarchicalProgressListener progress(100, progressListener);
+
+ Array<AbstractMeshDescription> targetMeshes(renderMeshAssetCopy->getSubmeshCount());
+ uint32_t numTotalVertices = 0;
+ bool hasTangents = false;
+ for (uint32_t submeshIndex = 0; submeshIndex < targetMeshes.size(); submeshIndex++)
+ {
+ const VertexBuffer& vb = renderMeshAssetCopy->getSubmesh(submeshIndex).getVertexBuffer();
+ const VertexFormat& vf = vb.getFormat();
+
+ RenderDataFormat::Enum outFormat;
+
+ uint32_t bufferIndex = (uint32_t)vf.getBufferIndexFromID(vf.getSemanticID(RenderVertexSemantic::POSITION));
+ targetMeshes[submeshIndex].pPosition = (PxVec3*)vb.getBufferAndFormat(outFormat, bufferIndex);
+ PX_ASSERT(outFormat == RenderDataFormat::FLOAT3);
+
+ bufferIndex = (uint32_t)vf.getBufferIndexFromID(vf.getSemanticID(RenderVertexSemantic::NORMAL));
+ targetMeshes[submeshIndex].pNormal = (PxVec3*)(vb.getBufferAndFormat(outFormat, bufferIndex));
+ if (outFormat != RenderDataFormat::FLOAT3)
+ {
+ // Phil - you might need to handle other normal formats
+ targetMeshes[submeshIndex].pNormal = NULL;
+ }
+
+ bufferIndex = (uint32_t)vf.getBufferIndexFromID(vf.getSemanticID(RenderVertexSemantic::TANGENT));
+ const void* tangents = vb.getBufferAndFormat(outFormat, bufferIndex);
+ if (outFormat == RenderDataFormat::FLOAT3)
+ {
+ targetMeshes[submeshIndex].pTangent = (PxVec3*)tangents;
+ hasTangents = true;
+ }
+ else if (outFormat == RenderDataFormat::FLOAT4)
+ {
+ targetMeshes[submeshIndex].pTangent4 = (PxVec4*)tangents;
+ hasTangents = true;
+ }
+
+ const uint32_t numVertices = renderMeshAssetCopy->getSubmesh(submeshIndex).getVertexCount(0);
+ targetMeshes[submeshIndex].numVertices = numVertices;
+
+ bufferIndex = (uint32_t)vf.getBufferIndexFromID(vf.getID(LATCH_TO_NEAREST_SLAVE_NAME));
+ uint32_t* submeshSlaveFlags = (uint32_t*)vb.getBufferAndFormat(outFormat, bufferIndex);
+ targetMeshes[submeshIndex].pVertexFlags = submeshSlaveFlags;
+ PX_ASSERT(submeshSlaveFlags == NULL || outFormat == RenderDataFormat::UINT1);
+
+ if (!skipConstraints)
+ {
+ bufferIndex = (uint32_t)vf.getBufferIndexFromID(vf.getID(LATCH_TO_NEAREST_MASTER_NAME));
+ uint32_t* submeshMasterFlags = (uint32_t*)vb.getBufferAndFormat(outFormat, bufferIndex);
+ PX_ASSERT(submeshMasterFlags == NULL || outFormat == RenderDataFormat::UINT1);
+
+ if (submeshSlaveFlags != NULL && submeshMasterFlags != NULL)
+ {
+ // overwrite the empty slaves with the master mask
+ // provides self-attachment, very important!
+ // the original slave values are in the orig render mesh still
+ for (uint32_t i = 0; i < numVertices; i++)
+ {
+ if (submeshSlaveFlags[i] == 0)
+ {
+ submeshSlaveFlags[i] = submeshMasterFlags[i];
+ }
+ if (submeshSlaveFlags[i] == 0)
+ {
+ submeshSlaveFlags[i] = 0xffffffff;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (submeshSlaveFlags != NULL)
+ {
+ // overwrite the empty slaves with 0xffffffff flags
+ for (uint32_t i = 0; i < numVertices; i++)
+ {
+ if (submeshSlaveFlags[i] == 0)
+ {
+ submeshSlaveFlags[i] = 0xffffffff;
+ }
+ }
+ }
+ }
+
+ numTotalVertices += targetMeshes[submeshIndex].numVertices;
+ }
+
+ if (physicalMesh.isTetrahedralMesh)
+ {
+ ParamArray<ClothingGraphicalLodParametersNS::TetraLink_Type> tetraMap(&graphicalLod, "tetraMap", reinterpret_cast<ParamDynamicArrayStruct*>(&graphicalLod.tetraMap));
+ progress.setSubtaskWork(50, "Generate Tetra Map");
+ generateTetraMap(targetMeshes.begin(), targetMeshes.size(), physicalMesh, masterFlags, tetraMap, &progress);
+ progress.completeSubtask();
+ }
+ else
+ {
+ ParamArray<uint32_t> immediateClothMap(&graphicalLod, "immediateClothMap", reinterpret_cast<ParamDynamicArrayStruct*>(&graphicalLod.immediateClothMap));
+ uint32_t numNotFoundVertices = 0;
+ progress.setSubtaskWork(5, "Generate immediate mapping");
+
+
+ generateImmediateClothMap(targetMeshes.begin(), targetMeshes.size(), physicalMesh, masterFlags,
+ 0.0f, numNotFoundVertices, normalResemblance, immediateClothMap, &progress);
+
+ progress.completeSubtask();
+
+ if (immediateClothMap.isEmpty() || numNotFoundVertices > 0 || hasTangents)
+ {
+ // if more than 3/4 of all vertices are not found, completely forget about immediate mode.
+ const bool clearImmediateMap = (numNotFoundVertices > numTotalVertices * 3 / 4);
+
+ progress.setSubtaskWork(45, "Generate mesh-mesh skinning");
+ ParamArray<SkinClothMap> skinClothMap(&graphicalLod, "skinClothMap",
+ reinterpret_cast<ParamDynamicArrayStruct*>(&graphicalLod.skinClothMap));
+
+ generateSkinClothMap(targetMeshes.begin(), targetMeshes.size(), physicalMesh,
+ masterFlags, graphicalLod.immediateClothMap.buf, numNotFoundVertices,
+ skinClothMap, graphicalLod.skinClothMapOffset, clearImmediateMap, &progress);
+
+ graphicalLod.skinClothMapThickness = 1.0f;
+
+ progress.completeSubtask();
+
+ if (clearImmediateMap)
+ {
+ immediateClothMap.clear();
+ }
+ }
+ }
+
+ if (physicalMesh.normals.arraySizes[0] == 0)
+ {
+ progress.setSubtaskWork(50, "Update Painting");
+
+ // update painting stuff from all submeshes
+
+ ClothingPhysicalMeshImpl* tempMesh = mModule->createPhysicalMeshInternal(mPhysicalMeshes[physicalMeshId]);
+
+ tempMesh->allocateNormalBuffer();
+ if (!skipConstraints)
+ {
+ tempMesh->allocateConstrainCoefficientBuffer();
+ }
+
+ AbstractMeshDescription pMesh;
+ pMesh.pPosition = physicalMesh.vertices.buf;
+ pMesh.pNormal = physicalMesh.normals.buf;
+ ClothingPhysicalMeshParametersNS::ConstrainCoefficient_Type* myConstrains = physicalMesh.constrainCoefficients.buf;
+ pMesh.numVertices = physicalMesh.numVertices;
+
+ pMesh.pIndices = physicalMesh.indices.buf;
+ pMesh.numIndices = physicalMesh.numIndices;
+
+ uint32_t maxNumBonesPerVertex = 0;
+ for (uint32_t submeshIndex = 0; submeshIndex < renderMeshAssetCopy->getSubmeshCount(); submeshIndex++)
+ {
+ const VertexFormat& vf = renderMeshAssetCopy->getSubmesh(submeshIndex).getVertexBuffer().getFormat();
+ RenderDataFormat::Enum format = vf.getBufferFormat((uint32_t)vf.getBufferIndexFromID(vf.getSemanticID(RenderVertexSemantic::BONE_INDEX)));
+ const uint32_t numBonesPerVertex = vertexSemanticFormatElementCount(RenderVertexSemantic::BONE_INDEX, format);
+ maxNumBonesPerVertex = PxMax(maxNumBonesPerVertex, numBonesPerVertex);
+ }
+
+ if (maxNumBonesPerVertex > 0)
+ {
+ tempMesh->setNumBonesPerVertex(maxNumBonesPerVertex);
+ tempMesh->allocateBoneIndexAndWeightBuffers();
+ pMesh.numBonesPerVertex = maxNumBonesPerVertex;
+ pMesh.pBoneIndices = physicalMesh.boneIndices.buf;
+ pMesh.pBoneWeights = physicalMesh.boneWeights.buf;
+ }
+
+ Array<Confidentially> confidence(pMesh.numVertices);
+
+ uint32_t graphicalVertexOffset = 0;
+ const uint32_t numGraphicalVerticesTotal = numTotalVertices;
+ PX_ASSERT(renderMeshAssetCopy->getSubmeshCount() == renderMeshAssetOrig->getSubmeshCount());
+
+ for (uint32_t submeshIndex = 0; submeshIndex < renderMeshAssetCopy->getSubmeshCount(); submeshIndex++)
+ {
+ const VertexBuffer& vb = renderMeshAssetCopy->getSubmesh(submeshIndex).getVertexBuffer();
+
+ if (vb.getVertexCount() == 0)
+ {
+ APEX_DEBUG_WARNING("submesh %d has no vertices at all!", submeshIndex);
+ continue;
+ }
+
+ const VertexBuffer& vbOrig = renderMeshAssetOrig->getSubmesh(submeshIndex).getVertexBuffer();
+ PX_ASSERT(vbOrig.getVertexCount() == vb.getVertexCount());
+
+ const VertexFormat& vf = vb.getFormat();
+ const uint32_t graphicalMaxDistanceIndex = (uint32_t)vf.getBufferIndexFromID(vf.getID(MAX_DISTANCE_NAME));
+ RenderDataFormat::Enum outFormat = vf.getBufferFormat(graphicalMaxDistanceIndex);
+ const float* graphicalMaxDistance = outFormat == RenderDataFormat::UNSPECIFIED ? NULL :
+ reinterpret_cast<const float*>(vb.getBuffer(graphicalMaxDistanceIndex));
+ PX_ASSERT(graphicalMaxDistance == NULL || outFormat == RenderDataFormat::FLOAT1);
+
+ const uint32_t graphicalCollisionSphereRadiusIndex = (uint32_t)vf.getBufferIndexFromID(vf.getID(COLLISION_SPHERE_RADIUS_NAME));
+ outFormat = vf.getBufferFormat(graphicalCollisionSphereRadiusIndex);
+ const float* graphicalCollisionSphereRadius = outFormat == RenderDataFormat::UNSPECIFIED ? NULL :
+ reinterpret_cast<const float*>(vb.getBuffer(graphicalCollisionSphereRadiusIndex));
+ PX_ASSERT(graphicalCollisionSphereRadius == NULL || outFormat == RenderDataFormat::FLOAT1);
+
+ const uint32_t graphicalCollisionSphereDistanceIndex = (uint32_t)vf.getBufferIndexFromID(vf.getID(COLLISION_SPHERE_DISTANCE_NAME));
+ outFormat = vf.getBufferFormat(graphicalCollisionSphereDistanceIndex);
+ const float* graphicalCollisionSphereDistance = outFormat == RenderDataFormat::UNSPECIFIED ? NULL :
+ reinterpret_cast<const float*>(vb.getBuffer(graphicalCollisionSphereDistanceIndex));
+ PX_ASSERT(graphicalCollisionSphereDistance == NULL || outFormat == RenderDataFormat::FLOAT1);
+ PX_ASSERT((graphicalCollisionSphereDistance == NULL && graphicalCollisionSphereRadius == NULL) || (graphicalCollisionSphereDistance != NULL && graphicalCollisionSphereRadius != NULL));
+
+ const uint32_t graphicalUsedForPhysicsIndex = (uint32_t)vf.getBufferIndexFromID(vf.getID(USED_FOR_PHYSICS_NAME));
+ outFormat = vf.getBufferFormat(graphicalUsedForPhysicsIndex);
+ const uint8_t* graphicalUsedForPhysics = outFormat == RenderDataFormat::UNSPECIFIED ? NULL :
+ reinterpret_cast<const uint8_t*>(vb.getBuffer(graphicalUsedForPhysicsIndex));
+ PX_ASSERT(graphicalUsedForPhysics == NULL || outFormat == RenderDataFormat::UBYTE1);
+
+ const uint32_t graphicalSlaveIndex = (uint32_t)vbOrig.getFormat().getBufferIndexFromID(vbOrig.getFormat().getID(LATCH_TO_NEAREST_SLAVE_NAME));
+ outFormat = vbOrig.getFormat().getBufferFormat(graphicalSlaveIndex);
+ const uint32_t* graphicalSlavesOrig = outFormat != RenderDataFormat::UINT1 ? NULL :
+ reinterpret_cast<const uint32_t*>(vbOrig.getBuffer(graphicalSlaveIndex));
+
+ // should not be used anymore!
+ outFormat = RenderDataFormat::UNSPECIFIED;
+
+ RenderDataFormat::Enum normalFormat;
+ uint32_t bufferIndex = (uint32_t)vf.getBufferIndexFromID(vf.getSemanticID(RenderVertexSemantic::NORMAL));
+ const PxVec3* graphicalNormals = reinterpret_cast<const PxVec3*>(vb.getBufferAndFormat(normalFormat, bufferIndex));
+ if (normalFormat != RenderDataFormat::FLOAT3)
+ {
+ // Phil - you might need to handle other normal formats
+ graphicalNormals = NULL;
+ }
+
+ RenderDataFormat::Enum positionFormat;
+ bufferIndex = (uint32_t)vf.getBufferIndexFromID(vf.getSemanticID(RenderVertexSemantic::POSITION));
+ const PxVec3* graphicalPositions = reinterpret_cast<const PxVec3*>(vb.getBufferAndFormat(positionFormat, bufferIndex));
+ if (positionFormat != RenderDataFormat::FLOAT3)
+ {
+ graphicalPositions = NULL;
+ }
+
+ RenderDataFormat::Enum boneIndexFormat;
+ bufferIndex = (uint32_t)vf.getBufferIndexFromID(vf.getSemanticID(RenderVertexSemantic::BONE_INDEX));
+ const uint16_t* graphicalBoneIndices = (const uint16_t*)vb.getBufferAndFormat(boneIndexFormat, bufferIndex);
+ if (boneIndexFormat != RenderDataFormat::USHORT1 && boneIndexFormat != RenderDataFormat::USHORT2 &&
+ boneIndexFormat != RenderDataFormat::USHORT3 && boneIndexFormat != RenderDataFormat::USHORT4)
+ {
+ // Phil - you might need to handle other normal formats
+ graphicalBoneIndices = NULL;
+ }
+
+ RenderDataFormat::Enum boneWeightFormat;
+ bufferIndex = (uint32_t)vf.getBufferIndexFromID(vf.getSemanticID(RenderVertexSemantic::BONE_WEIGHT));
+ const float* graphicalBoneWeights = reinterpret_cast<const float*>(vb.getBufferAndFormat(boneWeightFormat, bufferIndex));
+ if (boneWeightFormat != RenderDataFormat::FLOAT1 && boneWeightFormat != RenderDataFormat::FLOAT2 &&
+ boneWeightFormat != RenderDataFormat::FLOAT3 && boneWeightFormat != RenderDataFormat::FLOAT4)
+ {
+ // Phil - you might need to handle other normal formats
+ graphicalBoneWeights = NULL;
+ }
+
+ const uint32_t numBonesPerVertex = vertexSemanticFormatElementCount(RenderVertexSemantic::BONE_INDEX, boneIndexFormat);
+ PX_ASSERT((graphicalBoneIndices == NULL && graphicalBoneWeights == NULL && numBonesPerVertex == 0) ||
+ (graphicalBoneIndices != NULL && numBonesPerVertex > 0));
+
+ const uint32_t numGraphicalVertices = renderMeshAssetCopy->getSubmesh(submeshIndex).getVertexCount(0);
+ for (uint32_t graphicalVertexIndex = 0; graphicalVertexIndex < numGraphicalVertices; graphicalVertexIndex++)
+ {
+ if ((graphicalVertexIndex & 0xff) == 0)
+ {
+ const int32_t percent = int32_t(100 * (graphicalVertexIndex + graphicalVertexOffset) / numGraphicalVerticesTotal);
+ progress.setProgress(percent);
+ }
+
+ // figure out how many physical vertices this graphical vertex relates to
+ uint32_t indices[4];
+ float trust[4];
+
+ const bool isSlave =
+ (graphicalUsedForPhysics != NULL && graphicalUsedForPhysics[graphicalVertexIndex] == 0) ||
+ (graphicalSlavesOrig != NULL && graphicalSlavesOrig[graphicalVertexIndex] != 0);
+
+ uint32_t numIndices = getCorrespondingPhysicalVertices(graphicalLod, submeshIndex, graphicalVertexIndex, pMesh, graphicalVertexOffset, indices, trust);
+
+ // now we have the relevant physical vertices in indices[4]
+
+ if (!skipConstraints && graphicalMaxDistance != NULL && graphicalMaxDistance[graphicalVertexIndex] != mInvalidConstrainCoefficients.maxDistance &&
+ graphicalMaxDistance[graphicalVertexIndex] < 0.0f)
+ {
+ APEX_INVALID_PARAMETER("Max Distance at vertex %d (submesh %d) must be >= 0.0 (is %f) or equal to invalid (%f)",
+ graphicalVertexIndex, submeshIndex, graphicalMaxDistance[graphicalVertexIndex], mInvalidConstrainCoefficients.maxDistance);
+ }
+
+ for (uint32_t temporalIndex = 0; temporalIndex < numIndices; temporalIndex++)
+ {
+ const uint32_t vertexIndex = indices[temporalIndex];
+ const float vertexTrust = trust[temporalIndex];
+
+ if (ignoreUnusedVertices && isSlave)
+ {
+ continue;
+ }
+
+ if (vertexTrust < -0.0001f)
+ {
+ continue;
+ }
+
+ const float confidenceDelta = 0.1f;
+ if (!skipConstraints)
+ {
+ if (graphicalMaxDistance != NULL && graphicalMaxDistance[graphicalVertexIndex] != mInvalidConstrainCoefficients.maxDistance)
+ {
+ if (vertexTrust + confidenceDelta > confidence[vertexIndex].maxDistConfidence)
+ {
+ confidence[vertexIndex].maxDistConfidence = vertexTrust;
+
+ float& target = myConstrains[vertexIndex].maxDistance;
+ const float source = graphicalMaxDistance[graphicalVertexIndex];
+
+ target = source;
+ }
+ }
+
+ if (graphicalCollisionSphereDistance != NULL && graphicalCollisionSphereDistance[graphicalVertexIndex] != mInvalidConstrainCoefficients.collisionSphereDistance)
+ {
+ if (vertexTrust + confidenceDelta > confidence[vertexIndex].collisionDistConfidence)
+ {
+ confidence[vertexIndex].collisionDistConfidence = vertexTrust;
+
+ const float source = graphicalCollisionSphereDistance[graphicalVertexIndex];
+ float& target = myConstrains[vertexIndex].collisionSphereDistance;
+
+ target = source;
+ }
+ }
+
+ if (graphicalCollisionSphereRadius != NULL && graphicalCollisionSphereRadius[graphicalVertexIndex] != mInvalidConstrainCoefficients.collisionSphereRadius)
+ {
+ if (vertexTrust + confidenceDelta > confidence[vertexIndex].collisionRadiusConfidence)
+ {
+ confidence[vertexIndex].collisionRadiusConfidence = vertexTrust;
+
+ float& target = myConstrains[vertexIndex].collisionSphereRadius;
+ const float source = graphicalCollisionSphereRadius[graphicalVertexIndex];
+
+ target = source;
+ }
+ }
+ }
+
+ if (graphicalBoneIndices != NULL)
+ {
+ for (uint32_t i = 0; i < numBonesPerVertex; i++)
+ {
+ const float weight = (graphicalBoneWeights != NULL) ? graphicalBoneWeights[graphicalVertexIndex * numBonesPerVertex + i] : 1.0f;
+ if (weight > 0.0f)
+ {
+ tempMesh->addBoneToVertex(vertexIndex, graphicalBoneIndices[graphicalVertexIndex * numBonesPerVertex + i], weight);
+ }
+ }
+ }
+
+ if (!isSlave)
+ {
+ if (vertexTrust + confidenceDelta > confidence[vertexIndex].normalConfidence)
+ {
+ confidence[vertexIndex].normalConfidence = vertexTrust;
+
+ pMesh.pNormal[vertexIndex] = graphicalNormals[graphicalVertexIndex];
+ }
+ }
+ }
+ }
+
+ graphicalVertexOffset += numGraphicalVertices;
+ }
+
+
+ bool hasMaxDistance = false;
+ bool hasCollisionSphereDistance = false;
+ bool hasCollisionSphereRadius = false;
+ bool hasBoneWeights = false;
+ for (uint32_t i = 0; i < renderMeshAssetCopy->getSubmeshCount(); i++)
+ {
+ const VertexFormat& vf = renderMeshAssetCopy->getSubmesh(i).getVertexBuffer().getFormat();
+ RenderDataFormat::Enum outFormat;
+ outFormat = vf.getBufferFormat((uint32_t)vf.getBufferIndexFromID(vf.getID(MAX_DISTANCE_NAME)));
+ hasMaxDistance |= outFormat == RenderDataFormat::FLOAT1;
+ outFormat = vf.getBufferFormat((uint32_t)vf.getBufferIndexFromID(vf.getID(COLLISION_SPHERE_DISTANCE_NAME)));
+ hasCollisionSphereDistance |= outFormat == RenderDataFormat::FLOAT1;
+ outFormat = vf.getBufferFormat((uint32_t)vf.getBufferIndexFromID(vf.getID(COLLISION_SPHERE_RADIUS_NAME)));
+ hasCollisionSphereRadius |= outFormat == RenderDataFormat::FLOAT1;
+ outFormat = vf.getBufferFormat((uint32_t)vf.getBufferIndexFromID(vf.getSemanticID(RenderVertexSemantic::BONE_WEIGHT)));
+ hasBoneWeights |= outFormat != RenderDataFormat::UNSPECIFIED;
+ }
+
+ // all values that have not been set are set by nearest neighbor
+ uint32_t count[5] = { 0, 0, 0, 0, 0 };
+ const uint32_t numVertices = physicalMesh.numVertices;
+ for (uint32_t vertexIndex = 0; vertexIndex < numVertices; vertexIndex++)
+ {
+ if (!skipConstraints)
+ {
+ float& physicalMaxDistance = myConstrains[vertexIndex].maxDistance;
+ if (physicalMaxDistance == PX_MAX_F32)
+ {
+ count[0]++;
+ uint32_t submeshIndex = 0, graphicalVertexIndex = 0;
+ if (hasMaxDistance && getClosestVertex(renderMeshAssetOrig, pMesh.pPosition[vertexIndex], submeshIndex, graphicalVertexIndex, MAX_DISTANCE_NAME, ignoreUnusedVertices))
+ {
+ const VertexFormat& vf = renderMeshAssetCopy->getSubmesh(submeshIndex).getVertexBuffer().getFormat();
+ const uint32_t graphicalMaxDistanceIndex = (uint32_t)vf.getBufferIndexFromID(vf.getID(MAX_DISTANCE_NAME));
+ RenderDataFormat::Enum outFormat = vf.getBufferFormat(graphicalMaxDistanceIndex);
+ const float* graphicalMaxDistance = reinterpret_cast<const float*>(renderMeshAssetCopy->getSubmesh(submeshIndex).getVertexBuffer().getBuffer(graphicalMaxDistanceIndex));
+
+ PX_ASSERT(outFormat == RenderDataFormat::FLOAT1);
+ if (outFormat == RenderDataFormat::FLOAT1)
+ {
+ physicalMaxDistance = PxMax(0.0f, graphicalMaxDistance[graphicalVertexIndex]);
+ }
+ }
+ else
+ {
+ physicalMaxDistance = 0.0f;
+ }
+ }
+
+ float& physicalCollisionSphereDistance = myConstrains[vertexIndex].collisionSphereDistance;
+ if (physicalCollisionSphereDistance == PX_MAX_F32)
+ {
+ count[1]++;
+ uint32_t submeshIndex = 0, graphicalVertexIndex = 0;
+ if (hasCollisionSphereDistance && getClosestVertex(renderMeshAssetOrig, pMesh.pPosition[vertexIndex], submeshIndex, graphicalVertexIndex, COLLISION_SPHERE_DISTANCE_NAME, ignoreUnusedVertices))
+ {
+ const VertexFormat& vf = renderMeshAssetCopy->getSubmesh(submeshIndex).getVertexBuffer().getFormat();
+ const uint32_t graphicalCollisionSphereDistanceIndex = (uint32_t)vf.getBufferIndexFromID(vf.getID(COLLISION_SPHERE_DISTANCE_NAME));
+ RenderDataFormat::Enum outFormat = vf.getBufferFormat(graphicalCollisionSphereDistanceIndex);
+ const float* graphicalCollisionSphereDistance = reinterpret_cast<const float*>(renderMeshAssetCopy->getSubmesh(submeshIndex).getVertexBuffer().getBuffer(graphicalCollisionSphereDistanceIndex));
+
+ PX_ASSERT(outFormat == RenderDataFormat::FLOAT1);
+ if (outFormat == RenderDataFormat::FLOAT1)
+ {
+ physicalCollisionSphereDistance = graphicalCollisionSphereDistance[graphicalVertexIndex];
+ }
+ }
+ else
+ {
+ physicalCollisionSphereDistance = 0.0f;
+ }
+ }
+
+ float& physicalCollisionSphereRadius = myConstrains[vertexIndex].collisionSphereRadius;
+ if (physicalCollisionSphereRadius == PX_MAX_F32)
+ {
+ count[2]++;
+ uint32_t submeshIndex = 0, graphicalVertexIndex = 0;
+ if (hasCollisionSphereRadius && getClosestVertex(renderMeshAssetOrig, pMesh.pPosition[vertexIndex], submeshIndex, graphicalVertexIndex, COLLISION_SPHERE_RADIUS_NAME, ignoreUnusedVertices))
+ {
+ const VertexFormat& vf = renderMeshAssetCopy->getSubmesh(submeshIndex).getVertexBuffer().getFormat();
+ const uint32_t graphicalCollisionSphereRadiusIndex = (uint32_t)vf.getBufferIndexFromID(vf.getID(COLLISION_SPHERE_RADIUS_NAME));
+ RenderDataFormat::Enum outFormat = vf.getBufferFormat(graphicalCollisionSphereRadiusIndex);
+ const float* graphicalCollisionSphereRadius = reinterpret_cast<const float*>(renderMeshAssetCopy->getSubmesh(submeshIndex).getVertexBuffer().getBuffer(graphicalCollisionSphereRadiusIndex));
+
+ PX_ASSERT(outFormat == RenderDataFormat::FLOAT1);
+ if (outFormat == RenderDataFormat::FLOAT1)
+ {
+ physicalCollisionSphereRadius = graphicalCollisionSphereRadius[graphicalVertexIndex];
+ }
+ }
+ else
+ {
+ physicalCollisionSphereRadius = 0.0f;
+ }
+ }
+ }
+
+ PxVec3& physicalNormal = pMesh.pNormal[vertexIndex];
+ if (physicalNormal.isZero() && !(mDeriveNormalsFromBones && pMesh.numBonesPerVertex > 0))
+ {
+ count[3]++;
+ uint32_t submeshIndex = 0, graphicalVertexIndex = 0;
+ if (getClosestVertex(renderMeshAssetOrig, pMesh.pPosition[vertexIndex], submeshIndex, graphicalVertexIndex, NULL, true))
+ {
+ RenderDataFormat::Enum normalFormat;
+ const VertexBuffer& vb = renderMeshAssetCopy->getSubmesh(submeshIndex).getVertexBuffer();
+ const VertexFormat& vf = vb.getFormat();
+ uint32_t bufferIndex = (uint32_t)vf.getBufferIndexFromID(vf.getSemanticID(RenderVertexSemantic::NORMAL));
+ const PxVec3* graphicalNormals = (const PxVec3*)vb.getBufferAndFormat(normalFormat, bufferIndex);
+ if (normalFormat != RenderDataFormat::FLOAT3)
+ {
+ // Phil - you might need to handle other normal formats
+ graphicalNormals = NULL;
+ }
+ if (graphicalNormals != NULL)
+ {
+ physicalNormal = graphicalNormals[graphicalVertexIndex];
+ }
+ }
+ else
+ {
+ physicalNormal = PxVec3(0.0f, 1.0f, 0.0f);
+ }
+ }
+
+ float* boneWeights = (pMesh.pBoneWeights != NULL) ? pMesh.pBoneWeights + (vertexIndex * pMesh.numBonesPerVertex) : NULL;
+ if (boneWeights != NULL && hasBoneWeights)
+ {
+ // is first weight already 0.0 ?
+ if (boneWeights[0] <= 0.0f)
+ {
+ count[4]++;
+ uint32_t submeshIndex = 0, graphicalVertexIndex = 0;
+ if (getClosestVertex(renderMeshAssetOrig, pMesh.pPosition[vertexIndex], submeshIndex, graphicalVertexIndex, NULL, ignoreUnusedVertices))
+ {
+ const VertexBuffer& vb = renderMeshAssetCopy->getSubmesh(submeshIndex).getVertexBuffer();
+ const VertexFormat& vf = vb.getFormat();
+ uint16_t* boneIndices = (pMesh.pBoneIndices != NULL) ? pMesh.pBoneIndices + (vertexIndex * pMesh.numBonesPerVertex) : NULL;
+ if (boneIndices != NULL)
+ {
+ for (uint32_t i = 0; i < pMesh.numBonesPerVertex; i++)
+ {
+ boneIndices[i] = 0;
+ boneWeights[i] = 0.0f;
+ }
+
+ RenderDataFormat::Enum boneIndexFormat;
+ uint32_t bufferIndex = (uint32_t)vf.getBufferIndexFromID(vf.getSemanticID(RenderVertexSemantic::BONE_INDEX));
+ const uint16_t* graphicalBoneIndices = reinterpret_cast<const uint16_t*>(vb.getBufferAndFormat(boneIndexFormat, bufferIndex));
+ if (boneIndexFormat != RenderDataFormat::USHORT1 && boneIndexFormat != RenderDataFormat::USHORT2 &&
+ boneIndexFormat != RenderDataFormat::USHORT3 && boneIndexFormat != RenderDataFormat::USHORT4)
+ {
+ // Phil - you might need to handle other normal formats
+ graphicalBoneIndices = NULL;
+ }
+
+ RenderDataFormat::Enum boneWeightFormat;
+ bufferIndex = (uint32_t)vf.getBufferIndexFromID(vf.getSemanticID(RenderVertexSemantic::BONE_WEIGHT));
+ const float* graphicalBoneWeights = (const float*)vb.getBufferAndFormat(boneWeightFormat, bufferIndex);
+ if (boneWeightFormat != RenderDataFormat::FLOAT1 && boneWeightFormat != RenderDataFormat::FLOAT2 &&
+ boneWeightFormat != RenderDataFormat::FLOAT3 && boneWeightFormat != RenderDataFormat::FLOAT4)
+ {
+ // Phil - you might need to handle other normal formats
+ graphicalBoneWeights = NULL;
+ }
+
+ const uint32_t graphicalNumBonesPerVertex = vertexSemanticFormatElementCount(RenderVertexSemantic::BONE_INDEX, boneIndexFormat);
+ for (uint32_t i = 0; i < graphicalNumBonesPerVertex; i++)
+ {
+ const float weight = graphicalBoneWeights[graphicalVertexIndex * graphicalNumBonesPerVertex + i];
+ const uint16_t index = graphicalBoneIndices[graphicalVertexIndex * graphicalNumBonesPerVertex + i];
+ tempMesh->addBoneToVertex(vertexIndex, index, weight);
+ }
+ }
+ }
+ }
+ tempMesh->normalizeBonesOfVertex(vertexIndex);
+ }
+ }
+
+ if (mDeriveNormalsFromBones && pMesh.numBonesPerVertex > 0)
+ {
+ for (uint32_t vertexIndex = 0; vertexIndex < numVertices; vertexIndex++)
+ {
+ const PxVec3& pos = pMesh.pPosition[vertexIndex];
+ PxVec3& normal = pMesh.pNormal[vertexIndex];
+ normal = PxVec3(0.0f);
+
+ for (uint32_t j = 0; j < pMesh.numBonesPerVertex; j++)
+ {
+ const float boneWeight = pMesh.pBoneWeights[vertexIndex * pMesh.numBonesPerVertex + j];
+
+ if (boneWeight == 0.0f)
+ {
+ continue;
+ }
+
+ const uint16_t externalBoneIndex = pMesh.pBoneIndices[vertexIndex * pMesh.numBonesPerVertex + j];
+
+ const int32_t internalBoneIndex = getBoneInternalIndex(externalBoneIndex);
+
+ const ClothingAssetParametersNS::BoneEntry_Type& bone = mBones[(uint32_t)internalBoneIndex];
+ PxVec3 closest = bone.bindPose.getPosition();
+ float minDist2 = (closest - pos).magnitudeSquared();
+
+ // find closest point on outgoing bones
+ for (uint32_t k = 0; k < mBones.size(); k++)
+ {
+ if (mBones[k].parentIndex != internalBoneIndex)
+ {
+ continue;
+ }
+
+ // closest point on segment
+ const PxVec3& a = bone.bindPose.getPosition();
+ const PxVec3& b = mBones[k].bindPose.getPosition();
+ if (a == b)
+ {
+ continue;
+ }
+
+ const PxVec3 d = b - a;
+ float s = (pos - a).dot(d) / d.magnitudeSquared();
+ s = PxClamp(s, 0.0f, 1.0f);
+
+ PxVec3 proj = a + d * s;
+ float dist2 = (proj - pos).magnitudeSquared();
+
+ if (dist2 < minDist2)
+ {
+ minDist2 = dist2;
+ closest = proj;
+ }
+ }
+
+ PxVec3 n = pos - closest;
+ n.normalize();
+ normal += n * boneWeight;
+ }
+ normal.normalize();
+ }
+
+ tempMesh->smoothNormals(3);
+ }
+
+
+ progress.completeSubtask();
+
+ tempMesh->release();
+ tempMesh = NULL;
+ }
+}
+
+
+
+bool ClothingAssetAuthoringImpl::hasTangents(const RenderMeshAssetIntl& rma)
+{
+ bool bHasTangents = false;
+ for (uint32_t submeshIndex = 0; submeshIndex < rma.getSubmeshCount(); submeshIndex++)
+ {
+ const VertexBuffer& vb = rma.getSubmesh(submeshIndex).getVertexBuffer();
+ const VertexFormat& vf = vb.getFormat();
+ uint32_t bufferIndex = (uint32_t)vf.getBufferIndexFromID(vf.getSemanticID(apex::RenderVertexSemantic::TANGENT));
+ RenderDataFormat::Enum outFormat;
+ const void* tangents = vb.getBufferAndFormat(outFormat, bufferIndex);
+ if (tangents != NULL)
+ {
+ bHasTangents = true;
+ break;
+ }
+ }
+
+ return bHasTangents;
+}
+
+
+
+uint32_t ClothingAssetAuthoringImpl::getMaxNumGraphicalVertsActive(const ClothingGraphicalLodParameters& graphicalLod, uint32_t submeshIndex)
+{
+ uint32_t numVerts = 0;
+
+ const uint32_t numParts = (uint32_t)graphicalLod.physicsMeshPartitioning.arraySizes[0];
+ ClothingGraphicalLodParametersNS::PhysicsMeshPartitioning_Type* parts = graphicalLod.physicsMeshPartitioning.buf;
+
+ for (uint32_t i = 0; i < numParts; ++i)
+ {
+ if (parts[i].graphicalSubmesh == submeshIndex)
+ {
+ numVerts = PxMax(numVerts, parts[i].numSimulatedVertices);
+ }
+ }
+
+ return numVerts;
+}
+
+
+
+bool ClothingAssetAuthoringImpl::isMostlyImmediateSkinned(const RenderMeshAssetIntl& rma, const ClothingGraphicalLodParameters& graphicalLod)
+{
+ uint32_t immediateMapSize = (uint32_t)graphicalLod.immediateClothMap.arraySizes[0];
+ if (immediateMapSize == 0)
+ return false;
+
+ // figure out the number of immediate skinned verts.. more complicated than i thought.
+ uint32_t numImmediateSkinnedVerts = 0;
+ uint32_t totalSkinnedVerts = 0;
+ uint32_t* immediateMap = graphicalLod.immediateClothMap.buf;
+ uint32_t numSubmeshes = rma.getSubmeshCount();
+ uint32_t vertexOffset = 0;
+ for (uint32_t submeshIndex = 0; submeshIndex < numSubmeshes; ++submeshIndex)
+ {
+ const apex::RenderSubmesh& submesh = rma.getSubmesh(submeshIndex);
+ uint32_t numVertsToSkin = getMaxNumGraphicalVertsActive(graphicalLod, submeshIndex);
+ for (uint32_t vertexIndex = 0; vertexIndex < numVertsToSkin; ++vertexIndex)
+ {
+ uint32_t mapId = vertexOffset + vertexIndex;
+
+ PX_ASSERT(mapId < immediateMapSize);
+ const uint32_t mapEntry = immediateMap[mapId];
+ const uint32_t flags = mapEntry & ~ClothingConstants::ImmediateClothingReadMask;
+
+ // count the number of mesh-mesh skinned verts (the others are skinned to bones)
+ ++totalSkinnedVerts;
+ if ((flags & ClothingConstants::ImmediateClothingInSkinFlag) == 0)
+ {
+ ++numImmediateSkinnedVerts;
+ }
+
+ }
+ vertexOffset += submesh.getVertexCount(0);
+ }
+
+ return 2*numImmediateSkinnedVerts > totalSkinnedVerts;
+}
+
+
+
+bool ClothingAssetAuthoringImpl::conditionalMergeMapping(const RenderMeshAssetIntl& rma, ClothingGraphicalLodParameters& graphicalLod)
+{
+ bool merged = false;
+ // it's faster to do mesh-mesh skinning on all verts, instead of
+ // mesh-mesh skinning + immediateSkinning + tangent recompute
+ if (hasTangents(rma) && !isMostlyImmediateSkinned(rma, graphicalLod))
+ {
+ merged = mergeMapping(&graphicalLod);
+ }
+
+ return merged;
+}
+
+
+
+class SkinClothMapPredicate
+{
+public:
+ bool operator()(const SkinClothMapB& map1, const SkinClothMapB& map2) const
+ {
+ if (map1.submeshIndex < map2.submeshIndex)
+ {
+ return true;
+ }
+ else if (map1.submeshIndex > map2.submeshIndex)
+ {
+ return false;
+ }
+
+ return map1.faceIndex0 < map2.faceIndex0;
+ }
+};
+
+
+
+void ClothingAssetAuthoringImpl::sortSkinMapB(SkinClothMapB* skinClothMap, uint32_t skinClothMapSize, uint32_t* immediateClothMap, uint32_t immediateClothMapSize)
+{
+
+ sort<SkinClothMapB, SkinClothMapPredicate>(skinClothMap, skinClothMapSize, SkinClothMapPredicate());
+
+ if (immediateClothMap != NULL)
+ {
+ for (uint32_t j = 0; j < skinClothMapSize; j++)
+ {
+ const uint32_t vertexIndex = skinClothMap[j].vertexIndexPlusOffset;
+ if (vertexIndex < immediateClothMapSize)
+ {
+ PX_ASSERT((immediateClothMap[vertexIndex] & ClothingConstants::ImmediateClothingInSkinFlag) != 0);
+ immediateClothMap[vertexIndex] = j | ClothingConstants::ImmediateClothingInSkinFlag;
+ }
+ }
+ }
+}
+
+
+
+class F32Greater
+{
+public:
+ PX_INLINE bool operator()(float v1, float v2) const
+ {
+ return v1 > v2;
+ }
+};
+
+
+
+
+void ClothingAssetAuthoringImpl::setupPhysicalMesh(ClothingPhysicalMeshParameters& physicalMesh) const
+{
+ const uint32_t numIndicesPerElement = (physicalMesh.physicalMesh.isTetrahedralMesh) ? 4u : 3u;
+
+ // index buffer is sorted such that each triangle (or tetrahedra) has a higher or equal max distance than all tuples right of it.
+ for (uint32_t i = 0; i < physicalMesh.physicalMesh.numIndices; i += numIndicesPerElement)
+ {
+ float triangleMaxDistance = getMaxMaxDistance(physicalMesh.physicalMesh, i, numIndicesPerElement);
+ if (triangleMaxDistance == 0.0f // don't simulate triangles that may not move
+ || i == physicalMesh.physicalMesh.numIndices - numIndicesPerElement) // all vertices are painted, i.e. this is the last tuple.
+ {
+ const uint32_t maxIndex = (i == physicalMesh.physicalMesh.numIndices - numIndicesPerElement) ? i + numIndicesPerElement : i;
+ physicalMesh.physicalMesh.numSimulatedIndices = maxIndex;
+
+ // these values get set in reorderDeformableVertices
+ physicalMesh.physicalMesh.numSimulatedVertices = 0;
+ physicalMesh.physicalMesh.numMaxDistance0Vertices = 0;
+
+ if (triangleMaxDistance == 0.0f)
+ {
+ break;
+ }
+ }
+ }
+}
+
+
+
+void ClothingAssetAuthoringImpl::sortDeformableIndices(ClothingPhysicalMeshImpl& physicalMesh)
+{
+ if (physicalMesh.getNumVertices() == 0 || physicalMesh.getConstrainCoefficientBuffer() == NULL)
+ {
+ return;
+ }
+
+ uint32_t* deformableIndices = physicalMesh.getIndicesBuffer();
+ ClothingConstrainCoefficients* constrainCoeffs = physicalMesh.getConstrainCoefficientBuffer();
+
+ Array<uint32_t> deformableIndicesPermutation;
+ deformableIndicesPermutation.resize(physicalMesh.getNumIndices());
+
+ uint32_t numIndices = physicalMesh.isTetrahedralMesh() ? 4u : 3u;
+
+ for (uint32_t i = 0; i < physicalMesh.getNumIndices(); i++)
+ {
+ deformableIndicesPermutation[i] = i;
+ }
+
+ if (numIndices == 3)
+ {
+ TriangleGreater_3 triangleGreater(deformableIndices, constrainCoeffs);
+ nvidia::sort((uint32_t_3*)&deformableIndicesPermutation[0], physicalMesh.getNumIndices() / numIndices, triangleGreater);
+ }
+ else if (numIndices == 4)
+ {
+ TriangleGreater_4 triangleGreater(deformableIndices, constrainCoeffs);
+ nvidia::sort((uint32_t_4*)&deformableIndicesPermutation[0], physicalMesh.getNumIndices() / numIndices, triangleGreater);
+ }
+ else
+ {
+ PX_ALWAYS_ASSERT();
+ }
+
+
+ // inverse permutation
+ Array<int32_t> invPerm(physicalMesh.getNumIndices());
+ for (uint32_t i = 0; i < physicalMesh.getNumIndices(); i++)
+ {
+ PX_ASSERT(deformableIndicesPermutation[i] < physicalMesh.getNumIndices());
+ invPerm[deformableIndicesPermutation[i]] = (int32_t)i;
+ }
+
+
+ // apply permutation
+ ApexPermute<uint32_t>(deformableIndices, &deformableIndicesPermutation[0], physicalMesh.getNumIndices());
+
+ // update mappings into deformable index buffer
+ for (uint32_t i = 0; i < mGraphicalLods.size(); i++)
+ {
+ if (mPhysicalMeshes[mGraphicalLods[i]->physicalMeshId] == physicalMesh.getNvParameterized())
+ {
+ ClothingGraphicalMeshAssetWrapper meshAsset(reinterpret_cast<RenderMeshAssetIntl*>(mGraphicalLods[i]->renderMeshAssetPointer));
+ ClothingGraphicalLodParameters* graphicalLod = mGraphicalLods[i];
+
+ const uint32_t numGraphicalVertices = meshAsset.getNumTotalVertices();
+ if (graphicalLod->tetraMap.arraySizes[0] > 0)
+ {
+ for (uint32_t j = 0; j < numGraphicalVertices; j++)
+ {
+ graphicalLod->tetraMap.buf[j].tetraIndex0 = (uint32_t)invPerm[graphicalLod->tetraMap.buf[j].tetraIndex0];
+ }
+ }
+ const uint32_t skinClothMapBSize = (uint32_t)graphicalLod->skinClothMapB.arraySizes[0];
+ if (skinClothMapBSize > 0)
+ {
+ for (uint32_t j = 0; j < skinClothMapBSize; j++)
+ {
+ graphicalLod->skinClothMapB.buf[j].faceIndex0 = (uint32_t)invPerm[graphicalLod->skinClothMapB.buf[j].faceIndex0];
+ }
+
+ sortSkinMapB(graphicalLod->skinClothMapB.buf, (uint32_t)graphicalLod->skinClothMapB.arraySizes[0], graphicalLod->immediateClothMap.buf, numGraphicalVertices);
+ }
+ }
+ }
+
+ physicalMesh.updateMaxMaxDistance();
+}
+
+
+
+bool ClothingAssetAuthoringImpl::getGraphicalLodIndex(uint32_t lod, uint32_t& graphicalLodIndex) const
+{
+ graphicalLodIndex = UINT32_MAX;
+ for (uint32_t i = 0; i < mGraphicalLods.size(); i++)
+ {
+ if (mGraphicalLods[i]->lod == lod)
+ {
+ graphicalLodIndex = i;
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+uint32_t ClothingAssetAuthoringImpl::addGraphicalLod(uint32_t lod)
+{
+ uint32_t lodIndex = (uint32_t) - 1;
+ if (getGraphicalLodIndex(lod, lodIndex))
+ {
+ return lodIndex;
+ }
+
+ ClothingGraphicalLodParameters* newLod = DYNAMIC_CAST(ClothingGraphicalLodParameters*)(GetInternalApexSDK()->getParameterizedTraits()->createNvParameterized(ClothingGraphicalLodParameters::staticClassName()));
+ newLod->lod = lod;
+ newLod->renderMeshAssetPointer = NULL;
+ PX_ASSERT(newLod->physicalMeshId == (uint32_t) - 1);
+
+ mGraphicalLods.pushBack(NULL);
+
+ // insertion sort
+ int32_t current = (int32_t)mGraphicalLods.size() - 1;
+ while (current > 0 && mGraphicalLods[(uint32_t)current - 1]->lod > newLod->lod)
+ {
+ mGraphicalLods[(uint32_t)current] = mGraphicalLods[(uint32_t)current - 1];
+ current--;
+ }
+ PX_ASSERT(current >= 0);
+ PX_ASSERT((uint32_t)current < mGraphicalLods.size());
+ mGraphicalLods[(uint32_t)current] = newLod;
+
+ return (uint32_t)current;
+}
+
+
+
+void ClothingAssetAuthoringImpl::clearCooked()
+{
+ ParamArray<ClothingAssetParametersNS::CookedEntry_Type> cookedEntries(mParams, "cookedData", reinterpret_cast<ParamDynamicArrayStruct*>(&mParams->cookedData));
+
+ if (cookedEntries.size() > 0)
+ {
+ if(cookedEntries[0].cookedData)
+ {
+ mPreviousCookedType = cookedEntries[0].cookedData->className();
+ }
+ }
+
+ cookedEntries.clear();
+}
+
+
+
+bool ClothingAssetAuthoringImpl::addGraphicalMesh(RenderMeshAssetAuthoring* renderMesh, uint32_t graphicalLodIndex)
+{
+ if (mGraphicalLods[graphicalLodIndex]->renderMeshAssetPointer != NULL)
+ {
+ reinterpret_cast<RenderMeshAssetIntl*>(mGraphicalLods[graphicalLodIndex]->renderMeshAssetPointer)->release();
+ mGraphicalLods[graphicalLodIndex]->renderMeshAssetPointer = NULL;
+ }
+ if (mGraphicalLods[graphicalLodIndex]->renderMeshAsset != NULL)
+ {
+ // PH: did the param object already get destroyed in the release call above?
+ mGraphicalLods[graphicalLodIndex]->renderMeshAsset->destroy();
+ mGraphicalLods[graphicalLodIndex]->renderMeshAsset = NULL;
+ }
+
+ if (renderMesh != NULL)
+ {
+ const uint32_t additionalSize = 7;
+ char buf[16];
+ int bufSize = 16;
+ char* rmaName = buf;
+ if (strlen(getName()) + additionalSize > 15)
+ {
+ bufSize = int32_t(strlen(getName()) + additionalSize + 2);
+ rmaName = (char*)PX_ALLOC((size_t)bufSize, PX_DEBUG_EXP("ClothingAssetAuthoring::addGraphicalMesh"));
+ }
+ nvidia::snprintf(rmaName, (size_t)bufSize, "%s_RMA%.3d", getName(), mGraphicalLods[graphicalLodIndex]->lod);
+
+ PX_ASSERT(mGraphicalLods[graphicalLodIndex]->renderMeshAssetPointer == NULL);
+ //mGraphicalMeshesRuntime[graphicalLodIndex] = DYNAMIC_CAST(RenderMeshAssetIntl*)(GetApexSDK()->createAsset(*renderMesh, rmaName));
+ NvParameterized::Interface* newAsset = GetInternalApexSDK()->getParameterizedTraits()->createNvParameterized(renderMesh->getNvParameterized()->className());
+ newAsset->copy(*renderMesh->getNvParameterized());
+
+ RenderMeshAssetIntl* rma = static_cast<RenderMeshAssetIntl*>(GetApexSDK()->createAsset(newAsset, rmaName));
+ PX_ASSERT(rma->getAssetNvParameterized()->equals(*renderMesh->getNvParameterized()));
+ if (rma->mergeBinormalsIntoTangents())
+ {
+ APEX_DEBUG_INFO("The ApexRenderMesh has Tangent and Binormal semantic (both FLOAT3), but clothing needs only Tangent (with FLOAT4). Converted internally");
+ }
+ mGraphicalLods[graphicalLodIndex]->renderMeshAssetPointer = rma;
+
+ PX_ASSERT(::strcmp(newAsset->className(), "RenderMeshAssetParameters") == 0);
+ mGraphicalLods[graphicalLodIndex]->renderMeshAsset = newAsset;
+
+ // make sure the isReferenced value is set!
+ NvParameterized::Handle handle(*newAsset);
+ newAsset->getParameterHandle("isReferenced", handle);
+ PX_ASSERT(handle.isValid());
+ if (handle.isValid())
+ {
+ bool val;
+ handle.getParamBool(val);
+ PX_ASSERT(!val);
+ handle.setParamBool(true);
+ }
+
+ if (rmaName != buf)
+ {
+ PX_FREE(rmaName);
+ rmaName = buf;
+ }
+
+ return true;
+ }
+ else
+ {
+ PX_ASSERT(mGraphicalLods[graphicalLodIndex] != NULL);
+
+ // store the pointer to the element that is removed
+ PX_ASSERT(mGraphicalLods[graphicalLodIndex]->renderMeshAssetPointer == NULL);
+ mGraphicalLods[graphicalLodIndex]->destroy();
+
+ for (uint32_t i = graphicalLodIndex; i < mGraphicalLods.size() - 1; i++)
+ {
+ mGraphicalLods[i] = mGraphicalLods[i + 1];
+ }
+
+ mGraphicalLods.back() = NULL; // set last element to NULL, otherwise the referred object gets destroyed in popBack
+ mGraphicalLods.popBack();
+
+ return false;
+ }
+}
+
+
+
+void ClothingAssetAuthoringImpl::initParams()
+{
+ PX_ASSERT(mParams != NULL);
+ if (mParams != NULL)
+ {
+ mParams->setSerializationCallback(this, NULL);
+ }
+
+ if (mParams->materialLibrary == NULL)
+ {
+ mOwnsMaterialLibrary = true;
+ mParams->materialLibrary = GetInternalApexSDK()->getParameterizedTraits()->createNvParameterized(ClothingMaterialLibraryParameters::staticClassName());
+ }
+}
+
+
+
+bool ClothingAssetAuthoringImpl::generateImmediateClothMap(const AbstractMeshDescription* targetMeshes, uint32_t numTargetMeshes,
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type& physicalMesh, uint32_t* masterFlags,
+ float epsilon, uint32_t& numNotFoundVertices, float normalResemblance, ParamArray<uint32_t>& result,
+ IProgressListener* progress) const
+{
+ // square because distance is also squared.
+ epsilon = epsilon * epsilon;
+
+ bool haveAllBuffers = true;
+
+ uint32_t numGraphicalVertices = 0;
+ for (uint32_t i = 0; i < numTargetMeshes; i++)
+ {
+ numGraphicalVertices += targetMeshes[i].numVertices;
+ bool hasAllBuffers = true;
+ hasAllBuffers &= targetMeshes[i].pPosition != NULL;
+ hasAllBuffers &= targetMeshes[i].pNormal != NULL;
+
+ haveAllBuffers &= hasAllBuffers;
+
+ if (!hasAllBuffers)
+ {
+ APEX_INTERNAL_ERROR("Render mesh asset does not have either position or normal for submesh %d!", i);
+ }
+ }
+
+ if (!haveAllBuffers)
+ {
+ numNotFoundVertices = 0;
+ return false;
+ }
+
+ result.resize(numGraphicalVertices);
+ for (uint32_t i = 0; i < numGraphicalVertices; i++)
+ {
+ result[i] = ClothingConstants::ImmediateClothingInvalidValue;
+ }
+
+ numNotFoundVertices = 0;
+ float notFoundError = 0.0f;
+ float maxDotError = 0.0f;
+ const float maxDotMinimum = PxClamp(PxCos(physx::shdfnd::degToRad(normalResemblance)), 0.0f, 1.0f);
+
+ const PxVec3* physicalPositions = physicalMesh.vertices.buf;
+ const PxVec3* physicalNormals = physicalMesh.skinningNormals.buf;
+ const uint32_t* physicsMasterFlags = masterFlags;
+ const uint32_t numPhysicsVertices = physicalMesh.numVertices;
+ PX_ASSERT(physicsMasterFlags != NULL);
+
+ uint32_t submeshVertexOffset = 0;
+ for (uint32_t submeshIndex = 0; submeshIndex < numTargetMeshes; submeshIndex++)
+ {
+ const PxVec3* positions = targetMeshes[submeshIndex].pPosition;
+ const PxVec3* normals = targetMeshes[submeshIndex].pNormal;
+ const uint32_t* slaveFlags = targetMeshes[submeshIndex].pVertexFlags;
+ const uint32_t numVertices = targetMeshes[submeshIndex].numVertices;
+
+ for (uint32_t index = 0; index < numVertices; index++)
+ {
+ if (progress != NULL && ((index & 0xff) == 0))
+ {
+ const int32_t percent = int32_t(100 * (index + submeshVertexOffset) / numGraphicalVertices);
+
+ progress->setProgress(percent);
+ }
+
+ float minDistanceSquared = FLT_MAX;
+ int32_t optimalMatch = -1;
+ float maxDot = 0.0f;
+ const uint32_t slave = slaveFlags != NULL ? slaveFlags[index] : 0xffffffff;
+
+ for (uint32_t vertexIndex = 0; vertexIndex < numPhysicsVertices && (minDistanceSquared > 0 || maxDot < maxDotMinimum); vertexIndex++)
+ {
+ const uint32_t master = physicsMasterFlags[vertexIndex];
+ if ((master & slave) == 0)
+ {
+ continue;
+ }
+
+ const float distSquared = (physicalPositions[vertexIndex] - positions[index]).magnitudeSquared();
+ const float dot = normals[index].dot(physicalNormals[vertexIndex]);
+ if (distSquared < minDistanceSquared || (distSquared == minDistanceSquared && PxAbs(dot) > PxAbs(maxDot)))
+ {
+ minDistanceSquared = distSquared;
+ optimalMatch = (int32_t)vertexIndex;
+ maxDot = dot;
+ }
+ }
+
+ if (optimalMatch == -1 || minDistanceSquared > epsilon || PxAbs(maxDot) < maxDotMinimum)
+ {
+ notFoundError += sqrtf(minDistanceSquared);
+ maxDotError += PxAbs(maxDot);
+
+ if (PxAbs(maxDot) < maxDotMinimum && minDistanceSquared <= epsilon)
+ {
+ result[index + submeshVertexOffset] = (uint32_t)optimalMatch;
+ result[index + submeshVertexOffset] |= ClothingConstants::ImmediateClothingBadNormal;
+ }
+ else
+ {
+ result[index + submeshVertexOffset] = ClothingConstants::ImmediateClothingInvalidValue;
+ }
+ numNotFoundVertices++;
+ }
+ else
+ {
+ result[index + submeshVertexOffset] = (uint32_t)optimalMatch;
+ if (maxDot < 0)
+ {
+ result[index + submeshVertexOffset] |= ClothingConstants::ImmediateClothingInvertNormal;
+ }
+ }
+ }
+
+ submeshVertexOffset += numVertices;
+ }
+
+ return result.size() == numGraphicalVertices;
+}
+
+
+
+bool ClothingAssetAuthoringImpl::generateSkinClothMap(const AbstractMeshDescription* targetMeshes, uint32_t numTargetMeshes,
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type& physicalMesh,
+ uint32_t* masterFlags, uint32_t* immediateMap, uint32_t numEmptyInImmediateMap,
+ ParamArray<SkinClothMap>& result, float& offsetAlongNormal,
+ bool integrateImmediateMap, IProgressListener* progress) const
+{
+ if (immediateMap == NULL || integrateImmediateMap)
+ {
+ uint32_t sum = 0;
+ for (uint32_t i = 0; i < numTargetMeshes; i++)
+ {
+ sum += targetMeshes[i].numVertices;
+ }
+ result.resize(sum);
+ }
+ else
+ {
+ result.resize(numEmptyInImmediateMap);
+ }
+
+ // figure out some details about the physical mesh
+ AbstractMeshDescription srcPM;
+ srcPM.numIndices = physicalMesh.numIndices;
+ srcPM.numVertices = physicalMesh.numVertices;
+ srcPM.pIndices = physicalMesh.indices.buf;
+ srcPM.pNormal = physicalMesh.skinningNormals.buf;
+ srcPM.pPosition = physicalMesh.vertices.buf;
+ srcPM.pVertexFlags = masterFlags;
+
+ srcPM.UpdateDerivedInformation(NULL);
+
+ // PH: Negating this leads to interesting effects, but also to some side effects...
+ offsetAlongNormal = DEFAULT_PM_OFFSET_ALONG_NORMAL_FACTOR * srcPM.avgEdgeLength;
+
+ const uint32_t physNumIndices = physicalMesh.numIndices;
+
+ // compute mapping
+ Array<TriangleWithNormals> triangles;
+ triangles.reserve(physNumIndices / 3);
+
+ // create a list of physics mesh triangles
+ float avgHalfDiagonal = 0.0f;
+ for (uint32_t i = 0; i < physNumIndices; i += 3)
+ {
+ TriangleWithNormals triangle;
+
+ // store vertex information in triangle
+ triangle.master = 0;
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ triangle.vertices[j] = srcPM.pPosition[srcPM.pIndices[i + j]];
+ triangle.normals[j] = srcPM.pNormal[srcPM.pIndices[i + j]];
+ triangle.master |= srcPM.pVertexFlags != NULL ? srcPM.pVertexFlags[srcPM.pIndices[i + j]] : 0xffffffff;
+ }
+ triangle.faceIndex0 = i;
+
+ triangle.init();
+ triangle.bounds.fattenFast(srcPM.avgEdgeLength);
+
+ PxVec3 boundsDiag = triangle.bounds.getExtents();
+ avgHalfDiagonal += boundsDiag.magnitude();
+ triangles.pushBack(triangle);
+ }
+ avgHalfDiagonal /= triangles.size();
+
+ // hash the triangles
+ ApexMeshHash hash;
+ hash.setGridSpacing(avgHalfDiagonal);
+ for (uint32_t i = 0; i < triangles.size(); i++)
+ {
+ hash.add(triangles[i].bounds, i);
+ }
+
+ // find the best triangle for each graphical vertex
+ SkinClothMap* mapEntry = result.begin();
+
+ Array<uint32_t> queryResult;
+
+ uint32_t targetOffset = 0;
+ for (uint32_t targetIndex = 0; targetIndex < numTargetMeshes; targetIndex++)
+ {
+ const uint32_t numVertices = targetMeshes[targetIndex].numVertices;
+ for (uint32_t vertexIndex = 0; vertexIndex < numVertices; vertexIndex++)
+ {
+ const uint32_t slave = targetMeshes[targetIndex].pVertexFlags != NULL ? targetMeshes[targetIndex].pVertexFlags[vertexIndex] : 0xffffffff;
+ PX_ASSERT(slave != 0);
+
+ const uint32_t index = vertexIndex + targetOffset;
+ const PxVec3 position = targetMeshes[targetIndex].pPosition[vertexIndex];
+ const PxVec3 normal = targetMeshes[targetIndex].pNormal[vertexIndex];
+ const PxVec3 normalRelative = position + (normal * offsetAlongNormal);
+ PxVec3 tangentRelative(0.0f);
+ if (targetMeshes[targetIndex].pTangent != NULL)
+ {
+ tangentRelative = position + (targetMeshes[targetIndex].pTangent[vertexIndex] * offsetAlongNormal);
+ }
+ else if (targetMeshes[targetIndex].pTangent4 != NULL)
+ {
+ const PxVec3 tangent(targetMeshes[targetIndex].pTangent4[vertexIndex].x,
+ targetMeshes[targetIndex].pTangent4[vertexIndex].y,
+ targetMeshes[targetIndex].pTangent4[vertexIndex].z);
+ tangentRelative = position + (tangent * offsetAlongNormal);
+ }
+
+ if (((immediateMap != NULL) && ((immediateMap[index] & ClothingConstants::ImmediateClothingBadNormal) != 0)) || integrateImmediateMap)
+ {
+
+ // read physics vertex
+ const uint32_t bestVertex = immediateMap[index] & ClothingConstants::ImmediateClothingReadMask;
+
+ // mark entry as invalid, because we put it into the skinClothMap
+ immediateMap[index] = ClothingConstants::ImmediateClothingInvalidValue;
+
+ float bestError = PX_MAX_F32;
+ int32_t bestIndex = -1;
+
+ for (uint32_t pIndex = 0; pIndex < physNumIndices; pIndex++)
+ {
+ if (srcPM.pIndices[pIndex] == bestVertex)
+ {
+ // this is a triangle that contains bestVertex (from the immediate map)
+
+ uint32_t faceIndex0 = pIndex - (pIndex % 3);
+ uint32_t triangleIndex = faceIndex0 / 3;
+ PX_ASSERT(triangleIndex < triangles.size());
+
+ TriangleWithNormals& triangle = triangles[triangleIndex];
+ PX_ASSERT(triangle.faceIndex0 == faceIndex0);
+
+ if (triangle.doNotUse)
+ {
+ continue;
+ }
+
+ if ((triangle.master & slave) == 0)
+ {
+ continue;
+ }
+
+ ModuleClothingHelpers::computeTriangleBarys(triangle, position, normalRelative, tangentRelative, offsetAlongNormal, int32_t(vertexIndex + targetOffset), false);
+
+ if (triangle.valid != 2)
+ {
+ continue;
+ }
+
+ float error = computeTriangleError(triangle, normal);
+
+ // use the best triangle that contains the vertex
+ if (error < bestError)
+ {
+ bestIndex = (int32_t)triangleIndex;
+ bestError = error;
+ }
+ }
+ }
+ //PX_ASSERT(bestIndex != -1);
+ if (bestIndex != -1)
+ {
+ immediateMap[index] = (uint32_t)(mapEntry - result.begin());
+ immediateMap[index] |= ClothingConstants::ImmediateClothingInSkinFlag;
+
+ mapEntry->vertexBary = triangles[(uint32_t)bestIndex].tempBaryVertex;
+ uint32_t faceIndex = triangles[(uint32_t)bestIndex].faceIndex0;
+ mapEntry->vertexIndex0 = srcPM.pIndices[faceIndex + 0];
+ mapEntry->vertexIndex1 = srcPM.pIndices[faceIndex + 1];
+ mapEntry->vertexIndex2 = srcPM.pIndices[faceIndex + 2];
+
+ mapEntry->normalBary = triangles[(uint32_t)bestIndex].tempBaryNormal;
+ mapEntry->tangentBary = triangles[(uint32_t)bestIndex].tempBaryTangent;
+ mapEntry->vertexIndexPlusOffset = index;
+ mapEntry++;
+
+ continue;
+ }
+ //PX_ASSERT(0 && "generateSkinClothMapC: We should never end up here");
+ }
+
+ if (immediateMap != NULL && immediateMap[index] != ClothingConstants::ImmediateClothingInvalidValue)
+ {
+ continue;
+ }
+
+ if (progress != NULL && (index & 0xf) == 0)
+ {
+ const uint32_t location = (uint32_t)(mapEntry - result.begin());
+ const int32_t percent = int32_t(100 * location / result.size());
+
+ progress->setProgress(percent);
+ }
+
+ int32_t bestTriangleNr = -1;
+ float bestTriangleError = PX_MAX_F32;
+
+ // query for physical triangles around the graphics vertex
+ hash.query(position, queryResult);
+ for (uint32_t q = 0; q < queryResult.size(); q++)
+ {
+ const uint32_t triangleNr = queryResult[q];
+ TriangleWithNormals& triangle = triangles[triangleNr];
+
+ if (triangle.doNotUse)
+ {
+ continue;
+ }
+
+ if ((triangle.master & slave) == 0)
+ {
+ continue;
+ }
+
+ if (!triangle.bounds.contains(position))
+ {
+ continue;
+ }
+
+ ModuleClothingHelpers::computeTriangleBarys(triangle, position, normalRelative, tangentRelative, offsetAlongNormal, int32_t(vertexIndex + targetOffset), false);
+
+ if (triangle.valid != 2)
+ {
+ continue;
+ }
+
+ const float error = computeTriangleError(triangle, normal);
+
+ if (error < bestTriangleError)
+ {
+ bestTriangleNr = (int32_t)triangleNr;
+ bestTriangleError = error;
+ }
+ }
+
+ if (bestTriangleNr < 0)
+ {
+ // nothing was found nearby, search in all triangles
+ bestTriangleError = PX_MAX_F32;
+ for (uint32_t j = 0; j < triangles.size() && bestTriangleError > 0.0f; j++)
+ {
+ TriangleWithNormals& triangle = triangles[j];
+
+ if (triangle.doNotUse)
+ {
+ continue;
+ }
+
+ if ((triangle.master & slave) == 0)
+ {
+ continue;
+ }
+
+ triangle.timestamp = -1;
+ ModuleClothingHelpers::computeTriangleBarys(triangle, position, normalRelative, tangentRelative, offsetAlongNormal, int32_t(vertexIndex + targetOffset), false);
+
+ if (triangle.valid == 0)
+ {
+ continue;
+ }
+
+ float error = computeTriangleError(triangle, normal);
+
+ // increase the error a lot, but still better than nothing
+ if (triangle.valid != 2)
+ {
+ error += 100.0f;
+ }
+
+ if (error < bestTriangleError)
+ {
+ bestTriangleError = error;
+ bestTriangleNr = (int32_t)j;
+ }
+ }
+ }
+
+ if (bestTriangleNr >= 0)
+ {
+ const TriangleWithNormals& bestTriangle = triangles[(uint32_t)bestTriangleNr];
+
+ if (immediateMap != NULL)
+ {
+ PX_ASSERT(immediateMap[index] == ClothingConstants::ImmediateClothingInvalidValue);
+ immediateMap[index] = (uint32_t)(mapEntry - result.begin());
+ immediateMap[index] |= ClothingConstants::ImmediateClothingInSkinFlag;
+ }
+
+ PX_ASSERT(bestTriangle.faceIndex0 % 3 == 0);
+ //mapEntry->tetraIndex = bestTriangle.tetraIndex;
+ //mapEntry->submeshIndex = targetIndex;
+
+ mapEntry->vertexBary = bestTriangle.tempBaryVertex;
+ uint32_t faceIndex = bestTriangle.faceIndex0;
+ mapEntry->vertexIndex0 = srcPM.pIndices[faceIndex + 0];
+ mapEntry->vertexIndex1 = srcPM.pIndices[faceIndex + 1];
+ mapEntry->vertexIndex2 = srcPM.pIndices[faceIndex + 2];
+ mapEntry->normalBary = bestTriangle.tempBaryNormal;
+ mapEntry->tangentBary = bestTriangle.tempBaryTangent;
+ mapEntry->vertexIndexPlusOffset = index;
+ mapEntry++;
+ }
+ else if (immediateMap != NULL)
+ {
+ PX_ASSERT(immediateMap[index] == ClothingConstants::ImmediateClothingInvalidValue);
+ }
+ }
+
+ targetOffset += numVertices;
+ }
+
+
+ uint32_t sizeused = (uint32_t)(mapEntry - result.begin());
+ if (sizeused < result.size())
+ {
+ APEX_DEBUG_WARNING("%d vertices could not be mapped, they will be static!", result.size() - sizeused);
+ }
+ result.resize(sizeused);
+
+ return true;
+}
+
+template <typename T>
+class SkinClothMapPredicate2
+{
+public:
+ bool operator()(const T& map1, const T& map2) const
+ {
+ return map1.vertexIndexPlusOffset < map2.vertexIndexPlusOffset;
+ }
+};
+
+
+void ClothingAssetAuthoringImpl::removeMaxDistance0Mapping(ClothingGraphicalLodParameters& graphicalLod, RenderMeshAssetIntl* renderMeshAsset) const
+{
+ ParamArray<SkinClothMap> skinClothMap(&graphicalLod, "skinClothMap",
+ reinterpret_cast<ParamDynamicArrayStruct*>(&graphicalLod.skinClothMap));
+
+ ParamArray<uint32_t> immediateClothMap(&graphicalLod, "immediateClothMap",
+ reinterpret_cast<ParamDynamicArrayStruct*>(&graphicalLod.immediateClothMap));
+
+ // temp array to keep the simulated verts, as we want to discard the fixed verts
+ Array<SkinClothMap> skinClothMapNew;
+ skinClothMapNew.reserve(skinClothMap.size());
+
+ uint32_t offset = 0;
+ for (uint32_t s = 0; s < renderMeshAsset->getSubmeshCount(); s++)
+ {
+ // get submesh data
+ const VertexBuffer& vb = renderMeshAsset->getSubmesh(s).getVertexBuffer();
+ const VertexFormat& vf = vb.getFormat();
+
+ const uint32_t graphicalMaxDistanceIndex = (uint32_t)vf.getBufferIndexFromID(vf.getID(MAX_DISTANCE_NAME));
+ RenderDataFormat::Enum outFormat = vf.getBufferFormat(graphicalMaxDistanceIndex);
+ const float* graphicalMaxDistance = outFormat == RenderDataFormat::UNSPECIFIED ? NULL :
+ reinterpret_cast<const float*>(vb.getBuffer(graphicalMaxDistanceIndex));
+
+ const uint32_t numVertices = renderMeshAsset->getSubmesh(s).getVertexCount(0);
+ if (graphicalMaxDistance == NULL)
+ {
+ PX_ALWAYS_ASSERT();
+ offset += numVertices;
+ continue;
+ }
+
+ PX_ASSERT(outFormat == RenderDataFormat::FLOAT1);
+
+ for (uint32_t vertexIndex = 0; vertexIndex < numVertices; vertexIndex++)
+ {
+ const uint32_t index = vertexIndex + offset;
+
+ uint32_t skinClothMapIndex = (uint32_t)-1;
+ if (immediateClothMap.size() > index && immediateClothMap[index] & ClothingConstants::ImmediateClothingInSkinFlag)
+ {
+ // read the index out of the skinClothMap
+ skinClothMapIndex = immediateClothMap[index] & ClothingConstants::ImmediateClothingReadMask;
+ immediateClothMap[index] = skinClothMapNew.size() | ClothingConstants::ImmediateClothingInSkinFlag;
+ }
+ else if (skinClothMap.size() > index && index == skinClothMap[index].vertexIndexPlusOffset)
+ {
+ // if there's no immediateMap, all verts should be in the skinClothMap
+ skinClothMapIndex = index;
+ }
+ else
+ {
+ // we only get here, if there are some verts without mapping -> bad!
+ for (uint32_t i = 0; i < skinClothMap.size(); i++)
+ {
+ if (index == skinClothMap[i].vertexIndexPlusOffset)
+ {
+ skinClothMapIndex = i;
+ }
+ }
+ }
+
+ if (skinClothMapIndex != (uint32_t)-1)
+ {
+ if (graphicalMaxDistance[vertexIndex] != mInvalidConstrainCoefficients.maxDistance
+ && graphicalMaxDistance[vertexIndex] == 0.0f)
+ {
+ // non-simulated verts are removed from the skinClothMap (not added to skinClothMapNew)
+ if (immediateClothMap.size() > index)
+ {
+ immediateClothMap[index] = ClothingConstants::ImmediateClothingInvalidValue;
+ }
+ }
+ else
+ {
+ // keep the entry for simulated verts
+ skinClothMapNew.pushBack(skinClothMap[skinClothMapIndex]);
+ }
+ }
+ }
+
+ offset += numVertices;
+ }
+
+ // store reduced skinClothMap
+ skinClothMap.resize(skinClothMapNew.size());
+ for (uint32_t i = 0; i < skinClothMapNew.size(); ++i)
+ {
+ skinClothMap[i] = skinClothMapNew[i];
+ }
+}
+
+bool ClothingAssetAuthoringImpl::generateTetraMap(const AbstractMeshDescription* targetMeshes, uint32_t numTargetMeshes,
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type& physicalMesh, uint32_t* /*masterFlags*/,
+ ParamArray<ClothingGraphicalLodParametersNS::TetraLink_Type>& result, IProgressListener* progress) const
+{
+ uint32_t numGraphicalVertices = 0;
+
+
+ bool haveAllBuffers = true;
+
+ for (uint32_t submeshIndex = 0; submeshIndex < numTargetMeshes; submeshIndex++)
+ {
+ numGraphicalVertices += targetMeshes[submeshIndex].numVertices;
+
+ bool hasAllBuffers = true;
+ hasAllBuffers &= targetMeshes[submeshIndex].pPosition != NULL;
+ hasAllBuffers &= targetMeshes[submeshIndex].pNormal != NULL;
+
+ haveAllBuffers &= hasAllBuffers;
+ if (!hasAllBuffers)
+ {
+ APEX_INTERNAL_ERROR("Render mesh asset does not have either position or normal for submesh %d!", submeshIndex);
+ }
+ }
+
+ if (!haveAllBuffers)
+ {
+ return false;
+ }
+
+ result.resize(numGraphicalVertices);
+ memset(result.begin(), 0, sizeof(ClothingGraphicalLodParametersNS::TetraLink_Type) * numGraphicalVertices);
+
+ uint32_t submeshVertexOffset = 0;
+
+ const uint32_t* physicalIndices = physicalMesh.indices.buf;
+ const PxVec3* physicalPositions = physicalMesh.vertices.buf;
+
+ for (uint32_t targetIndex = 0; targetIndex < numTargetMeshes; targetIndex++)
+ {
+ const uint32_t numVertices = targetMeshes[targetIndex].numVertices;
+
+ const PxVec3* positions = targetMeshes[targetIndex].pPosition;
+ const PxVec3* normals = targetMeshes[targetIndex].pNormal;
+
+ for (uint32_t vertexIndex = 0; vertexIndex < numVertices; vertexIndex++)
+ {
+ const uint32_t index = vertexIndex + submeshVertexOffset;
+ if (progress != NULL && (index & 0x3f) == 0)
+ {
+ const int32_t percent = int32_t(100 * index / numGraphicalVertices);
+ progress->setProgress(percent);
+ }
+
+ const PxVec3 position = positions[vertexIndex];
+
+ float bestWorstBary = FLT_MAX;
+ int32_t bestTet = -1;
+ PxVec3 bestBary(0.0f, 0.0f, 0.0f);
+ for (uint32_t j = 0; j < physicalMesh.numIndices; j += 4)
+ {
+ PxVec3 p[4];
+ for (uint32_t k = 0; k < 4; k++)
+ {
+ p[k] = physicalPositions[physicalIndices[j + k]];
+ }
+
+ PxVec3 bary;
+ generateBarycentricCoordinatesTet(p[0], p[1], p[2], p[3], position, bary);
+ float baryU = 1 - bary.x - bary.y - bary.z;
+ float worstBary = 0.0f;
+ worstBary = PxMax(worstBary, -bary.x);
+ worstBary = PxMax(worstBary, -bary.y);
+ worstBary = PxMax(worstBary, -bary.z);
+ worstBary = PxMax(worstBary, -baryU);
+ worstBary = PxMax(worstBary, bary.x - 1);
+ worstBary = PxMax(worstBary, bary.y - 1);
+ worstBary = PxMax(worstBary, bary.z - 1);
+ worstBary = PxMax(worstBary, baryU - 1);
+ //PX_ASSERT(worstBary + bestWorstBary > 0 && "they must not be 0 both!!!");
+ if (worstBary < bestWorstBary)
+ {
+ bestWorstBary = worstBary;
+ bestTet = (int32_t)j;
+ bestBary = bary;
+ }
+ }
+
+ PX_ASSERT(result[index].tetraIndex0 == 0);
+
+ result[index].vertexBary = bestBary;
+ result[index].tetraIndex0 = (uint32_t)bestTet;
+
+ // compute barycentric coordinates of normal
+ PxVec3 normal(1.0f, 0.0f, 0.0f);
+ if (normals != NULL)
+ {
+ normal = normals[vertexIndex];
+ normal.normalize();
+ }
+ const PxVec3& pa = physicalPositions[physicalIndices[bestTet + 0]];
+ const PxVec3& pb = physicalPositions[physicalIndices[bestTet + 1]];
+ const PxVec3& pc = physicalPositions[physicalIndices[bestTet + 2]];
+ const PxVec3& pd = physicalPositions[physicalIndices[bestTet + 3]];
+ PxBounds3 bounds;
+ bounds.setEmpty();
+ bounds.include(pa);
+ bounds.include(pb);
+ bounds.include(pc);
+ bounds.include(pd);
+ // we use a second point above pos, along the normal.
+ // The offset must be small but arbitrary since we normalize the resulting normal during skinning
+ const float offset = (bounds.minimum - bounds.maximum).magnitude() * 0.01f;
+ generateBarycentricCoordinatesTet(pa, pb, pc, pd, position + normal * offset, result[index].normalBary);
+
+ }
+
+
+ submeshVertexOffset += numVertices;
+ }
+
+ return true;
+}
+
+
+
+float ClothingAssetAuthoringImpl::computeBaryError(float baryX, float baryY) const
+{
+#if 0
+ const float triangleSize = 1.0f;
+ const float baryZ = 1.0f - baryX - baryY;
+
+ const float errorX = (baryX - (1.0f / 3.0f)) * triangleSize;
+ const float errorY = (baryY - (1.0f / 3.0f)) * triangleSize;
+ const float errorZ = (baryZ - (1.0f / 3.0f)) * triangleSize;
+
+ return (errorX * errorX) + (errorY * errorY) + (errorZ * errorZ);
+#elif 0
+ float dist = 0.0f;
+ if (-baryX > dist)
+ {
+ dist = -baryX;
+ }
+ if (-baryY > dist)
+ {
+ dist = -baryY;
+ }
+ float sum = baryX + baryY - 1.0f;
+ if (sum > dist)
+ {
+ dist = sum;
+ }
+ return dist * dist;
+#else
+ const float baryZ = 1.0f - baryX - baryY;
+
+ const float errorX = PxMax(PxAbs(baryX - 0.5f) - 0.5f, 0.0f);
+ const float errorY = PxMax(PxAbs(baryY - 0.5f) - 0.5f, 0.0f);
+ const float errorZ = PxMax(PxAbs(baryZ - 0.5f) - 0.5f, 0.0f);
+
+ return (errorX * errorX) + (errorY * errorY) + (errorZ * errorZ);
+#endif
+}
+
+
+
+float ClothingAssetAuthoringImpl::computeTriangleError(const TriangleWithNormals& triangle, const PxVec3& normal) const
+{
+ PxVec3 faceNormal = (triangle.vertices[1] - triangle.vertices[0]).cross(triangle.vertices[2] - triangle.vertices[0]);
+ faceNormal.normalize();
+
+ const float avgTriangleEdgeLength = ((triangle.vertices[0] - triangle.vertices[1]).magnitude() +
+ (triangle.vertices[0] - triangle.vertices[2]).magnitude() +
+ (triangle.vertices[1] - triangle.vertices[2]).magnitude()) / 3.0f;
+
+ float error = computeBaryError(triangle.tempBaryVertex.x, triangle.tempBaryVertex.y);
+
+ PX_ASSERT(PxAbs(1 - normal.magnitude()) < 0.001f); // make sure it's normalized.
+
+ //const float normalWeight = faceNormal.cross(normal).magnitude(); // 0 for co-linear, 1 for perpendicular
+ const float normalWeight = 0.5f * (1.0f - faceNormal.dot(normal));
+
+ error += PxClamp(normalWeight, 0.0f, 1.0f) * computeBaryError(triangle.tempBaryNormal.x, triangle.tempBaryNormal.y);
+
+ const float heightValue = triangle.tempBaryVertex.z / avgTriangleEdgeLength;
+ const float heightWeight = 0.1f + 2.5f * computeBaryError(triangle.tempBaryVertex.x, triangle.tempBaryVertex.y);
+ const float heightError = heightWeight * PxAbs(heightValue);
+ error += heightError;
+
+ return error;
+}
+
+}
+} // namespace nvidia
+
+#endif // WITHOUT_APEX_AUTHORING
+
diff --git a/APEX_1.4/module/clothing/src/ClothingAssetData.cpp b/APEX_1.4/module/clothing/src/ClothingAssetData.cpp
new file mode 100644
index 00000000..795e0f04
--- /dev/null
+++ b/APEX_1.4/module/clothing/src/ClothingAssetData.cpp
@@ -0,0 +1,874 @@
+/*
+ * 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 "ApexSimdMath.h"
+#include "PxPreprocessor.h"
+#include "RenderDataFormat.h"
+#include "ClothingAssetData.h"
+#include "PsIntrinsics.h"
+#include "PsVecMath.h"
+#include "PxMat44.h"
+
+#define NX_PARAMETERIZED_ONLY_LAYOUTS
+#include "ClothingGraphicalLodParameters.h"
+
+#pragma warning(disable : 4101 4127) // unreferenced local variable and conditional expression is constant
+
+
+namespace nvidia
+{
+using namespace physx::shdfnd;
+//using namespace physx::shdfnd::aos;
+
+namespace clothing
+{
+
+ClothingAssetSubMesh::ClothingAssetSubMesh() :
+ mPositions(NULL),
+ mNormals(NULL),
+ mTangents(NULL),
+ mBoneWeights(NULL),
+ mBoneIndices(NULL),
+ mIndices(NULL),
+ mUvs(NULL),
+
+ mPositionOutFormat(RenderDataFormat::UNSPECIFIED),
+ mNormalOutFormat(RenderDataFormat::UNSPECIFIED),
+ mTangentOutFormat(RenderDataFormat::UNSPECIFIED),
+ mBoneWeightOutFormat(RenderDataFormat::UNSPECIFIED),
+ mUvFormat(RenderDataFormat::UNSPECIFIED),
+
+ mVertexCount(0),
+ mIndicesCount(0),
+ mUvCount(0),
+ mNumBonesPerVertex(0),
+
+ mCurrentMaxVertexSimulation(0),
+ mCurrentMaxVertexAdditionalSimulation(0),
+ mCurrentMaxIndexSimulation(0)
+{
+}
+
+
+
+ClothingMeshAssetData::ClothingMeshAssetData() :
+ mImmediateClothMap(NULL),
+ mSkinClothMap(NULL),
+ mSkinClothMapB(NULL),
+ mTetraMap(NULL),
+
+ mImmediateClothMapCount(0),
+ mSkinClothMapCount(0),
+ mSkinClothMapBCount(0),
+ mTetraMapCount(0),
+
+ mSubmeshOffset(0),
+ mSubMeshCount(0),
+
+ mPhysicalMeshId(0),
+
+ mSkinClothMapThickness(0.0f),
+ mSkinClothMapOffset(0.0f),
+
+ mBounds(PxBounds3::empty()),
+
+ bActive(false)
+{
+
+}
+
+
+
+ClothingPhysicalMeshData::ClothingPhysicalMeshData() :
+ mVertices(NULL),
+ mVertexCount(0),
+ mSimulatedVertexCount(0),
+ mMaxDistance0VerticesCount(0),
+ mNormals(NULL),
+ mSkinningNormals(NULL),
+ mBoneIndices(NULL),
+ mBoneWeights(NULL),
+ mOptimizationData(NULL),
+ mIndices(NULL),
+
+ mSkinningNormalsCount(0),
+ mBoneWeightsCount(0),
+ mOptimizationDataCount(0),
+ mIndicesCount(0),
+ mSimulatedIndicesCount(0),
+
+ mNumBonesPerVertex(0)
+{
+
+}
+
+
+
+ClothingAssetData::ClothingAssetData() :
+ mData(NULL),
+ mCompressedNumBonesPerVertex(NULL),
+ mCompressedTangentW(NULL),
+ mExt2IntMorphMapping(NULL),
+ mCompressedNumBonesPerVertexCount(0),
+ mCompressedTangentWCount(0),
+ mExt2IntMorphMappingCount(0),
+
+ mAssetSize(0),
+ mGraphicalLodsCount(0),
+ mPhysicalMeshesCount(0),
+ mPhysicalMeshOffset(0),
+ mBoneCount(0),
+ mRootBoneIndex(0)
+{
+
+}
+
+
+
+
+ClothingAssetData::~ClothingAssetData()
+{
+ PX_FREE(mData);
+ mData = NULL;
+}
+
+
+
+void ClothingAssetData::skinToBones(AbstractMeshDescription& destMesh, uint32_t submeshIndex, uint32_t graphicalMeshIndex, uint32_t startVertex,
+ PxMat44* compositeMatrices, PxVec3* morphDisplacements)
+{
+ // This is no nice code, but it allows to have 8 different code paths through skinToBones that have all the if's figured out at compile time (hopefully)
+ PX_ASSERT(destMesh.pTangent == NULL);
+ PX_ASSERT(destMesh.pBitangent == NULL);
+
+ if (destMesh.pNormal != NULL)
+ {
+ if (mBoneCount != 0)
+ {
+ if (morphDisplacements != NULL)
+ {
+ if (destMesh.pTangent4 != NULL)
+ {
+ skinToBonesInternal<true, true, true, true>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ else
+ {
+ skinToBonesInternal<true, true, true, false>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ }
+ else
+ {
+ if (destMesh.pTangent4 != NULL)
+ {
+ skinToBonesInternal<true, true, false, true>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ else
+ {
+ skinToBonesInternal<true, true, false, false>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ }
+ }
+ else
+ {
+ if (morphDisplacements != NULL)
+ {
+ if (destMesh.pTangent4 != NULL)
+ {
+ skinToBonesInternal<true, false, true, true>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ else
+ {
+ skinToBonesInternal<true, false, true, false>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ }
+ else
+ {
+ if (destMesh.pTangent4 != NULL)
+ {
+ skinToBonesInternal<true, false, false, true>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ else
+ {
+ skinToBonesInternal<true, false, false, false>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ }
+ }
+ }
+ else
+ {
+ if (mBoneCount != 0)
+ {
+ if (morphDisplacements != NULL)
+ {
+ if (destMesh.pTangent4 != NULL)
+ {
+ skinToBonesInternal<false, true, true, true>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ else
+ {
+ skinToBonesInternal<false, true, true, false>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ }
+ else
+ {
+ if (destMesh.pTangent4 != NULL)
+ {
+ skinToBonesInternal<false, true, false, true>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ else
+ {
+ skinToBonesInternal<false, true, false, false>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ }
+ }
+ else
+ {
+ if (morphDisplacements != NULL)
+ {
+ if (destMesh.pTangent4 != NULL)
+ {
+ skinToBonesInternal<false, false, true, true>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ else
+ {
+ skinToBonesInternal<false, false, true, false>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ }
+ else
+ {
+ if (destMesh.pTangent4 != NULL)
+ {
+ skinToBonesInternal<false, false, false, true>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ else
+ {
+ skinToBonesInternal<false, false, false, false>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ }
+ }
+ }
+}
+
+
+template<bool withNormals, bool withBones, bool withMorph, bool withTangents>
+void ClothingAssetData::skinToBonesInternal(AbstractMeshDescription& destMesh, uint32_t submeshIndex, uint32_t graphicalMeshIndex,
+ uint32_t startVertex, PxMat44* compositeMatrices, PxVec3* morphDisplacements)
+{
+ PX_ASSERT(withNormals == (destMesh.pNormal != NULL));
+ PX_ASSERT(withMorph == (morphDisplacements != NULL));
+
+ PX_ASSERT(withTangents == (destMesh.pTangent4 != NULL));
+ PX_ASSERT(destMesh.pTangent == NULL);
+ PX_ASSERT(destMesh.pBitangent == NULL);
+
+ // so we need to start further behind, but to make vec3* still aligned it must be a multiple of 4, and to make
+ // compressedNumBones aligned, it needs to be a multiple of 16 (hence 16)
+ // The start offset is reduced by up to 16, and instead of skipping the first [0, 16) vertices and adding additional logic
+ // they just get computed as well, assuming much less overhead than an additional if in the innermost loop
+ // Note: This only works if the mesh-mesh skinning is executed afterwards!
+ const uint32_t startVertex16 = startVertex - (startVertex % 16);
+
+ PX_ASSERT(((size_t)(compositeMatrices) & 0xf) == 0); // make sure the pointer is 16 byte aligned!!
+
+ ClothingMeshAssetData* meshAsset = GetLod(graphicalMeshIndex);
+ PX_ASSERT(submeshIndex < meshAsset->mSubMeshCount);
+ ClothingAssetSubMesh* pSubmesh = GetSubmesh(meshAsset, submeshIndex);
+ const uint32_t numVertices = pSubmesh->mVertexCount - startVertex16;
+ if(numVertices == 0)
+ {
+ return;
+ }
+
+ // use the per-asset setting
+ const uint32_t startVertexDiv16 = startVertex16 / 16;
+ uint32_t mapSize = 0;
+ const uint32_t* compressedNumBonesPerVertexEa = getCompressedNumBonesPerVertex(graphicalMeshIndex, submeshIndex, mapSize);
+ PX_ASSERT((mapSize - startVertexDiv16) * 16 >= numVertices);
+
+ const uint32_t* compressedNumBonesPerVertex = (const uint32_t*)((uint32_t*)compressedNumBonesPerVertexEa + startVertexDiv16);
+
+ const PxVec3* PX_RESTRICT positionsEa = pSubmesh->mPositions + startVertex16;
+ PX_ASSERT(pSubmesh->mPositionOutFormat == RenderDataFormat::FLOAT3);
+ const PxVec3* PX_RESTRICT normalsEa = pSubmesh->mNormals + startVertex16;
+ PX_ASSERT(pSubmesh->mNormalOutFormat == RenderDataFormat::FLOAT3);
+
+ const PxVec4* PX_RESTRICT tangentsEa = pSubmesh->mTangents + (pSubmesh->mTangents != NULL ? startVertex16 : 0);
+ PX_ASSERT(tangentsEa == NULL || pSubmesh->mTangentOutFormat == RenderDataFormat::FLOAT4);
+
+ //These are effective addresses (ea)
+ PxVec3* PX_RESTRICT destPositionsEa = destMesh.pPosition + startVertex16;
+ PxVec3* PX_RESTRICT destNormalsEa = destMesh.pNormal + startVertex16;
+ PxVec4* PX_RESTRICT destTangentsEa = (destMesh.pTangent4 != NULL) ? destMesh.pTangent4 + startVertex16 : NULL;
+
+ uint32_t* morphReorderingEa = morphDisplacements != NULL ? getMorphMapping(graphicalMeshIndex) : NULL;
+ if (morphReorderingEa != NULL)
+ {
+ morphReorderingEa += startVertex16;
+ }
+ else if (withMorph)
+ {
+ // actually we don't have a morph map, so let's take one step back
+ skinToBonesInternal<withNormals, withBones, false, withTangents>(destMesh, submeshIndex, graphicalMeshIndex,
+ startVertex, compositeMatrices, NULL);
+ return;
+ }
+ PX_ASSERT((morphDisplacements != NULL) == (morphReorderingEa != NULL));
+
+ const uint16_t* PX_RESTRICT boneIndicesEa = NULL;
+ const float* PX_RESTRICT boneWeightsEa = NULL;
+
+ const uint32_t maxNumBonesPerVertex = pSubmesh->mNumBonesPerVertex;
+ if (withBones)
+ {
+ boneIndicesEa = (const uint16_t*)pSubmesh->mBoneIndices + (startVertex16 * maxNumBonesPerVertex);
+ boneWeightsEa = (const float*)pSubmesh->mBoneWeights + (startVertex16 * maxNumBonesPerVertex);
+ }
+
+
+ //bones per vertex is LS address!!!!
+ const uint32_t* PX_RESTRICT bonesPerVertex = compressedNumBonesPerVertex;
+
+ //OK. Need to split this up into an even larger subset of work!!!! Perhaps sets of 1024 vertices/normals/bones....
+
+ const uint32_t WorkSize = 160;
+
+ const uint32_t countWork = (numVertices + (WorkSize - 1)) / WorkSize;
+
+ for (uint32_t a = 0; a < countWork; ++a)
+ {
+ const uint32_t workCount = PxMin(numVertices - (a * WorkSize), WorkSize);
+
+ const PxVec3* PX_RESTRICT positions = (const PxVec3 * PX_RESTRICT)(void*)positionsEa;
+ const PxVec3* PX_RESTRICT normals = NULL;
+ const float* PX_RESTRICT tangents4 = NULL;
+ const uint16_t* PX_RESTRICT boneIndices = NULL;
+ const float* PX_RESTRICT boneWeights = NULL;
+
+ PxVec3* PX_RESTRICT destPositions = (PxVec3 * PX_RESTRICT)(void*)destPositionsEa;
+ PxVec3* PX_RESTRICT destNormals = NULL;
+ float* PX_RESTRICT destTangents4 = NULL;
+
+ uint32_t* morphReordering = NULL;
+ if (withMorph)
+ {
+ morphReordering = (uint32_t*)morphReorderingEa;
+ morphReorderingEa += workCount;
+ }
+
+ if (withBones)
+ {
+ boneIndices = (const uint16_t * PX_RESTRICT)(void*)boneIndicesEa;
+ boneWeights = (const float * PX_RESTRICT)(void*)boneWeightsEa;
+ }
+
+ if (withNormals)
+ {
+ destNormals = (PxVec3 * PX_RESTRICT)(void*)destNormalsEa;
+ normals = (const PxVec3 * PX_RESTRICT)(void*)normalsEa;
+ }
+
+ if (withTangents)
+ {
+ destTangents4 = (float*)(void*)destTangentsEa;
+ tangents4 = (const float*)(void*)tangentsEa;
+ }
+
+
+ const uint32_t count16 = (workCount + 15) / 16;
+ for (uint32_t i = 0; i < count16; ++i)
+ {
+ //Fetch in the next block of stuff...
+ const uint32_t maxVerts = PxMin(numVertices - (a * WorkSize) - (i * 16u), 16u);
+ uint32_t numBoneWeight = *bonesPerVertex++;
+
+ prefetchLine(positions + 16);
+
+ if (withNormals)
+ {
+ prefetchLine(normals + 16);
+ }
+
+ if (withBones)
+ {
+ prefetchLine(boneIndices + (4 * 16));
+ prefetchLine(boneWeights + (2 * 16));
+ prefetchLine(boneWeights + (4 * 16));
+ }
+
+ if (withTangents)
+ {
+ prefetchLine(tangents4 + (4 * 16));
+ }
+
+ for (uint32_t j = 0; j < maxVerts; j++)
+ {
+ const uint32_t vertexIndex = i * 16 + j;
+ const uint32_t numBones = (numBoneWeight & 0x3) + 1;
+ numBoneWeight >>= 2;
+
+ {
+ PxVec3 untransformedPosition = *positions;
+ if (withMorph)
+ {
+ const PxVec3* morphDisplacement = (PxVec3*)&morphDisplacements[morphReordering[vertexIndex]];
+ untransformedPosition += *morphDisplacement;
+ }
+ Simd4f positionV = gSimd4fZero;
+ Simd4f normalV = gSimd4fZero;
+ Simd4f tangentV = gSimd4fZero;
+
+ if (withBones)
+ {
+ for (uint32_t k = 0; k < numBones; k++)
+ {
+ float weight = boneWeights[k];
+
+ PX_ASSERT(PxIsFinite(weight));
+
+ const uint16_t boneNr = boneIndices[k];
+
+ PxMat44& skinningMatrixV = (PxMat44&)compositeMatrices[boneNr];
+
+ const Simd4f weightV = Simd4fScalarFactory(weight);
+
+ Simd4f transformedPositionV = applyAffineTransform(skinningMatrixV, createSimd3f(untransformedPosition));
+ transformedPositionV = transformedPositionV * weightV;
+ positionV = positionV + transformedPositionV;
+
+ if (withNormals)
+ {
+ Simd4f transformedNormalV = applyLinearTransform(skinningMatrixV, createSimd3f(*normals));
+ transformedNormalV = transformedNormalV * weightV;
+ normalV = normalV + transformedNormalV;
+ }
+
+ if (withTangents)
+ {
+ const Simd4f inTangent = Simd4fAlignedLoadFactory(tangents4);
+ const Simd4f transformedTangentV = applyLinearTransform(skinningMatrixV, inTangent);
+ tangentV = tangentV + transformedTangentV * weightV;
+ }
+ }
+ }
+ else
+ {
+ PxMat44& skinningMatrixV = (PxMat44&)compositeMatrices[0];
+ positionV = applyAffineTransform(skinningMatrixV, createSimd3f(untransformedPosition));
+ if (withNormals)
+ {
+ normalV = applyLinearTransform(skinningMatrixV, createSimd3f(*normals));
+ }
+ if (withTangents)
+ {
+ const Simd4f inTangent = Simd4fAlignedLoadFactory(tangents4);
+ tangentV = applyLinearTransform(skinningMatrixV, inTangent);
+ }
+
+ }
+
+ if (withNormals)
+ {
+ normalV = normalizeSimd3f(normalV);
+ store3(&(destNormals->x), normalV);
+ }
+
+
+ if (withTangents)
+ {
+ tangentV = normalizeSimd3f(tangentV);
+ const Simd4f bitangent = Simd4fScalarFactory(tangents4[3]);
+ const Simd4f outTangent = select(gSimd4fMaskXYZ, tangentV, bitangent);
+ storeAligned(destTangents4, outTangent);
+ }
+
+ // if all weights are 0, we use the bind pose
+ // we don't really need that and it just slows us down..
+ //*destPositions = (numBones == 0) ? *positions : ps;
+ //*destPositions = ps;
+ store3(&destPositions->x, positionV);
+ }
+
+ positions++;
+ positionsEa++;
+ normals++;
+ normalsEa++;
+ if (withBones)
+ {
+ boneWeights += maxNumBonesPerVertex;
+ boneWeightsEa += maxNumBonesPerVertex;
+ boneIndices += maxNumBonesPerVertex;
+ boneIndicesEa += maxNumBonesPerVertex;
+ }
+ if (withTangents)
+ {
+ tangents4 += 4;
+ tangentsEa++;
+ destTangents4 += 4;
+ destTangentsEa++;
+ }
+ destPositions++;
+ destPositionsEa++;
+ destNormals++;
+ destNormalsEa++;
+ }
+ }
+ }
+
+}
+
+
+
+uint32_t* ClothingAssetData::getMorphMapping(uint32_t graphicalLod)
+{
+ if (mExt2IntMorphMappingCount == 0)
+ {
+ return NULL;
+ }
+
+ if (graphicalLod == (uint32_t) - 1 || graphicalLod > mGraphicalLodsCount)
+ {
+ graphicalLod = mGraphicalLodsCount;
+ }
+
+ uint32_t offset = 0;
+ for (uint32_t i = 0; i < graphicalLod; i++)
+ {
+ const ClothingMeshAssetData* meshAsset = GetLod(i);
+ for (uint32_t s = 0; s < meshAsset->mSubMeshCount; s++)
+ {
+ offset += GetSubmesh(meshAsset, s)->mVertexCount;
+ }
+ }
+
+ PX_ASSERT(offset < mExt2IntMorphMappingCount);
+ return mExt2IntMorphMapping + offset;
+}
+
+
+
+const uint32_t* ClothingAssetData::getCompressedNumBonesPerVertex(uint32_t graphicalLod, uint32_t submeshIndex, uint32_t& mapSize)
+{
+ mapSize = 0;
+
+ uint32_t offset = 0;
+ for (uint32_t lodIndex = 0; lodIndex < mGraphicalLodsCount; lodIndex++)
+ {
+ const ClothingMeshAssetData* meshAsset = GetLod(lodIndex);
+
+ for (uint32_t s = 0; s < meshAsset->mSubMeshCount; s++)
+ {
+ const uint32_t numVertices = GetSubmesh(meshAsset, s)->mVertexCount;
+
+ uint32_t numEntries = (numVertices + 15) / 16;
+ while ((numEntries & 0x3) != 0) // this is a numEntries % 4
+ {
+ numEntries++;
+ }
+
+ if (lodIndex == graphicalLod && submeshIndex == s)
+ {
+ mapSize = numEntries;
+ PX_ASSERT((mapSize % 4) == 0);
+ return &mCompressedNumBonesPerVertex[offset];
+ }
+
+ offset += numEntries;
+ PX_ASSERT(mCompressedNumBonesPerVertexCount >= offset);
+ }
+ }
+ return NULL;
+}
+
+
+
+const uint32_t* ClothingAssetData::getCompressedTangentW(uint32_t graphicalLod, uint32_t submeshIndex, uint32_t& mapSize)
+{
+ mapSize = 0;
+
+ uint32_t offset = 0;
+ for (uint32_t lodIndex = 0; lodIndex < mGraphicalLodsCount; lodIndex++)
+ {
+ const ClothingMeshAssetData* meshAsset = GetLod(lodIndex);
+
+ for (uint32_t s = 0; s < meshAsset->mSubMeshCount; s++)
+ {
+ const uint32_t numVertices = GetSubmesh(meshAsset, s)->mVertexCount;
+
+ uint32_t numEntries = (numVertices + 31) / 32;
+ while ((numEntries & 0x3) != 0) // this is a numEntries % 4
+ {
+ numEntries++;
+ }
+
+ if (lodIndex == graphicalLod && submeshIndex == s)
+ {
+ mapSize = numEntries;
+ PX_ASSERT((mapSize % 4) == 0);
+ return (uint32_t*)&mCompressedTangentW[offset];
+ }
+
+ offset += numEntries;
+ PX_ASSERT(mCompressedTangentWCount >= offset);
+ }
+ }
+ return NULL;
+}
+
+
+
+void ClothingAssetData::getNormalsAndVerticesForFace(PxVec3* vtx, PxVec3* nrm, uint32_t i,
+ const AbstractMeshDescription& srcPM) const
+{
+ // copy indices for convenience
+ PX_ASSERT(i < srcPM.numIndices);
+ uint32_t di[3];
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ di[j] = srcPM.pIndices[i + j];
+ }
+
+ // To guarantee consistency in our implicit tetrahedral mesh definition we must always order vertices
+ // idx[0,1,2] = min, max and mid
+ uint32_t idx[3];
+ idx[0] = PxMin(di[0], PxMin(di[1], di[2]));
+ idx[1] = PxMax(di[0], PxMax(di[1], di[2]));
+ idx[2] = idx[0];
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ if ((idx[0] != di[j]) && (idx[1] != di[j]))
+ {
+ idx[2] = di[j];
+ }
+ }
+
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ vtx[j] = srcPM.pPosition[idx[j]];
+ nrm[j] = srcPM.pNormal[idx[j]];
+#ifdef _DEBUG
+ // sanity
+ // PH: These normals 'should' always be normalized, maybe we can get rid of the normalize completely!
+ const float length = nrm[j].magnitudeSquared();
+ if (!(length >= 0.99f && length <= 1.01f))
+ {
+ static bool first = true;
+ if (first)
+ {
+ PX_ALWAYS_ASSERT();
+ first = false;
+ }
+ }
+#else
+ // PH: let's try and disable it in release mode...
+ //nrm[j].normalize();
+#endif
+ };
+}
+
+
+uint32_t ClothingAssetData::skinClothMapBSkinVertex(PxVec3& dstPos, PxVec3* dstNormal, uint32_t vIndex,
+ ClothingGraphicalLodParametersNS::SkinClothMapB_Type* pTCMB, const ClothingGraphicalLodParametersNS::SkinClothMapB_Type* pTCMBEnd,
+ const AbstractMeshDescription& srcPM) const
+{
+ uint32_t numIterations(0);
+ //uint32_t numSkipped(0);
+
+ //PX_ASSERT(dstPos.isZero());
+ //PX_ASSERT(dstNormal == NULL || dstNormal->isZero());
+
+ PX_ASSERT(srcPM.avgEdgeLength != 0.0f);
+ const float pmThickness = srcPM.avgEdgeLength;
+
+ while ((pTCMB->vertexIndexPlusOffset == vIndex) && (pTCMB < pTCMBEnd))
+ {
+ // skip vertices that we couldn't find a binding for
+ if (pTCMB->faceIndex0 == 0xFFFFFFFF || pTCMB->faceIndex0 >= srcPM.numIndices)
+ {
+ pTCMB++;
+ //numSkipped++;
+ //numIterations++;
+ continue;
+ }
+
+ PxVec3 vtx[3], nrm[3];
+ getNormalsAndVerticesForFace(vtx, nrm, pTCMB->faceIndex0, srcPM);
+
+ const TetraEncoding_Local& tetEnc = tetraTableLocal[pTCMB->tetraIndex];
+ const PxVec3 tv0 = vtx[0] + (tetEnc.sign[0] * pmThickness) * nrm[0];
+ const PxVec3 tv1 = vtx[1] + (tetEnc.sign[1] * pmThickness) * nrm[1];
+ const PxVec3 tv2 = vtx[2] + (tetEnc.sign[2] * pmThickness) * nrm[2];
+ const PxVec3 tv3 = vtx[tetEnc.lastVtxIdx] + (tetEnc.sign[3] * pmThickness) * nrm[tetEnc.lastVtxIdx];
+
+ const PxVec3& vtb = pTCMB->vtxTetraBary;
+ const float vtbw = 1.0f - vtb.x - vtb.y - vtb.z;
+ dstPos = (vtb.x * tv0) + (vtb.y * tv1) + (vtb.z * tv2) + (vtbw * tv3);
+ PX_ASSERT(dstPos.isFinite());
+
+ if (dstNormal != NULL)
+ {
+ const PxVec3& ntb = pTCMB->nrmTetraBary;
+ const float ntbw = 1.0f - ntb.x - ntb.y - ntb.z;
+ *dstNormal = (ntb.x * tv0) + (ntb.y * tv1) + (ntb.z * tv2) + (ntbw * tv3);
+ PX_ASSERT(dstNormal->isFinite());
+ }
+
+ pTCMB++;
+ numIterations++;
+ }
+
+ if (dstNormal != NULL && numIterations > 0)
+ {
+ // PH: this code certainly does not work if numIterations is bigger than 1 (it would need to average by dividing through numIterations)
+ PX_ASSERT(numIterations == 1);
+ *dstNormal -= dstPos;
+ *dstNormal *= physx::shdfnd::recipSqrtFast(dstNormal->magnitudeSquared());
+ }
+
+ return numIterations;
+}
+
+
+uint32_t ClothingAssetData::skinClothMapB(PxVec3* dstPositions, PxVec3* dstNormals, uint32_t numVertices,
+ const AbstractMeshDescription& srcPM, ClothingGraphicalLodParametersNS::SkinClothMapB_Type* map,
+ uint32_t numVerticesInMap, bool computeNormals) const
+{
+ PX_ASSERT(srcPM.numIndices % 3 == 0);
+
+ PX_ASSERT(srcPM.avgEdgeLength != 0.0f);
+
+ ClothingGraphicalLodParametersNS::SkinClothMapB_Type* pTCMB = map;
+ ClothingGraphicalLodParametersNS::SkinClothMapB_Type* pTCMBEnd = map + numVerticesInMap;
+
+ for (uint32_t j = 0; j < numVerticesInMap; j++)
+ {
+ uint32_t vertexIndex = pTCMB->vertexIndexPlusOffset;
+
+ if (vertexIndex >= numVertices)
+ {
+ pTCMB++;
+ continue;
+ }
+
+ PxVec3& p = dstPositions[vertexIndex];
+
+ PxVec3* n = NULL;
+ if (computeNormals)
+ {
+ n = dstNormals + vertexIndex;
+ }
+
+ uint32_t numIters = skinClothMapBSkinVertex(p, n, vertexIndex, pTCMB, pTCMBEnd, srcPM);
+ if (numIters == 0)
+ {
+ // PH: find next submesh
+ const uint32_t currentIterations = (uint32_t)(size_t)(pTCMB - map);
+ for (uint32_t i = currentIterations; i < numVerticesInMap; i++)
+ {
+ if (map[i].submeshIndex > pTCMB->submeshIndex)
+ {
+ numIters = i - currentIterations;
+ break;
+ }
+ }
+
+ // only return if it's still 0
+ if (numIters == 0)
+ {
+ return currentIterations;
+ }
+ }
+
+ pTCMB += numIters;
+ }
+
+ return numVertices;
+}
+
+bool ClothingAssetData::skinToTetraMesh(AbstractMeshDescription& destMesh,
+ const AbstractMeshDescription& srcPM,
+ const ClothingMeshAssetData& graphicalLod)
+{
+ if (graphicalLod.mTetraMap == NULL)
+ {
+ return false;
+ }
+
+ PX_ASSERT(srcPM.numIndices % 4 == 0);
+
+ PX_ASSERT(destMesh.pIndices == NULL);
+ PX_ASSERT(destMesh.pTangent == NULL);
+ PX_ASSERT(destMesh.pBitangent == NULL);
+ const bool computeNormals = destMesh.pNormal != NULL;
+
+ PxVec3 dummyNormal;
+
+ const uint32_t numGraphicalVertices = destMesh.numVertices;
+
+ const uint32_t* mainIndices = GetPhysicalMesh(graphicalLod.mPhysicalMeshId)->mIndices;
+
+ for (uint32_t i = 0; i < numGraphicalVertices; i++)
+ {
+ const ClothingGraphicalLodParametersNS::TetraLink_Type& currentLink = graphicalLod.mTetraMap[i];
+ if (currentLink.tetraIndex0 >= srcPM.numIndices)
+ {
+ continue;
+ }
+
+ PxVec3& position = destMesh.pPosition[i];
+ position = PxVec3(0.0f);
+
+ float vertexBary[4];
+ vertexBary[0] = currentLink.vertexBary.x;
+ vertexBary[1] = currentLink.vertexBary.y;
+ vertexBary[2] = currentLink.vertexBary.z;
+ vertexBary[3] = 1 - vertexBary[0] - vertexBary[1] - vertexBary[2];
+
+ const uint32_t* indices = mainIndices + currentLink.tetraIndex0;
+
+ if (computeNormals)
+ {
+ PxVec3& normal = computeNormals ? destMesh.pNormal[i] : dummyNormal;
+ normal = PxVec3(0.0f);
+
+ float normalBary[4];
+ normalBary[0] = currentLink.normalBary.x;
+ normalBary[1] = currentLink.normalBary.y;
+ normalBary[2] = currentLink.normalBary.z;
+ normalBary[3] = 1 - normalBary[0] - normalBary[1] - normalBary[2];
+
+ // compute skinned positions and normals
+ for (uint32_t j = 0; j < 4; j++)
+ {
+ const PxVec3& pos = srcPM.pPosition[indices[j]];
+ position += pos * vertexBary[j];
+ normal += pos * normalBary[j];
+ }
+
+ normal = normal - position;
+ normal *= nvidia::recipSqrtFast(normal.magnitudeSquared());
+ }
+ else
+ {
+ // only compute skinned positions, not normals
+ for (uint32_t j = 0; j < 4; j++)
+ {
+ const PxVec3& pos = srcPM.pPosition[indices[j]];
+ position += pos * vertexBary[j];
+ }
+ }
+ PX_ASSERT(position.isFinite());
+ }
+ return true;
+}
+
+
+
+}
+}
diff --git a/APEX_1.4/module/clothing/src/ClothingAssetImpl.cpp b/APEX_1.4/module/clothing/src/ClothingAssetImpl.cpp
new file mode 100644
index 00000000..cba5ef51
--- /dev/null
+++ b/APEX_1.4/module/clothing/src/ClothingAssetImpl.cpp
@@ -0,0 +1,3849 @@
+/*
+ * 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 "ClothingAsset.h"
+
+#include "ApexAuthorableObject.h"
+#include "ClothingActorProxy.h"
+#include "ClothingAssetImpl.h"
+#include "ClothingAssetData.h"
+#include "ClothingGlobals.h"
+#include "ClothingPhysicalMeshImpl.h"
+#include "ClothingPreviewProxy.h"
+#include "ClothingScene.h"
+#include "CookingPhysX.h"
+#include "ModulePerfScope.h"
+#include "nvparameterized/NvParamUtils.h"
+
+#include "ApexMath.h"
+#include "ClothingActorParam.h"
+#include "ClothingAssetParameters.h"
+#include "ClothingGraphicalLodParameters.h"
+#include "ModuleClothingHelpers.h"
+
+#include "PxStrideIterator.h"
+#include "PsSort.h"
+#include "PsThread.h"
+#include "ApexUsingNamespace.h"
+#include "PxMat33.h"
+#include "PsVecMath.h"
+
+#include "SimulationAbstract.h"
+#include "ApexPermute.h"
+
+#include "ApexPvdClient.h"
+#include "PxPvdDataStream.h"
+
+#define PX_SIMD_SKINNING 1
+
+#pragma warning( disable: 4101 ) // PX_COMPILE_TIME_ASSERT causes these warnings since they are
+// used within our apex namespace
+
+namespace nvidia
+{
+namespace clothing
+{
+
+AuthObjTypeID ClothingAssetImpl::mAssetTypeID = 0xffffffff;
+
+ClothingAssetImpl::ClothingAssetImpl(ModuleClothingImpl* module, ResourceList& list, const char* name) :
+ mModule(module),
+ mParams(DYNAMIC_CAST(ClothingAssetParameters*)(GetInternalApexSDK()->getParameterizedTraits()->createNvParameterized(ClothingAssetParameters::staticClassName()))),
+ mPhysicalMeshes(mParams, "physicalMeshes", reinterpret_cast<ParamDynamicArrayStruct*>(&mParams->physicalMeshes)),
+ mGraphicalLods(mParams, "graphicalLods", reinterpret_cast<ParamDynamicArrayStruct*>(&mParams->graphicalLods)),
+ mBones(mParams, "bones", reinterpret_cast<ParamDynamicArrayStruct*>(&mParams->bones)),
+ mBoneSpheres(mParams, "boneSpheres", reinterpret_cast<ParamDynamicArrayStruct*>(&mParams->boneSpheres)),
+ mSpherePairs(mParams, "boneSphereConnections", reinterpret_cast<ParamDynamicArrayStruct*>(&mParams->boneSphereConnections)),
+ mBoneActors(mParams, "boneActors", reinterpret_cast<ParamDynamicArrayStruct*>(&mParams->boneActors)),
+ mBoneVertices(mParams, "boneVertices", reinterpret_cast<ParamDynamicArrayStruct*>(&mParams->boneVertices)),
+ mBonePlanes(mParams, "bonePlanes", reinterpret_cast<ParamDynamicArrayStruct*>(&mParams->bonePlanes)),
+ mCollisionConvexes(mParams, "collisionConvexes", reinterpret_cast<ParamDynamicArrayStruct*>(&mParams->collisionConvexes)),
+ mName(name),
+ mExt2IntMorphMappingMaxValue(0),
+ mDirty(false),
+ mMorphMappingWarning(false)
+{
+ // this constructor is only executed when initializing the authoring asset
+ list.add(*this);
+
+#ifndef WITHOUT_PVD
+ mActors.setupForPvd(static_cast<ApexResourceInterface*>(this), "ClothingActors", "ClothingActor");
+#endif
+
+ // make sure these two methods are compiled!
+ AbstractMeshDescription pcm;
+ pcm.avgEdgeLength = 0.1f;
+}
+
+
+ClothingAssetImpl::ClothingAssetImpl(ModuleClothingImpl* module, ResourceList& list, NvParameterized::Interface* params, const char* name) :
+ mModule(module),
+ mParams(NULL),
+ mName(name),
+ mExt2IntMorphMappingMaxValue(0),
+ mDirty(false),
+ mMorphMappingWarning(false)
+{
+
+#ifndef WITHOUT_PVD
+ mActors.setupForPvd(static_cast<ApexResourceInterface*>(this), "ClothingActors", "ClothingActor");
+#endif
+
+ // wrong name?
+ if (params != NULL && ::strcmp(params->className(), ClothingAssetParameters::staticClassName()) != 0)
+ {
+ APEX_INTERNAL_ERROR(
+ "The parameterized interface is of type <%s> instead of <%s>. "
+ "This object will be initialized by an empty one instead!",
+ params->className(),
+ ClothingAssetParameters::staticClassName());
+
+ params->destroy();
+ params = NULL;
+ }
+ else if (params != NULL)
+ {
+ ClothingAssetParameters* checkParams = DYNAMIC_CAST(ClothingAssetParameters*)(params);
+
+ uint32_t boneRefsMesh = 0, boneRefsRB = 0;
+ for (int i = 0; i < checkParams->bones.arraySizes[0]; i++)
+ {
+ boneRefsMesh += checkParams->bones.buf[i].numMeshReferenced;
+ boneRefsRB += checkParams->bones.buf[i].numRigidBodiesReferenced;
+ }
+
+ if (checkParams->bones.arraySizes[0] > 0 && (boneRefsRB + boneRefsMesh == 0))
+ {
+ APEX_INTERNAL_ERROR(
+ "This parameterized object has not been prepared before serialization. "
+ "It will not be able to work and has been replaced by an empty one instead. "
+ "See NvParameterized::Interface::callPreSerializeCallback()");
+
+ params->destroy();
+ params = NULL;
+ }
+ }
+
+ if (params == NULL)
+ {
+ params = DYNAMIC_CAST(ClothingAssetParameters*)(GetInternalApexSDK()->getParameterizedTraits()->createNvParameterized(ClothingAssetParameters::staticClassName()));
+ }
+
+
+ PX_ASSERT(nvidia::strcmp(params->className(), ClothingAssetParameters::staticClassName()) == 0);
+ if (::strcmp(params->className(), ClothingAssetParameters::staticClassName()) == 0)
+ {
+ mParams = static_cast<ClothingAssetParameters*>(params);
+ mParams->setSerializationCallback(this, NULL);
+
+ bool ok = false;
+ PX_UNUSED(ok);
+
+ ok = mPhysicalMeshes.init(mParams, "physicalMeshes", reinterpret_cast<ParamDynamicArrayStruct*>(&mParams->physicalMeshes));
+ PX_ASSERT(ok);
+ ok = mGraphicalLods.init(mParams, "graphicalLods", reinterpret_cast<ParamDynamicArrayStruct*>(&mParams->graphicalLods));
+ PX_ASSERT(ok);
+ ok = mBones.init(mParams, "bones", reinterpret_cast<ParamDynamicArrayStruct*>(&mParams->bones));
+ PX_ASSERT(ok);
+ ok = mBoneSpheres.init(mParams, "boneSpheres", reinterpret_cast<ParamDynamicArrayStruct*>(&mParams->boneSpheres));
+ PX_ASSERT(ok);
+ ok = mSpherePairs.init(mParams, "boneSphereConnections", reinterpret_cast<ParamDynamicArrayStruct*>(&mParams->boneSphereConnections));
+ PX_ASSERT(ok);
+ ok = mBoneActors.init(mParams, "boneActors", reinterpret_cast<ParamDynamicArrayStruct*>(&mParams->boneActors));
+ PX_ASSERT(ok);
+ ok = mBoneVertices.init(mParams, "boneVertices", reinterpret_cast<ParamDynamicArrayStruct*>(&mParams->boneVertices));
+ PX_ASSERT(ok);
+ ok = mBonePlanes.init(mParams, "bonePlanes", reinterpret_cast<ParamDynamicArrayStruct*>(&mParams->bonePlanes));
+ PX_ASSERT(ok);
+ ok = mCollisionConvexes.init(mParams, "collisionConvexes", reinterpret_cast<ParamDynamicArrayStruct*>(&mParams->collisionConvexes));
+ PX_ASSERT(ok);
+
+ for (uint32_t i = 0; i < mGraphicalLods.size(); i++)
+ {
+ if (mGraphicalLods[i]->renderMeshAsset == NULL)
+ continue;
+
+ char buf[128];
+ size_t len = PxMin(mName.len(), 120u);
+ buf[0] = 0;
+ nvidia::strlcat(buf, len + 1, mName.c_str());
+ buf[len] = '_';
+ nvidia::snprintf(buf + len + 1, 128 - len - 1, "%d", i);
+ Asset* asset = GetApexSDK()->createAsset(mGraphicalLods[i]->renderMeshAsset, buf);
+ PX_ASSERT(::strcmp(asset->getObjTypeName(), RENDER_MESH_AUTHORING_TYPE_NAME) == 0);
+
+ RenderMeshAssetIntl* rma = static_cast<RenderMeshAssetIntl*>(asset);
+ if (rma->mergeBinormalsIntoTangents())
+ {
+ mDirty = true;
+ APEX_DEBUG_INFO("Performance warning. This asset <%s> has to be re-saved to speed up loading", name);
+ }
+
+ mGraphicalLods[i]->renderMeshAssetPointer = rma;
+ mDirty |= reorderGraphicsVertices(i, i == 0); // only warn the first time
+ }
+
+ bool cookingInvalid = false;
+
+ for (uint32_t i = 0; i < mPhysicalMeshes.size(); i++)
+ {
+ bool reorderVerts = false;
+ if (mPhysicalMeshes[i]->physicalMesh.numMaxDistance0Vertices == 0)
+ {
+ reorderVerts = true;
+ }
+
+ if (reorderVerts)
+ {
+ ClothingPhysicalMeshImpl* mesh = mModule->createPhysicalMeshInternal(mPhysicalMeshes[i]);
+
+ if (mesh != NULL)
+ {
+ const bool changed = reorderDeformableVertices(*mesh);
+
+ mesh->release();
+
+ cookingInvalid |= changed;
+ mDirty |= changed;
+ }
+ }
+ }
+
+ if (mParams->materialLibrary != NULL && cookingInvalid)
+ {
+ // So, if we turn on zerostretch also for the new solver, we should make sure the values are set soft enough not to introduce too much ghost forces
+ ClothingMaterialLibraryParameters* matLib = static_cast<ClothingMaterialLibraryParameters*>(mParams->materialLibrary);
+
+ for (int32_t i = 0; i < matLib->materials.arraySizes[0]; i++)
+ {
+ float& limit = matLib->materials.buf[i].hardStretchLimitation;
+
+ if (limit >= 1.0f)
+ {
+ limit = PxMax(limit, 1.1f); // must be either 0 (disabled) or > 1.1 for stability
+ }
+ }
+ }
+
+ if (mParams->boundingBox.minimum.isZero() && mParams->boundingBox.maximum.isZero())
+ {
+ updateBoundingBox();
+ }
+
+ uint32_t cookNow = 0;
+ const char* cookedDataClass = "Embedded";
+
+ ParamArray<ClothingAssetParametersNS::CookedEntry_Type> cookedEntries(mParams, "cookedData", reinterpret_cast<ParamDynamicArrayStruct*>(&mParams->cookedData));
+ for (uint32_t i = 0; i < cookedEntries.size(); i++)
+ {
+ if (cookedEntries[i].cookedData != NULL)
+ {
+ BackendFactory* cookedDataBackend = mModule->getBackendFactory(cookedEntries[i].cookedData->className());
+ PX_ASSERT(cookedDataBackend);
+ if (cookedDataBackend != NULL)
+ {
+ // compare data version with current version of the data backend
+ uint32_t cookedDataVersion = cookedDataBackend->getCookedDataVersion(cookedEntries[i].cookedData);
+ uint32_t cookingVersion = cookedDataBackend->getCookingVersion();
+
+ if (cookingVersion != cookedDataVersion || cookingInvalid
+#if PX_PHYSICS_VERSION_MAJOR == 3
+ // don't use native CookingPhysX, only use embedded solver
+ || cookedDataVersion == CookingPhysX::getCookingVersion()
+#endif
+ )
+ {
+ cookNow = cookedDataVersion;
+ cookedEntries[i].cookedData->destroy();
+ cookedEntries[i].cookedData = NULL;
+ }
+ }
+ }
+ }
+ if (cookNow != 0)
+ {
+ APEX_DEBUG_WARNING("Asset (%s) cooked data version (%d/0x%08x) does not match the current sdk version. Recooking.", name, cookNow, cookNow);
+ }
+
+ if (cookedEntries.isEmpty())
+ {
+ ClothingAssetParametersNS::CookedEntry_Type entry;
+ entry.scale = 1.0f;
+ entry.cookedData = NULL;
+ cookedEntries.pushBack(entry);
+ APEX_DEBUG_INFO("Asset (%s) has no cooked data and will be re-cooked every time it's loaded, asset needs to be resaved!", name);
+ cookNow = 1;
+ }
+
+ if (cookNow != 0)
+ {
+ BackendFactory* cookingBackend = mModule->getBackendFactory(cookedDataClass);
+
+ PX_ASSERT(cookingBackend != NULL);
+
+ for (uint32_t i = 0; i < cookedEntries.size(); i++)
+ {
+ if (cookedEntries[i].cookedData == NULL && cookingBackend != NULL)
+ {
+ ClothingAssetParametersNS::CookedEntry_Type& entry = cookedEntries[i];
+
+ CookingAbstract* cookingJob = cookingBackend->createCookingJob();
+ prepareCookingJob(*cookingJob, entry.scale, NULL, NULL);
+
+ if (cookingJob->isValid())
+ {
+ entry.cookedData = cookingJob->execute();
+ }
+ PX_DELETE_AND_RESET(cookingJob);
+ }
+ }
+
+ mDirty = true;
+ }
+ }
+
+ list.add(*this);
+}
+
+
+
+uint32_t ClothingAssetImpl::forceLoadAssets()
+{
+ uint32_t assetLoadedCount = 0;
+
+ for (uint32_t i = 0; i < mGraphicalLods.size(); i++)
+ {
+ if (mGraphicalLods[i]->renderMeshAssetPointer == NULL)
+ continue;
+
+ RenderMeshAssetIntl* rma = reinterpret_cast<RenderMeshAssetIntl*>(mGraphicalLods[i]->renderMeshAssetPointer);
+ assetLoadedCount += rma->forceLoadAssets();
+ }
+
+ return assetLoadedCount;
+
+}
+
+
+
+NvParameterized::Interface* ClothingAssetImpl::getDefaultActorDesc()
+{
+ NvParameterized::Interface* ret = NULL;
+
+ if (mModule != NULL)
+ {
+ ret = mModule->getApexClothingActorParams();
+
+ if (ret != NULL)
+ {
+ ret->initDefaults();
+
+ // need to customize it per asset
+ PX_ASSERT(nvidia::strcmp(ret->className(), ClothingActorParam::staticClassName()) == 0);
+ ClothingActorParam* actorDesc = static_cast<ClothingActorParam*>(ret);
+ actorDesc->clothingMaterialIndex = mParams->materialIndex;
+ }
+ }
+
+ return ret;
+}
+
+
+
+NvParameterized::Interface* ClothingAssetImpl::getDefaultAssetPreviewDesc()
+{
+ NvParameterized::Interface* ret = NULL;
+
+ if (mModule != NULL)
+ {
+ ret = mModule->getApexClothingPreviewParams();
+
+ if (ret != NULL)
+ {
+ ret->initDefaults();
+ }
+ }
+
+ return ret;
+}
+
+
+
+Actor* ClothingAssetImpl::createApexActor(const NvParameterized::Interface& params, Scene& apexScene)
+{
+ if (!isValidForActorCreation(params, apexScene))
+ {
+ return NULL;
+ }
+ ClothingActorProxy* proxy = NULL;
+ ClothingScene* clothingScene = mModule->getClothingScene(apexScene);
+ proxy = PX_NEW(ClothingActorProxy)(params, this, *clothingScene, &mActors);
+ PX_ASSERT(proxy != NULL);
+ return proxy;
+}
+
+
+NvParameterized::Interface* ClothingAssetImpl::releaseAndReturnNvParameterizedInterface()
+{
+ NvParameterized::Interface* ret = mParams;
+ mParams->setSerializationCallback(NULL, NULL);
+ mParams = NULL;
+ release();
+ return ret;
+}
+
+
+
+bool ClothingAssetImpl::isValidForActorCreation(const NvParameterized::Interface& params, Scene& apexScene) const
+{
+ bool ret = false;
+
+ if (ClothingActorImpl::isValidDesc(params))
+ {
+ ClothingScene* clothingScene = mModule->getClothingScene(apexScene);
+ if (clothingScene)
+ {
+ if (!clothingScene->isSimulating())
+ {
+ ret = true;
+ }
+ else
+ {
+ APEX_INTERNAL_ERROR("Cannot create ClothingActor while simulation is running");
+ }
+ }
+ }
+ else
+ {
+ APEX_INVALID_PARAMETER("ClothingActorDesc is invalid");
+ }
+ return ret;
+}
+
+
+bool ClothingAssetImpl::isDirty() const
+{
+ return mDirty;
+}
+
+
+
+void ClothingAssetImpl::release()
+{
+ mModule->mSdk->releaseAsset(*this);
+}
+
+
+
+ClothingActor* ClothingAssetImpl::getActor(uint32_t index)
+{
+ READ_ZONE();
+ if (index < mActors.getSize())
+ {
+ return DYNAMIC_CAST(ClothingActorProxy*)(mActors.getResource(index));
+ }
+ return NULL;
+}
+
+
+
+float ClothingAssetImpl::getMaximumSimulationBudget(uint32_t solverIterations) const
+{
+ uint32_t maxCost = 0;
+
+ for (uint32_t i = 0; i < mPhysicalMeshes.size(); i++)
+ {
+ uint32_t iterations = (uint32_t)(mPhysicalMeshes[i]->physicalMesh.numSimulatedVertices * solverIterations);
+ maxCost = PxMax(maxCost, iterations);
+ }
+
+ return static_cast<float>(maxCost);
+}
+
+
+
+uint32_t ClothingAssetImpl::getNumGraphicalLodLevels() const
+{
+ READ_ZONE();
+ return mGraphicalLods.size();
+}
+
+
+
+uint32_t ClothingAssetImpl::getGraphicalLodValue(uint32_t lodLevel) const
+{
+ READ_ZONE();
+ if (lodLevel < mGraphicalLods.size())
+ {
+ return mGraphicalLods[lodLevel]->lod;
+ }
+
+ return uint32_t(-1);
+}
+
+
+
+float ClothingAssetImpl::getBiggestMaxDistance() const
+{
+ READ_ZONE();
+ float maxValue = 0.0f;
+ for (uint32_t i = 0; i < mPhysicalMeshes.size(); i++)
+ {
+ maxValue = PxMax(maxValue, mPhysicalMeshes[i]->physicalMesh.maximumMaxDistance);
+ }
+
+ return maxValue;
+}
+
+
+
+bool ClothingAssetImpl::remapBoneIndex(const char* name, uint32_t newIndex)
+{
+ WRITE_ZONE();
+ uint32_t found = 0;
+ const uint32_t numBones = mBones.size();
+ for (uint32_t i = 0; i < numBones; i++)
+ {
+ if (mBones[i].name != NULL && (::strcmp(mBones[i].name, name) == 0))
+ {
+ mBones[i].externalIndex = (int32_t)newIndex;
+ found++;
+ }
+ }
+
+ if (found > 1)
+ {
+ APEX_DEBUG_WARNING("The asset contains %i bones with name %s. All occurences were mapped.", found, name);
+ }
+ else if (found == 0)
+ {
+ APEX_DEBUG_INFO("The asset does not contain a bone with name %s", name);
+ }
+
+ return (found == 1); // sanity
+}
+
+
+
+const char* ClothingAssetImpl::getBoneName(uint32_t internalIndex) const
+{
+ READ_ZONE();
+ if (internalIndex >= mBones.size())
+ {
+ return "";
+ }
+
+ return mBones[internalIndex].name;
+}
+
+
+
+bool ClothingAssetImpl::getBoneBasePose(uint32_t internalIndex, PxMat44& result) const
+{
+ READ_ZONE();
+ if (internalIndex < mBones.size())
+ {
+ result = mBones[internalIndex].bindPose;
+ return true;
+ }
+ return false;
+}
+
+
+
+void ClothingAssetImpl::getBoneMapping(uint32_t* internal2externalMap) const
+{
+ READ_ZONE();
+ for (uint32_t i = 0; i < mBones.size(); i++)
+ {
+ internal2externalMap[(uint32_t)mBones[i].internalIndex] = (uint32_t)mBones[i].externalIndex;
+ }
+}
+
+
+
+uint32_t ClothingAssetImpl::prepareMorphTargetMapping(const PxVec3* originalPositions, uint32_t numPositions, float epsilon)
+{
+ WRITE_ZONE();
+ uint32_t numInternalVertices = 0;
+ for (uint32_t i = 0; i < mGraphicalLods.size(); i++)
+ {
+ RenderMeshAssetIntl* rma = getGraphicalMesh(i);
+ if (rma == NULL)
+ continue;
+
+ for (uint32_t s = 0; s < rma->getSubmeshCount(); s++)
+ {
+ numInternalVertices += rma->getSubmesh(s).getVertexCount(0);
+ }
+ }
+ numInternalVertices += mBoneVertices.size();
+
+ mExt2IntMorphMapping.resize(numInternalVertices);
+ uint32_t indexWritten = 0;
+
+ uint32_t numLarger = 0;
+ float epsilon2 = epsilon * epsilon;
+
+ for (uint32_t i = 0; i < mGraphicalLods.size(); i++)
+ {
+ RenderMeshAssetIntl* rma = getGraphicalMesh(i);
+ if (rma == NULL)
+ continue;
+
+ for (uint32_t s = 0; s < rma->getSubmeshCount(); s++)
+ {
+ const uint32_t numVertices = rma->getSubmesh(s).getVertexCount(0);
+ const VertexFormat& format = rma->getSubmesh(s).getVertexBuffer().getFormat();
+ const uint32_t positionIndex = (uint32_t)format.getBufferIndexFromID(format.getSemanticID(RenderVertexSemantic::POSITION));
+ if (format.getBufferFormat(positionIndex) == RenderDataFormat::FLOAT3)
+ {
+ PxVec3* positions = (PxVec3*)rma->getSubmesh(s).getVertexBuffer().getBuffer(positionIndex);
+ for (uint32_t v = 0; v < numVertices; v++)
+ {
+ float closestDist2 = PX_MAX_F32;
+ uint32_t closestIndex = (uint32_t) - 1;
+ for (uint32_t iv = 0; iv < numPositions; iv++)
+ {
+ float dist2 = (originalPositions[iv] - positions[v]).magnitudeSquared();
+ if (dist2 < closestDist2)
+ {
+ closestDist2 = dist2;
+ closestIndex = iv;
+ }
+ }
+ PX_ASSERT(closestIndex != (uint32_t) - 1);
+ mExt2IntMorphMapping[indexWritten++] = closestIndex;
+ numLarger += closestDist2 < epsilon2 ? 0 : 1;
+ }
+ }
+ else
+ {
+ PX_ALWAYS_ASSERT();
+ }
+ }
+ }
+
+ for (uint32_t i = 0; i < mBoneVertices.size(); i++)
+ {
+ float closestDist2 = PX_MAX_F32;
+ uint32_t closestIndex = (uint32_t) - 1;
+ for (uint32_t iv = 0; iv < numPositions; iv++)
+ {
+ float dist2 = (originalPositions[iv] - mBoneVertices[i]).magnitudeSquared();
+ if (dist2 < closestDist2)
+ {
+ closestDist2 = dist2;
+ closestIndex = iv;
+ }
+ }
+ PX_ASSERT(closestIndex != (uint32_t) - 1);
+ mExt2IntMorphMapping[indexWritten++] = closestIndex;
+ numLarger += closestDist2 < epsilon2 ? 0 : 1;
+ }
+
+ PX_ASSERT(indexWritten == numInternalVertices);
+ mExt2IntMorphMappingMaxValue = numPositions;
+
+ return numLarger;
+}
+
+
+
+void ClothingAssetImpl::preSerialize(void* /*userData*/)
+{
+ mDirty = false;
+}
+
+
+
+RenderMeshAssetIntl* ClothingAssetImpl::getGraphicalMesh(uint32_t index)
+{
+ if (index < mGraphicalLods.size())
+ {
+ return reinterpret_cast<RenderMeshAssetIntl*>(mGraphicalLods[index]->renderMeshAssetPointer);
+ }
+
+ return NULL;
+}
+
+
+
+const ClothingGraphicalLodParameters* ClothingAssetImpl::getGraphicalLod(uint32_t index) const
+{
+ if (index < mGraphicalLods.size())
+ {
+ return mGraphicalLods[index];
+ }
+
+ return NULL;
+}
+
+
+void ClothingAssetImpl::releaseClothingActor(ClothingActor& actor)
+{
+ ClothingActorProxy* proxy = DYNAMIC_CAST(ClothingActorProxy*)(&actor);
+ proxy->destroy();
+}
+
+
+
+void ClothingAssetImpl::releaseClothingPreview(ClothingPreview& preview)
+{
+ ClothingPreviewProxy* proxy = DYNAMIC_CAST(ClothingPreviewProxy*)(&preview);
+ proxy->destroy();
+}
+
+
+
+bool ClothingAssetImpl::writeBoneMatrices(PxMat44 localPose, const PxMat44* newBoneMatrices, const uint32_t byteStride,
+ const uint32_t numBones, PxMat44* dest, bool isInternalOrder, bool multInvBindPose)
+{
+ PX_PROFILE_ZONE("ClothingAssetImpl::writeBoneMatrices", GetInternalApexSDK()->getContextId());
+
+ PX_ASSERT(byteStride >= sizeof(PxMat44));
+
+ bool changed = false;
+
+ if (mBones.isEmpty())
+ {
+ APEX_INTERNAL_ERROR("bone map is empty, this is a error condition");
+ }
+ else
+ {
+ // PH: if bones are present, but not set, we just have to write them with global pose
+ const uint8_t* src = (const uint8_t*)newBoneMatrices;
+ const uint32_t numBonesReferenced = mParams->bonesReferenced;
+ for (uint32_t i = 0; i < mBones.size(); i++)
+ {
+ PX_ASSERT(mBones[i].internalIndex < (int32_t)mBones.size());
+ PX_ASSERT(isInternalOrder || mBones[i].externalIndex >= 0);
+ const uint32_t internalIndex = i;
+ const uint32_t externalIndex = isInternalOrder ? i : mBones[i].externalIndex;
+ if (internalIndex < numBonesReferenced && mBones[i].internalIndex >= 0)
+ {
+ PxMat44& oldMat = dest[internalIndex];
+ PX_ALIGN(16, PxMat44) newMat;
+
+ if (src != NULL && externalIndex < numBones)
+ {
+ PxMat44 skinningTransform = *(const PxMat44*)(src + byteStride * externalIndex);
+ if (multInvBindPose)
+ {
+ skinningTransform = skinningTransform * mInvBindPoses[internalIndex];
+ }
+ newMat = localPose * skinningTransform;
+ }
+ else
+ {
+ newMat = localPose;
+ }
+
+ if (newMat != oldMat) // PH: let's hope this comparison is not too slow
+ {
+ changed |= (i < numBonesReferenced);
+ oldMat = newMat;
+ }
+ }
+ }
+ }
+ return changed;
+}
+
+
+
+ClothingPhysicalMeshParametersNS::PhysicalMesh_Type* ClothingAssetImpl::getPhysicalMeshFromLod(uint32_t graphicalLodId) const
+{
+ const uint32_t physicalMeshId = mGraphicalLods[graphicalLodId]->physicalMeshId;
+
+ // -1 is also bigger than mPhysicalMeshes.size() for an unsigned
+ if (physicalMeshId >= mPhysicalMeshes.size())
+ {
+ return NULL;
+ }
+
+ return &mPhysicalMeshes[physicalMeshId]->physicalMesh;
+}
+
+
+ClothingPhysicalMeshParametersNS::SkinClothMapB_Type* ClothingAssetImpl::getTransitionMapB(uint32_t dstPhysicalMeshId, uint32_t srcPhysicalMeshId, float& thickness, float& offset)
+{
+ if (srcPhysicalMeshId + 1 == dstPhysicalMeshId)
+ {
+ thickness = mPhysicalMeshes[dstPhysicalMeshId]->transitionDownThickness;
+ offset = mPhysicalMeshes[dstPhysicalMeshId]->transitionDownOffset;
+ return mPhysicalMeshes[dstPhysicalMeshId]->transitionDownB.buf;
+ }
+ else if (srcPhysicalMeshId == dstPhysicalMeshId + 1)
+ {
+ thickness = mPhysicalMeshes[dstPhysicalMeshId]->transitionUpThickness;
+ offset = mPhysicalMeshes[dstPhysicalMeshId]->transitionUpOffset;
+ return mPhysicalMeshes[dstPhysicalMeshId]->transitionUpB.buf;
+ }
+
+ thickness = 0.0f;
+ offset = 0.0f;
+ return NULL;
+}
+
+
+
+ClothingPhysicalMeshParametersNS::SkinClothMapD_Type* ClothingAssetImpl::getTransitionMap(uint32_t dstPhysicalMeshId, uint32_t srcPhysicalMeshId, float& thickness, float& offset)
+{
+ if (srcPhysicalMeshId + 1 == dstPhysicalMeshId)
+ {
+ thickness = mPhysicalMeshes[dstPhysicalMeshId]->transitionDownThickness;
+ offset = mPhysicalMeshes[dstPhysicalMeshId]->transitionDownOffset;
+ return mPhysicalMeshes[dstPhysicalMeshId]->transitionDown.buf;
+ }
+ else if (srcPhysicalMeshId == dstPhysicalMeshId + 1)
+ {
+ thickness = mPhysicalMeshes[dstPhysicalMeshId]->transitionUpThickness;
+ offset = mPhysicalMeshes[dstPhysicalMeshId]->transitionUpOffset;
+ return mPhysicalMeshes[dstPhysicalMeshId]->transitionUp.buf;
+ }
+
+ thickness = 0.0f;
+ offset = 0.0f;
+ return NULL;
+}
+
+
+
+NvParameterized::Interface* ClothingAssetImpl::getCookedData(float actorScale)
+{
+ NvParameterized::Interface* closest = NULL;
+ float closestDiff = PX_MAX_F32;
+
+ for (int32_t i = 0; i < mParams->cookedData.arraySizes[0]; i++)
+ {
+ NvParameterized::Interface* cookedData = mParams->cookedData.buf[i].cookedData;
+ const float cookedDataScale = mParams->cookedData.buf[i].scale;
+
+ if (cookedData == NULL)
+ {
+ continue;
+ }
+
+#ifdef _DEBUG
+ if (::strcmp(cookedData->className(), ClothingCookedParam::staticClassName()) == 0)
+ {
+ // silly debug verification
+ PX_ASSERT(cookedDataScale == ((ClothingCookedParam*)cookedData)->actorScale);
+ }
+#endif
+
+ const float scaleDiff = PxAbs(actorScale - cookedDataScale);
+ if (scaleDiff < closestDiff)
+ {
+ closest = cookedData;
+ closestDiff = scaleDiff;
+ }
+ }
+
+ if (closest != NULL && closestDiff < 0.01f)
+ {
+ return closest;
+ }
+
+ return NULL;
+}
+
+
+
+uint32_t ClothingAssetImpl::getCookedPhysXVersion() const
+{
+ uint32_t version = 0;
+
+ for (int32_t i = 0; i < mParams->cookedData.arraySizes[0]; i++)
+ {
+ const NvParameterized::Interface* cookedData = mParams->cookedData.buf[i].cookedData;
+ if (cookedData != NULL)
+ {
+ const char* className = cookedData->className();
+ BackendFactory* factory = mModule->getBackendFactory(className);
+
+ uint32_t v = factory->getCookedDataVersion(cookedData);
+ PX_ASSERT(version == 0 || version == v);
+ version = v;
+ }
+ }
+
+ // version == 0 usually means that there is no maxdistance > 0 at all!
+ //PX_ASSERT(version != 0);
+ return version;
+}
+
+
+
+ClothSolverMode::Enum ClothingAssetImpl::getClothSolverMode() const
+{
+ return ClothSolverMode::v3;
+}
+
+
+
+SimulationAbstract* ClothingAssetImpl::getSimulation(uint32_t physicalMeshId, NvParameterized::Interface* cookedParam, ClothingScene* clothingScene)
+{
+ SimulationAbstract* result = NULL;
+
+ mUnusedSimulationMutex.lock();
+
+ for (uint32_t i = 0; i < mUnusedSimulation.size(); i++)
+ {
+ PX_ASSERT(mUnusedSimulation[i] != NULL);
+ if (mUnusedSimulation[i]->physicalMeshId != physicalMeshId)
+ {
+ continue;
+ }
+
+ if (mUnusedSimulation[i]->getCookedData() != cookedParam)
+ {
+ continue;
+ }
+
+ if (mUnusedSimulation[i]->getClothingScene() != clothingScene)
+ {
+ continue;
+ }
+
+ // we found one
+ result = mUnusedSimulation[i];
+ for (uint32_t j = i + 1; j < mUnusedSimulation.size(); j++)
+ {
+ mUnusedSimulation[j - 1] = mUnusedSimulation[j];
+ }
+
+ mUnusedSimulation.popBack();
+ break;
+ }
+
+ mUnusedSimulationMutex.unlock();
+
+ return result;
+}
+
+
+
+void ClothingAssetImpl::returnSimulation(SimulationAbstract* simulation)
+{
+ PX_ASSERT(simulation != NULL);
+
+ bool isAssetParam = false;
+ for (int32_t i = 0; i < mParams->cookedData.arraySizes[0]; i++)
+ {
+ isAssetParam |= mParams->cookedData.buf[i].cookedData == simulation->getCookedData();
+ }
+
+ nvidia::Mutex::ScopedLock scopeLock(mUnusedSimulationMutex);
+
+ if (mModule->getMaxUnusedPhysXResources() == 0 || !isAssetParam || !simulation->needsExpensiveCreation())
+ {
+ destroySimulation(simulation);
+ return;
+ }
+
+ if (mUnusedSimulation.size() > mModule->getMaxUnusedPhysXResources())
+ {
+ destroySimulation(mUnusedSimulation[0]);
+
+ for (uint32_t i = 1; i < mUnusedSimulation.size(); i++)
+ {
+ mUnusedSimulation[i - 1] = mUnusedSimulation[i];
+ }
+
+ mUnusedSimulation[mUnusedSimulation.size() - 1] = simulation;
+ }
+ else
+ {
+ mUnusedSimulation.pushBack(simulation);
+ }
+
+ simulation->disablePhysX(mModule->getDummyActor());
+}
+
+
+
+void ClothingAssetImpl::destroySimulation(SimulationAbstract* simulation)
+{
+ PX_ASSERT(simulation != NULL);
+
+ simulation->unregisterPhysX();
+ PX_DELETE_AND_RESET(simulation);
+}
+
+
+
+void ClothingAssetImpl::initCollision(SimulationAbstract* simulation, const PxMat44* boneTansformations,
+ ResourceList& actorPlanes,
+ ResourceList& actorConvexes,
+ ResourceList& actorSpheres,
+ ResourceList& actorCapsules,
+ ResourceList& actorTriangleMeshes,
+ const ClothingActorParam* actorParam,
+ const PxMat44& globalPose, bool localSpaceSim)
+{
+ simulation->initCollision( mBoneActors.begin(), mBoneActors.size(), mBoneSpheres.begin(), mBoneSpheres.size(), mSpherePairs.begin(), mSpherePairs.size(), mBonePlanes.begin(), mBonePlanes.size(), mCollisionConvexes.begin(), mCollisionConvexes.size(), mBones.begin(), boneTansformations,
+ actorPlanes, actorConvexes, actorSpheres, actorCapsules, actorTriangleMeshes,
+ actorParam->actorDescTemplate, actorParam->shapeDescTemplate, actorParam->actorScale,
+ globalPose, localSpaceSim);
+}
+
+
+
+void ClothingAssetImpl::updateCollision(SimulationAbstract* simulation, const PxMat44* boneTansformations,
+ ResourceList& actorPlanes,
+ ResourceList& actorConvexes,
+ ResourceList& actorSpheres,
+ ResourceList& actorCapsules,
+ ResourceList& actorTriangleMeshes,
+ bool teleport)
+{
+ simulation->updateCollision(mBoneActors.begin(), mBoneActors.size(), mBoneSpheres.begin(), mBoneSpheres.size(), mBonePlanes.begin(), mBonePlanes.size(), mBones.begin(), boneTansformations,
+ actorPlanes, actorConvexes, actorSpheres, actorCapsules, actorTriangleMeshes, teleport);
+}
+
+
+
+uint32_t ClothingAssetImpl::getPhysicalMeshID(uint32_t graphicalLodId) const
+{
+ if (graphicalLodId >= mGraphicalLods.size())
+ {
+ return (uint32_t) - 1;
+ }
+
+ return mGraphicalLods[graphicalLodId]->physicalMeshId;
+}
+
+
+
+void ClothingAssetImpl::visualizeSkinCloth(RenderDebugInterface& renderDebug, AbstractMeshDescription& srcPM, bool showTets, float actorScale) const
+{
+#ifdef WITHOUT_DEBUG_VISUALIZE
+ PX_UNUSED(renderDebug);
+ PX_UNUSED(srcPM);
+ PX_UNUSED(showTets);
+ PX_UNUSED(actorScale);
+#else
+ using RENDER_DEBUG::DebugColors;
+ using RENDER_DEBUG::DebugRenderState;
+
+ if ((srcPM.pPosition != NULL) && (srcPM.pIndices != NULL) && (srcPM.pNormal != NULL))
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->pushRenderState();
+
+ RENDER_DEBUG_IFACE(&renderDebug)->removeFromCurrentState(DebugRenderState::SolidShaded);
+
+ const uint32_t colorWhite = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::White);
+ const uint32_t colorRed = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Red);
+ const uint32_t colorDarkRed = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::DarkRed);
+ const uint32_t colorGreen = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Green);
+ const uint32_t colorPurple = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Purple);
+
+ const float meshThickness = srcPM.avgEdgeLength * actorScale;
+ // for each triangle in the Physical Mesh draw lines delimiting all the tetras
+ for (uint32_t i = 0; i < srcPM.numIndices; i += 3)
+ {
+ if (showTets)
+ {
+ PxVec3 vtx[3], nrm[3];
+ getNormalsAndVerticesForFace(vtx, nrm, i, srcPM);
+
+ // draw lines for all edges of each tetrahedron (sure, there are redundant lines, but this is for debugging purposes)
+ for (uint32_t tIdx = 0; tIdx < TETRA_LUT_SIZE; tIdx++)
+ {
+ // compute the tetra vertices based on the index
+ const TetraEncoding& tetEnc = tetraTable[tIdx];
+ PxVec3 tv0 = vtx[0] + (tetEnc.sign[0] * nrm[0] * meshThickness);
+ PxVec3 tv1 = vtx[1] + (tetEnc.sign[1] * nrm[1] * meshThickness);
+ PxVec3 tv2 = vtx[2] + (tetEnc.sign[2] * nrm[2] * meshThickness);
+ PxVec3 tv3 = vtx[tetEnc.lastVtxIdx] + (tetEnc.sign[3] * nrm[tetEnc.lastVtxIdx] * meshThickness);
+
+ uint32_t color = tIdx < 3 ? colorGreen : colorPurple;
+
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(color);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(tv1, tv2);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(tv2, tv3);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(tv3, tv1);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(tv0, tv1);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(tv0, tv2);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(tv0, tv3);
+ }
+ }
+ else
+ {
+ uint32_t idx[3] =
+ {
+ srcPM.pIndices[i + 0],
+ srcPM.pIndices[i + 1],
+ srcPM.pIndices[i + 2],
+ };
+
+ PxVec3 vtx[3], nrm[3];
+ for (uint32_t u = 0; u < 3; u++)
+ {
+ vtx[u] = srcPM.pPosition[idx[u]];
+ nrm[u] = srcPM.pNormal[idx[u]] * meshThickness;
+ }
+
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorWhite);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugTri(vtx[0], vtx[1], vtx[2]);
+
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorGreen);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugTri(vtx[0] + nrm[0], vtx[1] + nrm[1], vtx[2] + nrm[2]);
+ for (uint32_t u = 0; u < 3; u++)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(vtx[u], vtx[u] + nrm[u]);
+ }
+
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorPurple);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugTri(vtx[0] - nrm[0], vtx[1] - nrm[1], vtx[2] - nrm[2]);
+ for (uint32_t u = 0; u < 3; u++)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(vtx[u], vtx[u] - nrm[u]);
+ }
+ }
+ }
+
+#if 1
+ // display some features of the physical mesh as it's updated at runtime
+
+ srcPM.UpdateDerivedInformation(&renderDebug);
+
+ // draw the mesh's bounding box
+ PxBounds3 bounds(srcPM.pMin, srcPM.pMax);
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorRed);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugBound(bounds);
+
+ // draw line from the centroid to the top-most corner of the AABB
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorDarkRed);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(srcPM.centroid, srcPM.pMax);
+
+ // draw white line along the same direction (but negated) to display the avgEdgeLength
+ PxVec3 dirToPMax = (srcPM.pMax - srcPM.centroid);
+ dirToPMax.normalize();
+ PxVec3 pEdgeLengthAway = srcPM.centroid - (dirToPMax * srcPM.avgEdgeLength);
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorWhite);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(srcPM.centroid, pEdgeLengthAway);
+
+ // draw green line along the same direction to display the physical mesh thickness
+ PxVec3 pPmThicknessAway = srcPM.centroid + (dirToPMax * meshThickness);
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorGreen);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(srcPM.centroid, pPmThicknessAway);
+#endif
+
+ RENDER_DEBUG_IFACE(&renderDebug)->popRenderState();
+ }
+#endif
+}
+
+
+
+void ClothingAssetImpl::visualizeSkinClothMap(RenderDebugInterface& renderDebug, AbstractMeshDescription& srcPM,
+ SkinClothMapB* skinClothMapB, uint32_t skinClothMapBSize,
+ SkinClothMap* skinClothMap, uint32_t skinClothMapSize,
+ float actorScale, bool onlyBad, bool invalidBary) const
+{
+#ifdef WITHOUT_DEBUG_VISUALIZE
+ PX_UNUSED(renderDebug);
+ PX_UNUSED(srcPM);
+ PX_UNUSED(skinClothMapB);
+ PX_UNUSED(skinClothMapBSize);
+ PX_UNUSED(skinClothMap);
+ PX_UNUSED(skinClothMapSize);
+ PX_UNUSED(actorScale);
+ PX_UNUSED(onlyBad);
+ PX_UNUSED(invalidBary);
+#else
+ using RENDER_DEBUG::DebugColors;
+ using RENDER_DEBUG::DebugRenderState;
+
+ RENDER_DEBUG_IFACE(&renderDebug)->pushRenderState();
+
+ RENDER_DEBUG_IFACE(&renderDebug)->removeFromCurrentState(DebugRenderState::SolidShaded);
+ const float meshThickness = srcPM.avgEdgeLength * actorScale;
+
+ if ((skinClothMapB != NULL) && (srcPM.pPosition != NULL) && (srcPM.pIndices != NULL) && (srcPM.pNormal != NULL))
+ {
+ const uint32_t colorRed = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Red);
+ const uint32_t colorDarkRed = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::DarkRed);
+ const uint32_t colorBlue = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Blue);
+ const uint32_t colorYellow = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Yellow);
+ const uint32_t colorGreen = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Green);
+ const uint32_t colorPurple = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Purple);
+
+ for (uint32_t i = 0; i < skinClothMapBSize; i++)
+ {
+ const SkinClothMapB& mapping = skinClothMapB[i];
+
+ if (mapping.faceIndex0 >= srcPM.numIndices)
+ {
+ break;
+ }
+
+ const PxVec3 vtb = mapping.vtxTetraBary;
+ const float vtb_w = 1.0f - vtb.x - vtb.y - vtb.z;
+ const bool badVtx =
+ vtb.x < 0.0f || vtb.x > 1.0f ||
+ vtb.y < 0.0f || vtb.y > 1.0f ||
+ vtb.z < 0.0f || vtb.z > 1.0f ||
+ vtb_w < 0.0f || vtb_w > 1.0f;
+
+ const PxVec3 ntb = mapping.nrmTetraBary;
+ const float ntb_w = 1.0f - ntb.x - ntb.y - ntb.z;
+
+ const bool badNrm =
+ ntb.x < 0.0f || ntb.x > 1.0f ||
+ ntb.y < 0.0f || ntb.y > 1.0f ||
+ ntb.z < 0.0f || ntb.z > 1.0f ||
+ ntb_w < 0.0f || ntb_w > 1.0f;
+
+ if (!onlyBad || badVtx || badNrm)
+ {
+ PxVec3 vtx[3], nrm[3];
+ getNormalsAndVerticesForFace(vtx, nrm, mapping.faceIndex0, srcPM);
+
+ const TetraEncoding& tetEnc = tetraTable[mapping.tetraIndex];
+
+ const PxVec3 tv0 = vtx[0] + (tetEnc.sign[0] * nrm[0] * meshThickness);
+ const PxVec3 tv1 = vtx[1] + (tetEnc.sign[1] * nrm[1] * meshThickness);
+ const PxVec3 tv2 = vtx[2] + (tetEnc.sign[2] * nrm[2] * meshThickness);
+ const PxVec3 tv3 = vtx[tetEnc.lastVtxIdx] + (tetEnc.sign[3] * nrm[tetEnc.lastVtxIdx] * meshThickness);
+
+ const PxVec3 centroid = (tv0 + tv1 + tv2 + tv3) * 0.25f;
+ const PxVec3 graphicsPos = (vtb.x * tv0) + (vtb.y * tv1) + (vtb.z * tv2) + (vtb_w * tv3);
+ const PxVec3 graphicsNrm = (ntb.x * tv0) + (ntb.y * tv1) + (ntb.z * tv2) + (ntb_w * tv3);
+
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorYellow);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugPoint(graphicsPos, meshThickness * 0.1f);
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorBlue);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(graphicsPos, graphicsNrm);
+
+ if (badVtx && onlyBad)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorRed);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(centroid, graphicsPos);
+ }
+
+ if (badNrm && onlyBad)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorDarkRed);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(centroid, graphicsPos);
+ }
+
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(mapping.tetraIndex < 3 ? colorGreen : colorPurple);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(tv1, tv2);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(tv2, tv3);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(tv3, tv1);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(tv0, tv1);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(tv0, tv2);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(tv0, tv3);
+ }
+ }
+ }
+ else if ((skinClothMap != NULL) && (srcPM.pPosition != NULL) && (srcPM.pIndices != NULL) && (srcPM.pNormal != NULL))
+ {
+ const uint32_t colorWhite = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::White);
+ const uint32_t colorRed = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Red);
+ const uint32_t colorDarkRed = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::DarkRed);
+ const uint32_t colorBlue = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Blue);
+ const uint32_t colorYellow = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Yellow);
+ const uint32_t colorGreen = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Green);
+ const uint32_t colorPurple = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Purple);
+
+ for (uint32_t i = 0; i < skinClothMapSize; i++)
+ {
+ const SkinClothMap& mapping = skinClothMap[i];
+
+ if (mapping.vertexIndex0 >= srcPM.numVertices || mapping.vertexIndex1 >= srcPM.numVertices || mapping.vertexIndex2 >= srcPM.numVertices)
+ {
+ continue;
+ }
+
+ PxVec3 baryVtx = mapping.vertexBary;
+ const float heightVtx = baryVtx.z;
+ baryVtx.z = 1.0f - baryVtx.x - baryVtx.y;
+
+ PxVec3 baryNrm = mapping.normalBary;
+ const float heightNrm = baryNrm.z;
+ baryNrm.z = 1.0f - baryNrm.x - baryNrm.y;
+
+ bool badVtx =
+ baryVtx.x < 0.0f || baryVtx.x > 1.0f ||
+ baryVtx.y < 0.0f || baryVtx.y > 1.0f ||
+ baryVtx.z < 0.0f || baryVtx.z > 1.0f ||
+ heightVtx < -1.0f || heightVtx > 1.0f;
+
+ bool badNrm =
+ baryNrm.x < 0.0f || baryNrm.x > 1.0f ||
+ baryNrm.y < 0.0f || baryNrm.y > 1.0f ||
+ baryNrm.z < 0.0f || baryNrm.z > 1.0f ||
+ heightNrm < -1.0f || heightNrm > 1.0f;
+
+ if (!onlyBad || badVtx || badNrm)
+ {
+ uint32_t idx[3] =
+ {
+ mapping.vertexIndex0,
+ mapping.vertexIndex1,
+ mapping.vertexIndex2,
+ };
+
+ PxVec3 vtx[3], nrm[3];
+ PxVec3 centroid(0.0f);
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ vtx[j] = srcPM.pPosition[idx[j]];
+ nrm[j] = srcPM.pNormal[idx[j]] * meshThickness;
+ centroid += vtx[j];
+ }
+ centroid /= 3.0f;
+
+
+ uint32_t b = (uint32_t)(255 * i / skinClothMapSize);
+ uint32_t color = (b << 16) + (b << 8) + b;
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(color);
+
+ PxVec3 vertexBary = mapping.vertexBary;
+ float vertexHeight = vertexBary.z;
+ vertexBary.z = 1.0f - vertexBary.x - vertexBary.y;
+ const PxVec3 vertexPos = vertexBary.x * vtx[0] + vertexBary.y * vtx[1] + vertexBary.z * vtx[2];
+ const PxVec3 vertexNrm = vertexBary.x * nrm[0] + vertexBary.y * nrm[1] + vertexBary.z * nrm[2]; // meshThickness is already in
+ const PxVec3 graphicsPos = vertexPos + vertexNrm * vertexHeight;
+
+ if (invalidBary)
+ {
+ uint32_t invalidColor = 0;
+ invalidColor = vertexBary == PxVec3(PX_MAX_F32) ? colorRed : invalidColor;
+ invalidColor = mapping.normalBary == PxVec3(PX_MAX_F32) ? colorPurple : invalidColor;
+ invalidColor = mapping.tangentBary == PxVec3(PX_MAX_F32) ? colorBlue : invalidColor;
+
+ if (invalidColor != 0)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(invalidColor);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugTri(vtx[0], vtx[1], vtx[2]);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugPoint(graphicsPos, meshThickness * 0.1f);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(centroid, graphicsPos);
+ }
+ continue;
+ }
+
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(centroid, graphicsPos);
+
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorYellow);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugPoint(graphicsPos, meshThickness * 0.1f);
+
+ if (badVtx && onlyBad)
+ {
+ // draw the projected position as well
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorRed);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(vertexPos, graphicsPos);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(vertexPos, centroid);
+ }
+
+ PxVec3 normalBary = mapping.normalBary;
+ float normalHeight = normalBary.z;
+ normalBary.z = 1.0f - normalBary.x - normalBary.y;
+ const PxVec3 normalPos = normalBary.x * vtx[0] + normalBary.y * vtx[1] + normalBary.z * vtx[2];
+ const PxVec3 normalNrm = normalBary.x * nrm[0] + normalBary.y * nrm[1] + normalBary.z * nrm[2]; // meshThickness is already in
+ const PxVec3 graphicsNrm = normalPos + normalNrm * normalHeight;
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorBlue);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(graphicsNrm, graphicsPos);
+#if 0
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Black));
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(graphicsNrm, centroid);
+#endif
+
+ if (badNrm && onlyBad)
+ {
+ // draw the projected normal as well
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorDarkRed);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(normalPos, graphicsNrm);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(normalPos, centroid);
+ }
+
+ // turn the rendering on for the rest
+ badVtx = badNrm = true;
+
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorWhite);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugTri(vtx[0], vtx[1], vtx[2]);
+ if ((badVtx && heightVtx > 0.0f) || (badNrm && heightNrm > 0.0f))
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorGreen);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugTri(vtx[0] + nrm[0], vtx[1] + nrm[1], vtx[2] + nrm[2]);
+ for (uint32_t u = 0; u < 3; u++)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(vtx[u], vtx[u] + nrm[u]);
+ }
+ }
+ else if ((badVtx && heightVtx < 0.0f) || (badNrm && heightNrm < 0.0f))
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorPurple);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugTri(vtx[0] - nrm[0], vtx[1] - nrm[1], vtx[2] - nrm[2]);
+ for (uint32_t u = 0; u < 3; u++)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(vtx[u], vtx[u] - nrm[u]);
+ }
+ }
+ }
+ }
+ }
+
+ RENDER_DEBUG_IFACE(&renderDebug)->popRenderState();
+#endif
+}
+
+
+
+void ClothingAssetImpl::visualizeBones(RenderDebugInterface& renderDebug, const PxMat44* matrices, bool skeleton, float boneFramesScale, float boneNamesScale)
+{
+#ifdef WITHOUT_DEBUG_VISUALIZE
+ PX_UNUSED(renderDebug);
+ PX_UNUSED(matrices);
+ PX_UNUSED(skeleton);
+ PX_UNUSED(boneFramesScale);
+ PX_UNUSED(boneNamesScale);
+#else
+
+ using RENDER_DEBUG::DebugColors;
+ using RENDER_DEBUG::DebugRenderState;
+
+ RENDER_DEBUG_IFACE(&renderDebug)->pushRenderState();
+
+ const uint32_t activeBoneColor = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Purple);
+ const uint32_t passiveBoneColor = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Blue);
+
+ const uint32_t colorWhite = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::White);
+ const uint32_t colorRed = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Red);
+ const uint32_t colorGreen = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Green);
+ const uint32_t colorBlue = RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::Blue);
+
+ RENDER_DEBUG_IFACE(&renderDebug)->addToCurrentState(RENDER_DEBUG::DebugRenderState::CenterText);
+ RENDER_DEBUG_IFACE(&renderDebug)->addToCurrentState(RENDER_DEBUG::DebugRenderState::CameraFacing);
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentTextScale(boneNamesScale);
+
+ if ((skeleton || boneFramesScale > 0.0f || boneNamesScale > 0.0f) && mPhysicalMeshes.size() > 0)
+ {
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type& physicalMesh = mPhysicalMeshes[0]->physicalMesh;
+ float sphereSize = 0.3f * physicalMesh.averageEdgeLength;
+ uint32_t rootIdx = mParams->rootBoneIndex;
+ PxMat44 absPose = matrices[rootIdx] * mBones[rootIdx].bindPose;
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::DarkRed));
+ RENDER_DEBUG_IFACE(&renderDebug)->debugSphere(absPose.getPosition(), sphereSize);
+ }
+
+ for (uint32_t i = 0; i < getNumUsedBones(); i++)
+ {
+ const int32_t parent = mBones[i].parentIndex;
+
+ PxMat44 absPose = matrices[i] * mBones[i].bindPose;
+
+ if (skeleton && parent >= 0 && parent < (int32_t)getNumUsedBones())
+ {
+ PX_ASSERT((uint32_t)parent != i);
+ PxMat44 absPoseParent = matrices[(uint32_t)parent] * mBones[(uint32_t)parent].bindPose;
+ if ((mBones[(uint32_t)parent].numMeshReferenced + mBones[(uint32_t)parent].numRigidBodiesReferenced) == 0)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(passiveBoneColor);
+ }
+ else
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(activeBoneColor);
+ }
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(absPose.getPosition(), absPoseParent.getPosition());
+ }
+
+ if (boneFramesScale > 0.0f)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorRed);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(absPose.getPosition(), absPose.getPosition() + absPose.column0.getXYZ() * boneFramesScale);
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorGreen);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(absPose.getPosition(), absPose.getPosition() + absPose.column1.getXYZ() * boneFramesScale);
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorBlue);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(absPose.getPosition(), absPose.getPosition() + absPose.column2.getXYZ() * boneFramesScale);
+ }
+
+ if (boneNamesScale > 0.0f)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(colorWhite);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugText(absPose.getPosition(), mBones[i].name.buf);
+ }
+ }
+
+ RENDER_DEBUG_IFACE(&renderDebug)->popRenderState();
+#endif
+}
+
+
+
+uint32_t ClothingAssetImpl::initializeAssetData(ClothingAssetData& assetData, const uint32_t uvChannel)
+{
+ //OK. Stage 1 - need to calculate the sizes required...
+
+ const uint32_t numLods = mGraphicalLods.size();
+ uint32_t numSubMeshes = 0;
+
+ for (uint32_t a = 0; a < numLods; ++a)
+ {
+ ClothingGraphicalMeshAssetWrapper meshAsset(reinterpret_cast<RenderMeshAssetIntl*>(mGraphicalLods[a]->renderMeshAssetPointer));
+ numSubMeshes += meshAsset.getSubmeshCount();
+ }
+
+ const uint32_t numPhysicalMeshes = mPhysicalMeshes.size();
+
+ const uint32_t requiredSize = ((sizeof(ClothingMeshAssetData) * numLods + sizeof(ClothingAssetSubMesh) * numSubMeshes
+ + sizeof(ClothingPhysicalMeshData) * numPhysicalMeshes) + 15) & 0xfffffff0;
+
+ void* data = PX_ALLOC(requiredSize, PX_DEBUG_EXP("ClothingAssetData"));
+ memset(data, 0, requiredSize);
+
+ assetData.mData = (uint8_t*)data;
+ assetData.mAssetSize = requiredSize;
+
+ //assetData.m_pLods = (ClothingMeshAssetData*)data;
+
+ assetData.mGraphicalLodsCount = numLods;
+
+ assetData.mRootBoneIndex = mParams->rootBoneIndex;
+
+ ClothingAssetSubMesh* pMeshes = (ClothingAssetSubMesh*)(((uint8_t*)data) + sizeof(ClothingMeshAssetData) * numLods);
+
+ uint32_t maxVertices = 0;
+
+ for (uint32_t a = 0; a < numLods; ++a)
+ {
+ ClothingGraphicalMeshAssetWrapper meshAsset(reinterpret_cast<RenderMeshAssetIntl*>(mGraphicalLods[a]->renderMeshAssetPointer));
+
+ const ClothingGraphicalLodParameters* graphicalLod = mGraphicalLods[a];
+
+ const uint32_t subMeshCount = meshAsset.getSubmeshCount();
+ ClothingMeshAssetData* pAsset = assetData.GetLod(a);
+ PX_PLACEMENT_NEW(pAsset, ClothingMeshAssetData());
+ //pAsset->m_pMeshes = pMeshes;
+ pAsset->mSubMeshCount = subMeshCount;
+
+ //Params to set
+ pAsset->mImmediateClothMap = graphicalLod->immediateClothMap.buf;
+ pAsset->mImmediateClothMapCount = (uint32_t)graphicalLod->immediateClothMap.arraySizes[0];
+
+
+ pAsset->mSkinClothMap = graphicalLod->skinClothMap.buf;
+ pAsset->mSkinClothMapCount = (uint32_t)graphicalLod->skinClothMap.arraySizes[0];
+
+ pAsset->mSkinClothMapB = graphicalLod->skinClothMapB.buf;
+ pAsset->mSkinClothMapBCount = (uint32_t)graphicalLod->skinClothMapB.arraySizes[0];
+
+ pAsset->mTetraMap = graphicalLod->tetraMap.buf;
+ pAsset->mTetraMapCount = (uint32_t)graphicalLod->tetraMap.arraySizes[0];
+
+ pAsset->mPhysicalMeshId = graphicalLod->physicalMeshId;
+
+ pAsset->mSkinClothMapThickness = graphicalLod->skinClothMapThickness;
+ pAsset->mSkinClothMapOffset = graphicalLod->skinClothMapOffset;
+
+ pAsset->mBounds = mParams->boundingBox;
+
+ //For now - we'll set this outside again
+ pAsset->bActive = true;
+
+ pAsset->mSubmeshOffset = (uint32_t)((uint8_t*)pMeshes - assetData.mData);
+
+ for (uint32_t b = 0; b < subMeshCount; ++b)
+ {
+ PX_PLACEMENT_NEW(&pMeshes[b], ClothingAssetSubMesh());
+
+ RenderDataFormat::Enum outFormat;
+ pMeshes[b].mPositions = (const PxVec3*)meshAsset.getVertexBuffer(b, RenderVertexSemantic::POSITION, outFormat);
+ pMeshes[b].mPositionOutFormat = outFormat;
+ pMeshes[b].mNormals = (const PxVec3*)meshAsset.getVertexBuffer(b, RenderVertexSemantic::NORMAL, outFormat);
+ pMeshes[b].mNormalOutFormat = outFormat;
+
+ pMeshes[b].mTangents = (const PxVec4*)meshAsset.getVertexBuffer(b, RenderVertexSemantic::TANGENT, outFormat);
+ pMeshes[b].mTangentOutFormat = outFormat;
+ PX_ASSERT(((size_t)pMeshes[b].mTangents & 0xf) == 0);
+
+ pMeshes[b].mBoneWeights = (const float*)meshAsset.getVertexBuffer(b, RenderVertexSemantic::BONE_WEIGHT, outFormat);
+ pMeshes[b].mBoneWeightOutFormat = outFormat;
+ pMeshes[b].mBoneIndices = (const uint16_t*)meshAsset.getVertexBuffer(b, RenderVertexSemantic::BONE_INDEX, outFormat);
+ pMeshes[b].mVertexCount = meshAsset.getNumVertices(b);
+ pMeshes[b].mNumBonesPerVertex = meshAsset.getNumBonesPerVertex(b);
+
+ maxVertices = PxMax(maxVertices, meshAsset.getNumVertices(b));
+
+ pMeshes[b].mIndices = (const uint32_t*)meshAsset.getIndexBuffer(b);
+ pMeshes[b].mIndicesCount = meshAsset.getNumIndices(b);
+
+ const VertexUV* PX_RESTRICT uvs = NULL;
+ RenderDataFormat::Enum uvFormat = RenderDataFormat::UNSPECIFIED;
+ switch (uvChannel)
+ {
+ case 0:
+ uvs = (const VertexUV*)meshAsset.getVertexBuffer(b, RenderVertexSemantic::TEXCOORD0, uvFormat);
+ break;
+ case 1:
+ uvs = (const VertexUV*)meshAsset.getVertexBuffer(b, RenderVertexSemantic::TEXCOORD1, uvFormat);
+ break;
+ case 2:
+ uvs = (const VertexUV*)meshAsset.getVertexBuffer(b, RenderVertexSemantic::TEXCOORD2, uvFormat);
+ break;
+ case 3:
+ uvs = (const VertexUV*)meshAsset.getVertexBuffer(b, RenderVertexSemantic::TEXCOORD3, uvFormat);
+ break;
+ }
+
+ pMeshes[b].mUvs = (VertexUVLocal*)uvs;
+ pMeshes[b].mUvFormat = uvFormat;
+ }
+ pMeshes += subMeshCount;
+ }
+
+
+ ClothingPhysicalMeshData* pPhysicalMeshes = (ClothingPhysicalMeshData*)pMeshes;
+
+ assetData.mPhysicalMeshOffset = (uint32_t)((uint8_t*)pMeshes - assetData.mData);
+
+ for (uint32_t a = 0; a < numPhysicalMeshes; ++a)
+ {
+ ClothingPhysicalMeshData* pPhysicalMesh = &pPhysicalMeshes[a];
+ PX_PLACEMENT_NEW(pPhysicalMesh, ClothingPhysicalMeshData);
+
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type* physicalMesh = getPhysicalMeshFromLod(a);
+ ClothingPhysicalMeshParameters* pPhysicalMeshParams = mPhysicalMeshes[a];
+ PX_UNUSED(pPhysicalMeshParams);
+
+ pPhysicalMesh->mVertices = physicalMesh->vertices.buf;
+ pPhysicalMesh->mVertexCount = physicalMesh->numVertices;
+ pPhysicalMesh->mSimulatedVertexCount = physicalMesh->numSimulatedVertices;
+ pPhysicalMesh->mMaxDistance0VerticesCount = physicalMesh->numMaxDistance0Vertices;
+
+ pPhysicalMesh->mNormals = physicalMesh->normals.buf;
+ pPhysicalMesh->mSkinningNormals = physicalMesh->skinningNormals.buf;
+ pPhysicalMesh->mSkinningNormalsCount = (uint32_t)physicalMesh->skinningNormals.arraySizes[0];
+ pPhysicalMesh->mNumBonesPerVertex = physicalMesh->numBonesPerVertex;
+
+ pPhysicalMesh->mBoneIndices = physicalMesh->boneIndices.buf;
+ pPhysicalMesh->mBoneWeights = physicalMesh->boneWeights.buf;
+ PX_ASSERT(physicalMesh->boneIndices.arraySizes[0] == physicalMesh->boneWeights.arraySizes[0]);
+ pPhysicalMesh->mBoneWeightsCount = (uint32_t)physicalMesh->boneWeights.arraySizes[0];
+
+ pPhysicalMesh->mOptimizationData = physicalMesh->optimizationData.buf;
+ pPhysicalMesh->mOptimizationDataCount = (uint32_t)physicalMesh->optimizationData.arraySizes[0];
+
+ pPhysicalMesh->mIndices = physicalMesh->indices.buf;
+ pPhysicalMesh->mIndicesCount = (uint32_t)physicalMesh->indices.arraySizes[0];
+ pPhysicalMesh->mSimulatedIndicesCount = physicalMesh->numSimulatedIndices;
+ }
+
+ //Initialized compressed num bones per vertex...
+ mCompressedNumBonesPerVertexMutex.lock();
+ if (mCompressedNumBonesPerVertex.empty())
+ {
+ initializeCompressedNumBonesPerVertex();
+ }
+ mCompressedNumBonesPerVertexMutex.unlock();
+
+ assetData.mCompressedNumBonesPerVertexCount = mCompressedNumBonesPerVertex.size();
+ assetData.mCompressedNumBonesPerVertex = assetData.mCompressedNumBonesPerVertexCount > 0 ? &(mCompressedNumBonesPerVertex.front()) : NULL;
+
+ assetData.mCompressedTangentWCount = mCompressedTangentW.size();
+ assetData.mCompressedTangentW = assetData.mCompressedTangentWCount > 0 ? &(mCompressedTangentW.front()) : NULL;
+
+ assetData.mPhysicalMeshesCount = mPhysicalMeshes.size();
+ assetData.mExt2IntMorphMappingCount = mExt2IntMorphMapping.size();
+ if (mExt2IntMorphMapping.size())
+ {
+ assetData.mExt2IntMorphMapping = &(mExt2IntMorphMapping.front());
+ }
+ else
+ {
+ assetData.mExt2IntMorphMapping = NULL;
+ }
+
+ assetData.mBoneCount = mBones.size();
+
+ return maxVertices;
+
+}
+
+
+
+const RenderMeshAsset* ClothingAssetImpl::getRenderMeshAsset(uint32_t lodLevel) const
+{
+ READ_ZONE();
+
+ if (lodLevel < mGraphicalLods.size())
+ {
+ return reinterpret_cast<RenderMeshAssetIntl*>(mGraphicalLods[lodLevel]->renderMeshAssetPointer);
+ }
+
+ return NULL;
+}
+
+
+
+uint32_t ClothingAssetImpl::getMeshSkinningMapSize(uint32_t lod)
+{
+ WRITE_ZONE();
+ if (lod >= mGraphicalLods.size())
+ {
+ APEX_INVALID_PARAMETER("lod %i not a valid lod level. There are only %i graphical lods.", lod, mGraphicalLods.size());
+ return 0;
+ }
+ ClothingGraphicalLodParameters* graphicalLod = mGraphicalLods[lod];
+
+ // make sure everything can be skinned using the skinClothMap,
+ // so the user doesn't have to care about immediate skinning as well
+ mergeMapping(graphicalLod);
+
+ return (uint32_t)mGraphicalLods[lod]->skinClothMap.arraySizes[0];
+}
+
+
+
+void ClothingAssetImpl::getMeshSkinningMap(uint32_t lod, ClothingMeshSkinningMap* map)
+{
+ WRITE_ZONE();
+
+ if (lod >= mGraphicalLods.size())
+ {
+ APEX_INVALID_PARAMETER("lod %i not a valid lod level. There are only %i graphical lods.", lod, mGraphicalLods.size());
+ return;
+ }
+ ClothingGraphicalLodParameters* graphicalLod = mGraphicalLods[lod];
+
+ // make sure everything can be skinned using the skinClothMap,
+ // so the user doesn't have to care about immediate skinning as well
+ mergeMapping(graphicalLod);
+
+ PX_ASSERT(graphicalLod->skinClothMapOffset > 0.0f); // skinClothMapOffset would only be needed if it's negative, but it's not expected to be
+
+ // copy the values
+ int32_t size = mGraphicalLods[lod]->skinClothMap.arraySizes[0];
+ for (int32_t i = 0; i < size; ++i)
+ {
+ const SkinClothMap& skinMap = mGraphicalLods[lod]->skinClothMap.buf[i];
+ map[i].positionBary = skinMap.vertexBary;
+ map[i].vertexIndex0 = skinMap.vertexIndex0;
+ map[i].normalBary = skinMap.normalBary;
+ map[i].vertexIndex1 = skinMap.vertexIndex1;
+ map[i].tangentBary = skinMap.tangentBary;
+ map[i].vertexIndex2 = skinMap.vertexIndex2;
+ }
+}
+
+
+
+bool ClothingAssetImpl::releaseGraphicalData()
+{
+ WRITE_ZONE();
+ bool ok = true;
+ for (uint32_t i = 0; i < mGraphicalLods.size(); ++i)
+ {
+ if (mGraphicalLods[i]->skinClothMapB.arraySizes[0] > 0 || mGraphicalLods[i]->tetraMap.arraySizes[0] > 0)
+ {
+ APEX_DEBUG_WARNING("Asset contains data that is not supported for external skinning, graphical data cannot be released. Reexport the asset with a newer APEX version.");
+ ok = false;
+ }
+
+ if (mGraphicalLods[i]->immediateClothMap.arraySizes[0] > 0)
+ {
+ APEX_DEBUG_WARNING("Asset contains immediate map data, graphical data cannot be released. Call getMeshSkinningMap first.");
+ ok = false;
+ }
+ }
+
+ if (mActors.getSize() > 0)
+ {
+ APEX_DEBUG_WARNING("Graphical data in asset cannot be released while there are actors of this asset.");
+ ok = false;
+ }
+
+ if (ok)
+ {
+ mModule->notifyReleaseGraphicalData(this);
+
+ for (uint32_t i = 0; i < mGraphicalLods.size(); ++i)
+ {
+ if (mGraphicalLods[i]->renderMeshAssetPointer != NULL)
+ {
+ RenderMeshAssetIntl* rma = reinterpret_cast<RenderMeshAssetIntl*>(mGraphicalLods[i]->renderMeshAssetPointer);
+ rma->release();
+ mGraphicalLods[i]->renderMeshAssetPointer = NULL;
+
+ mGraphicalLods[i]->renderMeshAsset->destroy();
+ mGraphicalLods[i]->renderMeshAsset = NULL;
+ }
+
+ ParamArray<SkinClothMap> skinClothMap(mGraphicalLods[i], "skinClothMap",
+ reinterpret_cast<ParamDynamicArrayStruct*>(&mGraphicalLods[i]->skinClothMap));
+ skinClothMap.clear();
+ }
+ }
+
+ return ok;
+}
+
+
+
+void ClothingAssetImpl::setupInvBindMatrices()
+{
+ if (mInvBindPoses.size() == mBones.size())
+ {
+ return;
+ }
+
+ mInvBindPoses.resize(mBones.size());
+ for (uint32_t i = 0; i < mBones.size(); i++)
+ {
+ mInvBindPoses[i] = mBones[i].bindPose.inverseRT();
+ }
+}
+
+
+
+void ClothingAssetImpl::prepareCookingJob(CookingAbstract& job, float scale, PxVec3* gravityDirection, PxVec3* morphedPhysicalMesh)
+{
+ PxVec3* tempVerticesForScale = NULL;
+ uint32_t tempVerticesOffset = 0;
+ if (scale != 1.0f || morphedPhysicalMesh != NULL)
+ {
+ uint32_t numMaxVertices = 0;
+ for (uint32_t physicalMeshId = 0; physicalMeshId < mPhysicalMeshes.size(); physicalMeshId++)
+ {
+ numMaxVertices += mPhysicalMeshes[physicalMeshId]->physicalMesh.numVertices;
+ }
+ numMaxVertices += mBoneVertices.size();
+
+ tempVerticesForScale = (PxVec3*)PX_ALLOC(sizeof(PxVec3) * numMaxVertices, PX_DEBUG_EXP("tempVerticesForScale"));
+ PX_ASSERT(tempVerticesForScale != NULL);
+
+ for (uint32_t physicalMeshId = 0; physicalMeshId < mPhysicalMeshes.size(); physicalMeshId++)
+ {
+ const uint32_t numVertices = mPhysicalMeshes[physicalMeshId]->physicalMesh.numVertices;
+ PxVec3* origVertices = morphedPhysicalMesh != NULL ? morphedPhysicalMesh + tempVerticesOffset : mPhysicalMeshes[physicalMeshId]->physicalMesh.vertices.buf;
+ PxVec3* tempVertices = tempVerticesForScale + tempVerticesOffset;
+ for (uint32_t i = 0; i < numVertices; i++)
+ {
+ tempVertices[i] = origVertices[i] * scale;
+ }
+ tempVerticesOffset += numVertices;
+ }
+ }
+
+ tempVerticesOffset = 0;
+
+ for (uint32_t physicalMeshId = 0; physicalMeshId < mPhysicalMeshes.size(); physicalMeshId++)
+ {
+ CookingAbstract::PhysicalMesh physicalMesh;
+ physicalMesh.meshID = physicalMeshId;
+ if (tempVerticesForScale != NULL)
+ {
+ physicalMesh.vertices = tempVerticesForScale + tempVerticesOffset;
+ }
+ else
+ {
+ physicalMesh.vertices = mPhysicalMeshes[physicalMeshId]->physicalMesh.vertices.buf;
+ }
+ physicalMesh.numVertices = mPhysicalMeshes[physicalMeshId]->physicalMesh.numVertices;
+ physicalMesh.numSimulatedVertices = mPhysicalMeshes[physicalMeshId]->physicalMesh.numSimulatedVertices;
+ physicalMesh.numMaxDistance0Vertices = mPhysicalMeshes[physicalMeshId]->physicalMesh.numMaxDistance0Vertices;
+ physicalMesh.indices = mPhysicalMeshes[physicalMeshId]->physicalMesh.indices.buf;
+ physicalMesh.numIndices = mPhysicalMeshes[physicalMeshId]->physicalMesh.numIndices;
+ physicalMesh.numSimulatedIndices = mPhysicalMeshes[physicalMeshId]->physicalMesh.numSimulatedIndices;
+ physicalMesh.isTetrahedral = mPhysicalMeshes[physicalMeshId]->physicalMesh.isTetrahedralMesh;
+
+ job.addPhysicalMesh(physicalMesh);
+
+ tempVerticesOffset += physicalMesh.numVertices;
+ }
+
+ if (tempVerticesForScale == NULL)
+ {
+ // verify that there are no invalid matrices
+ for (uint32_t i = 0; i < mBoneActors.size(); i++)
+ {
+ if (mBoneActors[i].capsuleRadius > 0.0f || mBoneActors[i].convexVerticesCount == 0)
+ {
+ continue;
+ }
+
+ uint32_t boneIndex = (uint32_t)mBoneActors[i].boneIndex;
+
+ const PxMat44& bpm44 = mBones[boneIndex].bindPose;
+ const PxMat44& lpm44 = mBoneActors[i].localPose;
+ const PxMat33 bpm33(bpm44.column0.getXYZ(),
+ bpm44.column1.getXYZ(),
+ bpm44.column2.getXYZ()),
+ lpm33(lpm44.column0.getXYZ(),
+ lpm44.column1.getXYZ(),
+ lpm44.column2.getXYZ());
+
+ const float det = bpm33.getDeterminant() * lpm33.getDeterminant();
+ if (det < 0.0f)
+ {
+ // invalid matrices found, need to use temporary buffer only for bone vertices now
+ tempVerticesForScale = (PxVec3*)GetInternalApexSDK()->getTempMemory(sizeof(PxVec3) * mBoneVertices.size());
+ PX_ASSERT(tempVerticesOffset == 0);
+ break;
+ }
+ }
+ }
+
+ if (tempVerticesForScale != NULL)
+ {
+ memset(tempVerticesForScale + tempVerticesOffset, 0xff, sizeof(PxVec3) * mBoneVertices.size());
+
+ PxVec3* boneVertices = morphedPhysicalMesh != NULL ? morphedPhysicalMesh + tempVerticesOffset : mBoneVertices.begin();
+
+ for (uint32_t i = 0; i < mBoneActors.size(); i++)
+ {
+ uint32_t boneIndex = (uint32_t)mBoneActors[i].boneIndex;
+ const PxMat44 bpm44(mBones[boneIndex].bindPose),
+ lpm44(mBoneActors[i].localPose);
+ const PxMat33 bpm33(bpm44.column0.getXYZ(),
+ bpm44.column1.getXYZ(),
+ bpm44.column2.getXYZ()),
+ lpm33(lpm44.column0.getXYZ(),
+ lpm44.column1.getXYZ(),
+ lpm44.column2.getXYZ());
+
+ const float det = bpm33.getDeterminant() * lpm33.getDeterminant();
+ for (uint32_t j = 0; j < mBoneActors[i].convexVerticesCount; j++)
+ {
+ uint32_t boneVertexIndex = mBoneActors[i].convexVerticesStart + j;
+ PxVec3 val = boneVertices[boneVertexIndex] * scale;
+ if (det < 0.0f)
+ {
+ val.z = -val.z;
+ }
+
+ tempVerticesForScale[boneVertexIndex + tempVerticesOffset] = val;
+ }
+ }
+
+ for (uint32_t i = 0; i < mBoneVertices.size(); i++)
+ {
+ PX_ASSERT(tempVerticesForScale[i + tempVerticesOffset].isFinite());
+ }
+ }
+
+ PxVec3* boneVertices = tempVerticesForScale != NULL ? tempVerticesForScale + tempVerticesOffset : mBoneVertices.begin();
+ job.setConvexBones(mBoneActors.begin(), mBoneActors.size(), mBones.begin(), mBones.size(), boneVertices, 256);
+
+ job.setScale(scale);
+ job.setVirtualParticleDensity(mParams->simulation.virtualParticleDensity);
+
+ if (mParams->materialLibrary != NULL)
+ {
+ ClothingMaterialLibraryParameters* matLib = static_cast<ClothingMaterialLibraryParameters*>(mParams->materialLibrary);
+ float selfcollisionThickness = matLib->materials.buf[mParams->materialIndex].selfcollisionThickness;
+ job.setSelfcollisionRadius(selfcollisionThickness);
+ }
+
+ PxVec3 gravityDir = mParams->simulation.gravityDirection;
+ if (gravityDir.isZero() && gravityDirection != NULL)
+ {
+ gravityDir = *gravityDirection;
+ }
+ if (gravityDir.isZero())
+ {
+ APEX_DEBUG_WARNING("(%s) Gravity direction is zero. Impossible to extract vertical- and zero-stretch fibers.", mName.c_str());
+ }
+ job.setGravityDirection(gravityDir);
+
+ job.freeTempMemoryWhenDone(tempVerticesForScale);
+}
+
+
+
+uint32_t* ClothingAssetImpl::getMorphMapping(uint32_t graphicalLod, uint32_t submeshIndex)
+{
+ if (mExt2IntMorphMapping.empty())
+ {
+ if (!mMorphMappingWarning)
+ {
+ APEX_INVALID_OPERATION("A clothing actor with morph displacements was specified, but the Asset <%s> was not prepared for morph displacements", mName.c_str());
+ mMorphMappingWarning = true;
+ }
+ return NULL;
+ }
+
+ if (graphicalLod == (uint32_t) - 1 || graphicalLod > mGraphicalLods.size())
+ {
+ graphicalLod = mGraphicalLods.size();
+ }
+
+ uint32_t offset = 0;
+ for (uint32_t i = 0; i < graphicalLod; i++)
+ {
+ RenderMeshAssetIntl* rma = getGraphicalMesh(i);
+ if (rma == NULL)
+ continue;
+
+ for (uint32_t s = 0; s < rma->getSubmeshCount(); s++)
+ {
+ offset += rma->getSubmesh(s).getVertexCount(0);
+ }
+ }
+
+
+ RenderMeshAssetIntl* rma = getGraphicalMesh(graphicalLod);
+ if (rma != NULL)
+ {
+ PX_ASSERT(submeshIndex < rma->getSubmeshCount());
+ submeshIndex = PxMin(submeshIndex, rma->getSubmeshCount());
+
+ for (uint32_t i = 0; i < submeshIndex; ++i)
+ {
+ offset += rma->getSubmesh(i).getVertexCount(0);
+ }
+ }
+
+ return mExt2IntMorphMapping.begin() + offset;
+}
+
+
+
+uint32_t ClothingAssetImpl::getPhysicalMeshOffset(uint32_t physicalMeshId)
+{
+ physicalMeshId = PxMin(physicalMeshId, mPhysicalMeshes.size());
+
+ uint32_t result = 0;
+
+ for (uint32_t i = 0; i < physicalMeshId; i++)
+ {
+ result += mPhysicalMeshes[i]->physicalMesh.numVertices;
+ }
+
+ return result;
+}
+
+
+
+class SkinClothMapFacePredicate
+{
+public:
+ bool operator()(const SkinClothMapB& map1, const SkinClothMapB& map2) const
+ {
+ if (map1.submeshIndex < map2.submeshIndex)
+ {
+ return true;
+ }
+ else if (map1.submeshIndex > map2.submeshIndex)
+ {
+ return false;
+ }
+
+ return map1.faceIndex0 < map2.faceIndex0;
+ }
+};
+
+
+
+class SkinClothMapBVertexPredicate
+{
+public:
+ bool operator()(const SkinClothMapB& map1, const SkinClothMapB& map2) const
+ {
+ return map1.vertexIndexPlusOffset < map2.vertexIndexPlusOffset;
+ }
+};
+
+
+
+void ClothingAssetImpl::getDisplacedPhysicalMeshPositions(PxVec3* morphDisplacements, ParamArray<PxVec3> displacedMeshPositions)
+{
+ uint32_t numPhysicalVertices = getPhysicalMeshOffset((uint32_t) - 1);
+ numPhysicalVertices += mBoneVertices.size();
+
+ if (numPhysicalVertices == 0)
+ {
+ displacedMeshPositions.clear();
+ return;
+ }
+
+ displacedMeshPositions.resize(numPhysicalVertices);
+ memset(displacedMeshPositions.begin(), 0, sizeof(PxVec3) * numPhysicalVertices);
+ float* resultWeights = (float*)PX_ALLOC(sizeof(float) * numPhysicalVertices, PX_DEBUG_EXP("ClothingAssetImpl::getDisplacedPhysicalMeshPositions"));
+ memset(resultWeights, 0, sizeof(float) * numPhysicalVertices);
+
+ uint32_t resultOffset = 0;
+ for (uint32_t pm = 0; pm < mPhysicalMeshes.size(); pm++)
+ {
+ uint32_t gm = 0;
+ for (; gm < mGraphicalLods.size(); gm++)
+ {
+ if (mGraphicalLods[gm]->physicalMeshId == pm)
+ {
+ break;
+ }
+ }
+
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type& physicalMesh = mPhysicalMeshes[pm]->physicalMesh;
+
+ if (gm < mGraphicalLods.size())
+ {
+ const ClothingGraphicalLodParameters* graphicalLod = mGraphicalLods[gm];
+
+ const RenderMeshAsset* rma = getRenderMeshAsset(gm);
+ uint32_t* morphMapping = getMorphMapping(gm, 0);
+ uint32_t morphOffset = 0;
+
+ AbstractMeshDescription pMesh;
+ pMesh.pIndices = physicalMesh.indices.buf;
+ pMesh.numIndices = physicalMesh.numIndices;
+ pMesh.pPosition = physicalMesh.vertices.buf;
+
+ if (graphicalLod->immediateClothMap.buf == NULL && graphicalLod->skinClothMapB.buf != NULL)
+ {
+ // PH: Need to resort the skinMapB buffer to vertex order, will resort back to face order just below
+ sort<SkinClothMapB, SkinClothMapBVertexPredicate>(graphicalLod->skinClothMapB.buf, (uint32_t)graphicalLod->skinClothMapB.arraySizes[0], SkinClothMapBVertexPredicate());
+ }
+
+ for (uint32_t submeshIndex = 0; submeshIndex < rma->getSubmeshCount(); submeshIndex++)
+ {
+ const RenderSubmesh& submesh = rma->getSubmesh(submeshIndex);
+
+ const uint32_t vertexCount = submesh.getVertexCount(0);
+ for (uint32_t vertexIndex = 0; vertexIndex < vertexCount; vertexIndex++)
+ {
+ const PxVec3 displacement = morphMapping != NULL ? morphDisplacements[morphMapping[morphOffset + vertexIndex]] : PxVec3(0.0f);
+
+ uint32_t indices[4];
+ float weight[4];
+
+ uint32_t numIndices = getCorrespondingPhysicalVertices(*graphicalLod, submeshIndex, vertexIndex, pMesh, morphOffset, indices, weight);
+
+ for (uint32_t i = 0; i < numIndices; i++)
+ {
+ weight[i] += 0.001f; // none of the weights is 0!
+ PX_ASSERT(weight[i] > 0.0f);
+ PX_ASSERT(indices[i] < pMesh.numIndices);
+ displacedMeshPositions[resultOffset + indices[i]] += (displacement + pMesh.pPosition[indices[i]]) * weight[i];
+ resultWeights[resultOffset + indices[i]] += weight[i];
+ }
+ }
+
+ morphOffset += vertexCount;
+ }
+
+ if (graphicalLod->immediateClothMap.buf == NULL && graphicalLod->skinClothMapB.buf != NULL)
+ {
+ nvidia::sort<SkinClothMapB, SkinClothMapFacePredicate>(graphicalLod->skinClothMapB.buf, (uint32_t)graphicalLod->skinClothMapB.arraySizes[0], SkinClothMapFacePredicate());
+ }
+
+ for (uint32_t i = 0; i < physicalMesh.numVertices; i++)
+ {
+ const uint32_t resultIndex = i + resultOffset;
+ if (resultWeights[resultIndex] > 0.0f)
+ {
+ displacedMeshPositions[resultIndex] /= resultWeights[resultIndex];
+ }
+ else
+ {
+ morphOffset = 0;
+ const PxVec3 physicsPosition = pMesh.pPosition[i];
+ float shortestDistance = PX_MAX_F32;
+ for (uint32_t submeshIndex = 0; submeshIndex < rma->getSubmeshCount() && shortestDistance > 0.0f; submeshIndex++)
+ {
+ const RenderSubmesh& submesh = rma->getSubmesh(submeshIndex);
+
+ const VertexFormat& format = submesh.getVertexBuffer().getFormat();
+ uint32_t positionIndex = (uint32_t)format.getBufferIndexFromID(format.getSemanticID(RenderVertexSemantic::POSITION));
+ PX_ASSERT(format.getBufferFormat(positionIndex) == RenderDataFormat::FLOAT3);
+ PxVec3* positions = (PxVec3*)submesh.getVertexBuffer().getBuffer(positionIndex);
+
+
+ const uint32_t vertexCount = submesh.getVertexCount(0);
+ for (uint32_t vertexIndex = 0; vertexIndex < vertexCount; vertexIndex++)
+ {
+ float dist2 = (physicsPosition - positions[vertexIndex]).magnitudeSquared();
+ if (dist2 < shortestDistance)
+ {
+ shortestDistance = dist2;
+ displacedMeshPositions[resultIndex] = physicsPosition + morphDisplacements[morphMapping[morphOffset + vertexIndex]];
+ if (dist2 == 0.0f)
+ {
+ break;
+ }
+ }
+ }
+ morphOffset += submesh.getVertexCount(0);
+ }
+ }
+ }
+ }
+
+ resultOffset += physicalMesh.numVertices;
+ }
+
+ PX_FREE(resultWeights);
+ resultWeights = NULL;
+
+ for (uint32_t ba = 0; ba < mBoneActors.size(); ba++)
+ {
+
+ for (uint32_t bi = 0; bi < mBoneActors[ba].convexVerticesCount; bi++)
+ {
+ uint32_t boneIndex = bi + mBoneActors[ba].convexVerticesStart;
+ PX_ASSERT(mBoneActors[ba].localPose == PxMat44(PxIdentity));
+ const PxMat44 bindPose = mBones[(uint32_t)mBoneActors[ba].boneIndex].bindPose;
+ const PxVec3 physicsPosition = bindPose.transform(mBoneVertices[boneIndex]);
+ PxVec3 resultPosition(0.0f);
+
+ float shortestDistance = PX_MAX_F32;
+ for (uint32_t gm = 0; gm < mGraphicalLods.size() && shortestDistance > 0.0f; gm++)
+ {
+ const RenderMeshAsset* rma = getRenderMeshAsset(gm);
+ uint32_t* morphMapping = getMorphMapping(gm, 0);
+ uint32_t morphOffset = 0;
+
+ for (uint32_t submeshIndex = 0; submeshIndex < rma->getSubmeshCount() && shortestDistance > 0.0f; submeshIndex++)
+ {
+ const RenderSubmesh& submesh = rma->getSubmesh(submeshIndex);
+
+ const VertexFormat& format = submesh.getVertexBuffer().getFormat();
+ uint32_t positionIndex = (uint32_t)format.getBufferIndexFromID(format.getSemanticID(RenderVertexSemantic::POSITION));
+ PX_ASSERT(format.getBufferFormat(positionIndex) == RenderDataFormat::FLOAT3);
+ PxVec3* positions = (PxVec3*)submesh.getVertexBuffer().getBuffer(positionIndex);
+
+
+ const uint32_t vertexCount = submesh.getVertexCount(0);
+ for (uint32_t vertexIndex = 0; vertexIndex < vertexCount; vertexIndex++)
+ {
+ float dist2 = (physicsPosition - positions[vertexIndex]).magnitudeSquared();
+ if (dist2 < shortestDistance)
+ {
+ shortestDistance = dist2;
+ resultPosition = physicsPosition + morphDisplacements[morphMapping[morphOffset + vertexIndex]];
+ if (dist2 == 0.0f)
+ {
+ break;
+ }
+ }
+ }
+ morphOffset += submesh.getVertexCount(0);
+ }
+ }
+
+ PxMat33 invBindPose(bindPose.column0.getXYZ(), bindPose.column1.getXYZ(), bindPose.column2.getXYZ());
+ invBindPose = invBindPose.getInverse();
+ displacedMeshPositions[resultOffset + boneIndex] = invBindPose.transform(resultPosition) + invBindPose.transform(-bindPose.getPosition());
+ }
+ }
+ resultOffset += mBoneVertices.size();
+
+
+ PX_ASSERT(resultOffset == numPhysicalVertices);
+}
+
+
+
+void ClothingAssetImpl::initializeCompressedNumBonesPerVertex()
+{
+ // PH: Merged the tangent w into this code, can be done at the same time
+ uint32_t numBonesElementCount = 0;
+ uint32_t numTangentElementCount = 0;
+ for (uint32_t lodIndex = 0; lodIndex < mGraphicalLods.size(); lodIndex++)
+ {
+ ClothingGraphicalMeshAssetWrapper meshAsset(reinterpret_cast<RenderMeshAssetIntl*>(mGraphicalLods[lodIndex]->renderMeshAssetPointer));
+
+ for (uint32_t submeshIdx = 0; submeshIdx < meshAsset.getSubmeshCount(); submeshIdx++)
+ {
+ const uint32_t numVertices = meshAsset.getNumVertices(submeshIdx);
+
+ // 3 bits per entry, 10 entries per U32
+ uint32_t numBoneEntries = (numVertices + 15) / 16;
+
+ RenderDataFormat::Enum outFormat = RenderDataFormat::UNSPECIFIED;
+ const PxVec4* PX_RESTRICT tangents = (const PxVec4*)meshAsset.getVertexBuffer(submeshIdx, RenderVertexSemantic::TANGENT, outFormat);
+ PX_ASSERT(tangents == NULL || outFormat == RenderDataFormat::FLOAT4);
+
+ uint32_t numTangentEntries = tangents != NULL ? (numVertices + 31) / 32 : 0;
+
+ // Round up such that map for all submeshes is 16 byte aligned
+ while ((numBoneEntries & 0x3) != 0) // this is a numEntries % 4
+ {
+ numBoneEntries++;
+ }
+
+ while ((numTangentEntries & 0x3) != 0)
+ {
+ numTangentEntries++;
+ }
+
+ numBonesElementCount += numBoneEntries;
+ numTangentElementCount += numTangentEntries;
+ }
+ }
+
+ if (numBonesElementCount > 0)
+ {
+ mCompressedNumBonesPerVertex.resize(numBonesElementCount, 0);
+
+ uint32_t numNonNormalizedVertices = 0;
+ uint32_t numInefficientVertices = 0;
+
+ uint32_t* bonesPerVertex = mCompressedNumBonesPerVertex.begin();
+ for (uint32_t lodIndex = 0; lodIndex < mGraphicalLods.size(); lodIndex++)
+ {
+ ClothingGraphicalMeshAssetWrapper meshAsset(reinterpret_cast<RenderMeshAssetIntl*>(mGraphicalLods[lodIndex]->renderMeshAssetPointer));
+
+ for (uint32_t submeshIdx = 0; submeshIdx < meshAsset.getSubmeshCount(); submeshIdx++)
+ {
+ uint32_t numVerticesWritten = 0;
+
+ RenderDataFormat::Enum outFormat = RenderDataFormat::UNSPECIFIED;
+ const float* PX_RESTRICT boneWeights = (const float*)meshAsset.getVertexBuffer(submeshIdx, RenderVertexSemantic::BONE_WEIGHT, outFormat);
+
+ const uint32_t numVertices = meshAsset.getNumVertices(submeshIdx);
+ const uint32_t numBonesPerVertex = meshAsset.getNumBonesPerVertex(submeshIdx);
+ PX_ASSERT((numBonesPerVertex > 0) == (boneWeights != NULL));
+
+ PX_ASSERT(((size_t)bonesPerVertex & 0xf) == 0); // make sure we start 16 byte aligned
+ for (uint32_t vertexIndex = 0; vertexIndex < numVertices; vertexIndex++)
+ {
+ uint32_t firstZeroBoneAfter = 0;
+ if (boneWeights != NULL)
+ {
+ const float* PX_RESTRICT vertexBoneWeights = boneWeights + (vertexIndex * numBonesPerVertex);
+ uint32_t firstZeroBone = numBonesPerVertex;
+ float sumWeights = 0.0f;
+ for (uint32_t k = 0; k < numBonesPerVertex; k++)
+ {
+ sumWeights += vertexBoneWeights[k];
+ if (vertexBoneWeights[k] == 0.0f)
+ {
+ firstZeroBone = PxMin(firstZeroBone, k);
+ }
+ else
+ {
+ firstZeroBoneAfter = k + 1;
+ }
+ }
+ PX_ASSERT(firstZeroBoneAfter <= numBonesPerVertex);
+
+ numNonNormalizedVertices += PxAbs(sumWeights - 1.0f) > 0.001f ? 1 : 0;
+ numInefficientVertices += firstZeroBone < firstZeroBoneAfter ? 1 : 0;
+ }
+ else
+ {
+ firstZeroBoneAfter = 1;
+ }
+
+ // write the value
+ if (numVerticesWritten == 16)
+ {
+ bonesPerVertex++;
+ numVerticesWritten = 0;
+ }
+
+ PX_ASSERT(firstZeroBoneAfter > 0);
+ PX_ASSERT(firstZeroBoneAfter < 5); // or else it doesn't fit
+ (*bonesPerVertex) |= ((firstZeroBoneAfter - 1) & 0x3) << (numVerticesWritten * 2);
+ numVerticesWritten++;
+ }
+
+ // if *bonesPerVertex contains data, advance
+ if (numVerticesWritten > 0)
+ {
+ bonesPerVertex++;
+ }
+
+ // advance until 16 byte aligned
+ while (((size_t)bonesPerVertex & 0xf) != 0)
+ {
+ bonesPerVertex++;
+ }
+ }
+ }
+
+ if (numNonNormalizedVertices > 0)
+ {
+ APEX_DEBUG_WARNING("The Clothing Asset <%s> has %d vertices with non-normalized bone weights. This may lead to wrongly displayed meshes.", mName.c_str(), numNonNormalizedVertices);
+ }
+
+ if (numInefficientVertices > 0)
+ {
+ APEX_DEBUG_WARNING("The Clothing Asset <%s> has %d vertices with non-sorted bone weights. This can decrease performance of the skinning. Resave the asset!", mName.c_str(), numInefficientVertices);
+ }
+ }
+
+ if (numTangentElementCount > 0)
+ {
+ mCompressedTangentW.resize(numTangentElementCount, 0);
+
+ uint32_t* tangentW = mCompressedTangentW.begin();
+ for (uint32_t lodIndex = 0; lodIndex < mGraphicalLods.size(); lodIndex++)
+ {
+ ClothingGraphicalMeshAssetWrapper meshAsset(reinterpret_cast<RenderMeshAssetIntl*>(mGraphicalLods[lodIndex]->renderMeshAssetPointer));
+
+ for (uint32_t submeshIdx = 0; submeshIdx < meshAsset.getSubmeshCount(); submeshIdx++)
+ {
+ uint32_t numVerticesWritten = 0;
+
+ RenderDataFormat::Enum outFormat = RenderDataFormat::UNSPECIFIED;
+ const PxVec4* PX_RESTRICT tangents = (const PxVec4*)meshAsset.getVertexBuffer(submeshIdx, RenderVertexSemantic::TANGENT, outFormat);
+ PX_ASSERT(outFormat == RenderDataFormat::FLOAT4);
+
+ PX_ASSERT(((size_t)tangentW & 0xf) == 0); // make sure we start 16 byte aligned
+
+ const uint32_t numVertices = meshAsset.getNumVertices(submeshIdx);
+ for (uint32_t vertexIndex = 0; vertexIndex < numVertices; vertexIndex++)
+ {
+ PX_ASSERT(PxAbs(tangents[vertexIndex].w) == 1.0f);
+ const uint32_t tangentWpositive = tangents[vertexIndex].w > 0.0f ? 1u : 0u;
+
+ // write the value
+ if (numVerticesWritten == 32)
+ {
+ tangentW++;
+ numVerticesWritten = 0;
+ }
+
+ (*tangentW) |= tangentWpositive << numVerticesWritten;
+ numVerticesWritten++;
+ }
+
+ // if *bonesPerVertex contains data, advance
+ if (numVerticesWritten > 0)
+ {
+ tangentW++;
+ }
+
+ // advance until 16 byte aligned
+ while (((size_t)tangentW & 0xf) != 0)
+ {
+ tangentW++;
+ }
+ }
+ }
+ }
+}
+
+
+
+uint32_t ClothingAssetImpl::getRootBoneIndex()
+{
+ PX_ASSERT(mParams->rootBoneIndex < getNumUsedBones());
+ return mParams->rootBoneIndex;
+}
+
+
+
+uint32_t ClothingAssetImpl::getInterCollisionChannels()
+{
+ return mParams->interCollisionChannels;
+}
+
+
+void ClothingAssetImpl::releaseCookedInstances()
+{
+ if (mParams != NULL && mActors.getSize() == 0)
+ {
+ for (int32_t i = 0; i < mParams->cookedData.arraySizes[0]; i++)
+ {
+ NvParameterized::Interface* cookedData = mParams->cookedData.buf[i].cookedData;
+ if (cookedData != NULL)
+ {
+ BackendFactory* factory = mModule->getBackendFactory(cookedData->className());
+ PX_ASSERT(factory != NULL);
+ if (factory != NULL)
+ {
+ factory->releaseCookedInstances(mParams->cookedData.buf[i].cookedData);
+ }
+ }
+ }
+ }
+}
+
+void ClothingAssetImpl::destroy()
+{
+ mActors.clear();
+
+ while (numCookingDependencies() > 0)
+ {
+ nvidia::Thread::sleep(0);
+ }
+
+ mModule->unregisterAssetWithScenes(this);
+
+ mUnusedSimulationMutex.lock();
+ for (uint32_t i = 0; i < mUnusedSimulation.size(); i++)
+ {
+ if (mUnusedSimulation[i] == NULL)
+ {
+ continue;
+ }
+
+ destroySimulation(mUnusedSimulation[i]);
+ mUnusedSimulation[i] = NULL;
+ }
+ mUnusedSimulation.clear();
+ mUnusedSimulationMutex.unlock();
+
+ releaseCookedInstances();
+
+ for (uint32_t i = 0; i < mPhysicalMeshes.size(); i++)
+ {
+ if (mParams != NULL)
+ {
+ // PH: we should only decrement if we don't use releaseAndReturnNvParameterizedInterface
+ mPhysicalMeshes[i]->referenceCount--;
+ }
+ }
+
+ for (uint32_t i = 0; i < mGraphicalLods.size(); i++)
+ {
+ if (mGraphicalLods[i]->renderMeshAssetPointer == NULL)
+ continue;
+
+ reinterpret_cast<RenderMeshAssetIntl*>(mGraphicalLods[i]->renderMeshAssetPointer)->release();
+ mGraphicalLods[i]->renderMeshAssetPointer = NULL;
+ }
+
+#ifndef WITHOUT_PVD
+ destroyPvdInstances();
+#endif
+ if (mParams != NULL)
+ {
+ // safety!
+ for (uint32_t i = 0; i < mPhysicalMeshes.size(); i++)
+ {
+ PX_ASSERT(mPhysicalMeshes[i]->referenceCount == 0);
+ }
+
+ mParams->setSerializationCallback(NULL, NULL);
+ mParams->destroy();
+ mParams = NULL;
+ }
+
+ mCompressedNumBonesPerVertex.reset();
+
+ delete this;
+}
+
+
+
+int32_t ClothingAssetImpl::getBoneInternalIndex(const char* boneName) const
+{
+ if (boneName == NULL)
+ {
+ return -1;
+ }
+
+ int32_t internalBoneIndex = -1;
+ for (uint32_t i = 0; i < mBones.size(); i++)
+ {
+ if (mBones[i].name != NULL && (::strcmp(mBones[i].name, boneName) == 0))
+ {
+ internalBoneIndex = (int32_t)i;
+ break;
+ }
+ }
+
+ return internalBoneIndex ;
+}
+
+
+
+int32_t ClothingAssetImpl::getBoneInternalIndex(uint32_t boneIndex) const
+{
+ if (boneIndex >= mBones.size())
+ {
+ return -1;
+ }
+
+ int32_t internalBoneIndex = -1;
+ for (uint32_t i = 0; i < mBones.size(); i++)
+ {
+ if (mBones[i].externalIndex == (int32_t)boneIndex)
+ {
+ internalBoneIndex = (int32_t)i;
+ break;
+ }
+ }
+
+ return internalBoneIndex;
+}
+
+
+
+class SortGraphicalVerts
+{
+public:
+ SortGraphicalVerts(uint32_t numVerts, uint32_t submeshOffset, const uint32_t* indices, uint32_t numIndices, ClothingGraphicalLodParameters* lodParameters,
+ ClothingPhysicalMeshParameters* physicsMesh, RenderMeshAssetIntl* renderMeshAsset = NULL) : mNumNotFoundVertices(0), mIndices(indices), mNumIndices(numIndices)
+ {
+ PX_UNUSED(physicsMesh);
+ mNew2Old.resize(numVerts, 0);
+ mOld2New.resize(numVerts, 0);
+ mVertexInfo.resize(numVerts);
+ for (uint32_t i = 0; i < numVerts; i++)
+ {
+ mNew2Old[i] = i;
+ mOld2New[i] = i;
+ mVertexInfo[i].idealPosition = (float)i;
+ }
+
+ // scale the max distance such that it gives a guess for the 'idealPosition'
+ // const float maxDistanceScale = (float)numVerts / physicsMesh->physicalMesh.maximumMaxDistance;
+ // ClothingPhysicalMeshParametersNS::ConstrainCoefficient_Type* coeffs = physicsMesh->physicalMesh.constrainCoefficients.buf;
+
+ if (lodParameters->immediateClothMap.arraySizes[0] > 0)
+ {
+ for (uint32_t i = 0; i < numVerts; i++)
+ {
+ const uint32_t immediateMap = lodParameters->immediateClothMap.buf[i + submeshOffset];
+ if (immediateMap != ClothingConstants::ImmediateClothingInvalidValue)
+ {
+ if ((immediateMap & ClothingConstants::ImmediateClothingInSkinFlag) == 0)
+ {
+ const uint32_t targetIndex = immediateMap & ClothingConstants::ImmediateClothingReadMask;
+ mVertexInfo[i].physicsMeshNumber = getMeshIndex(targetIndex, physicsMesh);
+ PX_UNUSED(targetIndex);
+ }
+ }
+ }
+ }
+
+ const uint32_t numSkins = (uint32_t)lodParameters->skinClothMap.arraySizes[0];
+ for (uint32_t i = 0; i < numSkins; i++)
+ {
+ const uint32_t vertexIndex = lodParameters->skinClothMap.buf[i].vertexIndexPlusOffset - submeshOffset;
+ if (vertexIndex < numVerts) // this also handles underflow
+ {
+ uint32_t physVertexIndex = PxMax(lodParameters->skinClothMap.buf[i].vertexIndex0, lodParameters->skinClothMap.buf[i].vertexIndex1);
+ physVertexIndex = PxMax(physVertexIndex, lodParameters->skinClothMap.buf[i].vertexIndex2);
+ const PxI32 submeshNumber = getMeshIndexMaxFromVert(physVertexIndex, physicsMesh);
+
+ mVertexInfo[vertexIndex].physicsMeshNumber = PxMax(submeshNumber, mVertexInfo[vertexIndex].physicsMeshNumber);
+ }
+ }
+
+ const uint32_t numSkinB = (uint32_t)lodParameters->skinClothMapB.arraySizes[0];
+ for (uint32_t i = 0; i < numSkinB; i++)
+ {
+ const uint32_t faceIndex0 = lodParameters->skinClothMapB.buf[i].faceIndex0;
+ PX_UNUSED(faceIndex0);
+ const uint32_t vertexIndex = lodParameters->skinClothMapB.buf[i].vertexIndexPlusOffset - submeshOffset;
+ if (vertexIndex < numVerts)
+ {
+ mVertexInfo[vertexIndex].physicsMeshNumber = PxMax(getMeshIndexMaxFromFace(faceIndex0, physicsMesh), mVertexInfo[vertexIndex].physicsMeshNumber);
+ }
+ }
+
+ const uint32_t numTetras = (uint32_t)lodParameters->tetraMap.arraySizes[0];
+ for (uint32_t i = 0; i < numTetras; i++)
+ {
+ const uint32_t tetraIndex0 = lodParameters->tetraMap.buf[i].tetraIndex0;
+ mVertexInfo[i].physicsMeshNumber = PxMax(getMeshIndexMaxFromFace(tetraIndex0, physicsMesh), mVertexInfo[i].physicsMeshNumber);
+ }
+
+ if (renderMeshAsset != NULL)
+ {
+ uint32_t numSkinClothMaps = (uint32_t)lodParameters->skinClothMap.arraySizes[0];
+ SkinClothMap* skinClothMaps = lodParameters->skinClothMap.buf;
+
+ uint32_t count = 0;
+ uint32_t targetOffset = 0;
+ for (uint32_t s = 0; s < renderMeshAsset->getSubmeshCount(); s++)
+ {
+ const VertexBuffer& vb = renderMeshAsset->getSubmesh(s).getVertexBuffer();
+ const VertexFormat& vf = vb.getFormat();
+
+ const uint32_t graphicalMaxDistanceIndex = (uint32_t)vf.getBufferIndexFromID(vf.getID("MAX_DISTANCE"));
+ RenderDataFormat::Enum outFormat = vf.getBufferFormat(graphicalMaxDistanceIndex);
+ const float* graphicalMaxDistance = outFormat == RenderDataFormat::UNSPECIFIED ? NULL :
+ reinterpret_cast<const float*>(vb.getBuffer(graphicalMaxDistanceIndex));
+ PX_ASSERT(graphicalMaxDistance == NULL || outFormat == RenderDataFormat::FLOAT1);
+
+ const uint32_t numVertices = renderMeshAsset->getSubmesh(s).getVertexCount(0);
+ for (uint32_t vertexIndex = 0; vertexIndex < numVertices; vertexIndex++)
+ {
+ const uint32_t index = vertexIndex + targetOffset;
+ if (graphicalMaxDistance != NULL && graphicalMaxDistance[vertexIndex] == 0.0f)
+ {
+ for (uint32_t i = 0; i < numSkinClothMaps; i++)
+ {
+ uint32_t grIndex = skinClothMaps[i].vertexIndexPlusOffset;
+ if (grIndex == index)
+ {
+ count++;
+
+ const uint32_t vertexIndex = grIndex - submeshOffset;
+ if (vertexIndex < numVerts) // this also handles underflow
+ {
+ mVertexInfo[vertexIndex].physicsMeshNumber = -1;
+ }
+ }
+ }
+ }
+ }
+
+ targetOffset += numVertices;
+ }
+ }
+
+ for (uint32_t i = 0; i < numVerts; i++)
+ {
+ if (mVertexInfo[i].physicsMeshNumber == -1)
+ {
+ // give it the largest number, such that it gets sorted to the very end instead of the very beginning. Then at least it's cpu skinned.
+ mVertexInfo[i].physicsMeshNumber = PX_MAX_I32;
+ mNumNotFoundVertices++;
+ }
+ PX_ASSERT(mVertexInfo[i].idealPosition != -1);
+ }
+
+ // we only know the submesh number for each individual vertex, but we need to make sure that this is consistent for each
+ // triangle. So we define the submesh number for a triangle as the min of all the submesh numbers of its vertices.
+ // Then we set the vertex submesh number to the min of all its triangle's submesh numbers.
+
+ Array<int32_t> triangleMeshIndex(mNumIndices / 3, 0x7fffffff);
+ for (uint32_t i = 0; i < triangleMeshIndex.size(); i++)
+ {
+ PxU32 index = i * 3;
+ PxI32 meshNumber = PxMin(mVertexInfo[mIndices[index]].physicsMeshNumber, mVertexInfo[mIndices[index + 1]].physicsMeshNumber);
+ triangleMeshIndex[i] = PxMin(meshNumber, mVertexInfo[mIndices[index + 2]].physicsMeshNumber);
+ }
+
+ // now let's redistribute it
+ for (uint32_t i = 0; i < triangleMeshIndex.size(); i++)
+ {
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ uint32_t index = mIndices[i * 3 + j];
+ if (triangleMeshIndex[i] < mVertexInfo[index].physicsMeshNumber)
+ {
+ mVertexInfo[index].physicsMeshNumber = triangleMeshIndex[i];
+ // we need to distinguish the ones that naturally belong to a submesh, or the border ones that got added this late
+ mVertexInfo[index].pulledInThroughTriangle = true;
+ }
+ }
+ }
+ }
+
+ PxI32 getMeshIndex(PxU32 vertexIndex, const ClothingPhysicalMeshParameters* physicsMesh)
+ {
+ if (physicsMesh->physicalMesh.numSimulatedVertices > vertexIndex)
+ {
+ return 0;
+ }
+
+ return 1;
+ }
+
+ PxI32 getMeshIndexMaxFromFace(PxU32 faceIndex0, const ClothingPhysicalMeshParameters* physicsMesh)
+ {
+ if (physicsMesh->physicalMesh.numSimulatedIndices > faceIndex0)
+ {
+ return 0;
+ }
+
+ return 1;
+ }
+
+ PxI32 getMeshIndexMaxFromVert(PxU32 vertexIndex, const ClothingPhysicalMeshParameters* physicsMesh)
+ {
+
+ if (physicsMesh->physicalMesh.numSimulatedVertices > vertexIndex)
+ {
+ return 0;
+ }
+
+ return 1;
+ }
+
+ bool operator()(const uint32_t a, const uint32_t b) const
+ {
+ if (mVertexInfo[a].pulledInThroughTriangle != mVertexInfo[b].pulledInThroughTriangle)
+ {
+ return mVertexInfo[a].pulledInThroughTriangle < mVertexInfo[b].pulledInThroughTriangle;
+ }
+
+ return mVertexInfo[a].idealPosition < mVertexInfo[b].idealPosition;
+ }
+
+ void sortVertices()
+ {
+ nvidia::sort(mNew2Old.begin(), mNew2Old.size(), *this);
+
+ for (uint32_t i = 0; i < mNew2Old.size(); i++)
+ {
+ mOld2New[mNew2Old[i]] = i;
+ }
+ }
+
+ uint32_t computeCost()
+ {
+ uint32_t totalDist = 0;
+ // const uint32_t numVertsInCacheLine = 4096 / 12;
+ for (uint32_t i = 0; i < mNumIndices; i += 3)
+ {
+ // create 3 edges
+ const uint32_t edges[3] =
+ {
+ (uint32_t)PxAbs((int32_t)mOld2New[mIndices[i + 0]] - (int32_t)mOld2New[mIndices[i + 1]]),
+ (uint32_t)PxAbs((int32_t)mOld2New[mIndices[i + 1]] - (int32_t)mOld2New[mIndices[i + 2]]),
+ (uint32_t)PxAbs((int32_t)mOld2New[mIndices[i + 2]] - (int32_t)mOld2New[mIndices[i + 0]]),
+ };
+
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ totalDist += edges[j];
+ }
+
+ }
+
+ return totalDist;
+ }
+
+ PxI32 getMesh(PxU32 newVertexIndex)
+ {
+ return mVertexInfo[mNew2Old[newVertexIndex]].physicsMeshNumber;
+ }
+
+ bool isAdditional(uint32_t newVertexIndex)
+ {
+ return mVertexInfo[mNew2Old[newVertexIndex]].pulledInThroughTriangle;
+ }
+
+ nvidia::Array<uint32_t> mOld2New;
+ nvidia::Array<uint32_t> mNew2Old;
+
+ uint32_t mNumNotFoundVertices;
+
+private:
+ SortGraphicalVerts& operator=(const SortGraphicalVerts&);
+
+ struct InternalInfo
+ {
+ InternalInfo() : physicsMeshNumber(-1), idealPosition(-1), idealChange(0.0f), idealCount(0.0f), pulledInThroughTriangle(false) {}
+ int32_t physicsMeshNumber;
+ float idealPosition;
+ float idealChange;
+ float idealCount;
+ bool pulledInThroughTriangle;
+ };
+
+ nvidia::Array<InternalInfo> mVertexInfo;
+
+ const uint32_t* mIndices;
+ const uint32_t mNumIndices;
+};
+
+
+
+template <typename T>
+class SkinClothMapPredicate
+{
+public:
+ bool operator()(const T& map1, const T& map2) const
+ {
+ return map1.vertexIndexPlusOffset < map2.vertexIndexPlusOffset;
+ }
+};
+
+
+
+class SortGraphicalIndices
+{
+public:
+ SortGraphicalIndices(uint32_t numIndices, uint32_t* indices) : mIndices(indices)
+ {
+ mTriangleInfo.resize(numIndices / 3);
+ for (uint32_t i = 0; i < mTriangleInfo.size(); i++)
+ {
+ mTriangleInfo[i].mesh = -1;
+ mTriangleInfo[i].originalPosition = i;
+ }
+
+ mNew2Old.resize(numIndices / 3);
+ mOld2New.resize(numIndices / 3);
+ for (uint32_t i = 0; i < mNew2Old.size(); i++)
+ {
+ mNew2Old[i] = i;
+ mOld2New[i] = i;
+ }
+ }
+
+ void setTriangleMesh(PxU32 triangle, PxI32 mesh)
+ {
+ mTriangleInfo[triangle].mesh = mesh;
+ }
+
+ PxI32 getTriangleMesh(PxU32 newTriangleIndex) const
+ {
+ return mTriangleInfo[mNew2Old[newTriangleIndex]].mesh;
+ }
+
+ bool operator()(const uint32_t t1, const uint32_t t2) const
+ {
+ if (mTriangleInfo[t1].mesh != mTriangleInfo[t2].mesh)
+ {
+ return mTriangleInfo[t1].mesh < mTriangleInfo[t2].mesh;
+ }
+
+ return mTriangleInfo[t1].originalPosition < mTriangleInfo[t2].originalPosition;
+ }
+
+ void sort()
+ {
+ nvidia::sort(mNew2Old.begin(), mNew2Old.size(), *this);
+
+ for (uint32_t i = 0; i < mNew2Old.size(); i++)
+ {
+ mOld2New[mNew2Old[i]] = i;
+ }
+
+ ApexPermute(mIndices, mNew2Old.begin(), mNew2Old.size(), 3);
+ }
+
+private:
+ nvidia::Array<uint32_t> mNew2Old;
+ nvidia::Array<uint32_t> mOld2New;
+ uint32_t* mIndices;
+
+ struct TriangleInfo
+ {
+ int32_t mesh;
+ uint32_t originalPosition;
+ };
+ nvidia::Array<TriangleInfo> mTriangleInfo;
+};
+
+
+
+bool ClothingAssetImpl::reorderGraphicsVertices(uint32_t graphicalLodId, bool perfWarning)
+{
+ PX_ASSERT(mGraphicalLods[graphicalLodId] != NULL);
+
+ const uint32_t curSortingVersion = 2; // bump this number when the sorting changes!
+
+ if (mGraphicalLods[graphicalLodId]->renderMeshAssetSorting >= curSortingVersion)
+ {
+ // nothing needs to be done.
+ return false;
+ }
+
+ mGraphicalLods[graphicalLodId]->renderMeshAssetSorting = curSortingVersion;
+
+ if (perfWarning)
+ {
+ APEX_DEBUG_INFO("Performance warning. This asset <%s> has to be re-saved to speed up loading", mName.c_str());
+ }
+
+ RenderMeshAssetIntl* rma = static_cast<RenderMeshAssetIntl*>(mGraphicalLods[graphicalLodId]->renderMeshAssetPointer);
+ PX_ASSERT(rma != NULL);
+ if (rma == NULL)
+ return false;
+
+ const uint32_t numSubMeshes = rma->getSubmeshCount();
+ uint32_t submeshVertexOffset = 0;
+
+ const uint32_t numSkinClothMap = (uint32_t)mGraphicalLods[graphicalLodId]->skinClothMap.arraySizes[0];
+ ClothingGraphicalLodParametersNS::SkinClothMapD_Type* skinClothMap = mGraphicalLods[graphicalLodId]->skinClothMap.buf;
+
+ const uint32_t numSkinClothMapB = (uint32_t)mGraphicalLods[graphicalLodId]->skinClothMapB.arraySizes[0];
+ ClothingGraphicalLodParametersNS::SkinClothMapB_Type* skinClothMapB = mGraphicalLods[graphicalLodId]->skinClothMapB.buf;
+
+ // allocate enough space
+ {
+ if (mGraphicalLods[graphicalLodId]->physicsMeshPartitioning.arraySizes[0] != (int32_t)numSubMeshes)
+ {
+ NvParameterized::Handle handle(*mGraphicalLods[graphicalLodId], "physicsMeshPartitioning");
+ PX_ASSERT(handle.isValid());
+ PX_ASSERT(handle.parameterDefinition()->type() == NvParameterized::TYPE_ARRAY);
+ handle.resizeArray((int32_t)numSubMeshes);
+ }
+ }
+
+ uint32_t meshPartitioningIndex = 0;
+ for (uint32_t s = 0; s < numSubMeshes; s++)
+ {
+ const RenderSubmesh& submesh = rma->getSubmesh(s);
+ const uint32_t numVertices = submesh.getVertexCount(0);
+
+ const uint32_t numIters = 2;
+ uint32_t costs[numIters] = { 0 };
+
+ ClothingPhysicalMeshParameters* physicsMesh = mPhysicalMeshes[mGraphicalLods[graphicalLodId]->physicalMeshId];
+
+ SortGraphicalVerts sortedVertices(numVertices, submeshVertexOffset, submesh.getIndexBuffer(0), submesh.getIndexCount(0), mGraphicalLods[graphicalLodId], physicsMesh, rma);
+
+ costs[0] = sortedVertices.computeCost();
+ sortedVertices.sortVertices(); // same ordering as before, but grouped by submeshes now
+
+ costs[1] = costs[0]; // stupid warnings
+ costs[1] = sortedVertices.computeCost();
+
+
+#if 0
+ // reorder based on triangle distances (into the vertex buffer)
+ // disable for now...
+ // PH: On the PS3 perf is 30% better if this is not performed! Needs much more further investigation!
+ uint32_t numIncreases = 0;
+ for (uint32_t i = 2; i < numIters; i++)
+ {
+ sortedVertices.refineIdealPositions(1.0f);
+ sortedVertices.sortVertices();
+ costs[i] = sortedVertices.computeCost();
+ if (costs[i] >= costs[i - 1])
+ {
+ numIncreases++;
+ if (numIncreases > 40)
+ {
+ break;
+ }
+ }
+ else if (numIncreases > 0)
+ {
+ numIncreases--;
+ }
+ }
+#endif
+
+ rma->getInternalSubmesh(s).applyPermutation(sortedVertices.mOld2New, sortedVertices.mNew2Old);
+
+ {
+ uint32_t vertexCount = 0;
+ uint32_t vertexAdditionalCount = 0;
+
+ while (vertexAdditionalCount < sortedVertices.mNew2Old.size() && sortedVertices.getMesh(vertexAdditionalCount) <= 0)
+ {
+ if (!sortedVertices.isAdditional(vertexAdditionalCount))
+ {
+ vertexCount = vertexAdditionalCount + 1;
+ }
+ vertexAdditionalCount++;
+ }
+
+ mGraphicalLods[graphicalLodId]->physicsMeshPartitioning.buf[meshPartitioningIndex].graphicalSubmesh = s;
+ mGraphicalLods[graphicalLodId]->physicsMeshPartitioning.buf[meshPartitioningIndex].numSimulatedVertices = vertexCount;
+ mGraphicalLods[graphicalLodId]->physicsMeshPartitioning.buf[meshPartitioningIndex].numSimulatedVerticesAdditional = vertexAdditionalCount;
+ }
+
+ // also sort the index buffer accordingly
+ {
+ uint32_t* indices = rma->getInternalSubmesh(s).getIndexBufferWritable(0);
+
+ uint32_t indexCount = submesh.getIndexCount(0);
+ uint32_t triCount = indexCount / 3;
+ SortGraphicalIndices sortedIndices(indexCount, indices);
+
+ for (uint32_t i = 0; i < triCount; i++)
+ {
+ int32_t meshIndex = 0;
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ meshIndex = PxMax(meshIndex, sortedVertices.getMesh(indices[i * 3 + j]));
+ }
+ sortedIndices.setTriangleMesh(i, meshIndex);
+ }
+
+ sortedIndices.sort();
+
+ uint32_t startTriangle = 0;
+ while (startTriangle < triCount) // && sortedIndices.getTriangleSubmesh(startTriangle) <= i)
+ {
+ startTriangle++;
+ }
+ mGraphicalLods[graphicalLodId]->physicsMeshPartitioning.buf[meshPartitioningIndex].numSimulatedIndices = startTriangle * 3;
+ }
+
+ // also adapt all mesh-mesh skinning tables
+
+ uint32_t* immediateMap = mGraphicalLods[graphicalLodId]->immediateClothMap.buf;
+ if (immediateMap != NULL)
+ {
+ ApexPermute(immediateMap + submeshVertexOffset, sortedVertices.mNew2Old.begin(), numVertices);
+ }
+
+ for (uint32_t i = 0; i < numSkinClothMap; i++)
+ {
+ if (skinClothMap[i].vertexIndexPlusOffset < submeshVertexOffset)
+ {
+ continue;
+ }
+ else if (skinClothMap[i].vertexIndexPlusOffset >= submeshVertexOffset + numVertices)
+ {
+ break;
+ }
+
+ uint32_t oldVertexIndex = skinClothMap[i].vertexIndexPlusOffset - submeshVertexOffset;
+ skinClothMap[i].vertexIndexPlusOffset = submeshVertexOffset + sortedVertices.mOld2New[oldVertexIndex];
+ }
+
+ for (uint32_t i = 0; i < numSkinClothMapB; i++)
+ {
+ const uint32_t vertexIndex = skinClothMapB[i].vertexIndexPlusOffset;
+ if (vertexIndex >= submeshVertexOffset && vertexIndex < submeshVertexOffset + numVertices)
+ {
+ skinClothMapB[i].vertexIndexPlusOffset = submeshVertexOffset + sortedVertices.mOld2New[vertexIndex - submeshVertexOffset];
+ }
+ }
+
+ submeshVertexOffset += numVertices;
+ meshPartitioningIndex++;
+ }
+
+ // make sure all maps are sorted again, only mapC type!
+ nvidia::sort(skinClothMap, numSkinClothMap, SkinClothMapPredicate<ClothingGraphicalLodParametersNS::SkinClothMapD_Type>());
+
+ uint32_t* immediateMap = mGraphicalLods[graphicalLodId]->immediateClothMap.buf;
+ if (immediateMap != NULL)
+ {
+ for (uint32_t i = 0; i < numSkinClothMap; i++)
+ {
+ PX_ASSERT((immediateMap[skinClothMap[i].vertexIndexPlusOffset] & ClothingConstants::ImmediateClothingInSkinFlag) == ClothingConstants::ImmediateClothingInSkinFlag);
+ immediateMap[skinClothMap[i].vertexIndexPlusOffset] = i | ClothingConstants::ImmediateClothingInSkinFlag;
+ }
+
+#ifdef _DEBUG
+ // sanity check
+ for (uint32_t i = 0; i < submeshVertexOffset; i++)
+ {
+ uint32_t imm = immediateMap[i];
+ if (imm != ClothingConstants::ImmediateClothingInvalidValue)
+ {
+ if ((imm & ClothingConstants::ImmediateClothingInSkinFlag) == ClothingConstants::ImmediateClothingInSkinFlag)
+ {
+ imm &= ClothingConstants::ImmediateClothingReadMask;
+
+ if (numSkinClothMap > 0)
+ {
+ PX_ASSERT(imm < numSkinClothMap);
+ PX_ASSERT(skinClothMap[imm].vertexIndexPlusOffset == i);
+ }
+ else if (numSkinClothMapB > 0)
+ {
+ PX_ASSERT(imm < numSkinClothMapB);
+ PX_ASSERT(skinClothMapB[imm].vertexIndexPlusOffset == i);
+ }
+ }
+ }
+ }
+#endif
+ }
+
+ return true;
+}
+
+
+
+class DeformableVerticesMaxDistancePredicate
+{
+public:
+ DeformableVerticesMaxDistancePredicate(ClothingConstrainCoefficients* constrainCoefficients) : mConstrainCoefficients(constrainCoefficients) {}
+ bool operator()(uint32_t oldindex1, uint32_t oldIndex2) const
+ {
+ return mConstrainCoefficients[oldindex1].maxDistance > mConstrainCoefficients[oldIndex2].maxDistance;
+ }
+
+private:
+ ClothingConstrainCoefficients* mConstrainCoefficients;
+};
+
+
+
+bool ClothingAssetImpl::reorderDeformableVertices(ClothingPhysicalMeshImpl& physicalMesh)
+{
+ ClothingPhysicalMeshParameters* params = static_cast<ClothingPhysicalMeshParameters*>(physicalMesh.getNvParameterized());
+
+ const uint32_t curSortingVersion = 1; // bump this number when the sorting changes!
+
+ if (params->physicalMesh.physicalMeshSorting >= curSortingVersion)
+ {
+ // nothing needs to be done.
+ return false;
+ }
+
+ params->physicalMesh.physicalMeshSorting = curSortingVersion;
+
+ uint32_t* indices = physicalMesh.getIndicesBuffer();
+
+ // create mapping arrays
+ Array<uint32_t> newIndices(physicalMesh.getNumVertices(), (uint32_t) - 1);
+ Array<uint32_t> oldIndices(physicalMesh.getNumVertices(), (uint32_t) - 1);
+ uint32_t nextIndex = 0;
+ for (uint32_t i = 0; i < physicalMesh.getNumIndices(); i++)
+ {
+ const uint32_t vertexIndex = indices[i];
+ if (newIndices[vertexIndex] == (uint32_t) - 1)
+ {
+ newIndices[vertexIndex] = nextIndex;
+ oldIndices[nextIndex] = vertexIndex;
+ nextIndex++;
+ }
+ }
+
+ uint32_t maxVertexIndex = 0;
+ for (uint32_t j = 0; j < params->physicalMesh.numSimulatedIndices; j++)
+ {
+ const uint32_t newVertexIndex = newIndices[indices[j]];
+ maxVertexIndex = PxMax(maxVertexIndex, newVertexIndex);
+ }
+
+ maxVertexIndex++;
+ params->physicalMesh.numSimulatedVertices = maxVertexIndex;
+
+ DeformableVerticesMaxDistancePredicate predicate(physicalMesh.getConstrainCoefficientBuffer());
+
+ // Sort mesh.
+ nvidia::sort(oldIndices.begin(), maxVertexIndex, predicate);
+
+ // fix newIndices, the sort has destroyed them
+ for (uint32_t i = 0; i < nextIndex; i++)
+ {
+ PX_ASSERT(newIndices[oldIndices[i]] != (uint32_t) - 1);
+ newIndices[oldIndices[i]] = i;
+ }
+
+ // move unused vertices to the end
+ if (nextIndex < physicalMesh.getNumVertices())
+ {
+ // TODO check if ApexPermute works without this
+ for (uint32_t i = 0; i < newIndices.size(); i++)
+ {
+ if (newIndices[i] == (uint32_t) - 1)
+ {
+ newIndices[i] = nextIndex;
+ oldIndices[nextIndex] = i;
+ nextIndex++;
+ }
+ }
+ }
+
+ PX_ASSERT(physicalMesh.getNumVertices() == oldIndices.size());
+ PX_ASSERT(nextIndex == physicalMesh.getNumVertices()); // at this point we assume that all vertices are referenced
+
+ // do reordering
+ physicalMesh.applyPermutation(oldIndices);
+
+ // set max distance 0 vertices
+ ClothingConstrainCoefficients* coeffs = physicalMesh.getConstrainCoefficientBuffer();
+
+ const uint32_t numSimulatedVertices = params->physicalMesh.numSimulatedVertices;
+
+ uint32_t vertexIndex = 0;
+ float eps = 1e-8;
+ for (; vertexIndex < numSimulatedVertices; vertexIndex++)
+ {
+ if (coeffs[vertexIndex].maxDistance <= eps)
+ {
+ break;
+ }
+ }
+
+ params->physicalMesh.numMaxDistance0Vertices = numSimulatedVertices - vertexIndex;
+
+ // safety
+ for (; vertexIndex < numSimulatedVertices; vertexIndex++)
+ {
+ PX_ASSERT(coeffs[vertexIndex].maxDistance <= eps);
+ }
+
+
+ // clean up existing references
+ for (uint32_t i = 0; i < physicalMesh.getNumIndices(); i++)
+ {
+ indices[i] = newIndices[indices[i]];
+ }
+
+ // update mappings into deformable vertex buffer
+ for (uint32_t i = 0; i < mGraphicalLods.size(); i++)
+ {
+ if (mPhysicalMeshes[mGraphicalLods[i]->physicalMeshId] == physicalMesh.getNvParameterized())
+ {
+ ClothingGraphicalMeshAssetWrapper meshAsset(reinterpret_cast<RenderMeshAssetIntl*>(mGraphicalLods[i]->renderMeshAssetPointer));
+ ClothingGraphicalLodParameters& graphicalLod = *mGraphicalLods[i];
+
+ const uint32_t numGraphicalVertices = meshAsset.getNumTotalVertices();
+
+ if (graphicalLod.immediateClothMap.arraySizes[0] > 0)
+ {
+ for (uint32_t j = 0; j < numGraphicalVertices; j++)
+ {
+ if (graphicalLod.immediateClothMap.buf[j] != ClothingConstants::ImmediateClothingInvalidValue)
+ {
+ if ((graphicalLod.immediateClothMap.buf[j] & ClothingConstants::ImmediateClothingInSkinFlag) == 0)
+ {
+ const uint32_t flags = graphicalLod.immediateClothMap.buf[j] & ~ClothingConstants::ImmediateClothingReadMask;
+ graphicalLod.immediateClothMap.buf[j] =
+ newIndices[graphicalLod.immediateClothMap.buf[j] & ClothingConstants::ImmediateClothingReadMask] | flags;
+ }
+ }
+ }
+ }
+
+ for(int32_t j = 0; j < graphicalLod.skinClothMap.arraySizes[0]; ++j)
+ {
+ graphicalLod.skinClothMap.buf[j].vertexIndex0 = newIndices[graphicalLod.skinClothMap.buf[j].vertexIndex0];
+ graphicalLod.skinClothMap.buf[j].vertexIndex1 = newIndices[graphicalLod.skinClothMap.buf[j].vertexIndex1];
+ graphicalLod.skinClothMap.buf[j].vertexIndex2 = newIndices[graphicalLod.skinClothMap.buf[j].vertexIndex2];
+ }
+ }
+ }
+
+ // update transition maps
+
+ if (params->transitionDown.arraySizes[0] > 0)
+ {
+ for (int32_t i = 0; i < params->transitionDown.arraySizes[0]; i++)
+ {
+ uint32_t& vertexIndex = params->transitionDown.buf[i].vertexIndexPlusOffset;
+ PX_ASSERT(vertexIndex == (uint32_t)i);
+ vertexIndex = newIndices[vertexIndex];
+ }
+
+ nvidia::sort(params->transitionDown.buf, (uint32_t)params->transitionDown.arraySizes[0], SkinClothMapPredicate<ClothingPhysicalMeshParametersNS::SkinClothMapD_Type>());
+ }
+
+ if (params->transitionUp.arraySizes[0] > 0)
+ {
+ for (int32_t i = 0; i < params->transitionUp.arraySizes[0]; i++)
+ {
+ uint32_t& vertexIndex = params->transitionUp.buf[i].vertexIndexPlusOffset;
+ PX_ASSERT(vertexIndex == (uint32_t)i);
+ vertexIndex = newIndices[vertexIndex];
+ }
+ nvidia::sort(params->transitionUp.buf, (uint32_t)params->transitionUp.arraySizes[0], SkinClothMapPredicate<ClothingPhysicalMeshParametersNS::SkinClothMapD_Type>());
+ }
+
+ return true;
+}
+
+
+
+float ClothingAssetImpl::getMaxMaxDistance(ClothingPhysicalMeshParametersNS::PhysicalMesh_Type& physicalMesh, uint32_t index, uint32_t numIndices) const
+{
+ uint32_t* indices = physicalMesh.indices.buf;
+ ClothingPhysicalMeshParametersNS::ConstrainCoefficient_Type* coeffs = physicalMesh.constrainCoefficients.buf;
+
+ float maxDist = coeffs[indices[index]].maxDistance;
+ for (uint32_t i = 1; i < numIndices; i++)
+ {
+ maxDist = PxMax(maxDist, coeffs[indices[index + i]].maxDistance);
+ }
+
+ return maxDist;
+}
+
+
+
+uint32_t ClothingAssetImpl::getCorrespondingPhysicalVertices(const ClothingGraphicalLodParameters& graphLod, uint32_t submeshIndex,
+ uint32_t graphicalVertexIndex, const AbstractMeshDescription& pMesh,
+ uint32_t submeshVertexOffset, uint32_t indices[4], float trust[4]) const
+{
+ PX_UNUSED(submeshIndex); // stupid release mode
+
+ PX_ASSERT(pMesh.numIndices > 0);
+ PX_ASSERT(pMesh.pIndices != NULL);
+
+
+ uint32_t result = 0;
+
+ if (graphLod.immediateClothMap.arraySizes[0] > 0)
+ {
+ indices[0] = graphLod.immediateClothMap.buf[graphicalVertexIndex + submeshVertexOffset];
+ trust[0] = 1.0f;
+
+ if (indices[0] != ClothingConstants::ImmediateClothingInvalidValue)
+ {
+ if ((indices[0] & ClothingConstants::ImmediateClothingInSkinFlag) == 0)
+ {
+ indices[0] &= ClothingConstants::ImmediateClothingReadMask;
+ result = 1;
+ }
+ else if (graphLod.skinClothMapB.arraySizes[0] > 0)
+ {
+ const int32_t temp = int32_t(indices[0] & ClothingConstants::ImmediateClothingReadMask);
+ if (temp < graphLod.skinClothMapB.arraySizes[0])
+ {
+ for (uint32_t i = 0; i < 3; i++)
+ {
+ PX_ASSERT(graphLod.skinClothMapB.buf[temp].faceIndex0 + i < pMesh.numIndices);
+ indices[i] = pMesh.pIndices[graphLod.skinClothMapB.buf[temp].faceIndex0 + i];
+ trust[i] = 1.0f; // PH: This should be lower for some vertices!
+ }
+ result = 3;
+ }
+ }
+ else if (graphLod.skinClothMap.arraySizes[0] > 0)
+ {
+ const int32_t temp = int32_t(indices[0] & ClothingConstants::ImmediateClothingReadMask);
+ if (temp < graphLod.skinClothMap.arraySizes[0])
+ {
+ PxVec3 bary = graphLod.skinClothMap.buf[temp].vertexBary;
+ bary.x = PxClamp(bary.x, 0.0f, 1.0f);
+ bary.y = PxClamp(bary.y, 0.0f, 1.0f);
+ bary.z = PxClamp(1.0f - bary.x - bary.y, 0.0f, 1.0f);
+ uint32_t physVertIndex[3] =
+ {
+ graphLod.skinClothMap.buf[temp].vertexIndex0,
+ graphLod.skinClothMap.buf[temp].vertexIndex1,
+ graphLod.skinClothMap.buf[temp].vertexIndex2
+ };
+ for (uint32_t i = 0; i < 3; i++)
+ {
+ //PX_ASSERT(graphLod.skinClothMap.buf[temp].faceIndex0 + i < pMesh.numIndices);
+ indices[i] = physVertIndex[i];
+ trust[i] = bary[i];
+ }
+ result = 3;
+ }
+ }
+ }
+ }
+ else if (graphLod.skinClothMapB.arraySizes[0] > 0)
+ {
+ PX_ASSERT(graphLod.skinClothMapB.buf[graphicalVertexIndex + submeshVertexOffset].submeshIndex == submeshIndex);
+ PX_ASSERT(graphLod.skinClothMapB.buf[graphicalVertexIndex + submeshVertexOffset].vertexIndexPlusOffset == graphicalVertexIndex + submeshVertexOffset);
+
+ for (uint32_t i = 0; i < 3; i++)
+ {
+ PX_ASSERT(graphLod.skinClothMapB.buf[graphicalVertexIndex + submeshVertexOffset].faceIndex0 + i < pMesh.numIndices);
+ indices[i] = pMesh.pIndices[graphLod.skinClothMapB.buf[graphicalVertexIndex + submeshVertexOffset].faceIndex0 + i];
+ trust[i] = 1.0f;
+ }
+ result = 3;
+ }
+ else if (graphLod.skinClothMap.arraySizes[0] > 0)
+ {
+ // we need to do binary search here
+ uint32_t curMin = 0;
+ uint32_t curMax = (uint32_t)graphLod.skinClothMap.arraySizes[0];
+ const uint32_t searchFor = graphicalVertexIndex + submeshVertexOffset;
+ while (curMax > curMin)
+ {
+ uint32_t middle = (curMin + curMax) >> 1;
+ PX_ASSERT(middle == graphLod.skinClothMap.buf[middle].vertexIndexPlusOffset);
+ const uint32_t probeResult = middle;
+ if (probeResult < searchFor)
+ {
+ curMin = middle + 1;
+ }
+ else
+ {
+ curMax = middle;
+ }
+ }
+
+ PX_ASSERT(curMin == graphLod.skinClothMap.buf[curMin].vertexIndexPlusOffset);
+ if (curMin == searchFor)
+ {
+ PxVec3 bary = graphLod.skinClothMap.buf[curMin].vertexBary;
+ bary.x = PxClamp(bary.x, 0.0f, 1.0f);
+ bary.y = PxClamp(bary.y, 0.0f, 1.0f);
+ bary.z = PxClamp(1.0f - bary.x - bary.y, 0.0f, 1.0f);
+
+ uint32_t physVertIndex[3] =
+ {
+ graphLod.skinClothMap.buf[curMin].vertexIndex0,
+ graphLod.skinClothMap.buf[curMin].vertexIndex1,
+ graphLod.skinClothMap.buf[curMin].vertexIndex2
+ };
+ for (uint32_t i = 0; i < 3; i++)
+ {
+ // PX_ASSERT(graphLod.skinClothMap.buf[curMin].faceIndex0 + i < pMesh.numIndices);
+ indices[i] = physVertIndex[i];
+ trust[i] = bary[i];
+ }
+ result = 3;
+ }
+ }
+ else if (graphLod.tetraMap.arraySizes[0] > 0)
+ {
+ for (uint32_t i = 0; i < 4; i++)
+ {
+ PX_ASSERT(graphLod.tetraMap.buf[graphicalVertexIndex + submeshVertexOffset].tetraIndex0 + i < pMesh.numIndices);
+ indices[i] = pMesh.pIndices[graphLod.tetraMap.buf[graphicalVertexIndex + submeshVertexOffset].tetraIndex0 + i];
+ trust[i] = 1.0f;
+ }
+ result = 4;
+ }
+
+ for (uint32_t i = 0; i < result; i++)
+ {
+ PX_ASSERT(trust[i] >= 0.0f);
+ PX_ASSERT(trust[i] <= 1.0f);
+ }
+
+ return result;
+}
+
+
+
+void ClothingAssetImpl::getNormalsAndVerticesForFace(PxVec3* vtx, PxVec3* nrm, uint32_t i, const AbstractMeshDescription& srcPM) const
+{
+ // copy indices for convenience
+ PX_ASSERT(i < srcPM.numIndices);
+ uint32_t di[3];
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ di[j] = srcPM.pIndices[i + j];
+ }
+
+ // To guarantee consistency in our implicit tetrahedral mesh definition we must always order vertices
+ // idx[0,1,2] = min, max and mid
+ uint32_t idx[3];
+ idx[0] = PxMin(di[0], PxMin(di[1], di[2]));
+ idx[1] = PxMax(di[0], PxMax(di[1], di[2]));
+ idx[2] = idx[0];
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ if ((idx[0] != di[j]) && (idx[1] != di[j]))
+ {
+ idx[2] = di[j];
+ }
+ }
+
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ vtx[j] = srcPM.pPosition[idx[j]];
+ nrm[j] = srcPM.pNormal[idx[j]];
+#ifdef _DEBUG
+ // sanity
+ // PH: These normals 'should' always be normalized, maybe we can get rid of the normalize completely!
+ const float length = nrm[j].magnitudeSquared();
+ if (!(length >= 0.99f && length <= 1.01f))
+ {
+ static bool first = true;
+ if (first)
+ {
+ PX_ALWAYS_ASSERT();
+ first = false;
+ }
+ }
+#else
+ // PH: let's try and disable it in release mode...
+ //nrm[j].normalize();
+#endif
+ };
+}
+
+
+
+bool ClothingAssetImpl::setBoneName(uint32_t internalIndex, const char* name)
+{
+ NvParameterized::Handle bonesHandle(*mParams);
+ mParams->getParameterHandle("bones", bonesHandle);
+
+ if (bonesHandle.isValid())
+ {
+ NvParameterized::Handle boneHandle(*mParams);
+ bonesHandle.getChildHandle((int32_t)internalIndex, boneHandle);
+
+ if (boneHandle.isValid())
+ {
+ NvParameterized::Handle nameHandle(*mParams);
+ boneHandle.getChildHandle(mParams, "name", nameHandle);
+
+ if (nameHandle.isValid())
+ {
+ mParams->setParamString(nameHandle, name);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+
+void ClothingAssetImpl::clearMapping(uint32_t graphicalLodIndex)
+{
+ if (mGraphicalLods[graphicalLodIndex]->immediateClothMap.buf != NULL)
+ {
+ ParamArray<uint32_t> immediateClothMap(mGraphicalLods[graphicalLodIndex], "immediateClothMap", reinterpret_cast<ParamDynamicArrayStruct*>(&mGraphicalLods[graphicalLodIndex]->immediateClothMap));
+ immediateClothMap.clear();
+ }
+ if (mGraphicalLods[graphicalLodIndex]->skinClothMapB.buf != NULL)
+ {
+ ParamArray<ClothingGraphicalLodParametersNS::SkinClothMapB_Type> skinClothMapB(mGraphicalLods[graphicalLodIndex], "skinClothMapB", reinterpret_cast<ParamDynamicArrayStruct*>(&mGraphicalLods[graphicalLodIndex]->skinClothMapB));
+ skinClothMapB.clear();
+ }
+ if (mGraphicalLods[graphicalLodIndex]->tetraMap.buf != NULL)
+ {
+ ParamArray<ClothingGraphicalLodParametersNS::TetraLink_Type> tetraMap(mGraphicalLods[graphicalLodIndex], "tetraMap", reinterpret_cast<ParamDynamicArrayStruct*>(&mGraphicalLods[graphicalLodIndex]->tetraMap));
+ tetraMap.clear();
+ }
+}
+
+
+
+bool ClothingAssetImpl::findTriangleForImmediateVertex(uint32_t& faceIndex, uint32_t& indexInTriangle, uint32_t physVertIndex, ClothingPhysicalMeshParametersNS::PhysicalMesh_Type& physicalMesh) const
+{
+ // find triangle with smallest faceIndex, indices have been sorted during authoring
+ // such that simulated triangles are first
+ for (uint32_t physIndex = 0; physIndex < (uint32_t)physicalMesh.indices.arraySizes[0]; physIndex++)
+ {
+ if (physicalMesh.indices.buf[physIndex] == physVertIndex)
+ {
+ // this is a triangle that contains the vertex from the immediate map)
+ uint32_t currentFaceIndex = physIndex - (physIndex%3);
+
+ faceIndex = currentFaceIndex;
+ indexInTriangle = physIndex - faceIndex;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+
+// we can't just regenerate the skinClothMap, because master/slave info is only available during authoring
+bool ClothingAssetImpl::mergeMapping(ClothingGraphicalLodParameters* graphicalLod)
+{
+ if (graphicalLod->immediateClothMap.buf == NULL)
+ return false;
+
+ ParamArray<uint32_t> immediateMap(graphicalLod, "immediateClothMap", reinterpret_cast<ParamDynamicArrayStruct*>(&graphicalLod->immediateClothMap));
+
+ // size of immediateMap (equals number of graphical vertices)
+ uint32_t immediateCount = (uint32_t)graphicalLod->immediateClothMap.arraySizes[0];
+
+ ParamArray<SkinClothMap> skinClothMap(graphicalLod, "skinClothMap",
+ reinterpret_cast<ParamDynamicArrayStruct*>(&graphicalLod->skinClothMap));
+
+ uint32_t oldSkinMapSize = skinClothMap.size();
+ skinClothMap.resize(immediateCount);
+
+ SkinClothMap* mapEntry = &skinClothMap[oldSkinMapSize];
+
+ // get RenderMeshAsset
+ ClothingGraphicalMeshAssetWrapper renderMesh(reinterpret_cast<RenderMeshAssetIntl*>(graphicalLod->renderMeshAssetPointer));
+ uint32_t numSubmeshes = renderMesh.getSubmeshCount();
+
+ ClothingPhysicalMeshParametersNS::PhysicalMesh_Type* physicalMesh = &mPhysicalMeshes[graphicalLod->physicalMeshId]->physicalMesh;
+ PX_ASSERT(physicalMesh != NULL);
+
+ // some updates for the case where we didn't have a skinClothMap yet
+ if (graphicalLod->skinClothMapThickness == 0.0f)
+ {
+ graphicalLod->skinClothMapThickness = 1.0f;
+ }
+ if (graphicalLod->skinClothMapOffset == 0.0f)
+ {
+ graphicalLod->skinClothMapOffset = DEFAULT_PM_OFFSET_ALONG_NORMAL_FACTOR * physicalMesh->averageEdgeLength;
+ }
+
+ uint32_t invalidCount = 0;
+
+ // iterate through immediate map, append verts to skinClothMap that are not yet in there
+ uint32_t mapVertIndex = 0;
+ for (uint32_t submeshIndex = 0; submeshIndex < numSubmeshes; ++submeshIndex)
+ {
+ RenderDataFormat::Enum outFormat;
+ const PxVec4* tangents = (const PxVec4*)renderMesh.getVertexBuffer(submeshIndex, RenderVertexSemantic::TANGENT, outFormat);
+ PX_ASSERT(tangents == NULL || outFormat == RenderDataFormat::FLOAT4);
+
+ const PxVec3* positions = (const PxVec3*)renderMesh.getVertexBuffer(submeshIndex, RenderVertexSemantic::POSITION, outFormat);
+ PX_ASSERT(positions == NULL || outFormat == RenderDataFormat::FLOAT3);
+
+ const PxVec3* normals = (const PxVec3*)renderMesh.getVertexBuffer(submeshIndex, RenderVertexSemantic::NORMAL, outFormat);
+ PX_ASSERT(normals == NULL || outFormat == RenderDataFormat::FLOAT3);
+
+ for (uint32_t submeshVertIndex = 0; submeshVertIndex < renderMesh.getNumVertices(submeshIndex); ++submeshVertIndex, ++mapVertIndex)
+ {
+ PX_ASSERT(mapVertIndex < immediateCount);
+
+ uint32_t physVertIndex = 0;
+ if (immediateMap[mapVertIndex] == ClothingConstants::ImmediateClothingInvalidValue)
+ {
+ ++invalidCount;
+ continue;
+ }
+
+ physVertIndex = immediateMap[mapVertIndex] & ClothingConstants::ImmediateClothingReadMask;
+
+ if ((immediateMap[mapVertIndex] & ClothingConstants::ImmediateClothingInSkinFlag) > 0)
+ {
+ // in that case physVertIndex is the index in the skinClothMap.
+ // set it to the current index, so we can sort it afterwards
+ skinClothMap[physVertIndex].vertexIndexPlusOffset = mapVertIndex;
+ continue;
+ }
+
+ // find triangle mapping
+ uint32_t faceIndex = UINT32_MAX;
+ uint32_t indexInTriangle = UINT32_MAX;
+ findTriangleForImmediateVertex(faceIndex, indexInTriangle, physVertIndex, *physicalMesh);
+
+ mapEntry->vertexIndex0 = physicalMesh->indices.buf[faceIndex + 0];
+ mapEntry->vertexIndex1 = physicalMesh->indices.buf[faceIndex + 1];
+ mapEntry->vertexIndex2 = physicalMesh->indices.buf[faceIndex + 2];
+
+ // for immediate skinned verts
+ // position, normal and tangent all have the same barycentric coord on the triangle
+ PxVec3 bary(0.0f);
+ if (indexInTriangle < 2)
+ {
+ bary[indexInTriangle] = 1.0f;
+ }
+
+ mapEntry->vertexBary = bary;
+ // mapEntry->vertexBary.z = 0 because it's on the triangle
+
+ // offset the normal
+ mapEntry->normalBary = bary;
+ mapEntry->normalBary.z = graphicalLod->skinClothMapOffset;
+
+ // we need to compute tangent bary's because there are no tangents on physical mesh
+ bary.x = bary.y = bary.z = UINT32_MAX;
+ if (positions != NULL && normals != NULL && tangents != NULL)
+ {
+ PxVec3 dummy(0.0f);
+ PxVec3 position = positions[submeshVertIndex];
+ PxVec3 tangent = tangents[submeshVertIndex].getXYZ();
+
+ // prepare triangle data
+ TriangleWithNormals triangle;
+ triangle.valid = 0;
+ triangle.faceIndex0 = faceIndex;
+ PxVec3* physNormals = physicalMesh->skinningNormals.buf;
+ if (physNormals == NULL)
+ {
+ physNormals = physicalMesh->normals.buf;
+ }
+ PX_ASSERT(physNormals != NULL);
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ uint32_t triVertIndex = physicalMesh->indices.buf[triangle.faceIndex0 + j];
+ triangle.vertices[j] = physicalMesh->vertices.buf[triVertIndex];
+ triangle.normals[j] = physNormals[triVertIndex];
+ }
+ triangle.init();
+
+ ModuleClothingHelpers::computeTriangleBarys(triangle, dummy, dummy, position + tangent, graphicalLod->skinClothMapOffset, 0, true);
+ mapEntry->tangentBary = triangle.tempBaryTangent;
+ }
+
+ mapEntry->vertexIndexPlusOffset = mapVertIndex;
+ mapEntry++;
+ }
+ }
+
+ skinClothMap.resize(skinClothMap.size() - invalidCount);
+
+ // make sure skinClothMap is sorted by graphical vertex order
+ nvidia::sort(graphicalLod->skinClothMap.buf, (uint32_t)graphicalLod->skinClothMap.arraySizes[0], SkinClothMapPredicate<ClothingGraphicalLodParametersNS::SkinClothMapD_Type>());
+
+ immediateMap.clear();
+
+ // notify actors of the asset change
+ for (uint32_t i = 0; i < getNumActors(); ++i)
+ {
+ ClothingActorImpl& actor = DYNAMIC_CAST(ClothingActorProxy*)(mActors.getResource(i))->impl;
+ actor.reinitActorData();
+ }
+
+ return true;
+}
+
+
+void ClothingAssetImpl::updateBoundingBox()
+{
+ PxBounds3 tempBounds;
+ tempBounds.setEmpty();
+
+ for (uint32_t graphicalMeshId = 0; graphicalMeshId < mGraphicalLods.size(); graphicalMeshId++)
+ {
+ if (mGraphicalLods[graphicalMeshId]->renderMeshAssetPointer == NULL)
+ continue;
+
+ RenderMeshAssetIntl* renderMeshAsset = reinterpret_cast<RenderMeshAssetIntl*>(mGraphicalLods[graphicalMeshId]->renderMeshAssetPointer);
+ for (uint32_t submeshIndex = 0; submeshIndex < renderMeshAsset->getSubmeshCount(); submeshIndex++)
+ {
+ const VertexBuffer& vb = renderMeshAsset->getInternalSubmesh(submeshIndex).getVertexBuffer();
+ const VertexFormat& vf = vb.getFormat();
+ uint32_t bufferIndex = (uint32_t)vf.getBufferIndexFromID(vf.getSemanticID(nvidia::apex::RenderVertexSemantic::POSITION));
+ RenderDataFormat::Enum positionFormat;
+ const PxVec3* pos = (const PxVec3*)vb.getBufferAndFormat(positionFormat, bufferIndex);
+ PX_ASSERT(positionFormat == nvidia::RenderDataFormat::FLOAT3);
+ const uint32_t numVertices = renderMeshAsset->getInternalSubmesh(submeshIndex).getVertexCount(0);
+ for (uint32_t i = 0; i < numVertices; i++)
+ {
+ tempBounds.include(pos[i]);
+ }
+ }
+ }
+ for (uint32_t i = 0; i < mPhysicalMeshes.size(); i++)
+ {
+ AbstractMeshDescription other;
+ other.pPosition = mPhysicalMeshes[i]->physicalMesh.vertices.buf;
+
+ for (uint32_t j = 0; j < other.numVertices; j++)
+ {
+ tempBounds.include(other.pPosition[j]);
+ }
+ }
+
+ mParams->boundingBox = tempBounds;
+}
+
+
+
+float ClothingAssetImpl::getMaxDistReduction(ClothingPhysicalMeshParameters& physicalMesh, float maxDistanceMultiplier) const
+{
+ return physicalMesh.physicalMesh.maximumMaxDistance * (1.0f - maxDistanceMultiplier);
+}
+
+
+
+#ifndef WITHOUT_PVD
+void ClothingAssetImpl::initPvdInstances(pvdsdk::PvdDataStream& pvdStream)
+{
+ ApexResourceInterface* pvdInstance = static_cast<ApexResourceInterface*>(this);
+
+ // Asset Params
+ pvdStream.createInstance(pvdsdk::NamespacedName(APEX_PVD_NAMESPACE, "ClothingAssetParameters"), mParams);
+ pvdStream.setPropertyValue(pvdInstance, "AssetParams", pvdsdk::DataRef<const uint8_t>((const uint8_t*)&mParams, sizeof(ClothingAssetParameters*)), pvdsdk::getPvdNamespacedNameForType<pvdsdk::ObjectRef>());
+
+ // update asset param properties (should we do this per frame? if so, how?)
+ pvdsdk::ApexPvdClient* client = GetInternalApexSDK()->getApexPvdClient();
+ PX_ASSERT(client != NULL);
+ client->updatePvd(mParams, *mParams);
+
+ mActors.initPvdInstances(pvdStream);
+}
+
+
+
+void ClothingAssetImpl::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(mParams, *mParams, pvdsdk::PvdAction::DESTROY);
+ pvdStream->destroyInstance(mParams);
+ }
+ }
+ }
+ }
+}
+#endif
+
+}
+} // namespace nvidia
+
+
diff --git a/APEX_1.4/module/clothing/src/ClothingCollisionImpl.cpp b/APEX_1.4/module/clothing/src/ClothingCollisionImpl.cpp
new file mode 100644
index 00000000..ea86b0d3
--- /dev/null
+++ b/APEX_1.4/module/clothing/src/ClothingCollisionImpl.cpp
@@ -0,0 +1,324 @@
+/*
+ * 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 "ClothingCollisionImpl.h"
+#include "ClothingActorImpl.h"
+
+using namespace nvidia;
+using namespace apex;
+using namespace clothing;
+
+
+ClothingCollisionImpl::ClothingCollisionImpl(ResourceList& list, ClothingActorImpl& owner) :
+mOwner(owner),
+mInRelease(false),
+mId(-1)
+{
+ list.add(*this);
+}
+
+
+void ClothingCollisionImpl::release()
+{
+ if (mInRelease)
+ return;
+ mInRelease = true;
+ mOwner.releaseCollision(*this);
+}
+
+
+void ClothingCollisionImpl::destroy()
+{
+ delete this;
+}
+
+
+void ClothingPlaneImpl::setPlane(const PxPlane& plane)
+{
+ mPlane = plane;
+ mOwner.notifyCollisionChange();
+}
+
+
+void ClothingSphereImpl::setPosition(const PxVec3& position)
+{
+ mPosition = position;
+ mOwner.notifyCollisionChange();
+}
+
+
+void ClothingSphereImpl::setRadius(float radius)
+{
+ mRadius = radius;
+ mOwner.notifyCollisionChange();
+}
+
+
+uint32_t ClothingTriangleMeshImpl::lockTriangles(const uint32_t** ids, const PxVec3** triangles)
+{
+ mLock.lock();
+ uint32_t numTriangles = mIds.size();
+ if (ids != NULL)
+ {
+ *ids = (numTriangles > 0) ? &mIds[0] : NULL;
+ }
+ if (triangles != NULL)
+ {
+ *triangles = (numTriangles > 0) ? &mTriangles[0] : NULL;
+ }
+ return numTriangles;
+};
+
+
+uint32_t ClothingTriangleMeshImpl::lockTrianglesWrite(const uint32_t** ids, PxVec3** triangles)
+{
+ mLock.lock();
+ uint32_t numTriangles = mIds.size();
+ if (ids != NULL)
+ {
+ *ids = (numTriangles > 0) ? &mIds[0] : NULL;
+ }
+ if (triangles != NULL)
+ {
+ *triangles = (numTriangles > 0) ? &mTriangles[0] : NULL;
+ }
+
+ mOwner.notifyCollisionChange();
+ return numTriangles;
+};
+
+
+void ClothingTriangleMeshImpl::unlockTriangles()
+{
+ mLock.unlock();
+};
+
+
+void ClothingTriangleMeshImpl::addTriangle(uint32_t id, const PxVec3& v0, const PxVec3& v1, const PxVec3& v2)
+{
+ mLock.lock();
+ ClothingTriangle& tri = mAddedTriangles.insert();
+ tri.v[0] = v0;
+ tri.v[1] = v1;
+ tri.v[2] = v2;
+ tri.id = id;
+ mLock.unlock();
+
+ mOwner.notifyCollisionChange();
+}
+
+
+void ClothingTriangleMeshImpl::addTriangles(const uint32_t* ids, const PxVec3* triangleVertices, uint32_t numTriangles)
+{
+ mLock.lock();
+ for (uint32_t i = 0; i < numTriangles; ++i)
+ {
+ ClothingTriangle& tri = mAddedTriangles.insert();
+ tri.v[0] = triangleVertices[3*i+0];
+ tri.v[1] = triangleVertices[3*i+1];
+ tri.v[2] = triangleVertices[3*i+2];
+ tri.id = ids[i];
+ }
+ mLock.unlock();
+
+ mOwner.notifyCollisionChange();
+}
+
+
+void ClothingTriangleMeshImpl::removeTriangle(uint32_t id)
+{
+ mLock.lock();
+ mRemoved.pushBack(id);
+ mLock.unlock();
+
+ mOwner.notifyCollisionChange();
+}
+
+
+void ClothingTriangleMeshImpl::removeTriangles(const uint32_t* ids, uint32_t numTriangles)
+{
+ mLock.lock();
+ mRemoved.reserve(mRemoved.size() + numTriangles);
+ for (uint32_t i = 0; i < numTriangles; ++i)
+ {
+ mRemoved.pushBack(ids[i]);
+ }
+ mLock.unlock();
+
+ mOwner.notifyCollisionChange();
+}
+
+
+void ClothingTriangleMeshImpl::clearTriangles()
+{
+ mLock.lock();
+ mTriangles.clear();
+ mIds.clear();
+ mLock.unlock();
+
+ mOwner.notifyCollisionChange();
+}
+
+
+void ClothingTriangleMeshImpl::setPose(PxMat44 pose)
+{
+ mPose = pose;
+
+ mOwner.notifyCollisionChange();
+}
+
+
+void ClothingTriangleMeshImpl::sortAddAndRemoves()
+{
+ if (mRemoved.size() > 1)
+ {
+ nvidia::sort<uint32_t>(&mRemoved[0], mRemoved.size());
+ }
+
+ if (mAddedTriangles.size() > 1)
+ {
+ nvidia::sort<ClothingTriangle>(&mAddedTriangles[0], mAddedTriangles.size());
+ }
+}
+
+
+void ClothingTriangleMeshImpl::update(const PxTransform& tm, const nvidia::Array<PxVec3>& allTrianglesOld, nvidia::Array<PxVec3>& allTrianglesOldTemp, nvidia::Array<PxVec3>& allTriangles)
+{
+ Array<PxVec3> trianglesOldTemp;
+ Array<PxVec3> trianglesTemp;
+ Array<uint32_t> idsTemp;
+
+ mLock.lock();
+
+ // sort all arrays to keep increasing id order
+ sortAddAndRemoves();
+
+ uint32_t triIdx = 0;
+ uint32_t numTriangles = mIds.size();
+
+ uint32_t removedIdx = 0;
+ uint32_t numRemoved = mRemoved.size();
+
+ uint32_t addedIdx = 0;
+ uint32_t numAdded = mAddedTriangles.size();
+
+ while (triIdx < numTriangles || removedIdx < numRemoved || addedIdx < numAdded)
+ {
+ PX_ASSERT(allTriangles.size() % 3 == 0);
+ PX_ASSERT(allTrianglesOldTemp.size() % 3 == 0);
+
+ uint32_t triangleId = (triIdx < numTriangles) ? mIds[triIdx] : UINT32_MAX;
+ uint32_t removedId = (removedIdx < numRemoved) ? mRemoved[removedIdx] : UINT32_MAX;
+ uint32_t addedId = (addedIdx < numAdded) ? mAddedTriangles[addedIdx].id : UINT32_MAX;
+
+ if (triangleId < removedId && triangleId <= addedId)
+ {
+ // handle existing triangle
+
+ // when a triangle with an already existing id is added, just update the value
+ PxVec3* v[3];
+ if (addedId == triangleId)
+ {
+ // new values from addTriangle
+ v[0] = &mAddedTriangles[addedIdx].v[0];
+ v[1] = &mAddedTriangles[addedIdx].v[1];
+ v[2] = &mAddedTriangles[addedIdx].v[2];
+ ++addedIdx;
+ }
+ else
+ {
+ // old values or edited values from lockTrianglesWrite
+ v[0] = &mTriangles[3*triIdx+0];
+ v[1] = &mTriangles[3*triIdx+1];
+ v[2] = &mTriangles[3*triIdx+2];
+ }
+ PxVec3 vGlobal[3] = {tm.transform(*v[0]), tm.transform(*v[1]), tm.transform(*v[2])};
+
+ // update triangle collision object with local triangle position
+ trianglesTemp.pushBack(*v[0]);
+ trianglesTemp.pushBack(*v[1]);
+ trianglesTemp.pushBack(*v[2]);
+ idsTemp.pushBack(mIds[triIdx]);
+
+ // write global triangle pos from last frame.
+ // mId contains the offset in the global triangles array
+ if (mId >= 0 && mId < (int32_t)allTrianglesOld.size())
+ {
+ allTrianglesOldTemp.pushBack(allTrianglesOld[mId + 3*triIdx+0]);
+ allTrianglesOldTemp.pushBack(allTrianglesOld[mId + 3*triIdx+1]);
+ allTrianglesOldTemp.pushBack(allTrianglesOld[mId + 3*triIdx+2]);
+ }
+ else
+ {
+ // if we cannot access an old buffer (e.g. when the simulation has changed)
+ // we just use the current pos as old pos as well
+ allTrianglesOldTemp.pushBack(vGlobal[0]);
+ allTrianglesOldTemp.pushBack(vGlobal[1]);
+ allTrianglesOldTemp.pushBack(vGlobal[2]);
+ }
+
+ // update internal global array
+ allTriangles.pushBack(vGlobal[0]);
+ allTriangles.pushBack(vGlobal[1]);
+ allTriangles.pushBack(vGlobal[2]);
+ ++triIdx;
+ }
+ else if (addedId < removedId)
+ {
+ // handle new triangle
+
+ // update triangle collision object with local triangle position
+ trianglesTemp.pushBack(mAddedTriangles[addedIdx].v[0]);
+ trianglesTemp.pushBack(mAddedTriangles[addedIdx].v[1]);
+ trianglesTemp.pushBack(mAddedTriangles[addedIdx].v[2]);
+ idsTemp.pushBack(addedId);
+
+ // set old and new positions in global array
+ PxVec3 v[3] = {tm.transform(mAddedTriangles[addedIdx].v[0]), tm.transform(mAddedTriangles[addedIdx].v[1]), tm.transform(mAddedTriangles[addedIdx].v[2])};
+ allTrianglesOldTemp.pushBack(v[0]);
+ allTrianglesOldTemp.pushBack(v[1]);
+ allTrianglesOldTemp.pushBack(v[2]);
+ allTriangles.pushBack(v[0]);
+ allTriangles.pushBack(v[1]);
+ allTriangles.pushBack(v[2]);
+ ++addedIdx;
+ }
+ else
+ {
+ // handle removal
+
+ ++removedIdx;
+ if (removedId == triangleId)
+ {
+ // an existing triangle was removed
+ ++triIdx;
+ }
+ if (removedId == addedId)
+ {
+ // a newly added triangle is also removed
+ ++addedIdx;
+ }
+ }
+
+ }
+
+ mTriangles.swap(trianglesTemp);
+ mIds.swap(idsTemp);
+
+ mRemoved.clear();
+ mAddedTriangles.clear();
+
+ mLock.unlock();
+
+ // use id to store the offset in the global triangles arrays
+ PX_ASSERT(allTriangles.size() % 3 == 0);
+ mId = (int32_t)allTriangles.size() - (int32_t)mTriangles.size();
+} \ No newline at end of file
diff --git a/APEX_1.4/module/clothing/src/ClothingCooking.cpp b/APEX_1.4/module/clothing/src/ClothingCooking.cpp
new file mode 100644
index 00000000..00950e85
--- /dev/null
+++ b/APEX_1.4/module/clothing/src/ClothingCooking.cpp
@@ -0,0 +1,163 @@
+/*
+ * 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 "ClothingCooking.h"
+#include "PsMemoryBuffer.h"
+#include "ParamArray.h"
+
+#include "CookingAbstract.h"
+
+#include "ClothingScene.h"
+
+#include "PsAtomic.h"
+
+namespace nvidia
+{
+namespace clothing
+{
+
+void ClothingCookingLock::lockCooking()
+{
+ atomicIncrement(&mNumCookingDependencies);
+}
+
+
+void ClothingCookingLock::unlockCooking()
+{
+ atomicDecrement(&mNumCookingDependencies);
+}
+
+
+ClothingCookingTask::ClothingCookingTask(ClothingScene* clothingScene, CookingAbstract& _job) : job(&_job), nextTask(NULL),
+ mState(Uninit), mClothingScene(clothingScene), mResult(NULL), mLockedObject(NULL)
+{
+ PX_ASSERT(((size_t)(void*)(&mState) & 0x00000003) == 0); // check alignment, mState must be aligned for the atomic exchange operations
+
+ PX_ASSERT(job != NULL);
+}
+
+
+ClothingCookingTask::~ClothingCookingTask()
+{
+ if (job != NULL)
+ {
+ PX_DELETE_AND_RESET(job);
+ }
+}
+
+
+void ClothingCookingTask::initCooking(PxTaskManager& tm, PxBaseTask* c)
+{
+ PxLightCpuTask::setContinuation(tm, c);
+
+ int32_t oldState = atomicCompareExchange((int32_t*)(&mState), WaitForRun, Uninit);
+ PX_ASSERT(oldState == Uninit);
+ PX_UNUSED(oldState);
+}
+
+
+void ClothingCookingTask::run()
+{
+ // run
+ NvParameterized::Interface* result = NULL;
+ int32_t oldState = atomicCompareExchange((int32_t*)(&mState), Running, WaitForRun);
+ PX_ASSERT(oldState != ReadyForRelease && oldState != Aborting && oldState != WaitForFetch);
+ if (oldState == WaitForRun) // the change was successful
+ {
+ result = job->execute();
+ }
+
+ unlockObject();
+
+ // try to run the next task. Must be called before in a state where it will be deleted
+ mClothingScene->submitCookingTask(NULL);
+
+ // finished
+ oldState = atomicCompareExchange((int32_t*)(&mState), WaitForFetch, Running);
+ if (oldState == Running)
+ {
+ mResult = result;
+ }
+ else
+ {
+ if (result != NULL)
+ {
+ result->destroy();
+ result = NULL;
+ }
+ atomicExchange((int32_t*)(&mState), ReadyForRelease);
+ PX_ASSERT(mResult == NULL);
+ }
+}
+
+NvParameterized::Interface* ClothingCookingTask::getResult()
+{
+ if (mResult != NULL)
+ {
+ int32_t oldState = atomicCompareExchange((int32_t*)(&mState), ReadyForRelease, WaitForFetch);
+ PX_ASSERT(oldState == WaitForFetch);
+ PX_UNUSED(oldState);
+ return mResult;
+ }
+ return NULL;
+}
+
+void ClothingCookingTask::lockObject(ClothingCookingLock* lockedObject)
+{
+ if (mLockedObject != NULL)
+ {
+ mLockedObject->unlockCooking();
+ }
+
+ mLockedObject = lockedObject;
+ if (mLockedObject != NULL)
+ {
+ mLockedObject->lockCooking();
+ }
+}
+
+void ClothingCookingTask::unlockObject()
+{
+ if (mLockedObject != NULL)
+ {
+ mLockedObject->unlockCooking();
+ mLockedObject = NULL;
+ }
+}
+
+void ClothingCookingTask::abort()
+{
+ int32_t oldState = atomicExchange((int32_t*)(&mState), Aborting);
+ PX_ASSERT(oldState >= WaitForRun);
+ if (oldState == WaitForFetch)
+ {
+ atomicExchange((int32_t*)(&mState), ReadyForRelease);
+ if (mResult != NULL)
+ {
+ NvParameterized::Interface* oldParam = mResult;
+ mResult = NULL;
+ oldParam->destroy();
+ }
+ unlockObject();
+ }
+ else if (oldState != Running)
+ {
+ PX_ASSERT(mResult == NULL);
+ atomicExchange((int32_t*)(&mState), ReadyForRelease);
+ unlockObject();
+ }
+}
+
+}
+}
+
diff --git a/APEX_1.4/module/clothing/src/ClothingPhysicalMeshImpl.cpp b/APEX_1.4/module/clothing/src/ClothingPhysicalMeshImpl.cpp
new file mode 100644
index 00000000..538a7e1a
--- /dev/null
+++ b/APEX_1.4/module/clothing/src/ClothingPhysicalMeshImpl.cpp
@@ -0,0 +1,1576 @@
+/*
+ * 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 "ClothingPhysicalMeshImpl.h"
+#include "ApexMeshHash.h"
+#include "ApexQuadricSimplifier.h"
+#include "ClothingAssetAuthoringImpl.h"
+#include "ModuleClothingImpl.h"
+
+#include "ApexPermute.h"
+#include "ApexSharedUtils.h"
+
+#include "PxStrideIterator.h"
+#include "PsMathUtils.h"
+#include "PsSort.h"
+
+namespace nvidia
+{
+namespace clothing
+{
+
+struct SortedEdge
+{
+ SortedEdge(uint32_t _i0, uint32_t _i1) : i0(PxMin(_i0, _i1)), i1(PxMax(_i0, _i1)) {}
+
+ bool operator==(const SortedEdge& other) const
+ {
+ return i0 == other.i0 && i1 == other.i1;
+ }
+ bool operator()(const SortedEdge& s1, const SortedEdge& s2) const
+ {
+ if (s1.i0 != s2.i0)
+ {
+ return s1.i0 < s2.i0;
+ }
+
+ return s1.i1 < s2.i1;
+ }
+
+ uint32_t i0, i1;
+};
+
+ClothingPhysicalMeshImpl::ClothingPhysicalMeshImpl(ModuleClothingImpl* module, ClothingPhysicalMeshParameters* params, ResourceList* list) :
+ mModule(module),
+ mParams(NULL),
+ ownsParams(false),
+ mSimplifier(NULL),
+ isDirty(false)
+{
+ if (params != NULL && nvidia::strcmp(params->className(), ClothingPhysicalMeshParameters::staticClassName()) != 0)
+ {
+ APEX_INTERNAL_ERROR(
+ "The parameterized interface is of type <%s> instead of <%s>. "
+ "An empty ClothingPhhsicalMesh has been created instead.",
+ params->className(),
+ ClothingPhysicalMeshParameters::staticClassName());
+
+ params = NULL;
+ }
+
+ if (params == NULL)
+ {
+ params = DYNAMIC_CAST(ClothingPhysicalMeshParameters*)(GetInternalApexSDK()->getParameterizedTraits()->createNvParameterized(ClothingPhysicalMeshParameters::staticClassName()));
+ ownsParams = true;
+ }
+ PX_ASSERT(params != NULL);
+
+ mParams = params;
+ mVertices.init(mParams, "physicalMesh.vertices", reinterpret_cast<ParamDynamicArrayStruct*>(&mParams->physicalMesh.vertices));
+ mNormals.init(mParams, "physicalMesh.normals", reinterpret_cast<ParamDynamicArrayStruct*>(&mParams->physicalMesh.normals));
+ mSkinningNormals.init(mParams, "physicalMesh.skinningNormals", reinterpret_cast<ParamDynamicArrayStruct*>(&mParams->physicalMesh.skinningNormals));
+ mConstrainCoefficients.init(mParams, "physicalMesh.constrainCoefficients", reinterpret_cast<ParamDynamicArrayStruct*>(&mParams->physicalMesh.constrainCoefficients));
+ mBoneIndices.init(mParams, "physicalMesh.boneIndices", reinterpret_cast<ParamDynamicArrayStruct*>(&mParams->physicalMesh.boneIndices));
+ mBoneWeights.init(mParams, "physicalMesh.boneWeights", reinterpret_cast<ParamDynamicArrayStruct*>(&mParams->physicalMesh.boneWeights));
+ mIndices.init(mParams, "physicalMesh.indices", reinterpret_cast<ParamDynamicArrayStruct*>(&mParams->physicalMesh.indices));
+
+ mNumSimulatedVertices = mParams->physicalMesh.numSimulatedVertices;
+ mNumMaxDistanc0Vertices = mParams->physicalMesh.numMaxDistance0Vertices;
+ mNumSimulatedIndices = mParams->physicalMesh.numSimulatedIndices;
+
+ mParams->referenceCount++;
+
+ mParams->setSerializationCallback(this);
+#if 0
+ // debugging only
+ char buf[32];
+ sprintf_s(buf, 32, "++ %p -> %d\n", mParams, mParams->referenceCount);
+ OutputDebugString(buf);
+#endif
+
+ if (mParams->physicalMesh.shortestEdgeLength == 0.0f)
+ {
+ computeEdgeLengths();
+ }
+
+ list->add(*this);
+}
+
+
+
+void ClothingPhysicalMeshImpl::release()
+{
+ PX_ASSERT(mParams != NULL);
+ if (mParams != NULL)
+ {
+ // make sure everything is set up correctly before we let the param object live on its own
+ preSerialize(NULL);
+
+ mParams->setSerializationCallback(NULL);
+ }
+ mModule->releasePhysicalMesh(this);
+}
+
+
+
+void ClothingPhysicalMeshImpl::destroy()
+{
+ if (mSimplifier != NULL)
+ {
+ delete mSimplifier;
+ mSimplifier = NULL;
+ }
+
+ if (mParams != NULL)
+ {
+ mParams->referenceCount--;
+#if 0
+ // debugging only
+ char buf[32];
+ sprintf_s(buf, 32, "-- %p -> %d\n", mParams, mParams->referenceCount);
+ OutputDebugString(buf);
+#endif
+ }
+
+ if (ownsParams && mParams)
+ {
+ PX_ASSERT(mParams->referenceCount == 0);
+ mParams->destroy();
+ }
+
+ delete this;
+}
+
+
+
+void ClothingPhysicalMeshImpl::makeCopy(ClothingPhysicalMeshParameters* params)
+{
+ PX_ASSERT(mParams != NULL);
+ params->copy(*mParams);
+}
+
+
+
+void ClothingPhysicalMeshImpl::allocateNormalBuffer()
+{
+ mNormals.resize(mParams->physicalMesh.numVertices);
+}
+
+
+
+void ClothingPhysicalMeshImpl::allocateSkinningNormalsBuffer()
+{
+ mSkinningNormals.resize(mParams->physicalMesh.numVertices);
+}
+
+
+void ClothingPhysicalMeshImpl::allocateMasterFlagsBuffer()
+{
+ uint32_t numVertices = mVertices.size();
+ mMasterFlags.resize(numVertices);
+
+ for (uint32_t i = 0; i < numVertices; i++)
+ {
+ mMasterFlags[i] = 0xffffffff;
+ }
+}
+
+
+void ClothingPhysicalMeshImpl::allocateConstrainCoefficientBuffer()
+{
+ WRITE_ZONE();
+ const uint32_t numVertices = mParams->physicalMesh.numVertices;
+ mConstrainCoefficients.resize(numVertices);
+
+ for (uint32_t i = 0; i < numVertices; i++)
+ {
+ mConstrainCoefficients[i].maxDistance = PX_MAX_F32;
+ mConstrainCoefficients[i].collisionSphereRadius = PX_MAX_F32;
+ mConstrainCoefficients[i].collisionSphereDistance = PX_MAX_F32;
+ }
+}
+
+
+
+void ClothingPhysicalMeshImpl::allocateBoneIndexAndWeightBuffers()
+{
+ const uint32_t numBonesPerVertex = mParams->physicalMesh.numBonesPerVertex;
+ if (numBonesPerVertex == 0)
+ {
+ APEX_DEBUG_WARNING("Number of bones per vertex is set to 0. Not allocating memory.");
+ return;
+ }
+ const uint32_t numVertices = mParams->physicalMesh.numVertices;
+
+ mBoneIndices.resize(numBonesPerVertex * numVertices);
+
+ // PH: At one point we can start trying to safe this buffer
+ //if (numBonesPerVertex > 1)
+ {
+ mBoneWeights.resize(numBonesPerVertex * numVertices);
+ }
+}
+
+
+
+void ClothingPhysicalMeshImpl::freeAdditionalBuffers()
+{
+
+ mNormals.resize(0);
+ mSkinningNormals.resize(0);
+ mConstrainCoefficients.resize(0);
+ mBoneIndices.resize(0);
+ mBoneWeights.resize(0);
+ mParams->physicalMesh.numBonesPerVertex = 0;
+}
+
+
+
+uint32_t ClothingPhysicalMeshImpl::getNumVertices() const
+{
+ READ_ZONE();
+ if (mSimplifier != NULL)
+ {
+ return mSimplifier->getNumVertices() - mSimplifier->getNumDeletedVertices();
+ }
+
+ return mParams->physicalMesh.numVertices;
+}
+
+
+
+uint32_t ClothingPhysicalMeshImpl::getNumSimulatedVertices() const
+{
+ READ_ZONE();
+ return mParams->physicalMesh.numSimulatedVertices;
+}
+
+
+
+uint32_t ClothingPhysicalMeshImpl::getNumMaxDistance0Vertices() const
+{
+ READ_ZONE();
+ return mParams->physicalMesh.numMaxDistance0Vertices;
+}
+
+
+
+uint32_t ClothingPhysicalMeshImpl::getNumIndices() const
+{
+ READ_ZONE();
+ if (mSimplifier != NULL)
+ {
+ return mSimplifier->getNumTriangles() * 3;
+ }
+
+ return mParams->physicalMesh.numIndices;
+}
+
+
+
+uint32_t ClothingPhysicalMeshImpl::getNumSimulatedIndices() const
+{
+ READ_ZONE();
+ if (mSimplifier != NULL)
+ {
+ return mSimplifier->getNumTriangles() * 3;
+ }
+
+ return mParams->physicalMesh.numSimulatedIndices;
+}
+
+
+
+void ClothingPhysicalMeshImpl::getIndices(void* indexDestination, uint32_t byteStride, uint32_t numIndices) const
+{
+ READ_ZONE();
+ numIndices = PxMin(numIndices, mParams->physicalMesh.numIndices);
+
+ if (byteStride == 0)
+ {
+ byteStride = sizeof(uint32_t);
+ }
+
+ if (byteStride < sizeof(uint32_t))
+ {
+ APEX_INTERNAL_ERROR("byte stride is too small (%d)", byteStride);
+ return;
+ }
+
+ const_cast<ClothingPhysicalMeshImpl*>(this)->writeBackData();
+
+ uint8_t* destPtr = (uint8_t*)indexDestination;
+ for (uint32_t i = 0; i < numIndices; i++)
+ {
+ (uint32_t&)(*(destPtr + byteStride * i)) = mIndices[i];
+ }
+}
+
+
+
+void ClothingPhysicalMeshImpl::simplify(uint32_t subdivisions, int32_t maxSteps, float maxError, IProgressListener* progressListener)
+{
+ WRITE_ZONE();
+ if (mParams->physicalMesh.isTetrahedralMesh)
+ {
+ APEX_INVALID_OPERATION("Cannot simplify a tetrahedral mesh");
+ return;
+ }
+
+ if (mParams->physicalMesh.boneIndices.buf != NULL || mParams->physicalMesh.boneWeights.buf != NULL)
+ {
+ APEX_INVALID_OPERATION("Cannot simplif a triangle mesh with additional bone data");
+ return;
+ }
+
+
+ const uint32_t numVertices = mParams->physicalMesh.numVertices;
+ const uint32_t numIndices = mParams->physicalMesh.numIndices;
+
+ if (numVertices == 0 || numIndices == 0)
+ {
+ return;
+ }
+
+ HierarchicalProgressListener progress(100, progressListener);
+
+ if (mSimplifier == NULL)
+ {
+ progress.setSubtaskWork(80, "Init simplificator");
+ mSimplifier = PX_NEW(ApexQuadricSimplifier);
+
+ for (uint32_t i = 0; i < numVertices; i++)
+ {
+ mSimplifier->registerVertex(mVertices[i]);
+ }
+
+ for (uint32_t i = 0; i < numIndices; i += 3)
+ {
+ mSimplifier->registerTriangle(mIndices[i + 0], mIndices[i + 1], mIndices[i + 2]);
+ }
+
+ mSimplifier->endRegistration(false, &progress);
+ progress.completeSubtask();
+ }
+
+ progress.setSubtaskWork(-1, "Simplification steps");
+
+ uint32_t steps = mSimplifier->simplify(subdivisions, maxSteps, maxError, &progress);
+
+ if (!isDirty)
+ {
+ isDirty = steps > 0;
+ }
+
+ progress.completeSubtask();
+}
+
+
+
+void ClothingPhysicalMeshImpl::setGeometry(bool tetraMesh, uint32_t numVertices, uint32_t vertexByteStride, const void* vertices,
+ const uint32_t* masterFlags, uint32_t numIndices, uint32_t indexByteStride, const void* indices)
+{
+ WRITE_ZONE();
+ if (vertexByteStride < sizeof(PxVec3))
+ {
+ APEX_INTERNAL_ERROR("vertexByteStride is too small (%d)", vertexByteStride);
+ return;
+ }
+
+ if (indexByteStride < sizeof(uint32_t))
+ {
+ APEX_INTERNAL_ERROR("indexByteStride is too small (%d)", indexByteStride);
+ return;
+ }
+
+ if (numVertices > 0 && vertices == NULL)
+ {
+ APEX_INTERNAL_ERROR("vertex pointer is NULL");
+ return;
+ }
+
+ if (numIndices > 0 && indices == NULL)
+ {
+ APEX_INTERNAL_ERROR("index pointer is NULL");
+ return;
+ }
+
+ if (tetraMesh && (numIndices % 4 != 0))
+ {
+ APEX_INTERNAL_ERROR("Indices must be a multiple of 4 for physical tetrahedral meshes");
+ return;
+ }
+
+ if (!tetraMesh && (numIndices % 3 != 0))
+ {
+ APEX_INTERNAL_ERROR("Indices must be a multiple of 3 for physical meshes");
+ return;
+ }
+
+ mParams->physicalMesh.isTetrahedralMesh = tetraMesh;
+
+ mParams->physicalMesh.numVertices = numVertices;
+ mParams->physicalMesh.numSimulatedVertices = numVertices;
+ mParams->physicalMesh.numMaxDistance0Vertices = 0;
+
+ mVertices.resize(numVertices);
+ mMasterFlags.resize(numVertices);
+
+ mNormals.resize(0);
+ mSkinningNormals.resize(0);
+
+ const uint8_t* srcVertices = (const uint8_t*)vertices;
+ for (uint32_t i = 0; i < numVertices; i++)
+ {
+ const PxVec3& currVec = *(const PxVec3*)(srcVertices + vertexByteStride * i);
+ mVertices[i] = currVec;
+
+ mMasterFlags[i] = masterFlags != NULL ? masterFlags[i] : 0xffffffff;
+ }
+
+
+ if (tetraMesh || !removeDuplicatedTriangles(numIndices, indexByteStride, indices))
+ {
+ mParams->physicalMesh.numIndices = numIndices;
+ mParams->physicalMesh.numSimulatedIndices = numIndices;
+ mIndices.resize(numIndices);
+
+ const uint8_t* srcIndices = (const uint8_t*)indices;
+ for (uint32_t i = 0; i < numIndices; i++)
+ {
+ const uint32_t currIndex = *(const uint32_t*)(srcIndices + indexByteStride * i);
+ mIndices[i] = currIndex;
+ }
+ }
+
+ if (mSimplifier != NULL)
+ {
+ delete mSimplifier;
+ mSimplifier = NULL;
+ }
+
+ clearMiscBuffers();
+ computeEdgeLengths();
+
+ if (!mParams->physicalMesh.isTetrahedralMesh)
+ {
+ mSkinningNormals.resize(numVertices);
+ updateSkinningNormals();
+ }
+}
+
+
+
+bool ClothingPhysicalMeshImpl::getIndices(uint32_t* indices, uint32_t byteStride) const
+{
+ READ_ZONE();
+ if (mIndices.size() == 0)
+ {
+ return false;
+ }
+
+ if (byteStride == 0)
+ {
+ byteStride = sizeof(uint32_t);
+ }
+
+ if (byteStride < sizeof(uint32_t))
+ {
+ APEX_INTERNAL_ERROR("bytestride too small (%d)", byteStride);
+ return false;
+ }
+
+ const_cast<ClothingPhysicalMeshImpl*>(this)->writeBackData();
+
+ const uint32_t numIndices = mParams->physicalMesh.numIndices;
+
+ PxStrideIterator<uint32_t> iterator(indices, byteStride);
+ for (uint32_t i = 0; i < numIndices; i++, ++iterator)
+ {
+ *iterator = mIndices[i];
+ }
+
+ return true;
+}
+
+
+
+bool ClothingPhysicalMeshImpl::getVertices(PxVec3* vertices, uint32_t byteStride) const
+{
+ READ_ZONE();
+ if (mVertices.size() == 0)
+ {
+ return false;
+ }
+
+ if (byteStride == 0)
+ {
+ byteStride = sizeof(PxVec3);
+ }
+
+ if (byteStride < sizeof(PxVec3))
+ {
+ APEX_INTERNAL_ERROR("bytestride too small (%d)", byteStride);
+ return false;
+ }
+
+ const_cast<ClothingPhysicalMeshImpl*>(this)->writeBackData();
+
+ const uint32_t numVertices = mParams->physicalMesh.numVertices;
+
+ PxStrideIterator<PxVec3> iterator(vertices, byteStride);
+ for (uint32_t i = 0; i < numVertices; i++, ++iterator)
+ {
+ *iterator = mVertices[i];
+ }
+
+ return true;
+}
+
+
+
+bool ClothingPhysicalMeshImpl::getNormals(PxVec3* normals, uint32_t byteStride) const
+{
+ READ_ZONE();
+ if (mNormals.size() == 0)
+ {
+ return false;
+ }
+
+ if (byteStride == 0)
+ {
+ byteStride = sizeof(PxVec3);
+ }
+
+ if (byteStride < sizeof(PxVec3))
+ {
+ APEX_INTERNAL_ERROR("bytestride too small (%d)", byteStride);
+ return false;
+ }
+
+ const_cast<ClothingPhysicalMeshImpl*>(this)->writeBackData();
+
+ const uint32_t numVertices = mParams->physicalMesh.numVertices;
+
+ PxStrideIterator<PxVec3> iterator(normals, byteStride);
+ for (uint32_t i = 0; i < numVertices; i++, ++iterator)
+ {
+ *iterator = mNormals[i];
+ }
+
+ return true;
+}
+
+
+
+bool ClothingPhysicalMeshImpl::getBoneIndices(uint16_t* boneIndices, uint32_t byteStride) const
+{
+ READ_ZONE();
+ if (mBoneIndices.size() == 0)
+ {
+ return false;
+ }
+
+ const uint32_t numBonesPerVertex = mParams->physicalMesh.numBonesPerVertex;
+ if (byteStride == 0)
+ {
+ byteStride = numBonesPerVertex * sizeof(uint16_t);
+ }
+
+ if (byteStride < numBonesPerVertex * sizeof(uint16_t))
+ {
+ APEX_INTERNAL_ERROR("bytestride too small (%d)", byteStride);
+ return false;
+ }
+
+ const uint32_t numElements = mParams->physicalMesh.numVertices * numBonesPerVertex;
+
+ PxStrideIterator<uint16_t> iterator(boneIndices, byteStride);
+ for (uint32_t i = 0; i < numElements; i += numBonesPerVertex, ++iterator)
+ {
+ for (uint32_t j = 0; j < numBonesPerVertex; j++)
+ {
+ uint16_t* current = iterator.ptr();
+ current[j] = mBoneIndices[i + j];
+ }
+ }
+
+ return true;
+}
+
+
+
+bool ClothingPhysicalMeshImpl::getBoneWeights(float* boneWeights, uint32_t byteStride) const
+{
+ READ_ZONE();
+ if (mBoneWeights.size() == 0)
+ {
+ return false;
+ }
+
+ const uint32_t numBonesPerVertex = mParams->physicalMesh.numBonesPerVertex;
+ if (byteStride == 0)
+ {
+ byteStride = numBonesPerVertex * sizeof(float);
+ }
+
+ if (byteStride < numBonesPerVertex * sizeof(float))
+ {
+ APEX_INTERNAL_ERROR("bytestride too small (%d)", byteStride);
+ return false;
+ }
+
+ const_cast<ClothingPhysicalMeshImpl*>(this)->writeBackData();
+
+ const uint32_t numElements = mParams->physicalMesh.numVertices * numBonesPerVertex;
+
+ PxStrideIterator<float> iterator(boneWeights, byteStride);
+ for (uint32_t i = 0; i < numElements; i += numBonesPerVertex, ++iterator)
+ {
+ for (uint32_t j = 0; j < numBonesPerVertex; j++)
+ {
+ float* current = iterator.ptr();
+ current[j] = mBoneWeights[i + j];
+ }
+ }
+
+
+ return true;
+}
+
+
+
+bool ClothingPhysicalMeshImpl::getConstrainCoefficients(ClothingConstrainCoefficients* coeffs, uint32_t byteStride) const
+{
+ READ_ZONE();
+ if (mConstrainCoefficients.size() == 0)
+ {
+ return false;
+ }
+
+ if (byteStride == 0)
+ {
+ byteStride = sizeof(ClothingConstrainCoefficients);
+ }
+
+ if (byteStride < sizeof(ClothingConstrainCoefficients))
+ {
+ APEX_INTERNAL_ERROR("bytestride too small (%d)", byteStride);
+ return false;
+ }
+
+ const_cast<ClothingPhysicalMeshImpl*>(this)->writeBackData();
+
+ const uint32_t numVertices = mParams->physicalMesh.numVertices;
+
+ PxStrideIterator<ClothingConstrainCoefficients> iterator(coeffs, byteStride);
+ for (uint32_t i = 0; i < numVertices; i++, ++iterator)
+ {
+ iterator->maxDistance = mConstrainCoefficients[i].maxDistance;
+ iterator->collisionSphereDistance = mConstrainCoefficients[i].collisionSphereDistance;
+ iterator->collisionSphereRadius = mConstrainCoefficients[i].collisionSphereRadius;
+ }
+
+ return true;
+}
+
+
+
+void ClothingPhysicalMeshImpl::getStats(ClothingPhysicalMeshStats& stats) const
+{
+ READ_ZONE();
+ memset(&stats, 0, sizeof(ClothingPhysicalMeshStats));
+
+ stats.totalBytes = sizeof(ClothingPhysicalMeshImpl);
+
+ /*
+
+ stats.numVertices = mNumVertices;
+ stats.numIndices = mNumIndices;
+
+ stats.totalBytes += (mVertices != NULL ? mNumVertices : 0) * sizeof(PxVec3);
+ stats.totalBytes += (mNormals != NULL ? mNumVertices : 0) * sizeof(PxVec3);
+ stats.totalBytes += (mSkinningNormals != NULL ? mNumVertices : 0) * sizeof(PxVec3);
+ stats.totalBytes += (mVertexFlags != NULL ? mNumVertices : 0) * sizeof(uint32_t);
+ stats.totalBytes += (mConstrainCoefficients != NULL ? mNumVertices : 0) * sizeof(ClothConstrainCoefficients);
+
+ stats.totalBytes += (mBoneIndices != NULL ? mNumVertices * mNumBonesPerVertex : 0) * sizeof(uint16_t);
+ stats.totalBytes += (mBoneWeights != NULL ? mNumVertices * mNumBonesPerVertex : 0) * sizeof(float);
+
+ stats.totalBytes += (mIndices != NULL ? mNumIndices : 0) * sizeof(uint32_t);
+ */
+}
+
+
+
+void ClothingPhysicalMeshImpl::writeBackData()
+{
+ if (!isDirty || mSimplifier == NULL)
+ {
+ return;
+ }
+
+ isDirty = false;
+
+ Array<int32_t> old2new(mSimplifier->getNumVertices());
+
+ PX_ASSERT(mSimplifier->getNumVertices() - mSimplifier->getNumDeletedVertices() < mParams->physicalMesh.numVertices);
+
+ uint32_t verticesWritten = 0;
+ for (uint32_t i = 0; i < mSimplifier->getNumVertices(); i++)
+ {
+ PxVec3 pos;
+ if (mSimplifier->getVertexPosition(i, pos))
+ {
+ old2new[i] = (int32_t)verticesWritten;
+ mVertices[verticesWritten++] = pos;
+ }
+ else
+ {
+ old2new[i] = -1;
+ }
+ }
+ PX_ASSERT(verticesWritten == (mSimplifier->getNumVertices() - mSimplifier->getNumDeletedVertices()));
+ mParams->physicalMesh.numVertices = verticesWritten;
+
+ PX_ASSERT(mSimplifier->getNumTriangles() * 3 < mParams->physicalMesh.numIndices);
+
+ uint32_t indicesWritten = 0;
+ uint32_t trianglesRead = 0;
+ while (indicesWritten < mSimplifier->getNumTriangles() * 3)
+ {
+ uint32_t v0, v1, v2;
+ if (mSimplifier->getTriangle(trianglesRead++, v0, v1, v2))
+ {
+ PX_ASSERT(old2new[v0] != -1);
+ PX_ASSERT(old2new[v1] != -1);
+ PX_ASSERT(old2new[v2] != -1);
+ mIndices[indicesWritten++] = (uint32_t)old2new[v0];
+ mIndices[indicesWritten++] = (uint32_t)old2new[v1];
+ mIndices[indicesWritten++] = (uint32_t)old2new[v2];
+ }
+ }
+ mParams->physicalMesh.numIndices = indicesWritten;
+
+ updateSkinningNormals();
+}
+
+
+void ClothingPhysicalMeshImpl::clearMiscBuffers()
+{
+ mConstrainCoefficients.resize(0);
+ mBoneIndices.resize(0);
+ mBoneWeights.resize(0);
+}
+
+
+
+void ClothingPhysicalMeshImpl::computeEdgeLengths() const
+{
+ const uint32_t numIndices = mParams->physicalMesh.numIndices;
+
+ float average = 0;
+ float shortest = PX_MAX_F32;
+
+ if (mParams->physicalMesh.isTetrahedralMesh)
+ {
+ for (uint32_t i = 0; i < numIndices; i += 4)
+ {
+ const float edge0 = (mVertices[mIndices[i + 0]] - mVertices[mIndices[i + 1]]).magnitudeSquared();
+ const float edge1 = (mVertices[mIndices[i + 0]] - mVertices[mIndices[i + 2]]).magnitudeSquared();
+ const float edge2 = (mVertices[mIndices[i + 0]] - mVertices[mIndices[i + 3]]).magnitudeSquared();
+ const float edge3 = (mVertices[mIndices[i + 1]] - mVertices[mIndices[i + 2]]).magnitudeSquared();
+ const float edge4 = (mVertices[mIndices[i + 1]] - mVertices[mIndices[i + 3]]).magnitudeSquared();
+ const float edge5 = (mVertices[mIndices[i + 2]] - mVertices[mIndices[i + 3]]).magnitudeSquared();
+ shortest = PxMin(shortest, edge0);
+ shortest = PxMin(shortest, edge1);
+ shortest = PxMin(shortest, edge2);
+ shortest = PxMin(shortest, edge3);
+ shortest = PxMin(shortest, edge4);
+ shortest = PxMin(shortest, edge5);
+
+ average += PxSqrt(edge0) + PxSqrt(edge1) + PxSqrt(edge2) + PxSqrt(edge3) + PxSqrt(edge4) + PxSqrt(edge5);
+ }
+ mParams->physicalMesh.isClosed = false;
+ }
+ else
+ {
+ // also check if the mesh is closed
+ nvidia::Array<SortedEdge> edges;
+
+ for (uint32_t i = 0; i < numIndices; i += 3)
+ {
+ const float edge0 = (mVertices[mIndices[i + 0]] - mVertices[mIndices[i + 1]]).magnitudeSquared();
+ const float edge1 = (mVertices[mIndices[i + 0]] - mVertices[mIndices[i + 2]]).magnitudeSquared();
+ const float edge2 = (mVertices[mIndices[i + 1]] - mVertices[mIndices[i + 2]]).magnitudeSquared();
+ shortest = PxMin(shortest, edge0);
+ shortest = PxMin(shortest, edge1);
+ shortest = PxMin(shortest, edge2);
+
+ average += PxSqrt(edge0) + PxSqrt(edge1) + PxSqrt(edge2);
+
+ edges.pushBack(SortedEdge(mIndices[i + 0], mIndices[i + 1]));
+ edges.pushBack(SortedEdge(mIndices[i + 1], mIndices[i + 2]));
+ edges.pushBack(SortedEdge(mIndices[i + 2], mIndices[i + 0]));
+ }
+
+ nvidia::sort(edges.begin(), edges.size(), SortedEdge(0, 0));
+
+ bool meshClosed = false;
+ if ((edges.size() & 0x1) == 0) // only works for even number of indices
+ {
+ meshClosed = true;
+ for (uint32_t i = 0; i < edges.size(); i += 2)
+ {
+ meshClosed &= edges[i] == edges[i + 1];
+
+ if (i > 0)
+ {
+ meshClosed &= !(edges[i - 1] == edges[i]);
+ }
+ }
+ }
+ mParams->physicalMesh.isClosed = meshClosed;
+ }
+
+ mParams->physicalMesh.shortestEdgeLength = PxSqrt(shortest);
+ if (numIndices > 0)
+ {
+ mParams->physicalMesh.averageEdgeLength = average / (float)numIndices;
+ }
+ else
+ {
+ mParams->physicalMesh.averageEdgeLength = 0.0f;
+ }
+}
+
+
+
+void ClothingPhysicalMeshImpl::addBoneToVertex(uint32_t vertexNumber, uint16_t boneIndex, float boneWeight)
+{
+ if (mBoneIndices.size() == 0 || mBoneWeights.size() == 0)
+ {
+ return;
+ }
+
+ const uint32_t numBonesPerVertex = mParams->physicalMesh.numBonesPerVertex;
+ for (uint32_t i = 0; i < numBonesPerVertex; i++)
+ {
+ if (mBoneIndices[vertexNumber * numBonesPerVertex + i] == boneIndex ||
+ mBoneWeights[vertexNumber * numBonesPerVertex + i] == 0.0f)
+ {
+ mBoneIndices[vertexNumber * numBonesPerVertex + i] = boneIndex;
+ mBoneWeights[vertexNumber * numBonesPerVertex + i] =
+ PxMax(mBoneWeights[vertexNumber * numBonesPerVertex + i], boneWeight);
+ sortBonesOfVertex(vertexNumber);
+ return;
+ }
+ }
+}
+
+
+
+void ClothingPhysicalMeshImpl::sortBonesOfVertex(uint32_t vertexNumber)
+{
+ const uint32_t numBonesPerVertex = mParams->physicalMesh.numBonesPerVertex;
+ if (mBoneIndices.size() == 0 || mBoneWeights.size() == 0 || numBonesPerVertex <= 1)
+ {
+ return;
+ }
+
+ // bubble sort
+ bool changed = true;
+ while (changed)
+ {
+ changed = false;
+ for (uint32_t i = 0; i < numBonesPerVertex - 1; i++)
+ {
+ const uint32_t index = vertexNumber * numBonesPerVertex + i;
+ if (mBoneWeights[index] < mBoneWeights[index + 1])
+ {
+ // swap
+ float tempF = mBoneWeights[index];
+ mBoneWeights[index] = mBoneWeights[index + 1];
+ mBoneWeights[index + 1] = tempF;
+
+ uint16_t tempI = mBoneIndices[index];
+ mBoneIndices[index] = mBoneIndices[index + 1];
+ mBoneIndices[index + 1] = tempI;
+
+ changed = true;
+ }
+ }
+ }
+}
+
+
+
+void ClothingPhysicalMeshImpl::normalizeBonesOfVertex(uint32_t vertexNumber)
+{
+ if (mBoneIndices.size() == 0 || mBoneWeights.size() == 0)
+ {
+ return;
+ }
+
+ const uint32_t numBonesPerVertex = mParams->physicalMesh.numBonesPerVertex;
+
+ float sum = 0;
+ float last = FLT_MAX;
+ for (uint32_t i = 0; i < numBonesPerVertex; i++)
+ {
+ sum += mBoneWeights[vertexNumber * numBonesPerVertex + i];
+
+ // make sure it is sorted!
+ PX_ASSERT(mBoneWeights[vertexNumber * numBonesPerVertex + i] <= last);
+ last = mBoneWeights[vertexNumber * numBonesPerVertex + i];
+ }
+
+ PX_UNUSED(last);
+
+ if (sum > 0)
+ {
+ float invSum = 1.0f / sum;
+ for (uint32_t i = 0; i < numBonesPerVertex; i++)
+ {
+ float& weight = mBoneWeights[vertexNumber * numBonesPerVertex + i];
+ if (weight > 0)
+ {
+ weight *= invSum;
+ }
+ else
+ {
+ mBoneIndices[vertexNumber * numBonesPerVertex + i] = 0;
+ }
+ }
+ }
+ else
+ {
+ for (uint32_t i = 0; i < numBonesPerVertex; i++)
+ {
+ mBoneIndices[vertexNumber * numBonesPerVertex + i] = 0;
+ mBoneWeights[vertexNumber * numBonesPerVertex + i] = 0.0f;
+ }
+ }
+}
+
+
+
+void ClothingPhysicalMeshImpl::updateSkinningNormals()
+{
+ // only for non-softbodies
+ if (isTetrahedralMesh())
+ {
+ return;
+ }
+
+ const uint32_t numVertices = mParams->physicalMesh.numVertices;
+ const uint32_t numIndices = mParams->physicalMesh.numIndices;
+
+ PX_ASSERT(mSkinningNormals.size() == mVertices.size());
+ memset(mSkinningNormals.begin(), 0, sizeof(PxVec3) * numVertices);
+
+ for (uint32_t i = 0; i < numIndices; i += 3)
+ {
+ PxVec3 normal;
+ normal = mVertices[mIndices[i + 1]] - mVertices[mIndices[i]];
+ normal = normal.cross(mVertices[mIndices[i + 2]] - mVertices[mIndices[i]]);
+ mSkinningNormals[mIndices[i]] += normal;
+ mSkinningNormals[mIndices[i + 1]] += normal;
+ mSkinningNormals[mIndices[i + 2]] += normal;
+ }
+
+ for (uint32_t i = 0; i < numVertices; i++)
+ {
+ mSkinningNormals[i].normalize();
+ }
+}
+
+
+
+void ClothingPhysicalMeshImpl::smoothNormals(uint32_t numIterations)
+{
+ const uint32_t increment = mParams->physicalMesh.isTetrahedralMesh ? 4u : 3u;
+ const uint32_t numIndices = mParams->physicalMesh.numIndices;
+
+ for (uint32_t iters = 0; iters < numIterations; iters++)
+ {
+ for (uint32_t i = 0; i < numIndices; i += increment)
+ {
+ PxVec3& n0 = mNormals[mIndices[i + 0]];
+ PxVec3& n1 = mNormals[mIndices[i + 1]];
+ PxVec3& n2 = mNormals[mIndices[i + 2]];
+ PxVec3 n = n0 + n1 + n2;
+ n.normalize();
+ n0 = n;
+ n1 = n;
+ n2 = n;
+ }
+ }
+}
+
+
+
+void ClothingPhysicalMeshImpl::updateOptimizationData()
+{
+ PX_ASSERT(mParams != NULL);
+
+ const int32_t numVertices = mParams->physicalMesh.vertices.arraySizes[0];
+ const uint32_t numBonesPerVertex = mParams->physicalMesh.numBonesPerVertex;
+
+ const float* boneWeights = mParams->physicalMesh.boneWeights.buf;
+ PX_ASSERT(boneWeights == NULL || mParams->physicalMesh.boneWeights.arraySizes[0] == numVertices * (int32_t)numBonesPerVertex);
+
+ const ClothingPhysicalMeshParametersNS::ConstrainCoefficient_Type* constrainCoeffs = mParams->physicalMesh.constrainCoefficients.buf;
+ PX_ASSERT(constrainCoeffs == NULL || mParams->physicalMesh.constrainCoefficients.arraySizes[0] == numVertices);
+
+ if (boneWeights == NULL && constrainCoeffs == NULL)
+ {
+ return;
+ }
+
+ uint32_t allocNumVertices = ((uint32_t)physx::shdfnd::ceil((float)numVertices / NUM_VERTICES_PER_CACHE_BLOCK)) * NUM_VERTICES_PER_CACHE_BLOCK; // allocate more to have a multiple of numVerticesPerCachBlock
+
+ NvParameterized::Handle optimizationDataHandle(*mParams, "physicalMesh.optimizationData");
+ PX_ASSERT(optimizationDataHandle.isValid());
+ optimizationDataHandle.resizeArray((int32_t)(allocNumVertices + 1) / 2);
+ uint8_t* optimizationData = mParams->physicalMesh.optimizationData.buf;
+ memset(optimizationData, 0, sizeof(uint8_t) * mParams->physicalMesh.optimizationData.arraySizes[0]);
+
+ for (int32_t i = 0; i < numVertices; ++i)
+ {
+ uint8_t numBones = 0;
+ if (boneWeights != NULL)
+ {
+ for (; numBones < numBonesPerVertex; numBones++)
+ {
+ if (boneWeights[i * numBonesPerVertex + numBones] == 0.0f)
+ {
+ break;
+ }
+ }
+ }
+
+ uint8_t& data = optimizationData[i / 2];
+ PX_ASSERT(numBones < 8); // we use 3 bits
+
+ if (constrainCoeffs != NULL)
+ {
+ uint8_t bitShift = 0;
+ if (i % 2 == 0)
+ {
+ data = 0;
+ }
+ else
+ {
+ bitShift = 4;
+ }
+ data |= numBones << bitShift;
+
+ // store for each vertex if collisionSphereDistance is < 0
+ if (constrainCoeffs[i].collisionSphereDistance < 0.0f)
+ {
+ data |= 8 << bitShift;
+ mParams->physicalMesh.hasNegativeBackstop = true;
+ }
+ else
+ {
+ data &= ~(8 << bitShift);
+ }
+ }
+ }
+}
+
+
+
+void ClothingPhysicalMeshImpl::updateMaxMaxDistance()
+{
+ const uint32_t numVertices = mParams->physicalMesh.numVertices;
+
+ float maxMaxDistance = 0.0f;
+ for (uint32_t i = 0; i < numVertices; i++)
+ {
+ maxMaxDistance = PxMax(maxMaxDistance, mConstrainCoefficients[i].maxDistance);
+ }
+
+ mParams->physicalMesh.maximumMaxDistance = maxMaxDistance;
+}
+
+
+
+void ClothingPhysicalMeshImpl::preSerialize(void* userData_)
+{
+ PX_UNUSED(userData_);
+
+ writeBackData();
+
+ // shrink the buffers
+
+ if (!mVertices.isEmpty() && mVertices.size() != mParams->physicalMesh.numVertices)
+ {
+ mVertices.resize(mParams->physicalMesh.numVertices);
+ }
+
+ if (!mNormals.isEmpty() && mNormals.size() != mParams->physicalMesh.numVertices)
+ {
+ mNormals.resize(mParams->physicalMesh.numVertices);
+ }
+
+ if (!mSkinningNormals.isEmpty() && mSkinningNormals.size() != mParams->physicalMesh.numVertices)
+ {
+ mSkinningNormals.resize(mParams->physicalMesh.numVertices);
+ }
+
+ if (!mConstrainCoefficients.isEmpty() && mConstrainCoefficients.size() != mParams->physicalMesh.numVertices)
+ {
+ mConstrainCoefficients.resize(mParams->physicalMesh.numVertices);
+ }
+
+ if (!mBoneIndices.isEmpty() && mBoneIndices.size() != mParams->physicalMesh.numVertices * mParams->physicalMesh.numBonesPerVertex)
+ {
+ mBoneIndices.resize(mParams->physicalMesh.numVertices * mParams->physicalMesh.numBonesPerVertex);
+ }
+
+ if (!mBoneWeights.isEmpty() && mBoneWeights.size() != mParams->physicalMesh.numVertices * mParams->physicalMesh.numBonesPerVertex)
+ {
+ mBoneWeights.resize(mParams->physicalMesh.numVertices * mParams->physicalMesh.numBonesPerVertex);
+ }
+
+ if (!mIndices.isEmpty() && mIndices.size() != mParams->physicalMesh.numIndices)
+ {
+ mIndices.resize(mParams->physicalMesh.numIndices);
+ }
+
+ updateOptimizationData();
+}
+
+
+
+void ClothingPhysicalMeshImpl::permuteBoneIndices(Array<int32_t>& old2newBoneIndices)
+{
+ if (mBoneIndices.size() == 0)
+ {
+ return;
+ }
+
+ const uint32_t numVertices = mParams->physicalMesh.numVertices;
+ const uint32_t numBonesPerVertex = mParams->physicalMesh.numBonesPerVertex;
+
+ for (uint32_t j = 0; j < numVertices; j++)
+ {
+ for (uint32_t k = 0; k < numBonesPerVertex; k++)
+ {
+ uint16_t& index = mBoneIndices[j * numBonesPerVertex + k];
+ PX_ASSERT(old2newBoneIndices[index] >= 0);
+ PX_ASSERT(old2newBoneIndices[index] <= 0xffff);
+ index = (uint16_t)old2newBoneIndices[index];
+ }
+ }
+}
+
+
+
+void ClothingPhysicalMeshImpl::applyTransformation(const PxMat44& transformation, float scale)
+{
+ const uint32_t numVertices = mParams->physicalMesh.numVertices;
+
+ PX_ASSERT(scale > 0.0f); // PH: negative scale won't work well here
+
+ for (uint32_t i = 0; i < numVertices; i++)
+ {
+ if (!mVertices.isEmpty())
+ {
+ mVertices[i] = (transformation.transform(mVertices[i])) * scale;
+ }
+ if (!mNormals.isEmpty())
+ {
+ mNormals[i] = transformation.transform(mNormals[i]);
+ }
+ if (!mSkinningNormals.isEmpty())
+ {
+ mSkinningNormals[i] = transformation.transform(mSkinningNormals[i]);
+ }
+ if (!mConstrainCoefficients.isEmpty())
+ {
+ mConstrainCoefficients[i].maxDistance *= scale;
+ mConstrainCoefficients[i].collisionSphereDistance *= scale;
+ mConstrainCoefficients[i].collisionSphereRadius *= scale;
+ }
+ }
+
+ PxMat33 t33(PxVec3(transformation.column0.x, transformation.column0.y, transformation.column0.z),
+ PxVec3(transformation.column1.x, transformation.column1.y, transformation.column1.z),
+ PxVec3(transformation.column2.x, transformation.column2.y, transformation.column2.z));
+
+ if (t33.getDeterminant() * scale < 0.0f)
+ {
+ const uint32_t numIndices = mParams->physicalMesh.numIndices;
+
+ if (mParams->physicalMesh.isTetrahedralMesh)
+ {
+ PX_ASSERT(numIndices % 4 == 0);
+ for (uint32_t i = 0; i < numIndices; i += 4)
+ {
+ nvidia::swap(mIndices[i + 2], mIndices[i + 3]);
+ }
+ }
+ else
+ {
+ // Flip the triangle indices to change winding (and thus normal generation in the PhysX SDK
+ PX_ASSERT(numIndices % 3 == 0);
+ for (uint32_t i = 0; i < numIndices; i += 3)
+ {
+ nvidia::swap(mIndices[i + 1], mIndices[i + 2]);
+ }
+ }
+
+ mParams->physicalMesh.flipNormals ^= true;
+
+ if (mParams->transitionDownB.buf != NULL || mParams->transitionUpB.buf != NULL)
+ {
+ APEX_DEBUG_WARNING("applyTransformation will not work with old assets, re-export from DCC tools");
+ }
+
+ const uint32_t numTransDown = (uint32_t)mParams->transitionDown.arraySizes[0];
+ for (uint32_t i = 0; i < numTransDown; i++)
+ {
+ mParams->transitionDown.buf[i].vertexBary.z *= scale;
+ mParams->transitionDown.buf[i].normalBary.z *= scale;
+ }
+
+ const uint32_t numTransUp = (uint32_t)mParams->transitionUp.arraySizes[0];
+ for (uint32_t i = 0; i < numTransUp; i++)
+ {
+ mParams->transitionUp.buf[i].vertexBary.z *= scale;
+ mParams->transitionUp.buf[i].normalBary.z *= scale;
+ }
+ }
+
+ mParams->physicalMesh.maximumMaxDistance *= scale;
+ mParams->physicalMesh.shortestEdgeLength *= scale;
+ mParams->physicalMesh.averageEdgeLength *= scale;
+}
+
+
+
+void ClothingPhysicalMeshImpl::applyPermutation(const Array<uint32_t>& permutation)
+{
+ const uint32_t numVertices = mParams->physicalMesh.numVertices;
+ const uint32_t numBonesPerVertex = mParams->physicalMesh.numBonesPerVertex;
+
+ if (!mVertices.isEmpty())
+ {
+ ApexPermute<PxVec3>(mVertices.begin(), &permutation[0], numVertices);
+ }
+
+ if (!mNormals.isEmpty())
+ {
+ ApexPermute<PxVec3>(mNormals.begin(), &permutation[0], numVertices);
+ }
+
+ if (!mSkinningNormals.isEmpty())
+ {
+ ApexPermute<PxVec3>(mSkinningNormals.begin(), &permutation[0], numVertices);
+ }
+
+ if (!mConstrainCoefficients.isEmpty())
+ {
+ ApexPermute<ClothingPhysicalMeshParametersNS::ConstrainCoefficient_Type>(mConstrainCoefficients.begin(), &permutation[0], numVertices);
+ }
+
+ if (!mBoneIndices.isEmpty())
+ {
+ ApexPermute<uint16_t>(mBoneIndices.begin(), &permutation[0], numVertices, numBonesPerVertex);
+ }
+
+ if (!mBoneWeights.isEmpty())
+ {
+ ApexPermute<float>(mBoneWeights.begin(), &permutation[0], numVertices, numBonesPerVertex);
+ }
+}
+
+
+
+struct OrderedTriangle
+{
+ void init(uint32_t _triNr, uint32_t _v0, uint32_t _v1, uint32_t _v2)
+ {
+ triNr = _triNr;
+ v0 = _v0;
+ v1 = _v1;
+ v2 = _v2;
+ // bubble sort
+ if (v0 > v1)
+ {
+ uint32_t v = v0;
+ v0 = v1;
+ v1 = v;
+ }
+ if (v1 > v2)
+ {
+ uint32_t v = v1;
+ v1 = v2;
+ v2 = v;
+ }
+ if (v0 > v1)
+ {
+ uint32_t v = v0;
+ v0 = v1;
+ v1 = v;
+ }
+ }
+ bool operator()(const OrderedTriangle& a, const OrderedTriangle& b) const
+ {
+ if (a.v0 < b.v0)
+ {
+ return true;
+ }
+ if (a.v0 > b.v0)
+ {
+ return false;
+ }
+ if (a.v1 < b.v1)
+ {
+ return true;
+ }
+ if (a.v1 > b.v1)
+ {
+ return false;
+ }
+ return (a.v2 < b.v2);
+ }
+ bool operator == (const OrderedTriangle& t) const
+ {
+ return v0 == t.v0 && v1 == t.v1 && v2 == t.v2;
+ }
+ uint32_t v0, v1, v2;
+ uint32_t triNr;
+};
+
+bool ClothingPhysicalMeshImpl::removeDuplicatedTriangles(uint32_t numIndices, uint32_t indexByteStride, const void* indices)
+{
+ uint32_t numTriangles = numIndices / 3;
+ Array<OrderedTriangle> triangles;
+ triangles.resize(numTriangles);
+
+ {
+ const uint8_t* srcIndices = (const uint8_t*)indices;
+ for (uint32_t i = 0; i < numTriangles; i++)
+ {
+ uint32_t i0 = *(const uint32_t*)(srcIndices);
+ srcIndices += indexByteStride;
+ uint32_t i1 = *(const uint32_t*)(srcIndices);
+ srcIndices += indexByteStride;
+ uint32_t i2 = *(const uint32_t*)(srcIndices);
+ srcIndices += indexByteStride;
+
+ triangles[i].init(i, i0, i1, i2);
+ }
+ }
+
+ nvidia::sort(triangles.begin(), triangles.size(), OrderedTriangle());
+
+ uint32_t fromPos = 0;
+ uint32_t toPos = 0;
+ while (fromPos < numTriangles)
+ {
+ OrderedTriangle& t = triangles[fromPos];
+ triangles[toPos] = t;
+ fromPos++;
+ toPos++;
+ while (fromPos < numTriangles && triangles[fromPos] == t)
+ {
+ fromPos++;
+ }
+ }
+ if (fromPos == toPos)
+ {
+ return false;
+ }
+
+ mParams->physicalMesh.numIndices = 3 * toPos;
+
+ mIndices.resize(mParams->physicalMesh.numIndices);
+ if (mParams->physicalMesh.numIndices > 0)
+ {
+ for (uint32_t i = 0; i < toPos; i++)
+ {
+ OrderedTriangle& t = triangles[i];
+ const uint8_t* srcIndices = (const uint8_t*)indices + 3 * t.triNr * indexByteStride;
+
+ mIndices[3 * i] = *(uint32_t*)srcIndices;
+ srcIndices += indexByteStride;
+ mIndices[3 * i + 1] = *(uint32_t*)srcIndices;
+ srcIndices += indexByteStride;
+ mIndices[3 * i + 2] = *(uint32_t*)srcIndices;
+ srcIndices += indexByteStride;
+ }
+ }
+
+ fixTriangleOrientations();
+ return true;
+}
+
+
+struct OrderedTriangleEdge
+{
+ void init(uint32_t _v0, uint32_t _v1, uint32_t _triNr, uint32_t _edgeNr)
+ {
+ if (_v0 < _v1)
+ {
+ v0 = _v0;
+ v1 = _v1;
+ }
+ else
+ {
+ v0 = _v1;
+ v1 = _v0;
+ }
+ triNr = _triNr;
+ edgeNr = _edgeNr;
+ }
+ bool operator()(const OrderedTriangleEdge& a, const OrderedTriangleEdge& b) const
+ {
+ if (a.v0 < b.v0)
+ {
+ return true;
+ }
+ if (a.v0 > b.v0)
+ {
+ return false;
+ }
+ return (a.v1 < b.v1);
+ }
+ bool operator == (const OrderedTriangleEdge& e) const
+ {
+ return v0 == e.v0 && v1 == e.v1;
+ }
+ uint32_t v0, v1;
+ uint32_t triNr, edgeNr;
+};
+
+void ClothingPhysicalMeshImpl::computeNeighborInformation(Array<int32_t> &neighbors)
+{
+ // compute neighbor information
+ const uint32_t numTriangles = mParams->physicalMesh.numIndices / 3;
+
+ Array<OrderedTriangleEdge> edges;
+ edges.resize(3 * numTriangles);
+
+ for (uint32_t i = 0; i < numTriangles; i++)
+ {
+ uint32_t i0 = mIndices[3 * i];
+ uint32_t i1 = mIndices[3 * i + 1];
+ uint32_t i2 = mIndices[3 * i + 2];
+ edges[3 * i ].init(i0, i1, i, 0);
+ edges[3 * i + 1].init(i1, i2, i, 1);
+ edges[3 * i + 2].init(i2, i0, i, 2);
+ }
+
+ nvidia::sort(edges.begin(), edges.size(), OrderedTriangleEdge());
+
+ neighbors.resize(3 * numTriangles, -1);
+
+ uint32_t i = 0;
+ while (i < edges.size())
+ {
+ OrderedTriangleEdge& e0 = edges[i];
+ i++;
+ while (i < edges.size() && edges[i] == e0)
+ {
+ OrderedTriangleEdge& e1 = edges[i];
+ neighbors[3 * e0.triNr + e0.edgeNr] = (int32_t)e1.triNr;
+ neighbors[3 * e1.triNr + e1.edgeNr] = (int32_t)e0.triNr;
+ i++;
+ }
+ }
+}
+
+
+void ClothingPhysicalMeshImpl::fixTriangleOrientations()
+{
+ PX_ASSERT(!mParams->physicalMesh.isTetrahedralMesh);
+ Array<int32_t> neighbors;
+ computeNeighborInformation(neighbors);
+
+ const uint32_t numTriangles = mParams->physicalMesh.numIndices / 3;
+
+ // 0 = non visited, 1 = visited, 2 = visited, to be flipped
+ Array<uint8_t> marks;
+ marks.resize(numTriangles, 0);
+
+ Array<uint32_t> queue;
+
+ for (uint32_t i = 0; i < numTriangles; i++)
+ {
+ if (marks[i] != 0)
+ {
+ continue;
+ }
+ queue.clear();
+ marks[i] = 1;
+ queue.pushBack(i);
+ while (!queue.empty())
+ {
+ uint32_t triNr = queue[queue.size() - 1];
+ queue.popBack();
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ int adjNr = neighbors[3 * triNr + j];
+ if (adjNr < 0 || marks[(uint32_t)adjNr] != 0)
+ {
+ continue;
+ }
+ queue.pushBack((uint32_t)adjNr);
+ uint32_t i0, i1;
+ if (marks[triNr] == 1)
+ {
+ i0 = mIndices[3 * triNr + j];
+ i1 = mIndices[3 * triNr + ((j + 1) % 3)];
+ }
+ else
+ {
+ i1 = mIndices[3 * triNr + j];
+ i0 = mIndices[3 * triNr + ((j + 1) % 3)];
+ }
+ // don't swap here because this would corrupt the neighbor information
+ marks[(uint32_t)adjNr] = 1;
+ if (mIndices[3 * (uint32_t)adjNr + 0] == i0 && mIndices[3 * (uint32_t)adjNr + 1] == i1)
+ {
+ marks[(uint32_t)adjNr] = 2;
+ }
+ if (mIndices[3 * (uint32_t)adjNr + 1] == i0 && mIndices[3 * (uint32_t)adjNr + 2] == i1)
+ {
+ marks[(uint32_t)adjNr] = 2;
+ }
+ if (mIndices[3 * (uint32_t)adjNr + 2] == i0 && mIndices[3 * (uint32_t)adjNr + 0] == i1)
+ {
+ marks[(uint32_t)adjNr] = 2;
+ }
+ }
+ }
+ }
+ for (uint32_t i = 0; i < numTriangles; i++)
+ {
+ if (marks[i] == 2)
+ {
+ uint32_t i0 = mIndices[3 * i];
+ mIndices[3 * i] = mIndices[3 * i + 1];
+ mIndices[3 * i + 1] = i0;
+ }
+ }
+}
+
+}
+} // namespace nvidia
+
+
diff --git a/APEX_1.4/module/clothing/src/ClothingRenderProxyImpl.cpp b/APEX_1.4/module/clothing/src/ClothingRenderProxyImpl.cpp
new file mode 100644
index 00000000..2576e8ef
--- /dev/null
+++ b/APEX_1.4/module/clothing/src/ClothingRenderProxyImpl.cpp
@@ -0,0 +1,270 @@
+/*
+ * 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 "ClothingRenderProxyImpl.h"
+
+#include "ClothingAssetImpl.h"
+#include "ClothingActorParam.h"
+#include "RenderMeshActorDesc.h"
+#include "RenderMeshAssetIntl.h"
+#include "ClothingScene.h"
+
+namespace nvidia
+{
+namespace clothing
+{
+
+ClothingRenderProxyImpl::ClothingRenderProxyImpl(RenderMeshAssetIntl* rma, bool useFallbackSkinning, bool useCustomVertexBuffer, const HashMap<uint32_t, ApexSimpleString>& overrideMaterials, const PxVec3* morphTargetNewPositions, const uint32_t* morphTargetVertexOffsets, ClothingScene* scene) :
+renderingDataPosition(NULL),
+renderingDataNormal(NULL),
+renderingDataTangent(NULL),
+mBounds(),
+mPose(PxMat44(PxIdentity)),
+mRenderMeshActor(NULL),
+mRenderMeshAsset(rma),
+mScene(scene),
+mUseFallbackSkinning(useFallbackSkinning),
+mMorphTargetNewPositions(morphTargetNewPositions),
+mTimeInPool(0)
+{
+ // create renderMeshActor
+ RenderMeshActorDesc desc;
+ desc.keepVisibleBonesPacked = false;
+ desc.forceFallbackSkinning = mUseFallbackSkinning;
+
+ // prepare material names array and copy the map with override names
+ const uint32_t numSubmeshes = rma->getSubmeshCount();
+ Array<const char*> overrideMaterialNames;
+ for (uint32_t si = 0; si < numSubmeshes; ++si)
+ {
+ const Pair<const uint32_t, ApexSimpleString>* overrideMat = overrideMaterials.find(si);
+ if (overrideMat != NULL)
+ {
+ overrideMaterialNames.pushBack(overrideMat->second.c_str());
+ mOverrideMaterials[si] = overrideMat->second;
+ }
+ else
+ {
+ overrideMaterialNames.pushBack(rma->getMaterialName(si));
+ }
+ }
+
+ desc.overrideMaterialCount = numSubmeshes;
+ desc.overrideMaterials = &overrideMaterialNames[0];
+ mRenderMeshActor = DYNAMIC_CAST(RenderMeshActorIntl*)(mRenderMeshAsset->createActor(desc));
+
+ // Necessary for clothing
+ mRenderMeshActor->setSkinningMode(RenderMeshActorSkinningMode::AllBonesPerPart);
+
+ if (useCustomVertexBuffer)
+ {
+ // get num verts and check if we need tangents
+ ClothingGraphicalMeshAssetWrapper meshAsset(rma);
+ uint32_t numRenderVertices = meshAsset.getNumTotalVertices();
+ bool renderTangents = meshAsset.hasChannel(NULL, RenderVertexSemantic::TANGENT);
+
+ // allocate aligned buffers and init to 0
+ const uint32_t alignedNumRenderVertices = (numRenderVertices + 15) & 0xfffffff0;
+ const uint32_t renderingDataSize = sizeof(PxVec3) * alignedNumRenderVertices * 2 + sizeof(PxVec4) * alignedNumRenderVertices * (renderTangents ? 1 : 0);
+ renderingDataPosition = (PxVec3*)PX_ALLOC(renderingDataSize, PX_DEBUG_EXP("SimulationAbstract::renderingDataPositions"));
+ renderingDataNormal = renderingDataPosition + alignedNumRenderVertices;
+ if (renderTangents)
+ {
+ renderingDataTangent = reinterpret_cast<PxVec4*>(renderingDataNormal + alignedNumRenderVertices);
+ PX_ASSERT(((size_t)renderingDataTangent & 0xf) == 0);
+ }
+ memset(renderingDataPosition, 0, renderingDataSize);
+
+ // update rma to use the custom buffers
+ uint32_t submeshOffset = 0;
+ for (uint32_t i = 0; i < meshAsset.getSubmeshCount(); i++)
+ {
+ PxVec3* position = renderingDataPosition + (renderingDataPosition != NULL ? submeshOffset : 0);
+ PxVec3* normal = renderingDataNormal + (renderingDataNormal != NULL ? submeshOffset : 0);
+ PxVec4* tangent = renderingDataTangent + (renderingDataTangent != NULL ? submeshOffset : 0);
+ mRenderMeshActor->addVertexBuffer(i, true, position, normal, tangent);
+
+ // morph targets
+ if (mMorphTargetNewPositions != NULL)
+ {
+ const PxVec3* staticPosition = mMorphTargetNewPositions + morphTargetVertexOffsets[i];
+ mRenderMeshActor->setStaticPositionReplacement(i, staticPosition);
+ }
+
+ submeshOffset += meshAsset.getNumVertices(i);
+ }
+ }
+}
+
+
+
+ClothingRenderProxyImpl::~ClothingRenderProxyImpl()
+{
+ mRMALock.lock();
+ if (mRenderMeshActor != NULL)
+ {
+ mRenderMeshActor->release();
+ mRenderMeshActor = NULL;
+ }
+ mRMALock.unlock();
+
+ if (renderingDataPosition != NULL)
+ {
+ PX_FREE(renderingDataPosition);
+ renderingDataPosition = NULL;
+ renderingDataNormal = NULL;
+ renderingDataTangent = NULL;
+ }
+}
+
+
+
+// from ApexInterface
+void ClothingRenderProxyImpl::release()
+{
+ WRITE_ZONE();
+ setTimeInPool(1);
+ if(mScene == NULL || mRenderMeshActor == NULL)
+ {
+ PX_DELETE(this);
+ }
+}
+
+
+
+// from Renderable
+void ClothingRenderProxyImpl::dispatchRenderResources(UserRenderer& api)
+{
+ mRMALock.lock();
+ if (mRenderMeshActor != NULL)
+ {
+ mRenderMeshActor->dispatchRenderResources(api, mPose);
+ }
+ mRMALock.unlock();
+}
+
+
+
+// from RenderDataProvider.h
+void ClothingRenderProxyImpl::updateRenderResources(bool rewriteBuffers, void* userRenderData)
+{
+ URR_SCOPE;
+
+ mRMALock.lock();
+ if (mRenderMeshActor != NULL)
+ {
+ mRenderMeshActor->updateRenderResources(renderingDataPosition == NULL, rewriteBuffers, userRenderData);
+ }
+ mRMALock.unlock();
+}
+
+
+void ClothingRenderProxyImpl::lockRenderResources()
+{
+ // no need to lock anything, as soon as the user can access the proxy, we don't write it anymore
+ // until he calls release
+}
+
+
+void ClothingRenderProxyImpl::unlockRenderResources()
+{
+}
+
+
+
+bool ClothingRenderProxyImpl::hasSimulatedData() const
+{
+ READ_ZONE();
+ return renderingDataPosition != NULL;
+}
+
+
+
+RenderMeshActorIntl* ClothingRenderProxyImpl::getRenderMeshActor()
+{
+ return mRenderMeshActor;
+}
+
+
+
+RenderMeshAssetIntl* ClothingRenderProxyImpl::getRenderMeshAsset()
+{
+ return mRenderMeshAsset;
+}
+
+
+
+void ClothingRenderProxyImpl::setOverrideMaterial(uint32_t submeshIndex, const char* overrideMaterialName)
+{
+ mOverrideMaterials[submeshIndex] = overrideMaterialName;
+ mRMALock.lock();
+ if (mRenderMeshActor != NULL)
+ {
+ mRenderMeshActor->setOverrideMaterial(submeshIndex, overrideMaterialName);
+ }
+ mRMALock.unlock();
+}
+
+
+
+bool ClothingRenderProxyImpl::overrideMaterialsEqual(const HashMap<uint32_t, ApexSimpleString>& overrideMaterials)
+{
+ uint32_t numEntries = mOverrideMaterials.size();
+ if (overrideMaterials.size() != numEntries)
+ return false;
+
+ for(HashMap<uint32_t, ApexSimpleString>::Iterator iter = mOverrideMaterials.getIterator(); !iter.done(); ++iter)
+ {
+ uint32_t submeshIndex = iter->first;
+ const Pair<const uint32_t, ApexSimpleString>* overrideMat = overrideMaterials.find(submeshIndex);
+
+ // submeshIndex not found
+ if (overrideMat == NULL)
+ return false;
+
+ // name is different
+ if (overrideMat->second != iter->second)
+ return false;
+ }
+
+ return true;
+}
+
+
+uint32_t ClothingRenderProxyImpl::getTimeInPool() const
+{
+ return mTimeInPool;
+}
+
+
+void ClothingRenderProxyImpl::setTimeInPool(uint32_t time)
+{
+ mTimeInPool = time;
+}
+
+
+void ClothingRenderProxyImpl::notifyAssetRelease()
+{
+ mRMALock.lock();
+ if (mRenderMeshActor != NULL)
+ {
+ mRenderMeshActor->release();
+ mRenderMeshActor = NULL;
+ }
+ mRenderMeshAsset = NULL;
+ mRMALock.unlock();
+}
+
+}
+} // namespace nvidia
+
diff --git a/APEX_1.4/module/clothing/src/ClothingScene.cpp b/APEX_1.4/module/clothing/src/ClothingScene.cpp
new file mode 100644
index 00000000..cd4f5985
--- /dev/null
+++ b/APEX_1.4/module/clothing/src/ClothingScene.cpp
@@ -0,0 +1,889 @@
+/*
+ * 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 "Apex.h"
+#include "ClothingScene.h"
+#include "ClothingActorImpl.h"
+#include "ClothingAssetImpl.h"
+#include "ClothingCooking.h"
+#include "SceneIntl.h"
+#include "ClothingRenderProxyImpl.h"
+
+#include "DebugRenderParams.h"
+#include "ProfilerCallback.h"
+
+#include "Simulation.h"
+
+#include "PsThread.h"
+#include "ApexUsingNamespace.h"
+#include "PsAtomic.h"
+
+#if APEX_CUDA_SUPPORT
+#include "PxGpuDispatcher.h"
+#endif
+
+#include "ApexPvdClient.h"
+
+namespace nvidia
+{
+namespace clothing
+{
+
+ClothingScene::ClothingScene(ModuleClothingImpl& _module, SceneIntl& scene, RenderDebugInterface* renderDebug, ResourceList& list)
+ : mModule(&_module)
+ , mApexScene(&scene)
+#if PX_PHYSICS_VERSION_MAJOR == 3
+ , mPhysXScene(NULL)
+#endif
+ , mSumBenefit(0)
+ , mWaitForSolverTask(NULL)
+ , mSimulationTask(NULL)
+ , mSceneRunning(0)
+ , mRenderDebug(renderDebug)
+ , mDebugRenderParams(NULL)
+ , mClothingDebugRenderParams(NULL)
+ , mCurrentCookingTask(NULL)
+ , mCurrentSimulationDelta(0)
+ , mAverageSimulationFrequency(0.0f)
+#ifndef _DEBUG
+ , mFramesCount(0)
+ , mSimulatedTime(0.f)
+ , mTimestep(0.f)
+#endif
+ , mCpuFactory(NULL, NULL)
+#if APEX_CUDA_SUPPORT
+ , mGpuFactory(NULL, NULL)
+ , mPhysXGpuIndicator(NULL)
+#endif
+{
+ mClothingBeforeTickStartTask.setScene(this);
+ list.add(*this);
+
+ /* Initialize reference to ClothingDebugRenderParams */
+ mDebugRenderParams = DYNAMIC_CAST(DebugRenderParams*)(mApexScene->getDebugRenderParams());
+ PX_ASSERT(mDebugRenderParams);
+ NvParameterized::Handle handle(*mDebugRenderParams), memberHandle(*mDebugRenderParams);
+ int size;
+
+ if (mDebugRenderParams->getParameterHandle("moduleName", handle) == NvParameterized::ERROR_NONE)
+ {
+ handle.getArraySize(size, 0);
+ handle.resizeArray(size + 1);
+ if (handle.getChildHandle(size, memberHandle) == NvParameterized::ERROR_NONE)
+ {
+ memberHandle.initParamRef(ClothingDebugRenderParams::staticClassName(), true);
+ }
+ }
+
+ /* Load reference to ClothingDebugRenderParams */
+ NvParameterized::Interface* refPtr = NULL;
+ memberHandle.getParamRef(refPtr);
+ mClothingDebugRenderParams = DYNAMIC_CAST(ClothingDebugRenderParams*)(refPtr);
+ PX_ASSERT(mClothingDebugRenderParams);
+
+ mLastSimulationDeltas.reserve(mModule->getAvgSimFrequencyWindowSize());
+
+ mWaitForSolverTask = PX_NEW(WaitForSolverTask)(this);
+
+ mSimulationTask = PX_NEW(ClothingSceneSimulateTask)(mApexScene, this, mModule, GetInternalApexSDK()->getProfileZoneManager());
+ mSimulationTask->setWaitTask(mWaitForSolverTask);
+}
+
+
+
+ClothingScene::~ClothingScene()
+{
+}
+
+
+
+void ClothingScene::simulate(float elapsedTime)
+{
+ for (uint32_t i = 0; i < mActorArray.size(); i++)
+ {
+ ClothingActorImpl* clothingActor = static_cast<ClothingActorImpl*>(mActorArray[i]);
+ clothingActor->waitForFetchResults();
+ }
+
+ if (mLastSimulationDeltas.size() < mLastSimulationDeltas.capacity())
+ {
+ mCurrentSimulationDelta = mLastSimulationDeltas.size();
+ mLastSimulationDeltas.pushBack(elapsedTime);
+ }
+ else if (mLastSimulationDeltas.size() > 0)
+ {
+ mCurrentSimulationDelta = (mCurrentSimulationDelta + 1) % mLastSimulationDeltas.size();
+ mLastSimulationDeltas[mCurrentSimulationDelta] = elapsedTime;
+ }
+
+ float temp = 0.0f;
+ for (uint32_t i = 0; i < mLastSimulationDeltas.size(); i++)
+ temp += mLastSimulationDeltas[i];
+
+ if (temp > 0.0f)
+ mAverageSimulationFrequency = (float)(mLastSimulationDeltas.size()) / temp;
+ else
+ mAverageSimulationFrequency = 0.0f;
+
+ tickRenderProxies();
+}
+
+
+
+bool ClothingScene::needsManualSubstepping() const
+{
+ // we could test if any of them is being simulated, but assuming some sane budget settings
+ // there will always be >0 clothing actors simulated if there are any present
+
+ if (!mModule->allowApexWorkBetweenSubsteps())
+ {
+ return false;
+ }
+
+ // PH: new rule. The actual simulation object needs to request this too!
+ bool manualSubstepping = false;
+ for (uint32_t i = 0; i < mActorArray.size(); i++)
+ {
+ ClothingActorImpl* clothingActor = static_cast<ClothingActorImpl*>(mActorArray[i]);
+ manualSubstepping |= clothingActor->needsManualSubstepping();
+ }
+ return manualSubstepping;
+}
+
+
+
+void ClothingScene::interStep(uint32_t substepNumber, uint32_t maxSubSteps)
+{
+ for (uint32_t i = 0; i < mActorArray.size(); i++)
+ {
+ ClothingActorImpl* clothingActor = static_cast<ClothingActorImpl*>(mActorArray[i]);
+
+ if (clothingActor->needsManualSubstepping())
+ {
+ clothingActor->tickSynchBeforeSimulate_LocksPhysX(0.0f, 0.0f, substepNumber, maxSubSteps);
+ clothingActor->skinPhysicsMesh(maxSubSteps > 1, (float)(substepNumber + 1) / (float)maxSubSteps);
+ clothingActor->updateConstrainPositions_LocksPhysX();
+ clothingActor->applyCollision_LocksPhysX();
+ }
+ }
+}
+
+
+
+void ClothingScene::submitTasks(float elapsedTime, float substepSize, uint32_t numSubSteps)
+{
+ PxTaskManager* taskManager = mApexScene->getTaskManager();
+ const bool isFinalStep = mApexScene->isFinalStep();
+
+ for (uint32_t i = 0; i < mActorArray.size(); i++)
+ {
+ ClothingActorImpl* clothingActor = static_cast<ClothingActorImpl*>(mActorArray[i]);
+#if APEX_UE4
+ clothingActor->initBeforeTickTasks(elapsedTime, substepSize, numSubSteps, taskManager, 0, 0);
+#else
+ clothingActor->initBeforeTickTasks(elapsedTime, substepSize, numSubSteps);
+#endif
+
+ if (isFinalStep)
+ {
+ clothingActor->submitTasksDuring(taskManager);
+ }
+ }
+
+ taskManager->submitUnnamedTask(mClothingBeforeTickStartTask);
+
+ mSimulationTask->setDeltaTime(elapsedTime);
+ if (elapsedTime > 0.0f)
+ {
+ taskManager->submitUnnamedTask(*mSimulationTask);
+ taskManager->submitUnnamedTask(*mWaitForSolverTask);
+ }
+}
+
+
+
+void ClothingScene::setTaskDependencies()
+{
+ PxTaskManager* taskManager = mApexScene->getTaskManager();
+ const PxTaskID physxTick = taskManager->getNamedTask(AST_PHYSX_SIMULATE);
+ PxTask* physxTickTask = taskManager->getTaskFromID(physxTick);
+
+#if APEX_DURING_TICK_TIMING_FIX
+ const PxTaskID duringFinishedId = taskManager->getNamedTask(AST_DURING_TICK_COMPLETE);
+#else
+ const PxTaskID duringFinishedId = taskManager->getNamedTask(AST_PHYSX_CHECK_RESULTS);
+#endif
+
+ bool startSimulateTask = mSimulationTask->getDeltaTime() > 0;
+
+#if APEX_UE4
+ PxTask* dependentTask = physxTickTask;
+ PxTaskID duringStartId = physxTick;
+
+ if (startSimulateTask)
+ {
+ dependentTask = mSimulationTask;
+ duringStartId = mSimulationTask->getTaskID();
+ mSimulationTask->startAfter(mClothingBeforeTickStartTask.getTaskID());
+ }
+#else
+ PxTaskID duringStartId = startSimulateTask ? mSimulationTask->getTaskID() : physxTick;
+#endif
+ const bool isFinalStep = mApexScene->isFinalStep();
+
+ for (uint32_t i = 0; i < mActorArray.size(); i++)
+ {
+ ApexActor* actor = mActorArray[i];
+ ClothingActorImpl* clothingActor = static_cast<ClothingActorImpl*>(actor);
+#if !APEX_UE4
+ PxTask* dependentTask = physxTickTask;
+ if (startSimulateTask)
+ {
+ dependentTask = mSimulationTask;
+ mSimulationTask->startAfter(mClothingBeforeTickStartTask.getTaskID());
+ }
+#endif
+
+ clothingActor->setTaskDependenciesBefore(dependentTask);
+
+ if (isFinalStep)
+ {
+ // PH: daisy chain the during tasks to not trash other (=PhysX) tasks' cache etc.
+ // HL: found a case where duringTick becomes the bottleneck because of the daisy chaining
+
+ /*duringStartId = */clothingActor->setTaskDependenciesDuring(duringStartId, duringFinishedId);
+ }
+ }
+#if APEX_UE4
+ mSimulationTask->startAfter(mClothingBeforeTickStartTask.getTaskID());
+#endif
+
+ mClothingBeforeTickStartTask.finishBefore(physxTick);
+
+ if (startSimulateTask)
+ {
+ mSimulationTask->finishBefore(physxTick);
+ mWaitForSolverTask->startAfter(mSimulationTask->getTaskID());
+ mWaitForSolverTask->startAfter(duringFinishedId);
+ mWaitForSolverTask->finishBefore(taskManager->getNamedTask(AST_PHYSX_FETCH_RESULTS));
+ }
+}
+
+
+
+void ClothingScene::fetchResults()
+{
+ if (!mApexScene->isFinalStep())
+ {
+ return;
+ }
+
+ PX_PROFILE_ZONE("ClothingScene::fetchResults", GetInternalApexSDK()->getContextId());
+
+ // make sure to start cooking tasks if possible (and delete old ones)
+ submitCookingTask(NULL);
+
+ if (!mModule->allowAsyncFetchResults())
+ {
+ for (uint32_t i = 0; i < mActorArray.size(); i++)
+ {
+ ClothingActorImpl* clothingActor = static_cast<ClothingActorImpl*>(mActorArray[i]);
+ clothingActor->waitForFetchResults();
+ }
+ }
+
+ // TBD - if we need to send callbacks to the user, add them here
+}
+
+
+#if PX_PHYSICS_VERSION_MAJOR == 3
+
+void ClothingScene::setModulePhysXScene(PxScene* newPhysXScene)
+{
+ if (mPhysXScene == newPhysXScene)
+ {
+ return;
+ }
+
+ PxScene* oldPhysXScene = mPhysXScene;
+
+ mPhysXScene = newPhysXScene;
+ for (uint32_t i = 0; i < mActorArray.size(); ++i)
+ {
+ // downcast
+ ClothingActorImpl* actor = static_cast<ClothingActorImpl*>(mActorArray[i]);
+
+ actor->setPhysXScene(newPhysXScene);
+ }
+
+ mClothingAssetsMutex.lock();
+ mClothingAssets.clear();
+ mClothingAssetsMutex.unlock();
+
+#if APEX_CUDA_SUPPORT
+ {
+ if (mGpuFactory.factory != NULL && oldPhysXScene != NULL)
+ {
+ mSimulationTask->clearGpuSolver();
+ PX_ASSERT(mApexScene->getTaskManager() == oldPhysXScene->getTaskManager());
+ if (newPhysXScene != NULL)
+ {
+ mModule->releaseClothFactory(oldPhysXScene->getTaskManager()->getGpuDispatcher()->getCudaContextManager());
+ }
+ mGpuFactory.clear();
+ }
+ }
+#else
+ {
+ if (mCpuFactory.factory != NULL && oldPhysXScene != NULL)
+ {
+ if (newPhysXScene != NULL)
+ {
+ mModule->releaseClothFactory(NULL);
+ }
+ mCpuFactory.clear();
+ }
+ }
+#endif
+}
+
+#endif
+
+void ClothingScene::release()
+{
+ mModule->releaseModuleSceneIntl(*this);
+}
+
+
+
+void ClothingScene::visualize()
+{
+#ifdef WITHOUT_DEBUG_VISUALIZE
+#else
+ if (!mClothingDebugRenderParams->Actors)
+ {
+ return;
+ }
+
+ for (uint32_t i = 0; i < mActorArray.size(); i++)
+ {
+ // downcast
+ ClothingActorImpl* actor = static_cast<ClothingActorImpl*>(mActorArray[i]);
+ actor->visualize();
+ }
+#endif
+}
+
+
+
+Module* ClothingScene::getModule()
+{
+ return mModule;
+}
+
+
+
+bool ClothingScene::isSimulating() const
+{
+ if (mApexScene != NULL)
+ {
+ return mApexScene->isSimulating();
+ }
+
+ return false;
+}
+
+
+
+void ClothingScene::registerAsset(ClothingAssetImpl* asset)
+{
+ mClothingAssetsMutex.lock();
+ for (uint32_t i = 0; i < mClothingAssets.size(); i++)
+ {
+ if (mClothingAssets[i] == asset)
+ {
+ mClothingAssetsMutex.unlock();
+ return;
+ }
+ }
+ mClothingAssets.pushBack(asset);
+ mClothingAssetsMutex.unlock();
+}
+
+
+
+void ClothingScene::unregisterAsset(ClothingAssetImpl* asset)
+{
+ // remove assets from assets list
+ mClothingAssetsMutex.lock();
+ for (int32_t i = (int32_t)mClothingAssets.size() - 1; i >= 0; i--)
+ {
+ if (mClothingAssets[(uint32_t)i] == asset)
+ {
+ mClothingAssets.replaceWithLast((uint32_t)i);
+ }
+ }
+ mClothingAssetsMutex.unlock();
+
+ removeRenderProxies(asset);
+}
+
+
+
+void ClothingScene::removeRenderProxies(ClothingAssetImpl* asset)
+{
+ // delete all render proxies that have the RenderMeshAsset
+ // of this ClothingAssetImpl
+ mRenderProxiesLock.lock();
+ uint32_t numGraphicalMeshes = asset->getNumGraphicalMeshes();
+ for (uint32_t i = 0; i < numGraphicalMeshes; ++i)
+ {
+ RenderMeshAssetIntl* renderMeshAsset = asset->getGraphicalMesh(i);
+
+ Array<ClothingRenderProxyImpl*>& renderProxies = mRenderProxies[renderMeshAsset];
+ for (int32_t i = (int32_t)renderProxies.size()-1; i >= 0 ; --i)
+ {
+ ClothingRenderProxyImpl* renderProxy = renderProxies[(uint32_t)i];
+ if (renderProxy->getTimeInPool() > 0)
+ {
+ PX_DELETE(renderProxies[(uint32_t)i]);
+ }
+ else
+ {
+ renderProxy->notifyAssetRelease();
+ }
+ }
+ renderProxies.clear();
+ mRenderProxies.erase(renderMeshAsset);
+ }
+ mRenderProxiesLock.unlock();
+}
+
+
+
+uint32_t ClothingScene::submitCookingTask(ClothingCookingTask* newTask)
+{
+ mCookingTaskMutex.lock();
+
+ ClothingCookingTask** currPointer = &mCurrentCookingTask;
+ ClothingCookingTask* lastTask = NULL;
+
+ uint32_t numRunning = 0;
+ uint32_t numReleased = 0;
+
+ while (*currPointer != NULL)
+ {
+ PX_ASSERT(lastTask == NULL || currPointer == &lastTask->nextTask);
+ if ((*currPointer)->readyForRelease())
+ {
+ ClothingCookingTask* releaseMe = *currPointer;
+ *currPointer = releaseMe->nextTask;
+ delete releaseMe;
+ numReleased++;
+ }
+ else
+ {
+ lastTask = *currPointer;
+ numRunning += lastTask->waitsForBeingScheduled() ? 0 : 1;
+ currPointer = &(*currPointer)->nextTask;
+ }
+ }
+
+ // set the linked list
+ *currPointer = newTask;
+ if (newTask != NULL)
+ {
+ PX_ASSERT(mApexScene->getTaskManager() != NULL);
+ newTask->initCooking(*mApexScene->getTaskManager(), NULL);
+ }
+
+ if (numRunning == 0 && mCurrentCookingTask != NULL)
+ {
+ PX_ASSERT(mCurrentCookingTask->waitsForBeingScheduled());
+ mCurrentCookingTask->removeReference();
+ }
+
+ mCookingTaskMutex.unlock();
+
+ return numReleased;
+}
+
+
+
+void ClothingScene::destroy()
+{
+ for (uint32_t i = 0; i < mActorArray.size(); i++)
+ {
+ ClothingActorImpl* clothingActor = static_cast<ClothingActorImpl*>(mActorArray[i]);
+ clothingActor->waitForFetchResults();
+ }
+
+ removeAllActors();
+
+ mClothingAssetsMutex.lock();
+ for (uint32_t i = 0 ; i < mClothingAssets.size(); i++)
+ {
+ // for PhysX3: making sure that fabrics (in assets) are released before the factories (in mSimulationTask)
+ mClothingAssets[i]->releaseCookedInstances();
+ }
+ mClothingAssets.clear();
+ mClothingAssetsMutex.unlock();
+
+ // clear render list
+ for (HashMap<RenderMeshAssetIntl*, Array<ClothingRenderProxyImpl*> >::Iterator iter = mRenderProxies.getIterator(); !iter.done(); ++iter)
+ {
+ Array<ClothingRenderProxyImpl*>& renderProxies = iter->second;
+
+ for (int32_t i = (int32_t)renderProxies.size()-1; i >= 0 ; --i)
+ {
+ uint32_t timeInPool = renderProxies[(uint32_t)i]->getTimeInPool();
+ if (timeInPool > 0)
+ {
+ PX_DELETE(renderProxies[(uint32_t)i]);
+ renderProxies.replaceWithLast((uint32_t)i);
+ }
+ else
+ {
+ // actually the scene is released, but we just want to make sure
+ // that the render proxy deletes itself when it's returned next time
+ renderProxies[(uint32_t)i]->notifyAssetRelease();
+ }
+ }
+
+ renderProxies.clear();
+ }
+ //mRenderProxies.clear();
+
+ while (mCurrentCookingTask != NULL)
+ {
+ submitCookingTask(NULL);
+ nvidia::Thread::sleep(0); // wait for remaining cooking tasks to finish
+ }
+
+ if (mSimulationTask != NULL)
+ {
+#if PX_PHYSICS_VERSION_MAJOR == 3
+ setModulePhysXScene(NULL); // does some cleanup necessary here. Only needed when module gets deleted without the apex scene being deleted before!
+#elif APEX_CUDA_SUPPORT
+ if (mGpuFactory.factory != NULL)
+ {
+ mSimulationTask->clearGpuSolver();
+ mGpuFactory.clear();
+ }
+#endif
+ PX_DELETE(mSimulationTask);
+ mSimulationTask = NULL;
+ }
+
+ if (mWaitForSolverTask != NULL)
+ {
+ PX_DELETE(mWaitForSolverTask);
+ mWaitForSolverTask = NULL;
+ }
+
+ {
+ if (mCpuFactory.factory != NULL)
+ {
+ mCpuFactory.clear();
+ }
+
+#if APEX_CUDA_SUPPORT
+ PX_ASSERT(mGpuFactory.factory == NULL);
+
+ ApexSDKIntl* apexSdk = GetInternalApexSDK();
+ apexSdk->unregisterPhysXIndicatorGpuClient(mPhysXGpuIndicator);
+ mPhysXGpuIndicator = NULL;
+#endif
+ }
+
+ mApexScene->moduleReleased(*this);
+ delete this;
+}
+
+
+
+void ClothingScene::ClothingBeforeTickStartTask::run()
+{
+#ifdef PROFILE
+ PIXBeginNamedEvent(0, "ClothingBeforeTickStartTask");
+#endif
+ for (uint32_t i = 0; i < m_pScene->mActorArray.size(); ++i)
+ {
+ ClothingActorImpl* actor = static_cast<ClothingActorImpl*>(m_pScene->mActorArray[i]);
+
+ actor->startBeforeTickTask();
+ }
+#ifdef PROFILE
+ PIXEndNamedEvent();
+#endif
+}
+
+
+
+const char* ClothingScene::ClothingBeforeTickStartTask::getName() const
+{
+#if APEX_UE4
+ return CLOTHING_BEFORE_TICK_START_TASK_NAME;
+#else
+ return "ClothingScene::ClothingBeforeTickStartTask";
+#endif
+}
+
+
+
+ClothFactory ClothingScene::getClothFactory(bool& useCuda)
+{
+#if APEX_CUDA_SUPPORT
+ if (useCuda)
+ {
+ if (mGpuFactory.factory == NULL)
+ {
+ PxCudaContextManager* contextManager = NULL;
+ PxGpuDispatcher* gpuDispatcher = mApexScene->getTaskManager()->getGpuDispatcher();
+ if (gpuDispatcher != NULL)
+ {
+ contextManager = gpuDispatcher->getCudaContextManager();
+ }
+
+ if (contextManager != NULL)
+ {
+ mGpuFactory = mModule->createClothFactory(contextManager);
+ if (mGpuFactory.factory != NULL)
+ {
+ ApexSDKIntl* apexSdk = GetInternalApexSDK();
+ mPhysXGpuIndicator = apexSdk->registerPhysXIndicatorGpuClient();
+ }
+ }
+ }
+
+ //APEX_DEBUG_INFO("Gpu Factory %p", mGpuFactory);
+ if (mGpuFactory.factory != NULL)
+ {
+ return mGpuFactory;
+ }
+ else
+ {
+ APEX_DEBUG_INFO("Gpu Factory could not be created");
+ useCuda = false;
+ }
+ }
+
+ if (!useCuda)
+#else
+ PX_UNUSED(useCuda);
+#endif
+ {
+ if (mCpuFactory.factory == NULL)
+ {
+ mCpuFactory = mModule->createClothFactory(NULL);
+ }
+
+ //APEX_DEBUG_INFO("Cpu Factory %p", mCpuFactory.factory);
+ return mCpuFactory;
+ }
+
+#if APEX_CUDA_SUPPORT
+ PX_ALWAYS_ASSERT_MESSAGE("this code path is unreachable, at least it used to be.");
+ return ClothFactory(NULL, NULL);
+#endif
+}
+
+
+
+cloth::Solver* ClothingScene::getClothSolver(bool useCuda)
+{
+ ClothFactory factory(NULL, NULL);
+#if APEX_CUDA_SUPPORT
+ if (useCuda)
+ {
+ factory = mGpuFactory;
+ }
+ else
+#else
+ PX_UNUSED(useCuda);
+#endif
+ {
+ factory = mCpuFactory;
+ }
+
+ PX_ASSERT(factory.factory != NULL);
+ if (factory.factory != NULL)
+ {
+ return mSimulationTask->getSolver(factory);
+ }
+
+ return NULL;
+}
+
+
+
+void ClothingScene::lockScene()
+{
+ mSceneLock.lock();
+
+ if (mSceneRunning == 1)
+ {
+ APEX_INVALID_OPERATION("The scene is running while the scene write lock is being acquired!");
+ PX_ALWAYS_ASSERT();
+ }
+}
+
+
+
+void ClothingScene::unlockScene()
+{
+ mSceneLock.unlock();
+}
+
+
+
+void ClothingScene::setSceneRunning(bool on)
+{
+#ifndef _DEBUG
+ int32_t newValue;
+ if (on)
+ {
+ APEX_CHECK_STAT_TIMER("--------- Start ClothingSimulationTime");
+ mClothingSimulationTime.getElapsedSeconds();
+
+ newValue = nvidia::atomicIncrement(&mSceneRunning);
+ }
+ else
+ {
+ StatValue dataVal;
+ dataVal.Float = (float)(1000.0f * mClothingSimulationTime.getElapsedSeconds());
+ APEX_CHECK_STAT_TIMER("--------- Stop ClothingSimulationTime");
+ mApexScene->setApexStatValue(SceneIntl::ClothingSimulationTime, dataVal);
+
+ // Warn if simulation time was bigger than timestep for 10 or more consecutive frames
+ float simulatedTime = 1000.0f * mApexScene->getElapsedTime();
+ if (simulatedTime < dataVal.Float)
+ {
+ mFramesCount++;
+ mSimulatedTime += simulatedTime;
+ mTimestep += dataVal.Float;
+ }
+
+ if (mFramesCount >= 10)
+ {
+ float averageSimulatedTime = mSimulatedTime / (float)mFramesCount;
+ float averageTimestep = mTimestep / (float)mFramesCount;
+ APEX_DEBUG_WARNING("Cloth complexity in scene is too high to be simulated in real time for 10 consecutive frames. (Average Delta Time: %f ms, Average Simulation Time: %f ms)",
+ averageSimulatedTime, averageTimestep);
+ mFramesCount = 0;
+ mSimulatedTime = 0.f;
+ mTimestep = 0.f;
+ }
+
+ newValue = nvidia::atomicDecrement(&mSceneRunning);
+ }
+
+ if (newValue != (on ? 1 : 0))
+ {
+ APEX_INTERNAL_ERROR("scene running state was not tracked properly!: on = %s, prevValue = %d", on ? "true" : "false", newValue);
+ }
+#else
+ PX_UNUSED(on);
+#endif
+}
+
+
+
+void ClothingScene::embeddedPostSim()
+{
+ for (uint32_t i = 0; i < mActorArray.size(); i++)
+ {
+ ClothingActorImpl* clothingActor = static_cast<ClothingActorImpl*>(mActorArray[i]);
+ clothingActor->startFetchTasks();
+ }
+}
+
+
+
+ClothingRenderProxyImpl* ClothingScene::getRenderProxy(RenderMeshAssetIntl* rma, bool useFallbackSkinning, bool useCustomVertexBuffer, const HashMap<uint32_t, ApexSimpleString>& overrideMaterials, const PxVec3* morphTargetNewPositions, const uint32_t* morphTargetVertexOffsets)
+{
+ if (rma == NULL)
+ {
+ return NULL;
+ }
+
+ ClothingRenderProxyImpl* renderProxy = NULL;
+
+
+ mRenderProxiesLock.lock();
+ Array<ClothingRenderProxyImpl*>& renderProxies = mRenderProxies[rma];
+ for (uint32_t i = 0; i < renderProxies.size(); ++i)
+ {
+ ClothingRenderProxyImpl* proxyInPool = renderProxies[i];
+ if (
+ proxyInPool->getTimeInPool() > 0 && // proxy is available
+ useFallbackSkinning == proxyInPool->usesFallbackSkinning() &&
+ useCustomVertexBuffer == proxyInPool->usesCustomVertexBuffer() &&
+ morphTargetNewPositions == proxyInPool->getMorphTargetBuffer() &&
+ proxyInPool->overrideMaterialsEqual(overrideMaterials)
+ )
+ {
+ renderProxy = proxyInPool;
+ break;
+ }
+ }
+
+ // no corresponding proxy in pool, so create one
+ if (renderProxy == NULL)
+ {
+ renderProxy = PX_NEW(ClothingRenderProxyImpl)(rma, useFallbackSkinning, useCustomVertexBuffer, overrideMaterials, morphTargetNewPositions, morphTargetVertexOffsets, this);
+ renderProxies.pushBack(renderProxy);
+ }
+
+ renderProxy->setTimeInPool(0);
+ mRenderProxiesLock.unlock();
+
+ return renderProxy;
+}
+
+
+
+void ClothingScene::tickRenderProxies()
+{
+ PX_PROFILE_ZONE("ClothingScene::tickRenderProxies", GetInternalApexSDK()->getContextId());
+ mRenderProxiesLock.lock();
+
+ for(HashMap<RenderMeshAssetIntl*, Array<ClothingRenderProxyImpl*> >::Iterator iter = mRenderProxies.getIterator(); !iter.done(); ++iter)
+ {
+ Array<ClothingRenderProxyImpl*>& renderProxies = iter->second;
+
+ for (int32_t i = (int32_t)renderProxies.size()-1; i >= 0 ; --i)
+ {
+ uint32_t timeInPool = renderProxies[(uint32_t)i]->getTimeInPool();
+
+ if (timeInPool > 0)
+ {
+ if (timeInPool > mModule->getMaxTimeRenderProxyInPool() + 1) // +1 because we add them with time 1
+ {
+ PX_DELETE(renderProxies[(uint32_t)i]);
+ renderProxies.replaceWithLast((uint32_t)i);
+ }
+ else
+ {
+ renderProxies[(uint32_t)i]->setTimeInPool(timeInPool+1);
+ }
+ }
+ }
+ }
+
+ mRenderProxiesLock.unlock();
+}
+
+}
+} // namespace nvidia
+
diff --git a/APEX_1.4/module/clothing/src/CookingAbstract.cpp b/APEX_1.4/module/clothing/src/CookingAbstract.cpp
new file mode 100644
index 00000000..8d40c927
--- /dev/null
+++ b/APEX_1.4/module/clothing/src/CookingAbstract.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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 "CookingAbstract.h"
+
+
+
+namespace nvidia
+{
+namespace clothing
+{
+
+using namespace nvidia;
+
+void CookingAbstract::PhysicalMesh::computeTriangleAreas()
+{
+ smallestTriangleArea = largestTriangleArea = 0.0f;
+
+ if (indices == NULL || vertices == NULL)
+ {
+ return;
+ }
+
+ smallestTriangleArea = PX_MAX_F32;
+
+ for (uint32_t i = 0; i < numIndices; i += 3)
+ {
+ const PxVec3 edge1 = vertices[indices[i + 1]] - vertices[indices[i]];
+ const PxVec3 edge2 = vertices[indices[i + 2]] - vertices[indices[i]];
+ const float triangleArea = edge1.cross(edge2).magnitude();
+
+ largestTriangleArea = PxMax(largestTriangleArea, triangleArea);
+ smallestTriangleArea = PxMin(smallestTriangleArea, triangleArea);
+ }
+}
+
+
+
+void CookingAbstract::addPhysicalMesh(const PhysicalMesh& physicalMesh)
+{
+ PhysicalMesh physicalMeshCopy = physicalMesh;
+ physicalMeshCopy.computeTriangleAreas();
+ mPhysicalMeshes.pushBack(physicalMeshCopy);
+}
+
+
+
+void CookingAbstract::setConvexBones(const BoneActorEntry* boneActors, uint32_t numBoneActors, const BoneEntry* boneEntries,
+ uint32_t numBoneEntries, const PxVec3* boneVertices, uint32_t maxConvexVertices)
+{
+ mBoneActors = boneActors;
+ mNumBoneActors = numBoneActors;
+ mBoneEntries = boneEntries;
+ mNumBoneEntries = numBoneEntries;
+ mBoneVertices = boneVertices;
+
+ PX_ASSERT(maxConvexVertices <= 256);
+ mMaxConvexVertices = maxConvexVertices;
+}
+
+
+bool CookingAbstract::isValid() const
+{
+ return mPhysicalMeshes.size() > 0;
+}
+
+}
+} \ No newline at end of file
diff --git a/APEX_1.4/module/clothing/src/ModuleClothingHelpers.cpp b/APEX_1.4/module/clothing/src/ModuleClothingHelpers.cpp
new file mode 100644
index 00000000..7fbe1c46
--- /dev/null
+++ b/APEX_1.4/module/clothing/src/ModuleClothingHelpers.cpp
@@ -0,0 +1,90 @@
+/*
+ * 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 "ModuleClothingHelpers.h"
+#include "AbstractMeshDescription.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+void AbstractMeshDescription::UpdateDerivedInformation(RenderDebugInterface* renderDebug)
+{
+ if (numIndices > 0)
+ {
+ pMin = pPosition[pIndices[0]];
+ pMax = pMin;
+ }
+ avgEdgeLength = 0;
+ avgTriangleArea = 0;
+
+ uint32_t triCount(numIndices / 3);
+ uint32_t edgeCount(numIndices);
+ for (uint32_t j = 0; j < numIndices; j += 3)
+ {
+ uint32_t i0 = pIndices[j + 0];
+ uint32_t i1 = pIndices[j + 1];
+ uint32_t i2 = pIndices[j + 2];
+
+ const PxVec3& v0 = pPosition[i0];
+ const PxVec3& v1 = pPosition[i1];
+ const PxVec3& v2 = pPosition[i2];
+
+ pMin.minimum(v0);
+ pMin.minimum(v1);
+ pMin.minimum(v2);
+
+ pMax.maximum(v0);
+ pMax.maximum(v1);
+ pMax.maximum(v2);
+
+ PxVec3 e0 = v1 - v0;
+ PxVec3 e1 = v2 - v1;
+ PxVec3 e2 = v0 - v2;
+
+ avgEdgeLength += e0.magnitude();
+ avgEdgeLength += e1.magnitude();
+ avgEdgeLength += e2.magnitude();
+
+
+ if (renderDebug)
+ {
+ using RENDER_DEBUG::DebugColors;
+ RENDER_DEBUG_IFACE(renderDebug)->setCurrentColor(RENDER_DEBUG_IFACE(renderDebug)->getDebugColor(DebugColors::DarkBlue));
+ RENDER_DEBUG_IFACE(renderDebug)->debugLine(v0, v1);
+ RENDER_DEBUG_IFACE(renderDebug)->debugLine(v1, v2);
+ RENDER_DEBUG_IFACE(renderDebug)->debugLine(v2, v0);
+ RENDER_DEBUG_IFACE(renderDebug)->setCurrentColor(RENDER_DEBUG_IFACE(renderDebug)->getDebugColor(DebugColors::Green));
+ RENDER_DEBUG_IFACE(renderDebug)->debugPoint(v0, 0.1f);
+ RENDER_DEBUG_IFACE(renderDebug)->debugPoint(v1, 0.1f);
+ RENDER_DEBUG_IFACE(renderDebug)->debugPoint(v2, 0.1f);
+ }
+
+ float triangleArea = e0.cross(e2).magnitude() * 0.5f;
+ avgTriangleArea += triangleArea;
+ triCount++;
+ }
+
+ avgEdgeLength /= edgeCount;
+ avgTriangleArea /= triCount;
+ centroid = 0.5f * (pMin + pMax);
+ radius = 0.5f * (pMax - pMin).magnitude();
+
+ //printf("Min = <%f, %f, %f>; Max = <%f, %f, %f>; centroid = <%f, %f, %f>; radius = %f; avgEdgeLength = %f; avgTriangleArea = %f;\n",
+ // pMin.x, pMin.y, pMin.z, pMax.x, pMax.y, pMax.z, centroid.x, centroid.y, centroid.z, radius, avgEdgeLength, avgTriangleArea);
+}
+
+}
+} // namespace nvidia
+
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
diff --git a/APEX_1.4/module/clothing/src/SimulationAbstract.cpp b/APEX_1.4/module/clothing/src/SimulationAbstract.cpp
new file mode 100644
index 00000000..22351f3a
--- /dev/null
+++ b/APEX_1.4/module/clothing/src/SimulationAbstract.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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 "SimulationAbstract.h"
+
+// for NUM_VERTICES_PER_CACHE_BLOCK
+#include "ClothingAssetImpl.h"
+
+
+namespace nvidia
+{
+namespace clothing
+{
+
+void SimulationAbstract::init(uint32_t numVertices, uint32_t numIndices, bool writebackNormals)
+{
+ sdkNumDeformableVertices = numVertices;
+ sdkNumDeformableIndices = numIndices;
+
+ const uint32_t alignedNumVertices = (numVertices + 15) & 0xfffffff0;
+ const uint32_t writeBackDataSize = (sizeof(PxVec3) * alignedNumVertices) * (writebackNormals ? 2 : 1);
+
+ PX_ASSERT(sdkWritebackPosition == NULL);
+ PX_ASSERT(sdkWritebackNormal == NULL);
+ sdkWritebackPosition = (PxVec3*)PX_ALLOC(writeBackDataSize, PX_DEBUG_EXP("SimulationAbstract::writebackData"));
+ sdkWritebackNormal = writebackNormals ? sdkWritebackPosition + alignedNumVertices : NULL;
+
+ const uint32_t allocNumVertices = (((numVertices + NUM_VERTICES_PER_CACHE_BLOCK - 1) / NUM_VERTICES_PER_CACHE_BLOCK)) * NUM_VERTICES_PER_CACHE_BLOCK;
+ PX_ASSERT(skinnedPhysicsPositions == NULL);
+ PX_ASSERT(skinnedPhysicsNormals == NULL);
+ skinnedPhysicsPositions = (PxVec3*)PX_ALLOC(sizeof(PxVec3) * allocNumVertices * 2, PX_DEBUG_EXP("SimulationAbstract::skinnedPhysicsPositions"));
+ skinnedPhysicsNormals = skinnedPhysicsPositions + allocNumVertices;
+}
+
+
+
+void SimulationAbstract::initSimulation(const tSimParams& s)
+{
+ simulation = s;
+}
+
+
+}
+} // namespace nvidia
+
diff --git a/APEX_1.4/module/clothing/src/autogen/ClothingActorParam.cpp b/APEX_1.4/module/clothing/src/autogen/ClothingActorParam.cpp
new file mode 100644
index 00000000..291289e7
--- /dev/null
+++ b/APEX_1.4/module/clothing/src/autogen/ClothingActorParam.cpp
@@ -0,0 +1,2394 @@
+// 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) 2008-2015 NVIDIA Corporation. All rights reserved.
+
+// This file was generated by NvParameterized/scripts/GenParameterized.pl
+
+
+#include "ClothingActorParam.h"
+#include <string.h>
+#include <stdlib.h>
+
+using namespace NvParameterized;
+
+namespace nvidia
+{
+namespace clothing
+{
+
+using namespace ClothingActorParamNS;
+
+const char* const ClothingActorParamFactory::vptr =
+ NvParameterized::getVptr<ClothingActorParam, ClothingActorParam::ClassAlignment>();
+
+const uint32_t NumParamDefs = 76;
+static NvParameterized::DefinitionImpl* ParamDefTable; // now allocated in buildTree [NumParamDefs];
+
+
+static const size_t ParamLookupChildrenTable[] =
+{
+ 1, 2, 3, 11, 12, 13, 14, 15, 16, 17, 18, 21, 24, 25, 27, 38, 54, 57, 58, 59, 61,
+ 63, 65, 66, 67, 68, 69, 70, 72, 73, 74, 75, 4, 5, 6, 7, 8, 9, 10, 19, 20, 22, 23,
+ 26, 28, 29, 30, 35, 36, 37, 31, 32, 33, 34, 39, 45, 46, 51, 52, 53, 40, 41, 42, 43,
+ 44, 47, 48, 49, 50, 55, 56, 60, 62, 64, 71,
+};
+
+#define TENUM(type) nvidia::##type
+#define CHILDREN(index) &ParamLookupChildrenTable[index]
+static const NvParameterized::ParamLookupNode ParamLookupTable[NumParamDefs] =
+{
+ { TYPE_STRUCT, false, 0, CHILDREN(0), 32 },
+ { TYPE_MAT44, false, (size_t)(&((ParametersStruct*)0)->globalPose), NULL, 0 }, // globalPose
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->useHardwareCloth), NULL, 0 }, // useHardwareCloth
+ { TYPE_STRUCT, false, (size_t)(&((ParametersStruct*)0)->flags), CHILDREN(32), 7 }, // flags
+ { TYPE_BOOL, false, (size_t)(&((ClothingActorFlags_Type*)0)->ParallelCpuSkinning), NULL, 0 }, // flags.ParallelCpuSkinning
+ { TYPE_BOOL, false, (size_t)(&((ClothingActorFlags_Type*)0)->RecomputeNormals), NULL, 0 }, // flags.RecomputeNormals
+ { TYPE_BOOL, false, (size_t)(&((ClothingActorFlags_Type*)0)->RecomputeTangents), NULL, 0 }, // flags.RecomputeTangents
+ { TYPE_BOOL, false, (size_t)(&((ClothingActorFlags_Type*)0)->Visualize), NULL, 0 }, // flags.Visualize
+ { TYPE_BOOL, false, (size_t)(&((ClothingActorFlags_Type*)0)->CorrectSimulationNormals), NULL, 0 }, // flags.CorrectSimulationNormals
+ { TYPE_BOOL, false, (size_t)(&((ClothingActorFlags_Type*)0)->ComputeRenderData), NULL, 0 }, // flags.ComputeRenderData
+ { TYPE_BOOL, false, (size_t)(&((ClothingActorFlags_Type*)0)->ComputePhysicsMeshNormals), NULL, 0 }, // flags.ComputePhysicsMeshNormals
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->fallbackSkinning), NULL, 0 }, // fallbackSkinning
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->slowStart), NULL, 0 }, // slowStart
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->useInternalBoneOrder), NULL, 0 }, // useInternalBoneOrder
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->updateStateWithGlobalMatrices), NULL, 0 }, // updateStateWithGlobalMatrices
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->uvChannelForTangentUpdate), NULL, 0 }, // uvChannelForTangentUpdate
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->maxDistanceBlendTime), NULL, 0 }, // maxDistanceBlendTime
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->clothingMaterialIndex), NULL, 0 }, // clothingMaterialIndex
+ { TYPE_STRUCT, false, (size_t)(&((ParametersStruct*)0)->windParams), CHILDREN(39), 2 }, // windParams
+ { TYPE_VEC3, false, (size_t)(&((WindParameters_Type*)0)->Velocity), NULL, 0 }, // windParams.Velocity
+ { TYPE_F32, false, (size_t)(&((WindParameters_Type*)0)->Adaption), NULL, 0 }, // windParams.Adaption
+ { TYPE_STRUCT, false, (size_t)(&((ParametersStruct*)0)->maxDistanceScale), CHILDREN(41), 2 }, // maxDistanceScale
+ { TYPE_F32, false, (size_t)(&((MaxDistanceScale_Type*)0)->Scale), NULL, 0 }, // maxDistanceScale.Scale
+ { TYPE_BOOL, false, (size_t)(&((MaxDistanceScale_Type*)0)->Multipliable), NULL, 0 }, // maxDistanceScale.Multipliable
+ { TYPE_U64, false, (size_t)(&((ParametersStruct*)0)->userData), NULL, 0 }, // userData
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->boneMatrices), CHILDREN(43), 1 }, // boneMatrices
+ { TYPE_MAT44, false, 1 * sizeof(physx::PxMat44), NULL, 0 }, // boneMatrices[]
+ { TYPE_STRUCT, false, (size_t)(&((ParametersStruct*)0)->clothDescTemplate), CHILDREN(44), 6 }, // clothDescTemplate
+ { TYPE_F32, false, (size_t)(&((ClothDescTemplate_Type*)0)->collisionResponseCoefficient), NULL, 0 }, // clothDescTemplate.collisionResponseCoefficient
+ { TYPE_U16, false, (size_t)(&((ClothDescTemplate_Type*)0)->collisionGroup), NULL, 0 }, // clothDescTemplate.collisionGroup
+ { TYPE_STRUCT, false, (size_t)(&((ClothDescTemplate_Type*)0)->groupsMask), CHILDREN(50), 4 }, // clothDescTemplate.groupsMask
+ { TYPE_U32, false, (size_t)(&((GroupsMask_Type*)0)->bits0), NULL, 0 }, // clothDescTemplate.groupsMask.bits0
+ { TYPE_U32, false, (size_t)(&((GroupsMask_Type*)0)->bits1), NULL, 0 }, // clothDescTemplate.groupsMask.bits1
+ { TYPE_U32, false, (size_t)(&((GroupsMask_Type*)0)->bits2), NULL, 0 }, // clothDescTemplate.groupsMask.bits2
+ { TYPE_U32, false, (size_t)(&((GroupsMask_Type*)0)->bits3), NULL, 0 }, // clothDescTemplate.groupsMask.bits3
+ { TYPE_BOUNDS3, false, (size_t)(&((ClothDescTemplate_Type*)0)->validBounds), NULL, 0 }, // clothDescTemplate.validBounds
+ { TYPE_U64, false, (size_t)(&((ClothDescTemplate_Type*)0)->compartment), NULL, 0 }, // clothDescTemplate.compartment
+ { TYPE_U64, false, (size_t)(&((ClothDescTemplate_Type*)0)->userData), NULL, 0 }, // clothDescTemplate.userData
+ { TYPE_STRUCT, false, (size_t)(&((ParametersStruct*)0)->shapeDescTemplate), CHILDREN(54), 6 }, // shapeDescTemplate
+ { TYPE_STRUCT, false, (size_t)(&((ShapeDescTemplate_Type*)0)->flags), CHILDREN(60), 5 }, // shapeDescTemplate.flags
+ { TYPE_BOOL, false, (size_t)(&((ShapeDescFlags_Type*)0)->NX_SF_VISUALIZATION), NULL, 0 }, // shapeDescTemplate.flags.NX_SF_VISUALIZATION
+ { TYPE_BOOL, false, (size_t)(&((ShapeDescFlags_Type*)0)->NX_SF_DISABLE_COLLISION), NULL, 0 }, // shapeDescTemplate.flags.NX_SF_DISABLE_COLLISION
+ { TYPE_BOOL, false, (size_t)(&((ShapeDescFlags_Type*)0)->NX_SF_DISABLE_RAYCASTING), NULL, 0 }, // shapeDescTemplate.flags.NX_SF_DISABLE_RAYCASTING
+ { TYPE_BOOL, false, (size_t)(&((ShapeDescFlags_Type*)0)->NX_SF_DYNAMIC_DYNAMIC_CCD), NULL, 0 }, // shapeDescTemplate.flags.NX_SF_DYNAMIC_DYNAMIC_CCD
+ { TYPE_BOOL, false, (size_t)(&((ShapeDescFlags_Type*)0)->NX_SF_DISABLE_SCENE_QUERIES), NULL, 0 }, // shapeDescTemplate.flags.NX_SF_DISABLE_SCENE_QUERIES
+ { TYPE_U16, false, (size_t)(&((ShapeDescTemplate_Type*)0)->collisionGroup), NULL, 0 }, // shapeDescTemplate.collisionGroup
+ { TYPE_STRUCT, false, (size_t)(&((ShapeDescTemplate_Type*)0)->groupsMask), CHILDREN(65), 4 }, // shapeDescTemplate.groupsMask
+ { TYPE_U32, false, (size_t)(&((GroupsMask_Type*)0)->bits0), NULL, 0 }, // shapeDescTemplate.groupsMask.bits0
+ { TYPE_U32, false, (size_t)(&((GroupsMask_Type*)0)->bits1), NULL, 0 }, // shapeDescTemplate.groupsMask.bits1
+ { TYPE_U32, false, (size_t)(&((GroupsMask_Type*)0)->bits2), NULL, 0 }, // shapeDescTemplate.groupsMask.bits2
+ { TYPE_U32, false, (size_t)(&((GroupsMask_Type*)0)->bits3), NULL, 0 }, // shapeDescTemplate.groupsMask.bits3
+ { TYPE_U16, false, (size_t)(&((ShapeDescTemplate_Type*)0)->materialIndex), NULL, 0 }, // shapeDescTemplate.materialIndex
+ { TYPE_U64, false, (size_t)(&((ShapeDescTemplate_Type*)0)->userData), NULL, 0 }, // shapeDescTemplate.userData
+ { TYPE_U64, false, (size_t)(&((ShapeDescTemplate_Type*)0)->name), NULL, 0 }, // shapeDescTemplate.name
+ { TYPE_STRUCT, false, (size_t)(&((ParametersStruct*)0)->actorDescTemplate), CHILDREN(69), 2 }, // actorDescTemplate
+ { TYPE_U64, false, (size_t)(&((ActorDescTemplate_Type*)0)->userData), NULL, 0 }, // actorDescTemplate.userData
+ { TYPE_U64, false, (size_t)(&((ActorDescTemplate_Type*)0)->name), NULL, 0 }, // actorDescTemplate.name
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->actorScale), NULL, 0 }, // actorScale
+ { TYPE_REF, false, (size_t)(&((ParametersStruct*)0)->runtimeCooked), NULL, 0 }, // runtimeCooked
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->morphDisplacements), CHILDREN(71), 1 }, // morphDisplacements
+ { TYPE_VEC3, false, 1 * sizeof(physx::PxVec3), NULL, 0 }, // morphDisplacements[]
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->morphPhysicalMeshNewPositions), CHILDREN(72), 1 }, // morphPhysicalMeshNewPositions
+ { TYPE_VEC3, false, 1 * sizeof(physx::PxVec3), NULL, 0 }, // morphPhysicalMeshNewPositions[]
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->morphGraphicalMeshNewPositions), CHILDREN(73), 1 }, // morphGraphicalMeshNewPositions
+ { TYPE_VEC3, false, 1 * sizeof(physx::PxVec3), NULL, 0 }, // morphGraphicalMeshNewPositions[]
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->allowAdaptiveTargetFrequency), NULL, 0 }, // allowAdaptiveTargetFrequency
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->useVelocityClamping), NULL, 0 }, // useVelocityClamping
+ { TYPE_BOUNDS3, false, (size_t)(&((ParametersStruct*)0)->vertexVelocityClamp), NULL, 0 }, // vertexVelocityClamp
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->pressure), NULL, 0 }, // pressure
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->multiplyGlobalPoseIntoBones), NULL, 0 }, // multiplyGlobalPoseIntoBones
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->overrideMaterialNames), CHILDREN(74), 1 }, // overrideMaterialNames
+ { TYPE_STRING, false, 1 * sizeof(NvParameterized::DummyStringStruct), NULL, 0 }, // overrideMaterialNames[]
+ { TYPE_ENUM, false, (size_t)(&((ParametersStruct*)0)->simulationBackend), NULL, 0 }, // simulationBackend
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->freezeByLOD), NULL, 0 }, // freezeByLOD
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->localSpaceSim), NULL, 0 }, // localSpaceSim
+ { TYPE_I32, false, (size_t)(&((ParametersStruct*)0)->teleportMode), NULL, 0 }, // teleportMode
+};
+
+
+bool ClothingActorParam::mBuiltFlag = false;
+NvParameterized::MutexType ClothingActorParam::mBuiltFlagMutex;
+
+ClothingActorParam::ClothingActorParam(NvParameterized::Traits* traits, void* buf, int32_t* refCount) :
+ NvParameters(traits, buf, refCount)
+{
+ //mParameterizedTraits->registerFactory(className(), &ClothingActorParamFactoryInst);
+
+ if (!buf) //Do not init data if it is inplace-deserialized
+ {
+ initDynamicArrays();
+ initStrings();
+ initReferences();
+ initDefaults();
+ }
+}
+
+ClothingActorParam::~ClothingActorParam()
+{
+ freeStrings();
+ freeReferences();
+ freeDynamicArrays();
+}
+
+void ClothingActorParam::destroy()
+{
+ // We cache these fields here to avoid overwrite in destructor
+ bool doDeallocateSelf = mDoDeallocateSelf;
+ NvParameterized::Traits* traits = mParameterizedTraits;
+ int32_t* refCount = mRefCount;
+ void* buf = mBuffer;
+
+ this->~ClothingActorParam();
+
+ NvParameters::destroy(this, traits, doDeallocateSelf, refCount, buf);
+}
+
+const NvParameterized::DefinitionImpl* ClothingActorParam::getParameterDefinitionTree(void)
+{
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+ if (!mBuiltFlag)
+ {
+ buildTree();
+ }
+ }
+
+ return(&ParamDefTable[0]);
+}
+
+const NvParameterized::DefinitionImpl* ClothingActorParam::getParameterDefinitionTree(void) const
+{
+ ClothingActorParam* tmpParam = const_cast<ClothingActorParam*>(this);
+
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+ if (!mBuiltFlag)
+ {
+ tmpParam->buildTree();
+ }
+ }
+
+ return(&ParamDefTable[0]);
+}
+
+NvParameterized::ErrorType ClothingActorParam::getParameterHandle(const char* long_name, Handle& handle) const
+{
+ ErrorType Ret = NvParameters::getParameterHandle(long_name, handle);
+ if (Ret != ERROR_NONE)
+ {
+ return(Ret);
+ }
+
+ size_t offset;
+ void* ptr;
+
+ getVarPtr(handle, ptr, offset);
+
+ if (ptr == NULL)
+ {
+ return(ERROR_INDEX_OUT_OF_RANGE);
+ }
+
+ return(ERROR_NONE);
+}
+
+NvParameterized::ErrorType ClothingActorParam::getParameterHandle(const char* long_name, Handle& handle)
+{
+ ErrorType Ret = NvParameters::getParameterHandle(long_name, handle);
+ if (Ret != ERROR_NONE)
+ {
+ return(Ret);
+ }
+
+ size_t offset;
+ void* ptr;
+
+ getVarPtr(handle, ptr, offset);
+
+ if (ptr == NULL)
+ {
+ return(ERROR_INDEX_OUT_OF_RANGE);
+ }
+
+ return(ERROR_NONE);
+}
+
+void ClothingActorParam::getVarPtr(const Handle& handle, void*& ptr, size_t& offset) const
+{
+ ptr = getVarPtrHelper(&ParamLookupTable[0], const_cast<ClothingActorParam::ParametersStruct*>(&parameters()), handle, offset);
+}
+
+
+/* Dynamic Handle Indices */
+/* [0] - overrideMaterialNames (not an array of structs) */
+
+void ClothingActorParam::freeParameterDefinitionTable(NvParameterized::Traits* traits)
+{
+ if (!traits)
+ {
+ return;
+ }
+
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ return;
+ }
+
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+
+ if (!mBuiltFlag)
+ {
+ return;
+ }
+
+ for (uint32_t i = 0; i < NumParamDefs; ++i)
+ {
+ ParamDefTable[i].~DefinitionImpl();
+ }
+
+ traits->free(ParamDefTable);
+
+ mBuiltFlag = false;
+}
+
+#define PDEF_PTR(index) (&ParamDefTable[index])
+
+void ClothingActorParam::buildTree(void)
+{
+
+ uint32_t allocSize = sizeof(NvParameterized::DefinitionImpl) * NumParamDefs;
+ ParamDefTable = (NvParameterized::DefinitionImpl*)(mParameterizedTraits->alloc(allocSize));
+ memset(ParamDefTable, 0, allocSize);
+
+ for (uint32_t i = 0; i < NumParamDefs; ++i)
+ {
+ NV_PARAM_PLACEMENT_NEW(ParamDefTable + i, NvParameterized::DefinitionImpl)(*mParameterizedTraits);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=0, longName=""
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[0];
+ ParamDef->init("", TYPE_STRUCT, "STRUCT", true);
+
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=1, longName="globalPose"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[1];
+ ParamDef->init("globalPose", TYPE_MAT44, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("editorDisplay", "false", true);
+ ParamDefTable[1].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("editorDisplay", "false", true);
+ HintTable[1].init("shortDescription", "The pose where the clothing asset will be put into the scene", true);
+ ParamDefTable[1].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=2, longName="useHardwareCloth"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[2];
+ ParamDef->init("useHardwareCloth", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Turns on hardware acceleration for the cloth simulation", true);
+ ParamDefTable[2].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=3, longName="flags"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[3];
+ ParamDef->init("flags", TYPE_STRUCT, "ClothingActorFlags", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "A selection of flags, can be updated at runtime.", true);
+ ParamDefTable[3].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=4, longName="flags.ParallelCpuSkinning"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[4];
+ ParamDef->init("ParallelCpuSkinning", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "All graphical vertices without correspondence to physical vertices or\ntriangles are skinned normally. This flag specifies whether this happens\nduring Physics scene simulation, or after.\nNote: If this flag is set, an inconsistency can arise when calling\nNxClothingActor::updateRenderResource in between NxApexScene::simulate\nand NxApexScene::fetchResults. As a workaround, you should only call\nNxClothingActor::updateRenderResources _after_ NxApexScene::fetchResults\nhas terminated.\n", true);
+ HintTable[1].init("shortDescription", "Determines whether or not to perform CPU skinning in parallel", true);
+ ParamDefTable[4].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=5, longName="flags.RecomputeNormals"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[5];
+ ParamDef->init("RecomputeNormals", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "This usually leads to better looking results, but is more expensive to\ncompute. Default is off.\n", true);
+ HintTable[1].init("shortDescription", "Fully recomputes the normals on the final mesh.", true);
+ ParamDefTable[5].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=6, longName="flags.RecomputeTangents"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[6];
+ ParamDef->init("RecomputeTangents", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "RecomputeTangents can only be set to false if less than half of the graphics mesh vertices have an exact\nmatch in the physics mesh. Otherwise it's always on.\n", true);
+ HintTable[1].init("shortDescription", "Fully recomputes the tangents on the final mesh.", true);
+ ParamDefTable[6].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=7, longName="flags.Visualize"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[7];
+ ParamDef->init("Visualize", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Determines whether or not to display debug visualization for this clothing actor", true);
+ ParamDefTable[7].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=8, longName="flags.CorrectSimulationNormals"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[8];
+ ParamDef->init("CorrectSimulationNormals", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "The MaxDistance=0 vertices can have a perturbed simulation normal. This usually\nhappens only for meshes where the MaxDistance=0 vertices are somewhere in the\nmiddle separating a simulated and non-simulated region. The normal for those\nvertices will be computed only by the simulated triangles which can lead to\nwrong results.\nThis solution will use the normals from the original simulation mesh and skin\nthem with respect to the local pose.\n", true);
+ HintTable[1].init("shortDescription", "", true);
+ ParamDefTable[8].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=9, longName="flags.ComputeRenderData"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[9];
+ ParamDef->init("ComputeRenderData", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "If set to false no skinning is done for this actor. Disable if all skinning is done outside of APEX.", true);
+ ParamDefTable[9].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=10, longName="flags.ComputePhysicsMeshNormals"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[10];
+ ParamDef->init("ComputePhysicsMeshNormals", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "If set to false the normals on the physics mesh are not computed. Disable skinning and normal calculation is done outside of APEX.", true);
+ ParamDefTable[10].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=11, longName="fallbackSkinning"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[11];
+ ParamDef->init("fallbackSkinning", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "Performs the regular boneweighted skinning on the CPU before giving the\ndata out through the rendering API.\n", true);
+ HintTable[1].init("shortDescription", "Performs skinning in software", true);
+ ParamDefTable[11].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=12, longName="slowStart"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[12];
+ ParamDef->init("slowStart", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "The first time a NxClothingActor starts to be simulated is with full max\ndistance. This prevents starting with full max distance and instead blending\nin as it will do the second time.\n", true);
+ HintTable[1].init("shortDescription", "Prevents from having full max distance right from the start", true);
+ ParamDefTable[12].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=13, longName="useInternalBoneOrder"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[13];
+ ParamDef->init("useInternalBoneOrder", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("editorDisplay", "false", true);
+ ParamDefTable[13].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("editorDisplay", "false", true);
+ HintTable[1].init("longDescription", "If this is set to true the bone buffers in updateState and the actor\ndescriptor have to be given in the same order as the bones are stored\ninternally in the asset. This can be queried using\nNxClothingAsset::getNumUsedBones and NxClothingAsset::getBoneName or\nNxClothingAsset::getBoneMapping.\n\nIf this is set to false, the bone buffers can be provided in the order as\nthey are stored in the application. This is either the bone order at\nauthoring time, or NxClothingAsset::remapBoneIndex can be called for each\nbone to let APEX know about the current ordering in the game. Note that\nthis is only recommended if the application already uses physx::PxMat44\n(or something binary equivalent) and does not have to convert the matrices.\n", true);
+ HintTable[2].init("shortDescription", "Expect internally ordered bone arrays in updateState call.", true);
+ ParamDefTable[13].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=14, longName="updateStateWithGlobalMatrices"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[14];
+ ParamDef->init("updateStateWithGlobalMatrices", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "Depending on what matrices are present, the state can be updated using\nglobal world or object space bone matrices or composite matrices. The\ncomposite matrix can be generated by multiplying the world or object space\nmatrix by the inverse bone bine pose.\n\nNote: If there are problems which might be caused by bind poses being\ndifferent in the ClothingAsset and in the game's animation system, changing\nthis to true (and thus providing global pose matrices) might fix the problem.\n", true);
+ HintTable[1].init("shortDescription", "Use world space matrices instead of composite (relative to bind pose) in NxClothingActor::updateState().", true);
+ ParamDefTable[14].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=15, longName="uvChannelForTangentUpdate"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[15];
+ ParamDef->init("uvChannelForTangentUpdate", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "Tangent update is done based on one UV channel. This allows selection of what\nUV channel is being used.\n", true);
+ HintTable[1].init("shortDescription", "This UV channel is used for updating tangent space", true);
+ ParamDefTable[15].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=16, longName="maxDistanceBlendTime"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[16];
+ ParamDef->init("maxDistanceBlendTime", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "Note: This also influences how quickly different physical LoDs can be switched", true);
+ HintTable[1].init("shortDescription", "Time in seconds how long it takes to go from zero maxDistance to full maxDistance", true);
+ ParamDefTable[16].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=17, longName="clothingMaterialIndex"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[17];
+ ParamDef->init("clothingMaterialIndex", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Use this material from the assets material library", true);
+ ParamDefTable[17].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=18, longName="windParams"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[18];
+ ParamDef->init("windParams", TYPE_STRUCT, "WindParameters", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The per-actor wind parameters", true);
+ ParamDefTable[18].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=19, longName="windParams.Velocity"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[19];
+ ParamDef->init("Velocity", TYPE_VEC3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The target velocity each vertex tries to achieve.", true);
+ ParamDefTable[19].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=20, longName="windParams.Adaption"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[20];
+ ParamDef->init("Adaption", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "This is roughly the inverse of the time in seconds it takes to adapt to the wind velocity.", true);
+ HintTable[1].init("shortDescription", "The rate of adaption. The higher this value, the faster the cloth reaches the wind velocity. Set to 0 to turn off wind.", true);
+ ParamDefTable[20].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=21, longName="maxDistanceScale"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[21];
+ ParamDef->init("maxDistanceScale", TYPE_STRUCT, "MaxDistanceScale", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Maximum distance scale", true);
+ ParamDefTable[21].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=22, longName="maxDistanceScale.Scale"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[22];
+ ParamDef->init("Scale", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Scale", true);
+ ParamDefTable[22].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=23, longName="maxDistanceScale.Multipliable"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[23];
+ ParamDef->init("Multipliable", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Multipliable", true);
+ ParamDefTable[23].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=24, longName="userData"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[24];
+ ParamDef->init("userData", TYPE_U64, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("editorDisplay", "false", true);
+ ParamDefTable[24].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("editorDisplay", "false", true);
+ HintTable[1].init("shortDescription", "Optional user data pointer associated with the clothing actor", true);
+ ParamDefTable[24].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=25, longName="boneMatrices"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[25];
+ ParamDef->init("boneMatrices", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("editorDisplay", "false", true);
+ ParamDefTable[25].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("editorDisplay", "false", true);
+ HintTable[1].init("longDescription", "These matrices are sometimes referred to as composite matrices. They are the\nmultiplication of the current world space bone pose with the inverse bind\npose in world space.\nNote: If \'updateStateWithGlobalMatrices\' is set to true, these must be\nglobal poses instead.\n", true);
+ HintTable[2].init("shortDescription", "An Array of matrices with the full transform for each bone", true);
+ ParamDefTable[25].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=26, longName="boneMatrices[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[26];
+ ParamDef->init("boneMatrices", TYPE_MAT44, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("editorDisplay", "false", true);
+ ParamDefTable[26].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("editorDisplay", "false", true);
+ HintTable[1].init("longDescription", "These matrices are sometimes referred to as composite matrices. They are the\nmultiplication of the current world space bone pose with the inverse bind\npose in world space.\nNote: If \'updateStateWithGlobalMatrices\' is set to true, these must be\nglobal poses instead.\n", true);
+ HintTable[2].init("shortDescription", "An Array of matrices with the full transform for each bone", true);
+ ParamDefTable[26].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=27, longName="clothDescTemplate"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[27];
+ ParamDef->init("clothDescTemplate", TYPE_STRUCT, "ClothDescTemplate", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Contains the parameters the application can override on the NxClothDesc when created", true);
+ ParamDefTable[27].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=28, longName="clothDescTemplate.collisionResponseCoefficient"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[28];
+ ParamDef->init("collisionResponseCoefficient", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "This is only needed if the twoway interaction flag is set in the clothing asset.", true);
+ HintTable[1].init("shortDescription", "Defines a factor for the impulse transfer from cloth to colliding rigid bodies.", true);
+ ParamDefTable[28].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=29, longName="clothDescTemplate.collisionGroup"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[29];
+ ParamDef->init("collisionGroup", TYPE_U16, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Sets which collision group this cloth is part of.", true);
+ ParamDefTable[29].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=30, longName="clothDescTemplate.groupsMask"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[30];
+ ParamDef->init("groupsMask", TYPE_STRUCT, "GroupsMask", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Sets the 128-bit mask used for collision filtering.", true);
+ ParamDefTable[30].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=31, longName="clothDescTemplate.groupsMask.bits0"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[31];
+ ParamDef->init("bits0", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "First part of 128-bit group mask", true);
+ ParamDefTable[31].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=32, longName="clothDescTemplate.groupsMask.bits1"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[32];
+ ParamDef->init("bits1", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Second part of 128-bit group mask", true);
+ ParamDefTable[32].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=33, longName="clothDescTemplate.groupsMask.bits2"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[33];
+ ParamDef->init("bits2", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Third part of 128-bit group mask", true);
+ ParamDefTable[33].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=34, longName="clothDescTemplate.groupsMask.bits3"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[34];
+ ParamDef->init("bits3", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Fourth part of 128-bit group mask", true);
+ ParamDefTable[34].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=35, longName="clothDescTemplate.validBounds"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[35];
+ ParamDef->init("validBounds", TYPE_BOUNDS3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "Only works if the flag NX_CLF_VALIDBOUNDS is set.", true);
+ HintTable[1].init("shortDescription", "Defines the volume outside of which cloth particle are automatically removed from the simulation. ", true);
+ ParamDefTable[35].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=36, longName="clothDescTemplate.compartment"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[36];
+ ParamDef->init("compartment", TYPE_U64, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("editorDisplay", "false", true);
+ ParamDefTable[36].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("editorDisplay", "false", true);
+ HintTable[1].init("longDescription", "Must be either a pointer to an NxCompartment of type NX_SCT_CLOTH or\nNX_SCT_SOFTBODY, or NULL. A NULL compartment means creating NX_CLF_HARDWARE\ncloth in the first available cloth compartment (a default cloth compartment\nis created if none exists). Software cloth with a NULL compartment is\ncreated in the scene proper.\n", true);
+ HintTable[2].init("shortDescription", "The compartment to place the cloth in.", true);
+ ParamDefTable[36].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=37, longName="clothDescTemplate.userData"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[37];
+ ParamDef->init("userData", TYPE_U64, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("editorDisplay", "false", true);
+ ParamDefTable[37].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("editorDisplay", "false", true);
+ HintTable[1].init("shortDescription", "Optional user data pointer.", true);
+ ParamDefTable[37].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=38, longName="shapeDescTemplate"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[38];
+ ParamDef->init("shapeDescTemplate", TYPE_STRUCT, "ShapeDescTemplate", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Contains the parameters the application can override on any actor shapes created", true);
+ ParamDefTable[38].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=39, longName="shapeDescTemplate.flags"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[39];
+ ParamDef->init("flags", TYPE_STRUCT, "ShapeDescFlags", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Shape description flags", true);
+ ParamDefTable[39].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=40, longName="shapeDescTemplate.flags.NX_SF_VISUALIZATION"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[40];
+ ParamDef->init("NX_SF_VISUALIZATION", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Enable debug renderer for this shape", true);
+ ParamDefTable[40].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=41, longName="shapeDescTemplate.flags.NX_SF_DISABLE_COLLISION"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[41];
+ ParamDef->init("NX_SF_DISABLE_COLLISION", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Disable collision detection for this shape (counterpart of NX_AF_DISABLE_COLLISION)", true);
+ ParamDefTable[41].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=42, longName="shapeDescTemplate.flags.NX_SF_DISABLE_RAYCASTING"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[42];
+ ParamDef->init("NX_SF_DISABLE_RAYCASTING", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Disable raycasting for this shape", true);
+ ParamDefTable[42].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=43, longName="shapeDescTemplate.flags.NX_SF_DYNAMIC_DYNAMIC_CCD"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[43];
+ ParamDef->init("NX_SF_DYNAMIC_DYNAMIC_CCD", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Enable dynamic-dynamic CCD for this shape. Used only when CCD is globally enabled and shape have a CCD skeleton.", true);
+ ParamDefTable[43].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=44, longName="shapeDescTemplate.flags.NX_SF_DISABLE_SCENE_QUERIES"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[44];
+ ParamDef->init("NX_SF_DISABLE_SCENE_QUERIES", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "Setting this to true will make the non-compartment CPU cloth not work.", true);
+ HintTable[1].init("shortDescription", "Disable participation in ray casts, overlap tests and sweeps.", true);
+ ParamDefTable[44].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=45, longName="shapeDescTemplate.collisionGroup"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[45];
+ ParamDef->init("collisionGroup", TYPE_U16, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "Default group is 0. Maximum possible group is 31. Collision groups are sets\nof shapes which may or may not be set to collision detect with each other;\nthis can be set using NxScene::setGroupCollisionFlag()\nSleeping: Does NOT wake the associated actor up automatically.\n", true);
+ HintTable[1].init("shortDescription", "Sets which collision group this shape is part of.", true);
+ ParamDefTable[45].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=46, longName="shapeDescTemplate.groupsMask"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[46];
+ ParamDef->init("groupsMask", TYPE_STRUCT, "GroupsMask", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Sets the 128-bit mask used for collision filtering.", true);
+ ParamDefTable[46].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=47, longName="shapeDescTemplate.groupsMask.bits0"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[47];
+ ParamDef->init("bits0", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "First part of 128-bit group mask", true);
+ ParamDefTable[47].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=48, longName="shapeDescTemplate.groupsMask.bits1"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[48];
+ ParamDef->init("bits1", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Second part of 128-bit group mask", true);
+ ParamDefTable[48].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=49, longName="shapeDescTemplate.groupsMask.bits2"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[49];
+ ParamDef->init("bits2", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Third part of 128-bit group mask", true);
+ ParamDefTable[49].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=50, longName="shapeDescTemplate.groupsMask.bits3"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[50];
+ ParamDef->init("bits3", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Fourth part of 128-bit group mask", true);
+ ParamDefTable[50].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=51, longName="shapeDescTemplate.materialIndex"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[51];
+ ParamDef->init("materialIndex", TYPE_U16, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The material index of the shape.", true);
+ ParamDefTable[51].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=52, longName="shapeDescTemplate.userData"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[52];
+ ParamDef->init("userData", TYPE_U64, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("editorDisplay", "false", true);
+ ParamDefTable[52].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("editorDisplay", "false", true);
+ HintTable[1].init("shortDescription", "Optional user data pointer", true);
+ ParamDefTable[52].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=53, longName="shapeDescTemplate.name"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[53];
+ ParamDef->init("name", TYPE_U64, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("editorDisplay", "false", true);
+ ParamDefTable[53].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("editorDisplay", "false", true);
+ HintTable[1].init("shortDescription", "Name of the shapes; must be set by the application and must be a persistent pointer.", true);
+ ParamDefTable[53].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=54, longName="actorDescTemplate"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[54];
+ ParamDef->init("actorDescTemplate", TYPE_STRUCT, "ActorDescTemplate", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Contains the parameters the application can override on any actors created", true);
+ ParamDefTable[54].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=55, longName="actorDescTemplate.userData"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[55];
+ ParamDef->init("userData", TYPE_U64, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("editorDisplay", "false", true);
+ ParamDefTable[55].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("editorDisplay", "false", true);
+ HintTable[1].init("shortDescription", "Optional user data pointer", true);
+ ParamDefTable[55].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=56, longName="actorDescTemplate.name"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[56];
+ ParamDef->init("name", TYPE_U64, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("editorDisplay", "false", true);
+ ParamDefTable[56].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("editorDisplay", "false", true);
+ HintTable[1].init("shortDescription", "Optional name string for the shape; must be set by the application and must be a persistent pointer.", true);
+ ParamDefTable[56].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=57, longName="actorScale"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[57];
+ ParamDef->init("actorScale", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "Setting globalPose doesn't change the actor scale, actorScale should be set separately.\n", true);
+ HintTable[1].init("shortDescription", "Scales the actor relative to the asset.", true);
+ ParamDefTable[57].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=58, longName="runtimeCooked"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[58];
+ ParamDef->init("runtimeCooked", TYPE_REF, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("INCLUDED", uint64_t(1), true);
+ ParamDefTable[58].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("INCLUDED", uint64_t(1), true);
+ HintTable[1].init("shortDescription", "Data cooked at runtime", true);
+ ParamDefTable[58].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+ static const char* const RefVariantVals[] = { "ClothingCookedParam" };
+ ParamDefTable[58].setRefVariantVals((const char**)RefVariantVals, 1);
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=59, longName="morphDisplacements"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[59];
+ ParamDef->init("morphDisplacements", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Displacements according to the current morph target.", true);
+ ParamDefTable[59].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=60, longName="morphDisplacements[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[60];
+ ParamDef->init("morphDisplacements", TYPE_VEC3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Displacements according to the current morph target.", true);
+ ParamDefTable[60].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=61, longName="morphPhysicalMeshNewPositions"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[61];
+ ParamDef->init("morphPhysicalMeshNewPositions", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "New positions for the physical meshes and convex collision volumes.", true);
+ ParamDefTable[61].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=62, longName="morphPhysicalMeshNewPositions[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[62];
+ ParamDef->init("morphPhysicalMeshNewPositions", TYPE_VEC3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "New positions for the physical meshes and convex collision volumes.", true);
+ ParamDefTable[62].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=63, longName="morphGraphicalMeshNewPositions"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[63];
+ ParamDef->init("morphGraphicalMeshNewPositions", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "New positions of all submeshes of all graphical meshes.", true);
+ ParamDefTable[63].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=64, longName="morphGraphicalMeshNewPositions[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[64];
+ ParamDef->init("morphGraphicalMeshNewPositions", TYPE_VEC3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "New positions of all submeshes of all graphical meshes.", true);
+ ParamDefTable[64].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=65, longName="allowAdaptiveTargetFrequency"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[65];
+ ParamDef->init("allowAdaptiveTargetFrequency", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Slightly modifies gravity to avoid high frequency jittering due to variable time steps.", true);
+ ParamDefTable[65].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=66, longName="useVelocityClamping"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[66];
+ ParamDef->init("useVelocityClamping", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Enable/disable velocity clamping", true);
+ ParamDefTable[66].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=67, longName="vertexVelocityClamp"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[67];
+ ParamDef->init("vertexVelocityClamp", TYPE_BOUNDS3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Vertex velocity clamping values", true);
+ ParamDefTable[67].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=68, longName="pressure"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[68];
+ ParamDef->init("pressure", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Set pressure of cloth, only works on closed meshes.", true);
+ ParamDefTable[68].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=69, longName="multiplyGlobalPoseIntoBones"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[69];
+ ParamDef->init("multiplyGlobalPoseIntoBones", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Enable/disable multiplying global pose into bones", true);
+ ParamDefTable[69].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=70, longName="overrideMaterialNames"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[70];
+ ParamDef->init("overrideMaterialNames", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Replacement material names for the ones provided by the render mesh asset inside the clothing asset.", true);
+ ParamDefTable[70].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ static const uint8_t dynHandleIndices[1] = { 0, };
+ ParamDef->setDynamicHandleIndicesMap(dynHandleIndices, 1);
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=71, longName="overrideMaterialNames[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[71];
+ ParamDef->init("overrideMaterialNames", TYPE_STRING, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Replacement material names for the ones provided by the render mesh asset inside the clothing asset.", true);
+ ParamDefTable[71].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=72, longName="simulationBackend"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[72];
+ ParamDef->init("simulationBackend", TYPE_ENUM, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Select which backend should be used. 'ForceNative' will only work when running with the 2.8.x PhysX SDK", true);
+ ParamDefTable[72].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+ static const char* const EnumVals[] = { "Default", "ForceNative", "ForceEmbedded" };
+ ParamDefTable[72].setEnumVals((const char**)EnumVals, 3);
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=73, longName="freezeByLOD"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[73];
+ ParamDef->init("freezeByLOD", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Cloth state frozen when LoD turns off simulation of the actor, instead of returning to the animated state.", true);
+ ParamDefTable[73].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=74, longName="localSpaceSim"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[74];
+ ParamDef->init("localSpaceSim", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "If this flag is enabled the simulation is done at origin, however the cloth is rendered at its global position.\nThe simulation of the actor is transformed such that the root bone ends up at origin. The scale of the actor is maintained during the simulation.\nIf a 3.x physX simulation backend is used, it is possible to add the inertia effects to the simulation, through\nthe inertiaScale parameter of the clothing material. So with an inertiaScale of 1.0 there should be no visible\ndifference between local space and global space simulation.\nKnown issues:\n- PhysX 2.8.4 does not support inertiaScale (it corresponds to inertiaScale=0.0f). So if localSpaceSim is enabled there's no inertia effect when the global pose of the clothing actor changes.\n- With 2.8.4 this only works for clothing on 1 character, without world collision. This is because collision volumes would interfere with the cloth that is simulated at origin.\nThis is not a problem in 3.x because there collision only happens with the collision volumes specifically defined for the clothing actor.\n", true);
+ HintTable[1].init("shortDescription", "Do simulation in local space.", true);
+ ParamDefTable[74].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=75, longName="teleportMode"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[75];
+ ParamDef->init("teleportMode", TYPE_I32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "0 = ClothingTeleportMode::Continuous\n1 = ClothingTeleportMode::Teleport\n2 = ClothingTeleportMode::TeleportAndReset\n", true);
+ HintTable[1].init("shortDescription", "Buffered teleport state for the next simulate call, gets set in updateState, is reset to Continuous during simulate().", true);
+ ParamDefTable[75].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // SetChildren for: nodeIndex=0, longName=""
+ {
+ static Definition* Children[32];
+ Children[0] = PDEF_PTR(1);
+ Children[1] = PDEF_PTR(2);
+ Children[2] = PDEF_PTR(3);
+ Children[3] = PDEF_PTR(11);
+ Children[4] = PDEF_PTR(12);
+ Children[5] = PDEF_PTR(13);
+ Children[6] = PDEF_PTR(14);
+ Children[7] = PDEF_PTR(15);
+ Children[8] = PDEF_PTR(16);
+ Children[9] = PDEF_PTR(17);
+ Children[10] = PDEF_PTR(18);
+ Children[11] = PDEF_PTR(21);
+ Children[12] = PDEF_PTR(24);
+ Children[13] = PDEF_PTR(25);
+ Children[14] = PDEF_PTR(27);
+ Children[15] = PDEF_PTR(38);
+ Children[16] = PDEF_PTR(54);
+ Children[17] = PDEF_PTR(57);
+ Children[18] = PDEF_PTR(58);
+ Children[19] = PDEF_PTR(59);
+ Children[20] = PDEF_PTR(61);
+ Children[21] = PDEF_PTR(63);
+ Children[22] = PDEF_PTR(65);
+ Children[23] = PDEF_PTR(66);
+ Children[24] = PDEF_PTR(67);
+ Children[25] = PDEF_PTR(68);
+ Children[26] = PDEF_PTR(69);
+ Children[27] = PDEF_PTR(70);
+ Children[28] = PDEF_PTR(72);
+ Children[29] = PDEF_PTR(73);
+ Children[30] = PDEF_PTR(74);
+ Children[31] = PDEF_PTR(75);
+
+ ParamDefTable[0].setChildren(Children, 32);
+ }
+
+ // SetChildren for: nodeIndex=3, longName="flags"
+ {
+ static Definition* Children[7];
+ Children[0] = PDEF_PTR(4);
+ Children[1] = PDEF_PTR(5);
+ Children[2] = PDEF_PTR(6);
+ Children[3] = PDEF_PTR(7);
+ Children[4] = PDEF_PTR(8);
+ Children[5] = PDEF_PTR(9);
+ Children[6] = PDEF_PTR(10);
+
+ ParamDefTable[3].setChildren(Children, 7);
+ }
+
+ // SetChildren for: nodeIndex=18, longName="windParams"
+ {
+ static Definition* Children[2];
+ Children[0] = PDEF_PTR(19);
+ Children[1] = PDEF_PTR(20);
+
+ ParamDefTable[18].setChildren(Children, 2);
+ }
+
+ // SetChildren for: nodeIndex=21, longName="maxDistanceScale"
+ {
+ static Definition* Children[2];
+ Children[0] = PDEF_PTR(22);
+ Children[1] = PDEF_PTR(23);
+
+ ParamDefTable[21].setChildren(Children, 2);
+ }
+
+ // SetChildren for: nodeIndex=25, longName="boneMatrices"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(26);
+
+ ParamDefTable[25].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=27, longName="clothDescTemplate"
+ {
+ static Definition* Children[6];
+ Children[0] = PDEF_PTR(28);
+ Children[1] = PDEF_PTR(29);
+ Children[2] = PDEF_PTR(30);
+ Children[3] = PDEF_PTR(35);
+ Children[4] = PDEF_PTR(36);
+ Children[5] = PDEF_PTR(37);
+
+ ParamDefTable[27].setChildren(Children, 6);
+ }
+
+ // SetChildren for: nodeIndex=30, longName="clothDescTemplate.groupsMask"
+ {
+ static Definition* Children[4];
+ Children[0] = PDEF_PTR(31);
+ Children[1] = PDEF_PTR(32);
+ Children[2] = PDEF_PTR(33);
+ Children[3] = PDEF_PTR(34);
+
+ ParamDefTable[30].setChildren(Children, 4);
+ }
+
+ // SetChildren for: nodeIndex=38, longName="shapeDescTemplate"
+ {
+ static Definition* Children[6];
+ Children[0] = PDEF_PTR(39);
+ Children[1] = PDEF_PTR(45);
+ Children[2] = PDEF_PTR(46);
+ Children[3] = PDEF_PTR(51);
+ Children[4] = PDEF_PTR(52);
+ Children[5] = PDEF_PTR(53);
+
+ ParamDefTable[38].setChildren(Children, 6);
+ }
+
+ // SetChildren for: nodeIndex=39, longName="shapeDescTemplate.flags"
+ {
+ static Definition* Children[5];
+ Children[0] = PDEF_PTR(40);
+ Children[1] = PDEF_PTR(41);
+ Children[2] = PDEF_PTR(42);
+ Children[3] = PDEF_PTR(43);
+ Children[4] = PDEF_PTR(44);
+
+ ParamDefTable[39].setChildren(Children, 5);
+ }
+
+ // SetChildren for: nodeIndex=46, longName="shapeDescTemplate.groupsMask"
+ {
+ static Definition* Children[4];
+ Children[0] = PDEF_PTR(47);
+ Children[1] = PDEF_PTR(48);
+ Children[2] = PDEF_PTR(49);
+ Children[3] = PDEF_PTR(50);
+
+ ParamDefTable[46].setChildren(Children, 4);
+ }
+
+ // SetChildren for: nodeIndex=54, longName="actorDescTemplate"
+ {
+ static Definition* Children[2];
+ Children[0] = PDEF_PTR(55);
+ Children[1] = PDEF_PTR(56);
+
+ ParamDefTable[54].setChildren(Children, 2);
+ }
+
+ // SetChildren for: nodeIndex=59, longName="morphDisplacements"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(60);
+
+ ParamDefTable[59].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=61, longName="morphPhysicalMeshNewPositions"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(62);
+
+ ParamDefTable[61].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=63, longName="morphGraphicalMeshNewPositions"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(64);
+
+ ParamDefTable[63].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=70, longName="overrideMaterialNames"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(71);
+
+ ParamDefTable[70].setChildren(Children, 1);
+ }
+
+ mBuiltFlag = true;
+
+}
+void ClothingActorParam::initStrings(void)
+{
+}
+
+void ClothingActorParam::initDynamicArrays(void)
+{
+ boneMatrices.buf = NULL;
+ boneMatrices.isAllocated = true;
+ boneMatrices.elementSize = sizeof(physx::PxMat44);
+ boneMatrices.arraySizes[0] = 0;
+ morphDisplacements.buf = NULL;
+ morphDisplacements.isAllocated = true;
+ morphDisplacements.elementSize = sizeof(physx::PxVec3);
+ morphDisplacements.arraySizes[0] = 0;
+ morphPhysicalMeshNewPositions.buf = NULL;
+ morphPhysicalMeshNewPositions.isAllocated = true;
+ morphPhysicalMeshNewPositions.elementSize = sizeof(physx::PxVec3);
+ morphPhysicalMeshNewPositions.arraySizes[0] = 0;
+ morphGraphicalMeshNewPositions.buf = NULL;
+ morphGraphicalMeshNewPositions.isAllocated = true;
+ morphGraphicalMeshNewPositions.elementSize = sizeof(physx::PxVec3);
+ morphGraphicalMeshNewPositions.arraySizes[0] = 0;
+ overrideMaterialNames.buf = NULL;
+ overrideMaterialNames.isAllocated = true;
+ overrideMaterialNames.elementSize = sizeof(NvParameterized::DummyStringStruct);
+ overrideMaterialNames.arraySizes[0] = 0;
+}
+
+void ClothingActorParam::initDefaults(void)
+{
+
+ freeStrings();
+ freeReferences();
+ freeDynamicArrays();
+ globalPose = physx::PxMat44(physx::PxVec4(1.0f));
+ useHardwareCloth = bool(true);
+ flags.ParallelCpuSkinning = bool(true);
+ flags.RecomputeNormals = bool(false);
+ flags.RecomputeTangents = bool(false);
+ flags.Visualize = bool(true);
+ flags.CorrectSimulationNormals = bool(true);
+ flags.ComputeRenderData = bool(true);
+ flags.ComputePhysicsMeshNormals = bool(true);
+ fallbackSkinning = bool(false);
+ slowStart = bool(true);
+ useInternalBoneOrder = bool(false);
+ updateStateWithGlobalMatrices = bool(false);
+ uvChannelForTangentUpdate = uint32_t(0);
+ maxDistanceBlendTime = float(1.0);
+ clothingMaterialIndex = uint32_t(0);
+ windParams.Velocity = physx::PxVec3(0.0f);
+ windParams.Adaption = float(0.0f);
+ maxDistanceScale.Scale = float(1.0f);
+ maxDistanceScale.Multipliable = bool(false);
+ userData = uint64_t(0);
+ clothDescTemplate.collisionResponseCoefficient = float(0.2);
+ clothDescTemplate.collisionGroup = uint16_t(0);
+ clothDescTemplate.groupsMask.bits0 = uint32_t(0);
+ clothDescTemplate.groupsMask.bits1 = uint32_t(0);
+ clothDescTemplate.groupsMask.bits2 = uint32_t(0);
+ clothDescTemplate.groupsMask.bits3 = uint32_t(0);
+ clothDescTemplate.validBounds = physx::PxBounds3(physx::PxVec3(PX_MAX_F32), physx::PxVec3(-PX_MAX_F32));
+ clothDescTemplate.compartment = uint64_t(0);
+ shapeDescTemplate.flags.NX_SF_VISUALIZATION = bool(true);
+ shapeDescTemplate.flags.NX_SF_DISABLE_COLLISION = bool(false);
+ shapeDescTemplate.flags.NX_SF_DISABLE_RAYCASTING = bool(true);
+ shapeDescTemplate.flags.NX_SF_DYNAMIC_DYNAMIC_CCD = bool(false);
+ shapeDescTemplate.flags.NX_SF_DISABLE_SCENE_QUERIES = bool(false);
+ shapeDescTemplate.collisionGroup = uint16_t(0);
+ shapeDescTemplate.groupsMask.bits0 = uint32_t(0);
+ shapeDescTemplate.groupsMask.bits1 = uint32_t(0);
+ shapeDescTemplate.groupsMask.bits2 = uint32_t(0);
+ shapeDescTemplate.groupsMask.bits3 = uint32_t(0);
+ shapeDescTemplate.materialIndex = uint16_t(0);
+ shapeDescTemplate.userData = uint64_t(0);
+ shapeDescTemplate.name = uint64_t(0);
+ actorDescTemplate.userData = uint64_t(0);
+ actorDescTemplate.name = uint64_t(0);
+ actorScale = float(1.0);
+ allowAdaptiveTargetFrequency = bool(true);
+ useVelocityClamping = bool(false);
+ vertexVelocityClamp = physx::PxBounds3(physx::PxVec3(-PX_MAX_F32), physx::PxVec3(PX_MAX_F32));
+ pressure = float(-1.0);
+ multiplyGlobalPoseIntoBones = bool(true);
+ simulationBackend = (const char*)"Default";
+ freezeByLOD = bool(false);
+ localSpaceSim = bool(false);
+ teleportMode = int32_t(0);
+
+ initDynamicArrays();
+ initStrings();
+ initReferences();
+}
+
+void ClothingActorParam::initReferences(void)
+{
+ runtimeCooked = NULL;
+
+}
+
+void ClothingActorParam::freeDynamicArrays(void)
+{
+ if (boneMatrices.isAllocated && boneMatrices.buf)
+ {
+ mParameterizedTraits->free(boneMatrices.buf);
+ }
+ if (morphDisplacements.isAllocated && morphDisplacements.buf)
+ {
+ mParameterizedTraits->free(morphDisplacements.buf);
+ }
+ if (morphPhysicalMeshNewPositions.isAllocated && morphPhysicalMeshNewPositions.buf)
+ {
+ mParameterizedTraits->free(morphPhysicalMeshNewPositions.buf);
+ }
+ if (morphGraphicalMeshNewPositions.isAllocated && morphGraphicalMeshNewPositions.buf)
+ {
+ mParameterizedTraits->free(morphGraphicalMeshNewPositions.buf);
+ }
+ if (overrideMaterialNames.isAllocated && overrideMaterialNames.buf)
+ {
+ mParameterizedTraits->free(overrideMaterialNames.buf);
+ }
+}
+
+void ClothingActorParam::freeStrings(void)
+{
+
+ for (int i = 0; i < overrideMaterialNames.arraySizes[0]; ++i)
+ {
+ if (overrideMaterialNames.buf[i].isAllocated && overrideMaterialNames.buf[i].buf)
+ {
+ mParameterizedTraits->strfree((char*)overrideMaterialNames.buf[i].buf);
+ }
+ }
+}
+
+void ClothingActorParam::freeReferences(void)
+{
+ if (runtimeCooked)
+ {
+ runtimeCooked->destroy();
+ }
+
+}
+
+} // namespace clothing
+} // namespace nvidia
diff --git a/APEX_1.4/module/clothing/src/autogen/ClothingAssetParameters.cpp b/APEX_1.4/module/clothing/src/autogen/ClothingAssetParameters.cpp
new file mode 100644
index 00000000..eee0c7f2
--- /dev/null
+++ b/APEX_1.4/module/clothing/src/autogen/ClothingAssetParameters.cpp
@@ -0,0 +1,2046 @@
+// 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) 2008-2015 NVIDIA Corporation. All rights reserved.
+
+// This file was generated by NvParameterized/scripts/GenParameterized.pl
+
+
+#include "ClothingAssetParameters.h"
+#include <string.h>
+#include <stdlib.h>
+
+using namespace NvParameterized;
+
+namespace nvidia
+{
+namespace clothing
+{
+
+using namespace ClothingAssetParametersNS;
+
+const char* const ClothingAssetParametersFactory::vptr =
+ NvParameterized::getVptr<ClothingAssetParameters, ClothingAssetParameters::ClassAlignment>();
+
+const uint32_t NumParamDefs = 60;
+static NvParameterized::DefinitionImpl* ParamDefTable; // now allocated in buildTree [NumParamDefs];
+
+
+static const size_t ParamLookupChildrenTable[] =
+{
+ 1, 3, 5, 15, 24, 25, 26, 27, 35, 37, 42, 44, 49, 51, 55, 56, 57, 58, 59, 2, 4, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 23, 28, 29, 30, 31, 32,
+ 33, 34, 36, 38, 39, 40, 41, 43, 45, 46, 47, 48, 50, 52, 53, 54,
+};
+
+#define TENUM(type) nvidia::##type
+#define CHILDREN(index) &ParamLookupChildrenTable[index]
+static const NvParameterized::ParamLookupNode ParamLookupTable[NumParamDefs] =
+{
+ { TYPE_STRUCT, false, 0, CHILDREN(0), 19 },
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->physicalMeshes), CHILDREN(19), 1 }, // physicalMeshes
+ { TYPE_REF, false, 1 * sizeof(NvParameterized::Interface*), NULL, 0 }, // physicalMeshes[]
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->graphicalLods), CHILDREN(20), 1 }, // graphicalLods
+ { TYPE_REF, false, 1 * sizeof(NvParameterized::Interface*), NULL, 0 }, // graphicalLods[]
+ { TYPE_STRUCT, false, (size_t)(&((ParametersStruct*)0)->simulation), CHILDREN(21), 9 }, // simulation
+ { TYPE_U32, false, (size_t)(&((SimulationParams_Type*)0)->hierarchicalLevels), NULL, 0 }, // simulation.hierarchicalLevels
+ { TYPE_F32, false, (size_t)(&((SimulationParams_Type*)0)->thickness), NULL, 0 }, // simulation.thickness
+ { TYPE_F32, false, (size_t)(&((SimulationParams_Type*)0)->virtualParticleDensity), NULL, 0 }, // simulation.virtualParticleDensity
+ { TYPE_VEC3, false, (size_t)(&((SimulationParams_Type*)0)->gravityDirection), NULL, 0 }, // simulation.gravityDirection
+ { TYPE_F32, false, (size_t)(&((SimulationParams_Type*)0)->sleepLinearVelocity), NULL, 0 }, // simulation.sleepLinearVelocity
+ { TYPE_BOOL, false, (size_t)(&((SimulationParams_Type*)0)->disableCCD), NULL, 0 }, // simulation.disableCCD
+ { TYPE_BOOL, false, (size_t)(&((SimulationParams_Type*)0)->untangling), NULL, 0 }, // simulation.untangling
+ { TYPE_BOOL, false, (size_t)(&((SimulationParams_Type*)0)->twowayInteraction), NULL, 0 }, // simulation.twowayInteraction
+ { TYPE_F32, false, (size_t)(&((SimulationParams_Type*)0)->restLengthScale), NULL, 0 }, // simulation.restLengthScale
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->bones), CHILDREN(30), 1 }, // bones
+ { TYPE_STRUCT, false, 1 * sizeof(BoneEntry_Type), CHILDREN(31), 7 }, // bones[]
+ { TYPE_I32, false, (size_t)(&((BoneEntry_Type*)0)->internalIndex), NULL, 0 }, // bones[].internalIndex
+ { TYPE_I32, false, (size_t)(&((BoneEntry_Type*)0)->externalIndex), NULL, 0 }, // bones[].externalIndex
+ { TYPE_U32, false, (size_t)(&((BoneEntry_Type*)0)->numMeshReferenced), NULL, 0 }, // bones[].numMeshReferenced
+ { TYPE_U32, false, (size_t)(&((BoneEntry_Type*)0)->numRigidBodiesReferenced), NULL, 0 }, // bones[].numRigidBodiesReferenced
+ { TYPE_I32, false, (size_t)(&((BoneEntry_Type*)0)->parentIndex), NULL, 0 }, // bones[].parentIndex
+ { TYPE_MAT44, false, (size_t)(&((BoneEntry_Type*)0)->bindPose), NULL, 0 }, // bones[].bindPose
+ { TYPE_STRING, false, (size_t)(&((BoneEntry_Type*)0)->name), NULL, 0 }, // bones[].name
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->bonesReferenced), NULL, 0 }, // bonesReferenced
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->bonesReferencedByMesh), NULL, 0 }, // bonesReferencedByMesh
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->rootBoneIndex), NULL, 0 }, // rootBoneIndex
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->boneActors), CHILDREN(38), 1 }, // boneActors
+ { TYPE_STRUCT, false, 1 * sizeof(ActorEntry_Type), CHILDREN(39), 6 }, // boneActors[]
+ { TYPE_I32, false, (size_t)(&((ActorEntry_Type*)0)->boneIndex), NULL, 0 }, // boneActors[].boneIndex
+ { TYPE_U32, false, (size_t)(&((ActorEntry_Type*)0)->convexVerticesStart), NULL, 0 }, // boneActors[].convexVerticesStart
+ { TYPE_U32, false, (size_t)(&((ActorEntry_Type*)0)->convexVerticesCount), NULL, 0 }, // boneActors[].convexVerticesCount
+ { TYPE_F32, false, (size_t)(&((ActorEntry_Type*)0)->capsuleRadius), NULL, 0 }, // boneActors[].capsuleRadius
+ { TYPE_F32, false, (size_t)(&((ActorEntry_Type*)0)->capsuleHeight), NULL, 0 }, // boneActors[].capsuleHeight
+ { TYPE_MAT44, false, (size_t)(&((ActorEntry_Type*)0)->localPose), NULL, 0 }, // boneActors[].localPose
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->boneVertices), CHILDREN(45), 1 }, // boneVertices
+ { TYPE_VEC3, false, 1 * sizeof(physx::PxVec3), NULL, 0 }, // boneVertices[]
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->boneSpheres), CHILDREN(46), 1 }, // boneSpheres
+ { TYPE_STRUCT, false, 1 * sizeof(BoneSphere_Type), CHILDREN(47), 3 }, // boneSpheres[]
+ { TYPE_I32, false, (size_t)(&((BoneSphere_Type*)0)->boneIndex), NULL, 0 }, // boneSpheres[].boneIndex
+ { TYPE_F32, false, (size_t)(&((BoneSphere_Type*)0)->radius), NULL, 0 }, // boneSpheres[].radius
+ { TYPE_VEC3, false, (size_t)(&((BoneSphere_Type*)0)->localPos), NULL, 0 }, // boneSpheres[].localPos
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->boneSphereConnections), CHILDREN(50), 1 }, // boneSphereConnections
+ { TYPE_U16, false, 1 * sizeof(uint16_t), NULL, 0 }, // boneSphereConnections[]
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->bonePlanes), CHILDREN(51), 1 }, // bonePlanes
+ { TYPE_STRUCT, false, 1 * sizeof(BonePlane_Type), CHILDREN(52), 3 }, // bonePlanes[]
+ { TYPE_I32, false, (size_t)(&((BonePlane_Type*)0)->boneIndex), NULL, 0 }, // bonePlanes[].boneIndex
+ { TYPE_VEC3, false, (size_t)(&((BonePlane_Type*)0)->n), NULL, 0 }, // bonePlanes[].n
+ { TYPE_F32, false, (size_t)(&((BonePlane_Type*)0)->d), NULL, 0 }, // bonePlanes[].d
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->collisionConvexes), CHILDREN(55), 1 }, // collisionConvexes
+ { TYPE_U32, false, 1 * sizeof(uint32_t), NULL, 0 }, // collisionConvexes[]
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->cookedData), CHILDREN(56), 1 }, // cookedData
+ { TYPE_STRUCT, false, 1 * sizeof(CookedEntry_Type), CHILDREN(57), 2 }, // cookedData[]
+ { TYPE_F32, false, (size_t)(&((CookedEntry_Type*)0)->scale), NULL, 0 }, // cookedData[].scale
+ { TYPE_REF, false, (size_t)(&((CookedEntry_Type*)0)->cookedData), NULL, 0 }, // cookedData[].cookedData
+ { TYPE_BOUNDS3, false, (size_t)(&((ParametersStruct*)0)->boundingBox), NULL, 0 }, // boundingBox
+ { TYPE_REF, false, (size_t)(&((ParametersStruct*)0)->materialLibrary), NULL, 0 }, // materialLibrary
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->materialIndex), NULL, 0 }, // materialIndex
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->interCollisionChannels), NULL, 0 }, // interCollisionChannels
+ { TYPE_STRING, false, (size_t)(&((ParametersStruct*)0)->toolString), NULL, 0 }, // toolString
+};
+
+
+bool ClothingAssetParameters::mBuiltFlag = false;
+NvParameterized::MutexType ClothingAssetParameters::mBuiltFlagMutex;
+
+ClothingAssetParameters::ClothingAssetParameters(NvParameterized::Traits* traits, void* buf, int32_t* refCount) :
+ NvParameters(traits, buf, refCount)
+{
+ //mParameterizedTraits->registerFactory(className(), &ClothingAssetParametersFactoryInst);
+
+ if (!buf) //Do not init data if it is inplace-deserialized
+ {
+ initDynamicArrays();
+ initStrings();
+ initReferences();
+ initDefaults();
+ }
+}
+
+ClothingAssetParameters::~ClothingAssetParameters()
+{
+ freeStrings();
+ freeReferences();
+ freeDynamicArrays();
+}
+
+void ClothingAssetParameters::destroy()
+{
+ // We cache these fields here to avoid overwrite in destructor
+ bool doDeallocateSelf = mDoDeallocateSelf;
+ NvParameterized::Traits* traits = mParameterizedTraits;
+ int32_t* refCount = mRefCount;
+ void* buf = mBuffer;
+
+ this->~ClothingAssetParameters();
+
+ NvParameters::destroy(this, traits, doDeallocateSelf, refCount, buf);
+}
+
+const NvParameterized::DefinitionImpl* ClothingAssetParameters::getParameterDefinitionTree(void)
+{
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+ if (!mBuiltFlag)
+ {
+ buildTree();
+ }
+ }
+
+ return(&ParamDefTable[0]);
+}
+
+const NvParameterized::DefinitionImpl* ClothingAssetParameters::getParameterDefinitionTree(void) const
+{
+ ClothingAssetParameters* tmpParam = const_cast<ClothingAssetParameters*>(this);
+
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+ if (!mBuiltFlag)
+ {
+ tmpParam->buildTree();
+ }
+ }
+
+ return(&ParamDefTable[0]);
+}
+
+NvParameterized::ErrorType ClothingAssetParameters::getParameterHandle(const char* long_name, Handle& handle) const
+{
+ ErrorType Ret = NvParameters::getParameterHandle(long_name, handle);
+ if (Ret != ERROR_NONE)
+ {
+ return(Ret);
+ }
+
+ size_t offset;
+ void* ptr;
+
+ getVarPtr(handle, ptr, offset);
+
+ if (ptr == NULL)
+ {
+ return(ERROR_INDEX_OUT_OF_RANGE);
+ }
+
+ return(ERROR_NONE);
+}
+
+NvParameterized::ErrorType ClothingAssetParameters::getParameterHandle(const char* long_name, Handle& handle)
+{
+ ErrorType Ret = NvParameters::getParameterHandle(long_name, handle);
+ if (Ret != ERROR_NONE)
+ {
+ return(Ret);
+ }
+
+ size_t offset;
+ void* ptr;
+
+ getVarPtr(handle, ptr, offset);
+
+ if (ptr == NULL)
+ {
+ return(ERROR_INDEX_OUT_OF_RANGE);
+ }
+
+ return(ERROR_NONE);
+}
+
+void ClothingAssetParameters::getVarPtr(const Handle& handle, void*& ptr, size_t& offset) const
+{
+ ptr = getVarPtrHelper(&ParamLookupTable[0], const_cast<ClothingAssetParameters::ParametersStruct*>(&parameters()), handle, offset);
+}
+
+
+/* Dynamic Handle Indices */
+/* [0] - physicalMeshes (not an array of structs) */
+/* [0] - graphicalLods (not an array of structs) */
+/* [1,6] - bones.name */
+/* [1,1] - cookedData.cookedData */
+
+void ClothingAssetParameters::freeParameterDefinitionTable(NvParameterized::Traits* traits)
+{
+ if (!traits)
+ {
+ return;
+ }
+
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ return;
+ }
+
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+
+ if (!mBuiltFlag)
+ {
+ return;
+ }
+
+ for (uint32_t i = 0; i < NumParamDefs; ++i)
+ {
+ ParamDefTable[i].~DefinitionImpl();
+ }
+
+ traits->free(ParamDefTable);
+
+ mBuiltFlag = false;
+}
+
+#define PDEF_PTR(index) (&ParamDefTable[index])
+
+void ClothingAssetParameters::buildTree(void)
+{
+
+ uint32_t allocSize = sizeof(NvParameterized::DefinitionImpl) * NumParamDefs;
+ ParamDefTable = (NvParameterized::DefinitionImpl*)(mParameterizedTraits->alloc(allocSize));
+ memset(ParamDefTable, 0, allocSize);
+
+ for (uint32_t i = 0; i < NumParamDefs; ++i)
+ {
+ NV_PARAM_PLACEMENT_NEW(ParamDefTable + i, NvParameterized::DefinitionImpl)(*mParameterizedTraits);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=0, longName=""
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[0];
+ ParamDef->init("", TYPE_STRUCT, "STRUCT", true);
+
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=1, longName="physicalMeshes"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[1];
+ ParamDef->init("physicalMeshes", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("INCLUDED", uint64_t(1), true);
+ ParamDefTable[1].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("INCLUDED", uint64_t(1), true);
+ HintTable[1].init("longDescription", "These are used for multiple graphical LoDs.", true);
+ HintTable[2].init("shortDescription", "An Array of physical meshes", true);
+ ParamDefTable[1].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+ static const char* const RefVariantVals[] = { "ClothingPhysicalMeshParameters" };
+ ParamDefTable[1].setRefVariantVals((const char**)RefVariantVals, 1);
+
+
+ ParamDef->setArraySize(-1);
+ static const uint8_t dynHandleIndices[1] = { 0, };
+ ParamDef->setDynamicHandleIndicesMap(dynHandleIndices, 1);
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=2, longName="physicalMeshes[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[2];
+ ParamDef->init("physicalMeshes", TYPE_REF, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("INCLUDED", uint64_t(1), true);
+ ParamDefTable[2].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("INCLUDED", uint64_t(1), true);
+ HintTable[1].init("longDescription", "These are used for multiple graphical LoDs.", true);
+ HintTable[2].init("shortDescription", "An Array of physical meshes", true);
+ ParamDefTable[2].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+ static const char* const RefVariantVals[] = { "ClothingPhysicalMeshParameters" };
+ ParamDefTable[2].setRefVariantVals((const char**)RefVariantVals, 1);
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=3, longName="graphicalLods"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[3];
+ ParamDef->init("graphicalLods", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("INCLUDED", uint64_t(1), true);
+ ParamDefTable[3].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("INCLUDED", uint64_t(1), true);
+ HintTable[1].init("longDescription", "Each LoD contains a graphical mesh and a reference to a physical mesh.", true);
+ HintTable[2].init("shortDescription", "An array of graphical Lods.", true);
+ ParamDefTable[3].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+ static const char* const RefVariantVals[] = { "ClothingGraphicalLodParameters" };
+ ParamDefTable[3].setRefVariantVals((const char**)RefVariantVals, 1);
+
+
+ ParamDef->setArraySize(-1);
+ static const uint8_t dynHandleIndices[1] = { 0, };
+ ParamDef->setDynamicHandleIndicesMap(dynHandleIndices, 1);
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=4, longName="graphicalLods[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[4];
+ ParamDef->init("graphicalLods", TYPE_REF, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("INCLUDED", uint64_t(1), true);
+ ParamDefTable[4].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("INCLUDED", uint64_t(1), true);
+ HintTable[1].init("longDescription", "Each LoD contains a graphical mesh and a reference to a physical mesh.", true);
+ HintTable[2].init("shortDescription", "An array of graphical Lods.", true);
+ ParamDefTable[4].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+ static const char* const RefVariantVals[] = { "ClothingGraphicalLodParameters" };
+ ParamDefTable[4].setRefVariantVals((const char**)RefVariantVals, 1);
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=5, longName="simulation"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[5];
+ ParamDef->init("simulation", TYPE_STRUCT, "SimulationParams", true);
+
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=6, longName="simulation.hierarchicalLevels"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[6];
+ ParamDef->init("hierarchicalLevels", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "Corresponds to NxClothMeshDesc::numHierarchyLevels.\nThis is orthogonal to the Hard Stretch Limitation in the Clothing Material.\n", true);
+ HintTable[1].init("shortDescription", "The number of cloth hierarhies. Only used to prevent stretching", true);
+ ParamDefTable[6].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=7, longName="simulation.thickness"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[7];
+ ParamDef->init("thickness", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "Each cloth particle will minimaly have as much distance to any collision volume.\nMost stable when this value corresponds roughly half the average edge length.\nCan be increased to prevent penetration artifacts.\n", true);
+ HintTable[1].init("shortDescription", "Minimal amount of separation between cloth particles and collision volumes.", true);
+ ParamDefTable[7].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=8, longName="simulation.virtualParticleDensity"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[8];
+ ParamDef->init("virtualParticleDensity", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "0 will create no virtual particles. 1 will create 3 virtual particles for every triangle. Everything else is in between.", true);
+ HintTable[1].init("shortDescription", "Select the amount of virtual particles generated.", true);
+ ParamDefTable[8].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=9, longName="simulation.gravityDirection"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[9];
+ ParamDef->init("gravityDirection", TYPE_VEC3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Direction of gravity for this asset.", true);
+ ParamDefTable[9].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=10, longName="simulation.sleepLinearVelocity"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[10];
+ ParamDef->init("sleepLinearVelocity", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "Most clothing doesn't need it, but it might be useful for smaller assets like flags and the like.", true);
+ HintTable[1].init("shortDescription", "Clothing will fall asleep if every vertex is slower than this velocity", true);
+ ParamDefTable[10].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=11, longName="simulation.disableCCD"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[11];
+ ParamDef->init("disableCCD", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "When turning off CCD, cloth particles can tunnel through fast moving collision volumes. But sometimes\nill turning collision volumes can excert large velocities on particles. This can help prevent it.\n", true);
+ HintTable[1].init("shortDescription", "Turn off CCD when colliding cloth particles with collision volumes", true);
+ ParamDefTable[11].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=12, longName="simulation.untangling"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[12];
+ ParamDef->init("untangling", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "This feature is highly experimental and still rather slow. Only use when self-collision could not\nhelp adequately.\n", true);
+ HintTable[1].init("shortDescription", "EXPERIMENTAL: Untangle Cloth when it's entangled.", true);
+ ParamDefTable[12].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=13, longName="simulation.twowayInteraction"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[13];
+ ParamDef->init("twowayInteraction", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "For clothing this is normally not needed, as clothing should only follow the kinematic shapes. Needed when interacting\nwith dynamic rigid bodies that need to be influenced by clothing.\n", true);
+ HintTable[1].init("shortDescription", "Make use of twoway interaction", true);
+ ParamDefTable[13].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=14, longName="simulation.restLengthScale"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[14];
+ ParamDef->init("restLengthScale", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Scale for cloth rest lengths.", true);
+ ParamDefTable[14].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=15, longName="bones"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[15];
+ ParamDef->init("bones", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "Each bone contains a bind pose and reference counters.", true);
+ HintTable[1].init("shortDescription", "Array of Bones", true);
+ ParamDefTable[15].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ static const uint8_t dynHandleIndices[2] = { 1, 6, };
+ ParamDef->setDynamicHandleIndicesMap(dynHandleIndices, 2);
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=16, longName="bones[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[16];
+ ParamDef->init("bones", TYPE_STRUCT, "BoneEntry", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "Each bone contains a bind pose and reference counters.", true);
+ HintTable[1].init("shortDescription", "Array of Bones", true);
+ ParamDefTable[16].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=17, longName="bones[].internalIndex"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[17];
+ ParamDef->init("internalIndex", TYPE_I32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "This usually corresponds to the array position this element is at.", true);
+ HintTable[1].init("shortDescription", "The index used internally for this bone.", true);
+ ParamDefTable[17].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=18, longName="bones[].externalIndex"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[18];
+ ParamDef->init("externalIndex", TYPE_I32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The index that was given by the application", true);
+ ParamDefTable[18].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=19, longName="bones[].numMeshReferenced"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[19];
+ ParamDef->init("numMeshReferenced", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The number of mesh vertices that have a non-zero weight to this bone.", true);
+ ParamDefTable[19].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=20, longName="bones[].numRigidBodiesReferenced"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[20];
+ ParamDef->init("numRigidBodiesReferenced", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The number of collision volumes attached to this bone", true);
+ ParamDefTable[20].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=21, longName="bones[].parentIndex"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[21];
+ ParamDef->init("parentIndex", TYPE_I32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The (internal) index of the parent bone", true);
+ ParamDefTable[21].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=22, longName="bones[].bindPose"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[22];
+ ParamDef->init("bindPose", TYPE_MAT44, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The matrix this bone has in the default pose", true);
+ ParamDefTable[22].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=23, longName="bones[].name"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[23];
+ ParamDef->init("name", TYPE_STRING, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The name of this bone", true);
+ ParamDefTable[23].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=24, longName="bonesReferenced"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[24];
+ ParamDef->init("bonesReferenced", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "Any bone in the bones array beyond this number is completely useless.", true);
+ HintTable[1].init("shortDescription", "Number of bones actually used by any of the meshes or collision volumes.", true);
+ ParamDefTable[24].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=25, longName="bonesReferencedByMesh"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[25];
+ ParamDef->init("bonesReferencedByMesh", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "Bones beyond this index can be used for collision volumes or not at all. This number is smaller or\nequal the 'bonesReferenced' number.\n", true);
+ HintTable[1].init("shortDescription", "Number of bones actually used by any of the meshes", true);
+ ParamDefTable[25].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=26, longName="rootBoneIndex"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[26];
+ ParamDef->init("rootBoneIndex", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Internal bone index with either parent=-1 or one bone with minimal distance to root when root is not inside the used bones", true);
+ ParamDefTable[26].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=27, longName="boneActors"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[27];
+ ParamDef->init("boneActors", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "Each collision volume belongs to a bone and contains a description of its shape.", true);
+ HintTable[1].init("shortDescription", "Array of collision volumes", true);
+ ParamDefTable[27].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=28, longName="boneActors[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[28];
+ ParamDef->init("boneActors", TYPE_STRUCT, "ActorEntry", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "Each collision volume belongs to a bone and contains a description of its shape.", true);
+ HintTable[1].init("shortDescription", "Array of collision volumes", true);
+ ParamDefTable[28].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=29, longName="boneActors[].boneIndex"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[29];
+ ParamDef->init("boneIndex", TYPE_I32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The (internal) index this collision volume is attached to", true);
+ ParamDefTable[29].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=30, longName="boneActors[].convexVerticesStart"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[30];
+ ParamDef->init("convexVerticesStart", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Index into the boneVertices array where the list of vertices for this shape starts.", true);
+ ParamDefTable[30].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=31, longName="boneActors[].convexVerticesCount"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[31];
+ ParamDef->init("convexVerticesCount", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The number vertices that make up this convex.", true);
+ ParamDefTable[31].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=32, longName="boneActors[].capsuleRadius"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[32];
+ ParamDef->init("capsuleRadius", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The radius of the capsule that describes this collision volume.", true);
+ ParamDefTable[32].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=33, longName="boneActors[].capsuleHeight"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[33];
+ ParamDef->init("capsuleHeight", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The height of the capsule that describes this collision volume.", true);
+ ParamDefTable[33].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=34, longName="boneActors[].localPose"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[34];
+ ParamDef->init("localPose", TYPE_MAT44, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The pose this collision volume has relative to the bone.", true);
+ ParamDefTable[34].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=35, longName="boneVertices"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[35];
+ ParamDef->init("boneVertices", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "All convexes use the same array but different parts of it.", true);
+ HintTable[1].init("shortDescription", "Array of vertices that belong to one or more convex collision volumes", true);
+ ParamDefTable[35].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=36, longName="boneVertices[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[36];
+ ParamDef->init("boneVertices", TYPE_VEC3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "All convexes use the same array but different parts of it.", true);
+ HintTable[1].init("shortDescription", "Array of vertices that belong to one or more convex collision volumes", true);
+ ParamDefTable[36].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=37, longName="boneSpheres"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[37];
+ ParamDef->init("boneSpheres", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "The spheres are connected to tapered capsules by the boneSphereConnections array.", true);
+ HintTable[1].init("shortDescription", "Array of spheres that describe the tapered capsules for clothing collision in PhysX3.", true);
+ ParamDefTable[37].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=38, longName="boneSpheres[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[38];
+ ParamDef->init("boneSpheres", TYPE_STRUCT, "BoneSphere", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "The spheres are connected to tapered capsules by the boneSphereConnections array.", true);
+ HintTable[1].init("shortDescription", "Array of spheres that describe the tapered capsules for clothing collision in PhysX3.", true);
+ ParamDefTable[38].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=39, longName="boneSpheres[].boneIndex"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[39];
+ ParamDef->init("boneIndex", TYPE_I32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The (internal) index this collision volume is attached to", true);
+ ParamDefTable[39].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=40, longName="boneSpheres[].radius"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[40];
+ ParamDef->init("radius", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The radius of the sphere that describes this collision volume.", true);
+ ParamDefTable[40].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=41, longName="boneSpheres[].localPos"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[41];
+ ParamDef->init("localPos", TYPE_VEC3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The position this collision volume has relative to the bone.", true);
+ ParamDefTable[41].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=42, longName="boneSphereConnections"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[42];
+ ParamDef->init("boneSphereConnections", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "This is an array of pairs, so the size must be dividible by 2.", true);
+ HintTable[1].init("shortDescription", "Array of indices into the boneSpheres array to describe pairs of spheres that form a capsule.", true);
+ ParamDefTable[42].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=43, longName="boneSphereConnections[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[43];
+ ParamDef->init("boneSphereConnections", TYPE_U16, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "This is an array of pairs, so the size must be dividible by 2.", true);
+ HintTable[1].init("shortDescription", "Array of indices into the boneSpheres array to describe pairs of spheres that form a capsule.", true);
+ ParamDefTable[43].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=44, longName="bonePlanes"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[44];
+ ParamDef->init("bonePlanes", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Array of planes used for collision convexes.", true);
+ ParamDefTable[44].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=45, longName="bonePlanes[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[45];
+ ParamDef->init("bonePlanes", TYPE_STRUCT, "BonePlane", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Array of planes used for collision convexes.", true);
+ ParamDefTable[45].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=46, longName="bonePlanes[].boneIndex"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[46];
+ ParamDef->init("boneIndex", TYPE_I32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The (internal) index this collision volume is attached to", true);
+ ParamDefTable[46].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=47, longName="bonePlanes[].n"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[47];
+ ParamDef->init("n", TYPE_VEC3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Plane normal.", true);
+ ParamDefTable[47].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=48, longName="bonePlanes[].d"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[48];
+ ParamDef->init("d", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Plane distance from origin.", true);
+ ParamDefTable[48].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=49, longName="collisionConvexes"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[49];
+ ParamDef->init("collisionConvexes", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Each entry is a bitmap that describes which bonePlanes are used to define a convex.", true);
+ ParamDefTable[49].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=50, longName="collisionConvexes[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[50];
+ ParamDef->init("collisionConvexes", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Each entry is a bitmap that describes which bonePlanes are used to define a convex.", true);
+ ParamDefTable[50].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=51, longName="cookedData"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[51];
+ ParamDef->init("cookedData", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ ParamDefTable[51].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ HintTable[1].init("shortDescription", "Various versions of cooked data", true);
+ ParamDefTable[51].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ static const uint8_t dynHandleIndices[2] = { 1, 1, };
+ ParamDef->setDynamicHandleIndicesMap(dynHandleIndices, 2);
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=52, longName="cookedData[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[52];
+ ParamDef->init("cookedData", TYPE_STRUCT, "CookedEntry", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ ParamDefTable[52].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ HintTable[1].init("shortDescription", "Various versions of cooked data", true);
+ ParamDefTable[52].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=53, longName="cookedData[].scale"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[53];
+ ParamDef->init("scale", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "", true);
+ ParamDefTable[53].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=54, longName="cookedData[].cookedData"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[54];
+ ParamDef->init("cookedData", TYPE_REF, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("INCLUDED", uint64_t(1), true);
+ ParamDefTable[54].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("INCLUDED", uint64_t(1), true);
+ HintTable[1].init("shortDescription", "Data cooked at runtime", true);
+ ParamDefTable[54].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+ static const char* const RefVariantVals[] = { "ClothingCookedParam", "ClothingCookedPhysX3Param" };
+ ParamDefTable[54].setRefVariantVals((const char**)RefVariantVals, 2);
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=55, longName="boundingBox"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[55];
+ ParamDef->init("boundingBox", TYPE_BOUNDS3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "This contains the simulated as well as the animated vertices.", true);
+ HintTable[1].init("shortDescription", "The Bounding-Box of the Asset", true);
+ ParamDefTable[55].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=56, longName="materialLibrary"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[56];
+ ParamDef->init("materialLibrary", TYPE_REF, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("INCLUDED", uint64_t(1), true);
+ ParamDefTable[56].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("INCLUDED", uint64_t(1), true);
+ HintTable[1].init("shortDescription", "The Material Library for this asset", true);
+ ParamDefTable[56].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+ static const char* const RefVariantVals[] = { "ClothingMaterialLibraryParameters" };
+ ParamDefTable[56].setRefVariantVals((const char**)RefVariantVals, 1);
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=57, longName="materialIndex"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[57];
+ ParamDef->init("materialIndex", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Default index for the material in the library", true);
+ ParamDefTable[57].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=58, longName="interCollisionChannels"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[58];
+ ParamDef->init("interCollisionChannels", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "Experimental. Each bit of the represents a channel, so there can be a maximum of 32 channels.\nClothingActors that have at least one channel in common will collide, if inter-collision is enabled in the module.\n(3.x simulation only)\n", true);
+ HintTable[1].init("shortDescription", "Experimental. Collision Channels for inter-collision", true);
+ ParamDefTable[58].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=59, longName="toolString"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[59];
+ ParamDef->init("toolString", TYPE_STRING, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Describes the authoring tool.", true);
+ ParamDefTable[59].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // SetChildren for: nodeIndex=0, longName=""
+ {
+ static Definition* Children[19];
+ Children[0] = PDEF_PTR(1);
+ Children[1] = PDEF_PTR(3);
+ Children[2] = PDEF_PTR(5);
+ Children[3] = PDEF_PTR(15);
+ Children[4] = PDEF_PTR(24);
+ Children[5] = PDEF_PTR(25);
+ Children[6] = PDEF_PTR(26);
+ Children[7] = PDEF_PTR(27);
+ Children[8] = PDEF_PTR(35);
+ Children[9] = PDEF_PTR(37);
+ Children[10] = PDEF_PTR(42);
+ Children[11] = PDEF_PTR(44);
+ Children[12] = PDEF_PTR(49);
+ Children[13] = PDEF_PTR(51);
+ Children[14] = PDEF_PTR(55);
+ Children[15] = PDEF_PTR(56);
+ Children[16] = PDEF_PTR(57);
+ Children[17] = PDEF_PTR(58);
+ Children[18] = PDEF_PTR(59);
+
+ ParamDefTable[0].setChildren(Children, 19);
+ }
+
+ // SetChildren for: nodeIndex=1, longName="physicalMeshes"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(2);
+
+ ParamDefTable[1].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=3, longName="graphicalLods"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(4);
+
+ ParamDefTable[3].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=5, longName="simulation"
+ {
+ static Definition* Children[9];
+ Children[0] = PDEF_PTR(6);
+ Children[1] = PDEF_PTR(7);
+ Children[2] = PDEF_PTR(8);
+ Children[3] = PDEF_PTR(9);
+ Children[4] = PDEF_PTR(10);
+ Children[5] = PDEF_PTR(11);
+ Children[6] = PDEF_PTR(12);
+ Children[7] = PDEF_PTR(13);
+ Children[8] = PDEF_PTR(14);
+
+ ParamDefTable[5].setChildren(Children, 9);
+ }
+
+ // SetChildren for: nodeIndex=15, longName="bones"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(16);
+
+ ParamDefTable[15].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=16, longName="bones[]"
+ {
+ static Definition* Children[7];
+ Children[0] = PDEF_PTR(17);
+ Children[1] = PDEF_PTR(18);
+ Children[2] = PDEF_PTR(19);
+ Children[3] = PDEF_PTR(20);
+ Children[4] = PDEF_PTR(21);
+ Children[5] = PDEF_PTR(22);
+ Children[6] = PDEF_PTR(23);
+
+ ParamDefTable[16].setChildren(Children, 7);
+ }
+
+ // SetChildren for: nodeIndex=27, longName="boneActors"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(28);
+
+ ParamDefTable[27].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=28, longName="boneActors[]"
+ {
+ static Definition* Children[6];
+ Children[0] = PDEF_PTR(29);
+ Children[1] = PDEF_PTR(30);
+ Children[2] = PDEF_PTR(31);
+ Children[3] = PDEF_PTR(32);
+ Children[4] = PDEF_PTR(33);
+ Children[5] = PDEF_PTR(34);
+
+ ParamDefTable[28].setChildren(Children, 6);
+ }
+
+ // SetChildren for: nodeIndex=35, longName="boneVertices"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(36);
+
+ ParamDefTable[35].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=37, longName="boneSpheres"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(38);
+
+ ParamDefTable[37].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=38, longName="boneSpheres[]"
+ {
+ static Definition* Children[3];
+ Children[0] = PDEF_PTR(39);
+ Children[1] = PDEF_PTR(40);
+ Children[2] = PDEF_PTR(41);
+
+ ParamDefTable[38].setChildren(Children, 3);
+ }
+
+ // SetChildren for: nodeIndex=42, longName="boneSphereConnections"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(43);
+
+ ParamDefTable[42].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=44, longName="bonePlanes"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(45);
+
+ ParamDefTable[44].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=45, longName="bonePlanes[]"
+ {
+ static Definition* Children[3];
+ Children[0] = PDEF_PTR(46);
+ Children[1] = PDEF_PTR(47);
+ Children[2] = PDEF_PTR(48);
+
+ ParamDefTable[45].setChildren(Children, 3);
+ }
+
+ // SetChildren for: nodeIndex=49, longName="collisionConvexes"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(50);
+
+ ParamDefTable[49].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=51, longName="cookedData"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(52);
+
+ ParamDefTable[51].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=52, longName="cookedData[]"
+ {
+ static Definition* Children[2];
+ Children[0] = PDEF_PTR(53);
+ Children[1] = PDEF_PTR(54);
+
+ ParamDefTable[52].setChildren(Children, 2);
+ }
+
+ mBuiltFlag = true;
+
+}
+void ClothingAssetParameters::initStrings(void)
+{
+ toolString.isAllocated = true;
+ toolString.buf = NULL;
+}
+
+void ClothingAssetParameters::initDynamicArrays(void)
+{
+ physicalMeshes.buf = NULL;
+ physicalMeshes.isAllocated = true;
+ physicalMeshes.elementSize = sizeof(NvParameterized::Interface*);
+ physicalMeshes.arraySizes[0] = 0;
+ graphicalLods.buf = NULL;
+ graphicalLods.isAllocated = true;
+ graphicalLods.elementSize = sizeof(NvParameterized::Interface*);
+ graphicalLods.arraySizes[0] = 0;
+ bones.buf = NULL;
+ bones.isAllocated = true;
+ bones.elementSize = sizeof(BoneEntry_Type);
+ bones.arraySizes[0] = 0;
+ boneActors.buf = NULL;
+ boneActors.isAllocated = true;
+ boneActors.elementSize = sizeof(ActorEntry_Type);
+ boneActors.arraySizes[0] = 0;
+ boneVertices.buf = NULL;
+ boneVertices.isAllocated = true;
+ boneVertices.elementSize = sizeof(physx::PxVec3);
+ boneVertices.arraySizes[0] = 0;
+ boneSpheres.buf = NULL;
+ boneSpheres.isAllocated = true;
+ boneSpheres.elementSize = sizeof(BoneSphere_Type);
+ boneSpheres.arraySizes[0] = 0;
+ boneSphereConnections.buf = NULL;
+ boneSphereConnections.isAllocated = true;
+ boneSphereConnections.elementSize = sizeof(uint16_t);
+ boneSphereConnections.arraySizes[0] = 0;
+ bonePlanes.buf = NULL;
+ bonePlanes.isAllocated = true;
+ bonePlanes.elementSize = sizeof(BonePlane_Type);
+ bonePlanes.arraySizes[0] = 0;
+ collisionConvexes.buf = NULL;
+ collisionConvexes.isAllocated = true;
+ collisionConvexes.elementSize = sizeof(uint32_t);
+ collisionConvexes.arraySizes[0] = 0;
+ cookedData.buf = NULL;
+ cookedData.isAllocated = true;
+ cookedData.elementSize = sizeof(CookedEntry_Type);
+ cookedData.arraySizes[0] = 0;
+}
+
+void ClothingAssetParameters::initDefaults(void)
+{
+
+ freeStrings();
+ freeReferences();
+ freeDynamicArrays();
+ simulation.hierarchicalLevels = uint32_t(0);
+ simulation.thickness = float(0.01);
+ simulation.virtualParticleDensity = float(0.0);
+ simulation.gravityDirection = physx::PxVec3(physx::PxVec3(0.0f));
+ simulation.sleepLinearVelocity = float(0.0);
+ simulation.disableCCD = bool(false);
+ simulation.untangling = bool(false);
+ simulation.twowayInteraction = bool(false);
+ simulation.restLengthScale = float(1.0);
+ bonesReferenced = uint32_t(0);
+ bonesReferencedByMesh = uint32_t(0);
+ rootBoneIndex = uint32_t(0);
+ boundingBox = physx::PxBounds3(physx::PxVec3(0.0f), physx::PxVec3(0.0f));
+ materialIndex = uint32_t(0);
+ interCollisionChannels = uint32_t(0);
+
+ initDynamicArrays();
+ initStrings();
+ initReferences();
+}
+
+void ClothingAssetParameters::initReferences(void)
+{
+ materialLibrary = NULL;
+
+}
+
+void ClothingAssetParameters::freeDynamicArrays(void)
+{
+ if (physicalMeshes.isAllocated && physicalMeshes.buf)
+ {
+ mParameterizedTraits->free(physicalMeshes.buf);
+ }
+ if (graphicalLods.isAllocated && graphicalLods.buf)
+ {
+ mParameterizedTraits->free(graphicalLods.buf);
+ }
+ if (bones.isAllocated && bones.buf)
+ {
+ mParameterizedTraits->free(bones.buf);
+ }
+ if (boneActors.isAllocated && boneActors.buf)
+ {
+ mParameterizedTraits->free(boneActors.buf);
+ }
+ if (boneVertices.isAllocated && boneVertices.buf)
+ {
+ mParameterizedTraits->free(boneVertices.buf);
+ }
+ if (boneSpheres.isAllocated && boneSpheres.buf)
+ {
+ mParameterizedTraits->free(boneSpheres.buf);
+ }
+ if (boneSphereConnections.isAllocated && boneSphereConnections.buf)
+ {
+ mParameterizedTraits->free(boneSphereConnections.buf);
+ }
+ if (bonePlanes.isAllocated && bonePlanes.buf)
+ {
+ mParameterizedTraits->free(bonePlanes.buf);
+ }
+ if (collisionConvexes.isAllocated && collisionConvexes.buf)
+ {
+ mParameterizedTraits->free(collisionConvexes.buf);
+ }
+ if (cookedData.isAllocated && cookedData.buf)
+ {
+ mParameterizedTraits->free(cookedData.buf);
+ }
+}
+
+void ClothingAssetParameters::freeStrings(void)
+{
+
+ for (int i = 0; i < bones.arraySizes[0]; ++i)
+ {
+ if (bones.buf[i].name.isAllocated && bones.buf[i].name.buf)
+ {
+ mParameterizedTraits->strfree((char*)bones.buf[i].name.buf);
+ }
+ }
+
+ if (toolString.isAllocated && toolString.buf)
+ {
+ mParameterizedTraits->strfree((char*)toolString.buf);
+ }
+}
+
+void ClothingAssetParameters::freeReferences(void)
+{
+
+ for (int i = 0; i < physicalMeshes.arraySizes[0]; ++i)
+ {
+ if (physicalMeshes.buf[i])
+ {
+ physicalMeshes.buf[i]->destroy();
+ }
+ }
+
+ for (int i = 0; i < graphicalLods.arraySizes[0]; ++i)
+ {
+ if (graphicalLods.buf[i])
+ {
+ graphicalLods.buf[i]->destroy();
+ }
+ }
+
+ for (int i = 0; i < cookedData.arraySizes[0]; i++)
+ {
+ if (cookedData.buf[i].cookedData)
+ {
+ cookedData.buf[i].cookedData->destroy();
+ }
+ }
+ if (materialLibrary)
+ {
+ materialLibrary->destroy();
+ }
+
+}
+
+} // namespace clothing
+} // namespace nvidia
diff --git a/APEX_1.4/module/clothing/src/autogen/ClothingCookedParam.cpp b/APEX_1.4/module/clothing/src/autogen/ClothingCookedParam.cpp
new file mode 100644
index 00000000..9a7b91ee
--- /dev/null
+++ b/APEX_1.4/module/clothing/src/autogen/ClothingCookedParam.cpp
@@ -0,0 +1,970 @@
+// 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) 2008-2015 NVIDIA Corporation. All rights reserved.
+
+// This file was generated by NvParameterized/scripts/GenParameterized.pl
+
+
+#include "ClothingCookedParam.h"
+#include <string.h>
+#include <stdlib.h>
+
+using namespace NvParameterized;
+
+namespace nvidia
+{
+namespace clothing
+{
+
+using namespace ClothingCookedParamNS;
+
+const char* const ClothingCookedParamFactory::vptr =
+ NvParameterized::getVptr<ClothingCookedParam, ClothingCookedParam::ClassAlignment>();
+
+const uint32_t NumParamDefs = 24;
+static NvParameterized::DefinitionImpl* ParamDefTable; // now allocated in buildTree [NumParamDefs];
+
+
+static const size_t ParamLookupChildrenTable[] =
+{
+ 1, 2, 4, 6, 15, 17, 18, 20, 22, 3, 5, 7, 8, 9, 10, 11, 12, 13, 14, 16, 19, 21, 23,
+};
+
+#define TENUM(type) nvidia::##type
+#define CHILDREN(index) &ParamLookupChildrenTable[index]
+static const NvParameterized::ParamLookupNode ParamLookupTable[NumParamDefs] =
+{
+ { TYPE_STRUCT, false, 0, CHILDREN(0), 9 },
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->actorScale), NULL, 0 }, // actorScale
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->convexCookedData), CHILDREN(9), 1 }, // convexCookedData
+ { TYPE_U8, false, 1 * sizeof(uint8_t), NULL, 0 }, // convexCookedData[]
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->convexMeshPointers), CHILDREN(10), 1 }, // convexMeshPointers
+ { TYPE_POINTER, false, 1 * sizeof(void*), NULL, 0 }, // convexMeshPointers[]
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->cookedPhysicalMeshes), CHILDREN(11), 1 }, // cookedPhysicalMeshes
+ { TYPE_STRUCT, false, 1 * sizeof(CookedPhysicalMesh_Type), CHILDREN(12), 7 }, // cookedPhysicalMeshes[]
+ { TYPE_U32, false, (size_t)(&((CookedPhysicalMesh_Type*)0)->physicalMeshId), NULL, 0 }, // cookedPhysicalMeshes[].physicalMeshId
+ { TYPE_U32, false, (size_t)(&((CookedPhysicalMesh_Type*)0)->cookedDataOffset), NULL, 0 }, // cookedPhysicalMeshes[].cookedDataOffset
+ { TYPE_U32, false, (size_t)(&((CookedPhysicalMesh_Type*)0)->cookedDataLength), NULL, 0 }, // cookedPhysicalMeshes[].cookedDataLength
+ { TYPE_POINTER, false, (size_t)(&((CookedPhysicalMesh_Type*)0)->deformableMeshPointer), NULL, 0 }, // cookedPhysicalMeshes[].deformableMeshPointer
+ { TYPE_U32, false, (size_t)(&((CookedPhysicalMesh_Type*)0)->deformableInvParticleWeightsOffset), NULL, 0 }, // cookedPhysicalMeshes[].deformableInvParticleWeightsOffset
+ { TYPE_U32, false, (size_t)(&((CookedPhysicalMesh_Type*)0)->virtualParticleIndicesOffset), NULL, 0 }, // cookedPhysicalMeshes[].virtualParticleIndicesOffset
+ { TYPE_U32, false, (size_t)(&((CookedPhysicalMesh_Type*)0)->virtualParticleIndicesLength), NULL, 0 }, // cookedPhysicalMeshes[].virtualParticleIndicesLength
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->deformableCookedData), CHILDREN(19), 1 }, // deformableCookedData
+ { TYPE_U8, false, 1 * sizeof(uint8_t), NULL, 0 }, // deformableCookedData[]
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->cookedDataVersion), NULL, 0 }, // cookedDataVersion
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->deformableInvParticleWeights), CHILDREN(20), 1 }, // deformableInvParticleWeights
+ { TYPE_F32, false, 1 * sizeof(float), NULL, 0 }, // deformableInvParticleWeights[]
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->virtualParticleIndices), CHILDREN(21), 1 }, // virtualParticleIndices
+ { TYPE_U32, false, 1 * sizeof(uint32_t), NULL, 0 }, // virtualParticleIndices[]
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->virtualParticleWeights), CHILDREN(22), 1 }, // virtualParticleWeights
+ { TYPE_VEC3, false, 1 * sizeof(physx::PxVec3), NULL, 0 }, // virtualParticleWeights[]
+};
+
+
+bool ClothingCookedParam::mBuiltFlag = false;
+NvParameterized::MutexType ClothingCookedParam::mBuiltFlagMutex;
+
+ClothingCookedParam::ClothingCookedParam(NvParameterized::Traits* traits, void* buf, int32_t* refCount) :
+ NvParameters(traits, buf, refCount)
+{
+ //mParameterizedTraits->registerFactory(className(), &ClothingCookedParamFactoryInst);
+
+ if (!buf) //Do not init data if it is inplace-deserialized
+ {
+ initDynamicArrays();
+ initStrings();
+ initReferences();
+ initDefaults();
+ }
+}
+
+ClothingCookedParam::~ClothingCookedParam()
+{
+ freeStrings();
+ freeReferences();
+ freeDynamicArrays();
+}
+
+void ClothingCookedParam::destroy()
+{
+ // We cache these fields here to avoid overwrite in destructor
+ bool doDeallocateSelf = mDoDeallocateSelf;
+ NvParameterized::Traits* traits = mParameterizedTraits;
+ int32_t* refCount = mRefCount;
+ void* buf = mBuffer;
+
+ this->~ClothingCookedParam();
+
+ NvParameters::destroy(this, traits, doDeallocateSelf, refCount, buf);
+}
+
+const NvParameterized::DefinitionImpl* ClothingCookedParam::getParameterDefinitionTree(void)
+{
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+ if (!mBuiltFlag)
+ {
+ buildTree();
+ }
+ }
+
+ return(&ParamDefTable[0]);
+}
+
+const NvParameterized::DefinitionImpl* ClothingCookedParam::getParameterDefinitionTree(void) const
+{
+ ClothingCookedParam* tmpParam = const_cast<ClothingCookedParam*>(this);
+
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+ if (!mBuiltFlag)
+ {
+ tmpParam->buildTree();
+ }
+ }
+
+ return(&ParamDefTable[0]);
+}
+
+NvParameterized::ErrorType ClothingCookedParam::getParameterHandle(const char* long_name, Handle& handle) const
+{
+ ErrorType Ret = NvParameters::getParameterHandle(long_name, handle);
+ if (Ret != ERROR_NONE)
+ {
+ return(Ret);
+ }
+
+ size_t offset;
+ void* ptr;
+
+ getVarPtr(handle, ptr, offset);
+
+ if (ptr == NULL)
+ {
+ return(ERROR_INDEX_OUT_OF_RANGE);
+ }
+
+ return(ERROR_NONE);
+}
+
+NvParameterized::ErrorType ClothingCookedParam::getParameterHandle(const char* long_name, Handle& handle)
+{
+ ErrorType Ret = NvParameters::getParameterHandle(long_name, handle);
+ if (Ret != ERROR_NONE)
+ {
+ return(Ret);
+ }
+
+ size_t offset;
+ void* ptr;
+
+ getVarPtr(handle, ptr, offset);
+
+ if (ptr == NULL)
+ {
+ return(ERROR_INDEX_OUT_OF_RANGE);
+ }
+
+ return(ERROR_NONE);
+}
+
+void ClothingCookedParam::getVarPtr(const Handle& handle, void*& ptr, size_t& offset) const
+{
+ ptr = getVarPtrHelper(&ParamLookupTable[0], const_cast<ClothingCookedParam::ParametersStruct*>(&parameters()), handle, offset);
+}
+
+
+/* Dynamic Handle Indices */
+
+void ClothingCookedParam::freeParameterDefinitionTable(NvParameterized::Traits* traits)
+{
+ if (!traits)
+ {
+ return;
+ }
+
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ return;
+ }
+
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+
+ if (!mBuiltFlag)
+ {
+ return;
+ }
+
+ for (uint32_t i = 0; i < NumParamDefs; ++i)
+ {
+ ParamDefTable[i].~DefinitionImpl();
+ }
+
+ traits->free(ParamDefTable);
+
+ mBuiltFlag = false;
+}
+
+#define PDEF_PTR(index) (&ParamDefTable[index])
+
+void ClothingCookedParam::buildTree(void)
+{
+
+ uint32_t allocSize = sizeof(NvParameterized::DefinitionImpl) * NumParamDefs;
+ ParamDefTable = (NvParameterized::DefinitionImpl*)(mParameterizedTraits->alloc(allocSize));
+ memset(ParamDefTable, 0, allocSize);
+
+ for (uint32_t i = 0; i < NumParamDefs; ++i)
+ {
+ NV_PARAM_PLACEMENT_NEW(ParamDefTable + i, NvParameterized::DefinitionImpl)(*mParameterizedTraits);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=0, longName=""
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[0];
+ ParamDef->init("", TYPE_STRUCT, "STRUCT", true);
+
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=1, longName="actorScale"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[1];
+ ParamDef->init("actorScale", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Actor scale", true);
+ ParamDefTable[1].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=2, longName="convexCookedData"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[2];
+ ParamDef->init("convexCookedData", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "All convexes are checked into the same buffer, one after the other.\n", true);
+ HintTable[1].init("shortDescription", "The cooked data for all the convex meshes.", true);
+ ParamDefTable[2].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=3, longName="convexCookedData[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[3];
+ ParamDef->init("convexCookedData", TYPE_U8, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "All convexes are checked into the same buffer, one after the other.\n", true);
+ HintTable[1].init("shortDescription", "The cooked data for all the convex meshes.", true);
+ ParamDefTable[3].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=4, longName="convexMeshPointers"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[4];
+ ParamDef->init("convexMeshPointers", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("DONOTSERIALIZE", uint64_t(1), true);
+ ParamDefTable[4].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("DONOTSERIALIZE", uint64_t(1), true);
+ HintTable[1].init("shortDescription", "Convex mesh pointers", true);
+ ParamDefTable[4].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=5, longName="convexMeshPointers[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[5];
+ ParamDef->init("convexMeshPointers", TYPE_POINTER, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("DONOTSERIALIZE", uint64_t(1), true);
+ ParamDefTable[5].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("DONOTSERIALIZE", uint64_t(1), true);
+ HintTable[1].init("shortDescription", "Convex mesh pointers", true);
+ ParamDefTable[5].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=6, longName="cookedPhysicalMeshes"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[6];
+ ParamDef->init("cookedPhysicalMeshes", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Cooked physical meshes", true);
+ ParamDefTable[6].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=7, longName="cookedPhysicalMeshes[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[7];
+ ParamDef->init("cookedPhysicalMeshes", TYPE_STRUCT, "CookedPhysicalMesh", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Cooked physical meshes", true);
+ ParamDefTable[7].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=8, longName="cookedPhysicalMeshes[].physicalMeshId"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[8];
+ ParamDef->init("physicalMeshId", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Physical mesh ID", true);
+ ParamDefTable[8].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=9, longName="cookedPhysicalMeshes[].cookedDataOffset"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[9];
+ ParamDef->init("cookedDataOffset", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Cooked data offset", true);
+ ParamDefTable[9].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=10, longName="cookedPhysicalMeshes[].cookedDataLength"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[10];
+ ParamDef->init("cookedDataLength", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Cooked data length", true);
+ ParamDefTable[10].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=11, longName="cookedPhysicalMeshes[].deformableMeshPointer"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[11];
+ ParamDef->init("deformableMeshPointer", TYPE_POINTER, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("DONOTSERIALIZE", uint64_t(1), true);
+ ParamDefTable[11].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("DONOTSERIALIZE", uint64_t(1), true);
+ HintTable[1].init("shortDescription", "Deformable mesh pointer", true);
+ ParamDefTable[11].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=12, longName="cookedPhysicalMeshes[].deformableInvParticleWeightsOffset"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[12];
+ ParamDef->init("deformableInvParticleWeightsOffset", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Deformable inverse particle weights offset", true);
+ ParamDefTable[12].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=13, longName="cookedPhysicalMeshes[].virtualParticleIndicesOffset"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[13];
+ ParamDef->init("virtualParticleIndicesOffset", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Virtual particle indices offset", true);
+ ParamDefTable[13].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=14, longName="cookedPhysicalMeshes[].virtualParticleIndicesLength"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[14];
+ ParamDef->init("virtualParticleIndicesLength", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Virtual particle indices length", true);
+ ParamDefTable[14].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=15, longName="deformableCookedData"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[15];
+ ParamDef->init("deformableCookedData", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Deformable cooked data", true);
+ ParamDefTable[15].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=16, longName="deformableCookedData[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[16];
+ ParamDef->init("deformableCookedData", TYPE_U8, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Deformable cooked data", true);
+ ParamDefTable[16].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=17, longName="cookedDataVersion"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[17];
+ ParamDef->init("cookedDataVersion", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "When loading into a different PhysX version, it will cook again on loading.", true);
+ HintTable[1].init("shortDescription", "The PhysX SDK Version this data was cooked from", true);
+ ParamDefTable[17].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=18, longName="deformableInvParticleWeights"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[18];
+ ParamDef->init("deformableInvParticleWeights", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Deformable inverse particle weights", true);
+ ParamDefTable[18].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=19, longName="deformableInvParticleWeights[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[19];
+ ParamDef->init("deformableInvParticleWeights", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Deformable inverse particle weights", true);
+ ParamDefTable[19].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=20, longName="virtualParticleIndices"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[20];
+ ParamDef->init("virtualParticleIndices", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Virtual particle indices", true);
+ ParamDefTable[20].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=21, longName="virtualParticleIndices[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[21];
+ ParamDef->init("virtualParticleIndices", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Virtual particle indices", true);
+ ParamDefTable[21].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=22, longName="virtualParticleWeights"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[22];
+ ParamDef->init("virtualParticleWeights", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Virtual particle weights", true);
+ ParamDefTable[22].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=23, longName="virtualParticleWeights[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[23];
+ ParamDef->init("virtualParticleWeights", TYPE_VEC3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Virtual particle weights", true);
+ ParamDefTable[23].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // SetChildren for: nodeIndex=0, longName=""
+ {
+ static Definition* Children[9];
+ Children[0] = PDEF_PTR(1);
+ Children[1] = PDEF_PTR(2);
+ Children[2] = PDEF_PTR(4);
+ Children[3] = PDEF_PTR(6);
+ Children[4] = PDEF_PTR(15);
+ Children[5] = PDEF_PTR(17);
+ Children[6] = PDEF_PTR(18);
+ Children[7] = PDEF_PTR(20);
+ Children[8] = PDEF_PTR(22);
+
+ ParamDefTable[0].setChildren(Children, 9);
+ }
+
+ // SetChildren for: nodeIndex=2, longName="convexCookedData"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(3);
+
+ ParamDefTable[2].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=4, longName="convexMeshPointers"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(5);
+
+ ParamDefTable[4].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=6, longName="cookedPhysicalMeshes"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(7);
+
+ ParamDefTable[6].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=7, longName="cookedPhysicalMeshes[]"
+ {
+ static Definition* Children[7];
+ Children[0] = PDEF_PTR(8);
+ Children[1] = PDEF_PTR(9);
+ Children[2] = PDEF_PTR(10);
+ Children[3] = PDEF_PTR(11);
+ Children[4] = PDEF_PTR(12);
+ Children[5] = PDEF_PTR(13);
+ Children[6] = PDEF_PTR(14);
+
+ ParamDefTable[7].setChildren(Children, 7);
+ }
+
+ // SetChildren for: nodeIndex=15, longName="deformableCookedData"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(16);
+
+ ParamDefTable[15].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=18, longName="deformableInvParticleWeights"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(19);
+
+ ParamDefTable[18].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=20, longName="virtualParticleIndices"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(21);
+
+ ParamDefTable[20].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=22, longName="virtualParticleWeights"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(23);
+
+ ParamDefTable[22].setChildren(Children, 1);
+ }
+
+ mBuiltFlag = true;
+
+}
+void ClothingCookedParam::initStrings(void)
+{
+}
+
+void ClothingCookedParam::initDynamicArrays(void)
+{
+ convexCookedData.buf = NULL;
+ convexCookedData.isAllocated = true;
+ convexCookedData.elementSize = sizeof(uint8_t);
+ convexCookedData.arraySizes[0] = 0;
+ convexMeshPointers.buf = NULL;
+ convexMeshPointers.isAllocated = true;
+ convexMeshPointers.elementSize = sizeof(void*);
+ convexMeshPointers.arraySizes[0] = 0;
+ cookedPhysicalMeshes.buf = NULL;
+ cookedPhysicalMeshes.isAllocated = true;
+ cookedPhysicalMeshes.elementSize = sizeof(CookedPhysicalMesh_Type);
+ cookedPhysicalMeshes.arraySizes[0] = 0;
+ deformableCookedData.buf = NULL;
+ deformableCookedData.isAllocated = true;
+ deformableCookedData.elementSize = sizeof(uint8_t);
+ deformableCookedData.arraySizes[0] = 0;
+ deformableInvParticleWeights.buf = NULL;
+ deformableInvParticleWeights.isAllocated = true;
+ deformableInvParticleWeights.elementSize = sizeof(float);
+ deformableInvParticleWeights.arraySizes[0] = 0;
+ virtualParticleIndices.buf = NULL;
+ virtualParticleIndices.isAllocated = true;
+ virtualParticleIndices.elementSize = sizeof(uint32_t);
+ virtualParticleIndices.arraySizes[0] = 0;
+ virtualParticleWeights.buf = NULL;
+ virtualParticleWeights.isAllocated = true;
+ virtualParticleWeights.elementSize = sizeof(physx::PxVec3);
+ virtualParticleWeights.arraySizes[0] = 0;
+}
+
+void ClothingCookedParam::initDefaults(void)
+{
+
+ freeStrings();
+ freeReferences();
+ freeDynamicArrays();
+ actorScale = float(1.0f);
+ cookedDataVersion = uint32_t(0);
+
+ initDynamicArrays();
+ initStrings();
+ initReferences();
+}
+
+void ClothingCookedParam::initReferences(void)
+{
+}
+
+void ClothingCookedParam::freeDynamicArrays(void)
+{
+ if (convexCookedData.isAllocated && convexCookedData.buf)
+ {
+ mParameterizedTraits->free(convexCookedData.buf);
+ }
+ if (convexMeshPointers.isAllocated && convexMeshPointers.buf)
+ {
+ mParameterizedTraits->free(convexMeshPointers.buf);
+ }
+ if (cookedPhysicalMeshes.isAllocated && cookedPhysicalMeshes.buf)
+ {
+ mParameterizedTraits->free(cookedPhysicalMeshes.buf);
+ }
+ if (deformableCookedData.isAllocated && deformableCookedData.buf)
+ {
+ mParameterizedTraits->free(deformableCookedData.buf);
+ }
+ if (deformableInvParticleWeights.isAllocated && deformableInvParticleWeights.buf)
+ {
+ mParameterizedTraits->free(deformableInvParticleWeights.buf);
+ }
+ if (virtualParticleIndices.isAllocated && virtualParticleIndices.buf)
+ {
+ mParameterizedTraits->free(virtualParticleIndices.buf);
+ }
+ if (virtualParticleWeights.isAllocated && virtualParticleWeights.buf)
+ {
+ mParameterizedTraits->free(virtualParticleWeights.buf);
+ }
+}
+
+void ClothingCookedParam::freeStrings(void)
+{
+}
+
+void ClothingCookedParam::freeReferences(void)
+{
+}
+
+} // namespace clothing
+} // namespace nvidia
diff --git a/APEX_1.4/module/clothing/src/autogen/ClothingCookedPhysX3Param.cpp b/APEX_1.4/module/clothing/src/autogen/ClothingCookedPhysX3Param.cpp
new file mode 100644
index 00000000..7e01986e
--- /dev/null
+++ b/APEX_1.4/module/clothing/src/autogen/ClothingCookedPhysX3Param.cpp
@@ -0,0 +1,1557 @@
+// 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) 2008-2015 NVIDIA Corporation. All rights reserved.
+
+// This file was generated by NvParameterized/scripts/GenParameterized.pl
+
+
+#include "ClothingCookedPhysX3Param.h"
+#include <string.h>
+#include <stdlib.h>
+
+using namespace NvParameterized;
+
+namespace nvidia
+{
+namespace clothing
+{
+
+using namespace ClothingCookedPhysX3ParamNS;
+
+const char* const ClothingCookedPhysX3ParamFactory::vptr =
+ NvParameterized::getVptr<ClothingCookedPhysX3Param, ClothingCookedPhysX3Param::ClassAlignment>();
+
+const uint32_t NumParamDefs = 43;
+static NvParameterized::DefinitionImpl* ParamDefTable; // now allocated in buildTree [NumParamDefs];
+
+
+static const size_t ParamLookupChildrenTable[] =
+{
+ 1, 2, 3, 5, 7, 9, 11, 13, 21, 26, 28, 30, 32, 34, 36, 37, 38, 42, 4, 6, 8, 10, 12,
+ 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 25, 27, 29, 31, 33, 35, 39, 40, 41,
+};
+
+#define TENUM(type) nvidia::##type
+#define CHILDREN(index) &ParamLookupChildrenTable[index]
+static const NvParameterized::ParamLookupNode ParamLookupTable[NumParamDefs] =
+{
+ { TYPE_STRUCT, false, 0, CHILDREN(0), 18 },
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->physicalMeshId), NULL, 0 }, // physicalMeshId
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->numVertices), NULL, 0 }, // numVertices
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->deformableRestLengths), CHILDREN(18), 1 }, // deformableRestLengths
+ { TYPE_F32, false, 1 * sizeof(float), NULL, 0 }, // deformableRestLengths[]
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->deformableIndices), CHILDREN(19), 1 }, // deformableIndices
+ { TYPE_U32, false, 1 * sizeof(uint32_t), NULL, 0 }, // deformableIndices[]
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->selfCollisionIndices), CHILDREN(20), 1 }, // selfCollisionIndices
+ { TYPE_U32, false, 1 * sizeof(uint32_t), NULL, 0 }, // selfCollisionIndices[]
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->selfCollisionNormalIndices), CHILDREN(21), 1 }, // selfCollisionNormalIndices
+ { TYPE_U32, false, 1 * sizeof(uint32_t), NULL, 0 }, // selfCollisionNormalIndices[]
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->selfCollisionNormalSetSizes), CHILDREN(22), 1 }, // selfCollisionNormalSetSizes
+ { TYPE_U32, false, 1 * sizeof(uint32_t), NULL, 0 }, // selfCollisionNormalSetSizes[]
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->deformableSets), CHILDREN(23), 1 }, // deformableSets
+ { TYPE_STRUCT, false, 1 * sizeof(SetDesc_Type), CHILDREN(24), 6 }, // deformableSets[]
+ { TYPE_U32, false, (size_t)(&((SetDesc_Type*)0)->fiberEnd), NULL, 0 }, // deformableSets[].fiberEnd
+ { TYPE_U32, false, (size_t)(&((SetDesc_Type*)0)->longestFiber), NULL, 0 }, // deformableSets[].longestFiber
+ { TYPE_U32, false, (size_t)(&((SetDesc_Type*)0)->shortestFiber), NULL, 0 }, // deformableSets[].shortestFiber
+ { TYPE_U32, false, (size_t)(&((SetDesc_Type*)0)->numEdges), NULL, 0 }, // deformableSets[].numEdges
+ { TYPE_F32, false, (size_t)(&((SetDesc_Type*)0)->avgEdgeLength), NULL, 0 }, // deformableSets[].avgEdgeLength
+ { TYPE_U32, false, (size_t)(&((SetDesc_Type*)0)->avgFiberLength), NULL, 0 }, // deformableSets[].avgFiberLength
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->deformablePhaseDescs), CHILDREN(30), 1 }, // deformablePhaseDescs
+ { TYPE_STRUCT, false, 1 * sizeof(PhaseDesc_Type), CHILDREN(31), 3 }, // deformablePhaseDescs[]
+ { TYPE_U32, false, (size_t)(&((PhaseDesc_Type*)0)->phaseType), NULL, 0 }, // deformablePhaseDescs[].phaseType
+ { TYPE_U32, false, (size_t)(&((PhaseDesc_Type*)0)->setIndex), NULL, 0 }, // deformablePhaseDescs[].setIndex
+ { TYPE_U32, false, (size_t)(&((PhaseDesc_Type*)0)->restValueOffset), NULL, 0 }, // deformablePhaseDescs[].restValueOffset
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->tetherAnchors), CHILDREN(34), 1 }, // tetherAnchors
+ { TYPE_U32, false, 1 * sizeof(uint32_t), NULL, 0 }, // tetherAnchors[]
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->tetherLengths), CHILDREN(35), 1 }, // tetherLengths
+ { TYPE_F32, false, 1 * sizeof(float), NULL, 0 }, // tetherLengths[]
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->deformableInvVertexWeights), CHILDREN(36), 1 }, // deformableInvVertexWeights
+ { TYPE_F32, false, 1 * sizeof(float), NULL, 0 }, // deformableInvVertexWeights[]
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->virtualParticleIndices), CHILDREN(37), 1 }, // virtualParticleIndices
+ { TYPE_U32, false, 1 * sizeof(uint32_t), NULL, 0 }, // virtualParticleIndices[]
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->virtualParticleWeights), CHILDREN(38), 1 }, // virtualParticleWeights
+ { TYPE_F32, false, 1 * sizeof(float), NULL, 0 }, // virtualParticleWeights[]
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->cookedDataVersion), NULL, 0 }, // cookedDataVersion
+ { TYPE_POINTER, false, (size_t)(&((ParametersStruct*)0)->fabricCPU), NULL, 0 }, // fabricCPU
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->fabricGPU), CHILDREN(39), 1 }, // fabricGPU
+ { TYPE_STRUCT, false, 1 * sizeof(FabricGPU_Type), CHILDREN(40), 2 }, // fabricGPU[]
+ { TYPE_POINTER, false, (size_t)(&((FabricGPU_Type*)0)->fabricGPU), NULL, 0 }, // fabricGPU[].fabricGPU
+ { TYPE_POINTER, false, (size_t)(&((FabricGPU_Type*)0)->factory), NULL, 0 }, // fabricGPU[].factory
+ { TYPE_REF, false, (size_t)(&((ParametersStruct*)0)->nextCookedData), NULL, 0 }, // nextCookedData
+};
+
+
+bool ClothingCookedPhysX3Param::mBuiltFlag = false;
+NvParameterized::MutexType ClothingCookedPhysX3Param::mBuiltFlagMutex;
+
+ClothingCookedPhysX3Param::ClothingCookedPhysX3Param(NvParameterized::Traits* traits, void* buf, int32_t* refCount) :
+ NvParameters(traits, buf, refCount)
+{
+ //mParameterizedTraits->registerFactory(className(), &ClothingCookedPhysX3ParamFactoryInst);
+
+ if (!buf) //Do not init data if it is inplace-deserialized
+ {
+ initDynamicArrays();
+ initStrings();
+ initReferences();
+ initDefaults();
+ }
+}
+
+ClothingCookedPhysX3Param::~ClothingCookedPhysX3Param()
+{
+ freeStrings();
+ freeReferences();
+ freeDynamicArrays();
+}
+
+void ClothingCookedPhysX3Param::destroy()
+{
+ // We cache these fields here to avoid overwrite in destructor
+ bool doDeallocateSelf = mDoDeallocateSelf;
+ NvParameterized::Traits* traits = mParameterizedTraits;
+ int32_t* refCount = mRefCount;
+ void* buf = mBuffer;
+
+ this->~ClothingCookedPhysX3Param();
+
+ NvParameters::destroy(this, traits, doDeallocateSelf, refCount, buf);
+}
+
+const NvParameterized::DefinitionImpl* ClothingCookedPhysX3Param::getParameterDefinitionTree(void)
+{
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+ if (!mBuiltFlag)
+ {
+ buildTree();
+ }
+ }
+
+ return(&ParamDefTable[0]);
+}
+
+const NvParameterized::DefinitionImpl* ClothingCookedPhysX3Param::getParameterDefinitionTree(void) const
+{
+ ClothingCookedPhysX3Param* tmpParam = const_cast<ClothingCookedPhysX3Param*>(this);
+
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+ if (!mBuiltFlag)
+ {
+ tmpParam->buildTree();
+ }
+ }
+
+ return(&ParamDefTable[0]);
+}
+
+NvParameterized::ErrorType ClothingCookedPhysX3Param::getParameterHandle(const char* long_name, Handle& handle) const
+{
+ ErrorType Ret = NvParameters::getParameterHandle(long_name, handle);
+ if (Ret != ERROR_NONE)
+ {
+ return(Ret);
+ }
+
+ size_t offset;
+ void* ptr;
+
+ getVarPtr(handle, ptr, offset);
+
+ if (ptr == NULL)
+ {
+ return(ERROR_INDEX_OUT_OF_RANGE);
+ }
+
+ return(ERROR_NONE);
+}
+
+NvParameterized::ErrorType ClothingCookedPhysX3Param::getParameterHandle(const char* long_name, Handle& handle)
+{
+ ErrorType Ret = NvParameters::getParameterHandle(long_name, handle);
+ if (Ret != ERROR_NONE)
+ {
+ return(Ret);
+ }
+
+ size_t offset;
+ void* ptr;
+
+ getVarPtr(handle, ptr, offset);
+
+ if (ptr == NULL)
+ {
+ return(ERROR_INDEX_OUT_OF_RANGE);
+ }
+
+ return(ERROR_NONE);
+}
+
+void ClothingCookedPhysX3Param::getVarPtr(const Handle& handle, void*& ptr, size_t& offset) const
+{
+ ptr = getVarPtrHelper(&ParamLookupTable[0], const_cast<ClothingCookedPhysX3Param::ParametersStruct*>(&parameters()), handle, offset);
+}
+
+
+/* Dynamic Handle Indices */
+
+void ClothingCookedPhysX3Param::freeParameterDefinitionTable(NvParameterized::Traits* traits)
+{
+ if (!traits)
+ {
+ return;
+ }
+
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ return;
+ }
+
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+
+ if (!mBuiltFlag)
+ {
+ return;
+ }
+
+ for (uint32_t i = 0; i < NumParamDefs; ++i)
+ {
+ ParamDefTable[i].~DefinitionImpl();
+ }
+
+ traits->free(ParamDefTable);
+
+ mBuiltFlag = false;
+}
+
+#define PDEF_PTR(index) (&ParamDefTable[index])
+
+void ClothingCookedPhysX3Param::buildTree(void)
+{
+
+ uint32_t allocSize = sizeof(NvParameterized::DefinitionImpl) * NumParamDefs;
+ ParamDefTable = (NvParameterized::DefinitionImpl*)(mParameterizedTraits->alloc(allocSize));
+ memset(ParamDefTable, 0, allocSize);
+
+ for (uint32_t i = 0; i < NumParamDefs; ++i)
+ {
+ NV_PARAM_PLACEMENT_NEW(ParamDefTable + i, NvParameterized::DefinitionImpl)(*mParameterizedTraits);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=0, longName=""
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[0];
+ ParamDef->init("", TYPE_STRUCT, "STRUCT", true);
+
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=1, longName="physicalMeshId"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[1];
+ ParamDef->init("physicalMeshId", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Physical mesh ID", true);
+ ParamDefTable[1].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=2, longName="numVertices"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[2];
+ ParamDef->init("numVertices", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Vertex count", true);
+ ParamDefTable[2].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=3, longName="deformableRestLengths"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[3];
+ ParamDef->init("deformableRestLengths", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Deformable rest lengths", true);
+ ParamDefTable[3].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=4, longName="deformableRestLengths[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[4];
+ ParamDef->init("deformableRestLengths", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Deformable rest lengths", true);
+ ParamDefTable[4].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=5, longName="deformableIndices"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[5];
+ ParamDef->init("deformableIndices", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Deformable indices", true);
+ ParamDefTable[5].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=6, longName="deformableIndices[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[6];
+ ParamDef->init("deformableIndices", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Deformable indices", true);
+ ParamDefTable[6].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=7, longName="selfCollisionIndices"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[7];
+ ParamDef->init("selfCollisionIndices", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Self collision indices", true);
+ ParamDefTable[7].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=8, longName="selfCollisionIndices[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[8];
+ ParamDef->init("selfCollisionIndices", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Self collision indices", true);
+ ParamDefTable[8].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=9, longName="selfCollisionNormalIndices"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[9];
+ ParamDef->init("selfCollisionNormalIndices", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Self collision normal indices", true);
+ ParamDefTable[9].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=10, longName="selfCollisionNormalIndices[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[10];
+ ParamDef->init("selfCollisionNormalIndices", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Self collision normal indices", true);
+ ParamDefTable[10].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=11, longName="selfCollisionNormalSetSizes"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[11];
+ ParamDef->init("selfCollisionNormalSetSizes", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Self collision normal set sizes", true);
+ ParamDefTable[11].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=12, longName="selfCollisionNormalSetSizes[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[12];
+ ParamDef->init("selfCollisionNormalSetSizes", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Self collision normal set sizes", true);
+ ParamDefTable[12].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=13, longName="deformableSets"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[13];
+ ParamDef->init("deformableSets", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Deformable sets", true);
+ ParamDefTable[13].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=14, longName="deformableSets[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[14];
+ ParamDef->init("deformableSets", TYPE_STRUCT, "SetDesc", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Deformable sets", true);
+ ParamDefTable[14].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=15, longName="deformableSets[].fiberEnd"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[15];
+ ParamDef->init("fiberEnd", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Fiber end", true);
+ ParamDefTable[15].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=16, longName="deformableSets[].longestFiber"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[16];
+ ParamDef->init("longestFiber", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Longest fiber", true);
+ ParamDefTable[16].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=17, longName="deformableSets[].shortestFiber"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[17];
+ ParamDef->init("shortestFiber", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Shortest fiber", true);
+ ParamDefTable[17].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=18, longName="deformableSets[].numEdges"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[18];
+ ParamDef->init("numEdges", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Edge count", true);
+ ParamDefTable[18].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=19, longName="deformableSets[].avgEdgeLength"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[19];
+ ParamDef->init("avgEdgeLength", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Average edge length", true);
+ ParamDefTable[19].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=20, longName="deformableSets[].avgFiberLength"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[20];
+ ParamDef->init("avgFiberLength", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Average fiber length", true);
+ ParamDefTable[20].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=21, longName="deformablePhaseDescs"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[21];
+ ParamDef->init("deformablePhaseDescs", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Deformable phase descriptions", true);
+ ParamDefTable[21].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=22, longName="deformablePhaseDescs[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[22];
+ ParamDef->init("deformablePhaseDescs", TYPE_STRUCT, "PhaseDesc", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Deformable phase descriptions", true);
+ ParamDefTable[22].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=23, longName="deformablePhaseDescs[].phaseType"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[23];
+ ParamDef->init("phaseType", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Phase type", true);
+ ParamDefTable[23].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=24, longName="deformablePhaseDescs[].setIndex"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[24];
+ ParamDef->init("setIndex", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Set index", true);
+ ParamDefTable[24].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=25, longName="deformablePhaseDescs[].restValueOffset"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[25];
+ ParamDef->init("restValueOffset", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Rest value offset", true);
+ ParamDefTable[25].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=26, longName="tetherAnchors"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[26];
+ ParamDef->init("tetherAnchors", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Tether anchors", true);
+ ParamDefTable[26].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=27, longName="tetherAnchors[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[27];
+ ParamDef->init("tetherAnchors", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Tether anchors", true);
+ ParamDefTable[27].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=28, longName="tetherLengths"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[28];
+ ParamDef->init("tetherLengths", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Tether lengths", true);
+ ParamDefTable[28].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=29, longName="tetherLengths[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[29];
+ ParamDef->init("tetherLengths", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Tether lengths", true);
+ ParamDefTable[29].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=30, longName="deformableInvVertexWeights"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[30];
+ ParamDef->init("deformableInvVertexWeights", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Deformable inverse vertex weights", true);
+ ParamDefTable[30].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=31, longName="deformableInvVertexWeights[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[31];
+ ParamDef->init("deformableInvVertexWeights", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Deformable inverse vertex weights", true);
+ ParamDefTable[31].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=32, longName="virtualParticleIndices"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[32];
+ ParamDef->init("virtualParticleIndices", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Virtual particle indices", true);
+ ParamDefTable[32].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=33, longName="virtualParticleIndices[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[33];
+ ParamDef->init("virtualParticleIndices", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Virtual particle indices", true);
+ ParamDefTable[33].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=34, longName="virtualParticleWeights"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[34];
+ ParamDef->init("virtualParticleWeights", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Virtual particle weights", true);
+ ParamDefTable[34].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=35, longName="virtualParticleWeights[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[35];
+ ParamDef->init("virtualParticleWeights", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Virtual particle weights", true);
+ ParamDefTable[35].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=36, longName="cookedDataVersion"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[36];
+ ParamDef->init("cookedDataVersion", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Cooked data version", true);
+ ParamDefTable[36].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=37, longName="fabricCPU"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[37];
+ ParamDef->init("fabricCPU", TYPE_POINTER, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("DONOTSERIALIZE", uint64_t(1), true);
+ ParamDefTable[37].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("DONOTSERIALIZE", uint64_t(1), true);
+ HintTable[1].init("shortDescription", "Fabric CPU pointer", true);
+ ParamDefTable[37].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=38, longName="fabricGPU"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[38];
+ ParamDef->init("fabricGPU", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("DONOTSERIALIZE", uint64_t(1), true);
+ ParamDefTable[38].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("DONOTSERIALIZE", uint64_t(1), true);
+ HintTable[1].init("shortDescription", "Fabric GPU array", true);
+ ParamDefTable[38].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=39, longName="fabricGPU[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[39];
+ ParamDef->init("fabricGPU", TYPE_STRUCT, "FabricGPU", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("DONOTSERIALIZE", uint64_t(1), true);
+ ParamDefTable[39].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("DONOTSERIALIZE", uint64_t(1), true);
+ HintTable[1].init("shortDescription", "Fabric GPU array", true);
+ ParamDefTable[39].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=40, longName="fabricGPU[].fabricGPU"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[40];
+ ParamDef->init("fabricGPU", TYPE_POINTER, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("DONOTSERIALIZE", uint64_t(1), true);
+ ParamDefTable[40].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("DONOTSERIALIZE", uint64_t(1), true);
+ HintTable[1].init("shortDescription", "Runtime pointer to shared fabric.", true);
+ ParamDefTable[40].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=41, longName="fabricGPU[].factory"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[41];
+ ParamDef->init("factory", TYPE_POINTER, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("DONOTSERIALIZE", uint64_t(1), true);
+ ParamDefTable[41].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("DONOTSERIALIZE", uint64_t(1), true);
+ HintTable[1].init("shortDescription", "Runtime pointer to the factory the fabric has been created with.", true);
+ ParamDefTable[41].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=42, longName="nextCookedData"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[42];
+ ParamDef->init("nextCookedData", TYPE_REF, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("INCLUDED", uint64_t(1), true);
+ ParamDefTable[42].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("INCLUDED", uint64_t(1), true);
+ HintTable[1].init("shortDescription", "Daisy-chain together multiple cooked data objects", true);
+ ParamDefTable[42].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+ static const char* const RefVariantVals[] = { "ClothingCookedPhysX3Param" };
+ ParamDefTable[42].setRefVariantVals((const char**)RefVariantVals, 1);
+
+
+
+ }
+
+ // SetChildren for: nodeIndex=0, longName=""
+ {
+ static Definition* Children[18];
+ Children[0] = PDEF_PTR(1);
+ Children[1] = PDEF_PTR(2);
+ Children[2] = PDEF_PTR(3);
+ Children[3] = PDEF_PTR(5);
+ Children[4] = PDEF_PTR(7);
+ Children[5] = PDEF_PTR(9);
+ Children[6] = PDEF_PTR(11);
+ Children[7] = PDEF_PTR(13);
+ Children[8] = PDEF_PTR(21);
+ Children[9] = PDEF_PTR(26);
+ Children[10] = PDEF_PTR(28);
+ Children[11] = PDEF_PTR(30);
+ Children[12] = PDEF_PTR(32);
+ Children[13] = PDEF_PTR(34);
+ Children[14] = PDEF_PTR(36);
+ Children[15] = PDEF_PTR(37);
+ Children[16] = PDEF_PTR(38);
+ Children[17] = PDEF_PTR(42);
+
+ ParamDefTable[0].setChildren(Children, 18);
+ }
+
+ // SetChildren for: nodeIndex=3, longName="deformableRestLengths"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(4);
+
+ ParamDefTable[3].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=5, longName="deformableIndices"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(6);
+
+ ParamDefTable[5].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=7, longName="selfCollisionIndices"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(8);
+
+ ParamDefTable[7].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=9, longName="selfCollisionNormalIndices"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(10);
+
+ ParamDefTable[9].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=11, longName="selfCollisionNormalSetSizes"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(12);
+
+ ParamDefTable[11].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=13, longName="deformableSets"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(14);
+
+ ParamDefTable[13].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=14, longName="deformableSets[]"
+ {
+ static Definition* Children[6];
+ Children[0] = PDEF_PTR(15);
+ Children[1] = PDEF_PTR(16);
+ Children[2] = PDEF_PTR(17);
+ Children[3] = PDEF_PTR(18);
+ Children[4] = PDEF_PTR(19);
+ Children[5] = PDEF_PTR(20);
+
+ ParamDefTable[14].setChildren(Children, 6);
+ }
+
+ // SetChildren for: nodeIndex=21, longName="deformablePhaseDescs"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(22);
+
+ ParamDefTable[21].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=22, longName="deformablePhaseDescs[]"
+ {
+ static Definition* Children[3];
+ Children[0] = PDEF_PTR(23);
+ Children[1] = PDEF_PTR(24);
+ Children[2] = PDEF_PTR(25);
+
+ ParamDefTable[22].setChildren(Children, 3);
+ }
+
+ // SetChildren for: nodeIndex=26, longName="tetherAnchors"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(27);
+
+ ParamDefTable[26].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=28, longName="tetherLengths"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(29);
+
+ ParamDefTable[28].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=30, longName="deformableInvVertexWeights"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(31);
+
+ ParamDefTable[30].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=32, longName="virtualParticleIndices"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(33);
+
+ ParamDefTable[32].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=34, longName="virtualParticleWeights"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(35);
+
+ ParamDefTable[34].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=38, longName="fabricGPU"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(39);
+
+ ParamDefTable[38].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=39, longName="fabricGPU[]"
+ {
+ static Definition* Children[2];
+ Children[0] = PDEF_PTR(40);
+ Children[1] = PDEF_PTR(41);
+
+ ParamDefTable[39].setChildren(Children, 2);
+ }
+
+ mBuiltFlag = true;
+
+}
+void ClothingCookedPhysX3Param::initStrings(void)
+{
+}
+
+void ClothingCookedPhysX3Param::initDynamicArrays(void)
+{
+ deformableRestLengths.buf = NULL;
+ deformableRestLengths.isAllocated = true;
+ deformableRestLengths.elementSize = sizeof(float);
+ deformableRestLengths.arraySizes[0] = 0;
+ deformableIndices.buf = NULL;
+ deformableIndices.isAllocated = true;
+ deformableIndices.elementSize = sizeof(uint32_t);
+ deformableIndices.arraySizes[0] = 0;
+ selfCollisionIndices.buf = NULL;
+ selfCollisionIndices.isAllocated = true;
+ selfCollisionIndices.elementSize = sizeof(uint32_t);
+ selfCollisionIndices.arraySizes[0] = 0;
+ selfCollisionNormalIndices.buf = NULL;
+ selfCollisionNormalIndices.isAllocated = true;
+ selfCollisionNormalIndices.elementSize = sizeof(uint32_t);
+ selfCollisionNormalIndices.arraySizes[0] = 0;
+ selfCollisionNormalSetSizes.buf = NULL;
+ selfCollisionNormalSetSizes.isAllocated = true;
+ selfCollisionNormalSetSizes.elementSize = sizeof(uint32_t);
+ selfCollisionNormalSetSizes.arraySizes[0] = 0;
+ deformableSets.buf = NULL;
+ deformableSets.isAllocated = true;
+ deformableSets.elementSize = sizeof(SetDesc_Type);
+ deformableSets.arraySizes[0] = 0;
+ deformablePhaseDescs.buf = NULL;
+ deformablePhaseDescs.isAllocated = true;
+ deformablePhaseDescs.elementSize = sizeof(PhaseDesc_Type);
+ deformablePhaseDescs.arraySizes[0] = 0;
+ tetherAnchors.buf = NULL;
+ tetherAnchors.isAllocated = true;
+ tetherAnchors.elementSize = sizeof(uint32_t);
+ tetherAnchors.arraySizes[0] = 0;
+ tetherLengths.buf = NULL;
+ tetherLengths.isAllocated = true;
+ tetherLengths.elementSize = sizeof(float);
+ tetherLengths.arraySizes[0] = 0;
+ deformableInvVertexWeights.buf = NULL;
+ deformableInvVertexWeights.isAllocated = true;
+ deformableInvVertexWeights.elementSize = sizeof(float);
+ deformableInvVertexWeights.arraySizes[0] = 0;
+ virtualParticleIndices.buf = NULL;
+ virtualParticleIndices.isAllocated = true;
+ virtualParticleIndices.elementSize = sizeof(uint32_t);
+ virtualParticleIndices.arraySizes[0] = 0;
+ virtualParticleWeights.buf = NULL;
+ virtualParticleWeights.isAllocated = true;
+ virtualParticleWeights.elementSize = sizeof(float);
+ virtualParticleWeights.arraySizes[0] = 0;
+ fabricGPU.buf = NULL;
+ fabricGPU.isAllocated = true;
+ fabricGPU.elementSize = sizeof(FabricGPU_Type);
+ fabricGPU.arraySizes[0] = 0;
+}
+
+void ClothingCookedPhysX3Param::initDefaults(void)
+{
+
+ freeStrings();
+ freeReferences();
+ freeDynamicArrays();
+ physicalMeshId = uint32_t(0);
+ numVertices = uint32_t(0);
+ cookedDataVersion = uint32_t(0);
+ fabricCPU = NULL;
+
+ initDynamicArrays();
+ initStrings();
+ initReferences();
+}
+
+void ClothingCookedPhysX3Param::initReferences(void)
+{
+ nextCookedData = NULL;
+
+}
+
+void ClothingCookedPhysX3Param::freeDynamicArrays(void)
+{
+ if (deformableRestLengths.isAllocated && deformableRestLengths.buf)
+ {
+ mParameterizedTraits->free(deformableRestLengths.buf);
+ }
+ if (deformableIndices.isAllocated && deformableIndices.buf)
+ {
+ mParameterizedTraits->free(deformableIndices.buf);
+ }
+ if (selfCollisionIndices.isAllocated && selfCollisionIndices.buf)
+ {
+ mParameterizedTraits->free(selfCollisionIndices.buf);
+ }
+ if (selfCollisionNormalIndices.isAllocated && selfCollisionNormalIndices.buf)
+ {
+ mParameterizedTraits->free(selfCollisionNormalIndices.buf);
+ }
+ if (selfCollisionNormalSetSizes.isAllocated && selfCollisionNormalSetSizes.buf)
+ {
+ mParameterizedTraits->free(selfCollisionNormalSetSizes.buf);
+ }
+ if (deformableSets.isAllocated && deformableSets.buf)
+ {
+ mParameterizedTraits->free(deformableSets.buf);
+ }
+ if (deformablePhaseDescs.isAllocated && deformablePhaseDescs.buf)
+ {
+ mParameterizedTraits->free(deformablePhaseDescs.buf);
+ }
+ if (tetherAnchors.isAllocated && tetherAnchors.buf)
+ {
+ mParameterizedTraits->free(tetherAnchors.buf);
+ }
+ if (tetherLengths.isAllocated && tetherLengths.buf)
+ {
+ mParameterizedTraits->free(tetherLengths.buf);
+ }
+ if (deformableInvVertexWeights.isAllocated && deformableInvVertexWeights.buf)
+ {
+ mParameterizedTraits->free(deformableInvVertexWeights.buf);
+ }
+ if (virtualParticleIndices.isAllocated && virtualParticleIndices.buf)
+ {
+ mParameterizedTraits->free(virtualParticleIndices.buf);
+ }
+ if (virtualParticleWeights.isAllocated && virtualParticleWeights.buf)
+ {
+ mParameterizedTraits->free(virtualParticleWeights.buf);
+ }
+ if (fabricGPU.isAllocated && fabricGPU.buf)
+ {
+ mParameterizedTraits->free(fabricGPU.buf);
+ }
+}
+
+void ClothingCookedPhysX3Param::freeStrings(void)
+{
+}
+
+void ClothingCookedPhysX3Param::freeReferences(void)
+{
+ if (nextCookedData)
+ {
+ nextCookedData->destroy();
+ }
+
+}
+
+} // namespace clothing
+} // namespace nvidia
diff --git a/APEX_1.4/module/clothing/src/autogen/ClothingDebugRenderParams.cpp b/APEX_1.4/module/clothing/src/autogen/ClothingDebugRenderParams.cpp
new file mode 100644
index 00000000..71ceee2e
--- /dev/null
+++ b/APEX_1.4/module/clothing/src/autogen/ClothingDebugRenderParams.cpp
@@ -0,0 +1,1327 @@
+// 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) 2008-2015 NVIDIA Corporation. All rights reserved.
+
+// This file was generated by NvParameterized/scripts/GenParameterized.pl
+
+
+#include "ClothingDebugRenderParams.h"
+#include <string.h>
+#include <stdlib.h>
+
+using namespace NvParameterized;
+
+namespace nvidia
+{
+namespace clothing
+{
+
+using namespace ClothingDebugRenderParamsNS;
+
+const char* const ClothingDebugRenderParamsFactory::vptr =
+ NvParameterized::getVptr<ClothingDebugRenderParams, ClothingDebugRenderParams::ClassAlignment>();
+
+const uint32_t NumParamDefs = 42;
+static NvParameterized::DefinitionImpl* ParamDefTable; // now allocated in buildTree [NumParamDefs];
+
+
+static const size_t ParamLookupChildrenTable[] =
+{
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+};
+
+#define TENUM(type) nvidia::##type
+#define CHILDREN(index) &ParamLookupChildrenTable[index]
+static const NvParameterized::ParamLookupNode ParamLookupTable[NumParamDefs] =
+{
+ { TYPE_STRUCT, false, 0, CHILDREN(0), 41 },
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->Actors), NULL, 0 }, // Actors
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->SkinnedPositions), NULL, 0 }, // SkinnedPositions
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->Backstop), NULL, 0 }, // Backstop
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->BackstopPrecise), NULL, 0 }, // BackstopPrecise
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->MaxDistance), NULL, 0 }, // MaxDistance
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->MaxDistanceInwards), NULL, 0 }, // MaxDistanceInwards
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->SkinMapAll), NULL, 0 }, // SkinMapAll
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->SkinMapBad), NULL, 0 }, // SkinMapBad
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->SkinMapActual), NULL, 0 }, // SkinMapActual
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->SkinMapInvalidBary), NULL, 0 }, // SkinMapInvalidBary
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->PhysicsMeshWire), NULL, 0 }, // PhysicsMeshWire
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->PhysicsMeshSolid), NULL, 0 }, // PhysicsMeshSolid
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->PhysicsMeshNormals), NULL, 0 }, // PhysicsMeshNormals
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->Skeleton), NULL, 0 }, // Skeleton
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->BoneFrames), NULL, 0 }, // BoneFrames
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->BoneNames), NULL, 0 }, // BoneNames
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->Velocities), NULL, 0 }, // Velocities
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->Wind), NULL, 0 }, // Wind
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->GraphicalVertexBones), NULL, 0 }, // GraphicalVertexBones
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->PhysicalVertexBones), NULL, 0 }, // PhysicalVertexBones
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->CollisionShapes), NULL, 0 }, // CollisionShapes
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->CollisionShapesWire), NULL, 0 }, // CollisionShapesWire
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->LengthFibers), NULL, 0 }, // LengthFibers
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->CrossSectionFibers), NULL, 0 }, // CrossSectionFibers
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->BendingFibers), NULL, 0 }, // BendingFibers
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->ShearingFibers), NULL, 0 }, // ShearingFibers
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->ZerostretchFibers), NULL, 0 }, // ZerostretchFibers
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->TethersActive), NULL, 0 }, // TethersActive
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->TethersInactive), NULL, 0 }, // TethersInactive
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->VirtualCollision), NULL, 0 }, // VirtualCollision
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->FiberRange), NULL, 0 }, // FiberRange
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->ShowInLocalSpace), NULL, 0 }, // ShowInLocalSpace
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->GlobalPose), NULL, 0 }, // GlobalPose
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->RecomputeSubmeshes), NULL, 0 }, // RecomputeSubmeshes
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->RecomputeVertices), NULL, 0 }, // RecomputeVertices
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->PhysicsMeshIndices), NULL, 0 }, // PhysicsMeshIndices
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->MassScale), NULL, 0 }, // MassScale
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->SelfCollision), NULL, 0 }, // SelfCollision
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->SelfCollisionWire), NULL, 0 }, // SelfCollisionWire
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->SelfCollisionAttenuation), NULL, 0 }, // SelfCollisionAttenuation
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->SolverMode), NULL, 0 }, // SolverMode
+};
+
+
+bool ClothingDebugRenderParams::mBuiltFlag = false;
+NvParameterized::MutexType ClothingDebugRenderParams::mBuiltFlagMutex;
+
+ClothingDebugRenderParams::ClothingDebugRenderParams(NvParameterized::Traits* traits, void* buf, int32_t* refCount) :
+ NvParameters(traits, buf, refCount)
+{
+ //mParameterizedTraits->registerFactory(className(), &ClothingDebugRenderParamsFactoryInst);
+
+ if (!buf) //Do not init data if it is inplace-deserialized
+ {
+ initDynamicArrays();
+ initStrings();
+ initReferences();
+ initDefaults();
+ }
+}
+
+ClothingDebugRenderParams::~ClothingDebugRenderParams()
+{
+ freeStrings();
+ freeReferences();
+ freeDynamicArrays();
+}
+
+void ClothingDebugRenderParams::destroy()
+{
+ // We cache these fields here to avoid overwrite in destructor
+ bool doDeallocateSelf = mDoDeallocateSelf;
+ NvParameterized::Traits* traits = mParameterizedTraits;
+ int32_t* refCount = mRefCount;
+ void* buf = mBuffer;
+
+ this->~ClothingDebugRenderParams();
+
+ NvParameters::destroy(this, traits, doDeallocateSelf, refCount, buf);
+}
+
+const NvParameterized::DefinitionImpl* ClothingDebugRenderParams::getParameterDefinitionTree(void)
+{
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+ if (!mBuiltFlag)
+ {
+ buildTree();
+ }
+ }
+
+ return(&ParamDefTable[0]);
+}
+
+const NvParameterized::DefinitionImpl* ClothingDebugRenderParams::getParameterDefinitionTree(void) const
+{
+ ClothingDebugRenderParams* tmpParam = const_cast<ClothingDebugRenderParams*>(this);
+
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+ if (!mBuiltFlag)
+ {
+ tmpParam->buildTree();
+ }
+ }
+
+ return(&ParamDefTable[0]);
+}
+
+NvParameterized::ErrorType ClothingDebugRenderParams::getParameterHandle(const char* long_name, Handle& handle) const
+{
+ ErrorType Ret = NvParameters::getParameterHandle(long_name, handle);
+ if (Ret != ERROR_NONE)
+ {
+ return(Ret);
+ }
+
+ size_t offset;
+ void* ptr;
+
+ getVarPtr(handle, ptr, offset);
+
+ if (ptr == NULL)
+ {
+ return(ERROR_INDEX_OUT_OF_RANGE);
+ }
+
+ return(ERROR_NONE);
+}
+
+NvParameterized::ErrorType ClothingDebugRenderParams::getParameterHandle(const char* long_name, Handle& handle)
+{
+ ErrorType Ret = NvParameters::getParameterHandle(long_name, handle);
+ if (Ret != ERROR_NONE)
+ {
+ return(Ret);
+ }
+
+ size_t offset;
+ void* ptr;
+
+ getVarPtr(handle, ptr, offset);
+
+ if (ptr == NULL)
+ {
+ return(ERROR_INDEX_OUT_OF_RANGE);
+ }
+
+ return(ERROR_NONE);
+}
+
+void ClothingDebugRenderParams::getVarPtr(const Handle& handle, void*& ptr, size_t& offset) const
+{
+ ptr = getVarPtrHelper(&ParamLookupTable[0], const_cast<ClothingDebugRenderParams::ParametersStruct*>(&parameters()), handle, offset);
+}
+
+
+/* Dynamic Handle Indices */
+
+void ClothingDebugRenderParams::freeParameterDefinitionTable(NvParameterized::Traits* traits)
+{
+ if (!traits)
+ {
+ return;
+ }
+
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ return;
+ }
+
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+
+ if (!mBuiltFlag)
+ {
+ return;
+ }
+
+ for (uint32_t i = 0; i < NumParamDefs; ++i)
+ {
+ ParamDefTable[i].~DefinitionImpl();
+ }
+
+ traits->free(ParamDefTable);
+
+ mBuiltFlag = false;
+}
+
+#define PDEF_PTR(index) (&ParamDefTable[index])
+
+void ClothingDebugRenderParams::buildTree(void)
+{
+
+ uint32_t allocSize = sizeof(NvParameterized::DefinitionImpl) * NumParamDefs;
+ ParamDefTable = (NvParameterized::DefinitionImpl*)(mParameterizedTraits->alloc(allocSize));
+ memset(ParamDefTable, 0, allocSize);
+
+ for (uint32_t i = 0; i < NumParamDefs; ++i)
+ {
+ NV_PARAM_PLACEMENT_NEW(ParamDefTable + i, NvParameterized::DefinitionImpl)(*mParameterizedTraits);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=0, longName=""
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[0];
+ ParamDef->init("", TYPE_STRUCT, "STRUCT", true);
+
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=1, longName="Actors"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[1];
+ ParamDef->init("Actors", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Enables/Disables visualization of all clothing actors", true);
+ ParamDefTable[1].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=2, longName="SkinnedPositions"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[2];
+ ParamDef->init("SkinnedPositions", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Marks each animation position with a small cross as the centers of the spheres in which the simulated vertices are allowed to move. Blue for static vertices, black to white for increasing max distance.", true);
+ ParamDefTable[2].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=3, longName="Backstop"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[3];
+ ParamDef->init("Backstop", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The part of the mesh with backstop is solidly rendered. Red for front faces, blue for back faces.", true);
+ ParamDefTable[3].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=4, longName="BackstopPrecise"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[4];
+ ParamDef->init("BackstopPrecise", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Draws small segments of the backstop sphere for each simulation vertex. (scalable)", true);
+ ParamDefTable[4].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=5, longName="MaxDistance"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[5];
+ ParamDef->init("MaxDistance", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Draws a line from the skinned position along the skinned normal with the length of the max distance this vertex is allowed to move. Note that the LoD mechanism can scale down the Max Distance of the asset.", true);
+ ParamDefTable[5].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=6, longName="MaxDistanceInwards"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[6];
+ ParamDef->init("MaxDistanceInwards", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Same as MaxDistance but to the other side. Bounded by backstop. The length of the line is either Max Distance or sphere collision distance, depending on which is smaller and restricts the motion of the vertex.", true);
+ ParamDefTable[6].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=7, longName="SkinMapAll"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[7];
+ ParamDef->init("SkinMapAll", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Draws the full support mesh for mesh-mesh skinning.", true);
+ ParamDefTable[7].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=8, longName="SkinMapBad"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[8];
+ ParamDef->init("SkinMapBad", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Draws the support mesh for mesh-mesh skinning. But only for vertices that actually lie outside of the support mesh and could cause problems", true);
+ ParamDefTable[8].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=9, longName="SkinMapActual"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[9];
+ ParamDef->init("SkinMapActual", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Draws the actual support mesh for mesh-mesh skinning (only the parts that are effectively used).", true);
+ ParamDefTable[9].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=10, longName="SkinMapInvalidBary"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[10];
+ ParamDef->init("SkinMapInvalidBary", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Draws physical triangles and corresponding graphical vertices that have invalid barycentric coordinates in the mesh skinning map. Red: invalid position bary. Purple: invalid normal bary. Blue: invalid tangent bary.", true);
+ ParamDefTable[10].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=11, longName="PhysicsMeshWire"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[11];
+ ParamDef->init("PhysicsMeshWire", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ ParamDefTable[11].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ HintTable[2].init("shortDescription", "Draws the simulation mesh, only the active region. From yellow to red, the closer a vertex gets to its max distance. (scalable)", true);
+ ParamDefTable[11].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=12, longName="PhysicsMeshSolid"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[12];
+ ParamDef->init("PhysicsMeshSolid", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ ParamDefTable[12].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ HintTable[2].init("shortDescription", "Same as PhysicsMeshWire but with solid triangles.", true);
+ ParamDefTable[12].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=13, longName="PhysicsMeshNormals"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[13];
+ ParamDef->init("PhysicsMeshNormals", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Displays the normals of the physics mesh (base for mesh-mesh skinning).", true);
+ ParamDefTable[13].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=14, longName="Skeleton"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[14];
+ ParamDef->init("Skeleton", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Draws lines from parent to child bones. Active bones are displayed in purple, passive in blue. Only the subset of bones that have a vertex from any of the meshes or a collision volume bound to them will be visible.", true);
+ ParamDefTable[14].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=15, longName="BoneFrames"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[15];
+ ParamDef->init("BoneFrames", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Draws the frame of each bone. (scalable)", true);
+ ParamDefTable[15].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=16, longName="BoneNames"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[16];
+ ParamDef->init("BoneNames", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Displays the name of each bone. (scalable)", true);
+ ParamDefTable[16].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=17, longName="Velocities"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[17];
+ ParamDef->init("Velocities", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Draws lines for each simulated vertex' velocity. (scalable)", true);
+ ParamDefTable[17].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=18, longName="Wind"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[18];
+ ParamDef->init("Wind", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Draws lines for each simulated vertex' velocity change due to wind, velocity callback or pressure. (scalable)", true);
+ ParamDefTable[18].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=19, longName="GraphicalVertexBones"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[19];
+ ParamDef->init("GraphicalVertexBones", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Draws colored lines from each graphical vertex to the bones it uses for skinning. White to black for decreasing weights.", true);
+ ParamDefTable[19].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=20, longName="PhysicalVertexBones"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[20];
+ ParamDef->init("PhysicalVertexBones", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Draws colored lines from each simulation vertex to the bones it uses for skinning. White to black for decreasing weights.", true);
+ ParamDefTable[20].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=21, longName="CollisionShapes"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[21];
+ ParamDef->init("CollisionShapes", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Draws solid capsules and spheres for the collision shapes.", true);
+ ParamDefTable[21].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=22, longName="CollisionShapesWire"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[22];
+ ParamDef->init("CollisionShapesWire", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Draws wire capsules and spheres for the collision shapes.", true);
+ ParamDefTable[22].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=23, longName="LengthFibers"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[23];
+ ParamDef->init("LengthFibers", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Show the vertical stretching fibers.", true);
+ ParamDefTable[23].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=24, longName="CrossSectionFibers"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[24];
+ ParamDef->init("CrossSectionFibers", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Show the horizontal stretching fibers.", true);
+ ParamDefTable[24].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=25, longName="BendingFibers"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[25];
+ ParamDef->init("BendingFibers", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Show the bending fibers.", true);
+ ParamDefTable[25].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=26, longName="ShearingFibers"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[26];
+ ParamDef->init("ShearingFibers", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Show the shearing fibers.", true);
+ ParamDefTable[26].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=27, longName="ZerostretchFibers"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[27];
+ ParamDef->init("ZerostretchFibers", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Show the zero-stretch phases.", true);
+ ParamDefTable[27].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=28, longName="TethersActive"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[28];
+ ParamDef->init("TethersActive", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Show the tether constraitns, only active ones (0.99 their length and longer).", true);
+ ParamDefTable[28].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=29, longName="TethersInactive"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[29];
+ ParamDef->init("TethersInactive", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Show the tether constraints, only inactive ones (less than 0.99 their length).", true);
+ ParamDefTable[29].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=30, longName="VirtualCollision"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[30];
+ ParamDef->init("VirtualCollision", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Show the virtual particles. Each has 3 lines to the vertices it connects to.", true);
+ ParamDefTable[30].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=31, longName="FiberRange"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[31];
+ ParamDef->init("FiberRange", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Combined with fiber debug rendering this visualizes the range where the stiffness of the chosen fiber type is scaled down. It shows how much the cloth is allowed to compress/stretch.", true);
+ ParamDefTable[31].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=32, longName="ShowInLocalSpace"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[32];
+ ParamDef->init("ShowInLocalSpace", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Enables/Disables debug rendering in local space (experts only!)", true);
+ ParamDefTable[32].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=33, longName="GlobalPose"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[33];
+ ParamDef->init("GlobalPose", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Shows the internally stored global pose transform", true);
+ ParamDefTable[33].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=34, longName="RecomputeSubmeshes"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[34];
+ ParamDef->init("RecomputeSubmeshes", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Shows the internal reordering of the render mesh asset into physical submeshes and non-simulated parts in shades of gray. This is used to split the cpu skinned part from the skinned part that is skinned the physics mesh.", true);
+ ParamDefTable[34].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=35, longName="RecomputeVertices"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[35];
+ ParamDef->init("RecomputeVertices", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Shows the position of the reordered render vertices that are being skinned to the physics mesh. Vertices attached to simulated triangles are rendered orange. Additional vertices along the border are rendered purple, they are needed to prevent visible seams from normal and tangent calculations.", true);
+ ParamDefTable[35].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=36, longName="PhysicsMeshIndices"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[36];
+ ParamDef->init("PhysicsMeshIndices", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Shows the indices of the physics mesh", true);
+ ParamDefTable[36].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=37, longName="MassScale"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[37];
+ ParamDef->init("MassScale", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Shows red crosses for particles where the mass is scaled for collision purpose", true);
+ ParamDefTable[37].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=38, longName="SelfCollision"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[38];
+ ParamDef->init("SelfCollision", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Shows spheres that represent the self collision thickness", true);
+ ParamDefTable[38].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=39, longName="SelfCollisionWire"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[39];
+ ParamDef->init("SelfCollisionWire", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Shows spheres that represent the self collision thickness", true);
+ ParamDefTable[39].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=40, longName="SelfCollisionAttenuation"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[40];
+ ParamDef->init("SelfCollisionAttenuation", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "All connections are drawn that have an attenuation smaller than the given value.\n0.0f disables the visualization, 1.0f shows all attenuated pairs.\n", true);
+ HintTable[1].init("shortDescription", "Draws a line between vertices where selfcollision is reduced or turned off.", true);
+ ParamDefTable[40].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=41, longName="SolverMode"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[41];
+ ParamDef->init("SolverMode", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "Shared: Fastest path. It means previous and current positions fit onto shared memory on the GPU.\nMixed: Only slightly slower than Shared. Current positions fit onto shared memory, previous positions need to be streamed in.\nGlobal: Significantly slower than Shared and Mixed. All data is read from global GPU memory. Try to reduce the vertex count and/or split up the asset.\n", true);
+ HintTable[1].init("shortDescription", "Displays which solver is used (2.x or 3.x), wether it runs on GPU, and if the simulation data fits into shared memory.", true);
+ ParamDefTable[41].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // SetChildren for: nodeIndex=0, longName=""
+ {
+ static Definition* Children[41];
+ Children[0] = PDEF_PTR(1);
+ Children[1] = PDEF_PTR(2);
+ Children[2] = PDEF_PTR(3);
+ Children[3] = PDEF_PTR(4);
+ Children[4] = PDEF_PTR(5);
+ Children[5] = PDEF_PTR(6);
+ Children[6] = PDEF_PTR(7);
+ Children[7] = PDEF_PTR(8);
+ Children[8] = PDEF_PTR(9);
+ Children[9] = PDEF_PTR(10);
+ Children[10] = PDEF_PTR(11);
+ Children[11] = PDEF_PTR(12);
+ Children[12] = PDEF_PTR(13);
+ Children[13] = PDEF_PTR(14);
+ Children[14] = PDEF_PTR(15);
+ Children[15] = PDEF_PTR(16);
+ Children[16] = PDEF_PTR(17);
+ Children[17] = PDEF_PTR(18);
+ Children[18] = PDEF_PTR(19);
+ Children[19] = PDEF_PTR(20);
+ Children[20] = PDEF_PTR(21);
+ Children[21] = PDEF_PTR(22);
+ Children[22] = PDEF_PTR(23);
+ Children[23] = PDEF_PTR(24);
+ Children[24] = PDEF_PTR(25);
+ Children[25] = PDEF_PTR(26);
+ Children[26] = PDEF_PTR(27);
+ Children[27] = PDEF_PTR(28);
+ Children[28] = PDEF_PTR(29);
+ Children[29] = PDEF_PTR(30);
+ Children[30] = PDEF_PTR(31);
+ Children[31] = PDEF_PTR(32);
+ Children[32] = PDEF_PTR(33);
+ Children[33] = PDEF_PTR(34);
+ Children[34] = PDEF_PTR(35);
+ Children[35] = PDEF_PTR(36);
+ Children[36] = PDEF_PTR(37);
+ Children[37] = PDEF_PTR(38);
+ Children[38] = PDEF_PTR(39);
+ Children[39] = PDEF_PTR(40);
+ Children[40] = PDEF_PTR(41);
+
+ ParamDefTable[0].setChildren(Children, 41);
+ }
+
+ mBuiltFlag = true;
+
+}
+void ClothingDebugRenderParams::initStrings(void)
+{
+}
+
+void ClothingDebugRenderParams::initDynamicArrays(void)
+{
+}
+
+void ClothingDebugRenderParams::initDefaults(void)
+{
+
+ freeStrings();
+ freeReferences();
+ freeDynamicArrays();
+ Actors = bool(true);
+ SkinnedPositions = float(0);
+ Backstop = bool(false);
+ BackstopPrecise = float(0);
+ MaxDistance = bool(0);
+ MaxDistanceInwards = bool(0);
+ SkinMapAll = bool(0);
+ SkinMapBad = bool(0);
+ SkinMapActual = bool(0);
+ SkinMapInvalidBary = bool(0);
+ PhysicsMeshWire = float(0);
+ PhysicsMeshSolid = float(0);
+ PhysicsMeshNormals = float(0);
+ Skeleton = bool(0);
+ BoneFrames = float(0);
+ BoneNames = float(0);
+ Velocities = float(0);
+ Wind = float(0);
+ GraphicalVertexBones = bool(0);
+ PhysicalVertexBones = bool(0);
+ CollisionShapes = bool(false);
+ CollisionShapesWire = bool(false);
+ LengthFibers = bool(false);
+ CrossSectionFibers = bool(false);
+ BendingFibers = bool(false);
+ ShearingFibers = bool(false);
+ ZerostretchFibers = bool(false);
+ TethersActive = bool(false);
+ TethersInactive = bool(false);
+ VirtualCollision = bool(false);
+ FiberRange = bool(false);
+ ShowInLocalSpace = bool(false);
+ GlobalPose = bool(false);
+ RecomputeSubmeshes = bool(false);
+ RecomputeVertices = bool(false);
+ PhysicsMeshIndices = bool(false);
+ MassScale = bool(false);
+ SelfCollision = bool(false);
+ SelfCollisionWire = bool(false);
+ SelfCollisionAttenuation = float(false);
+ SolverMode = bool(false);
+
+ initDynamicArrays();
+ initStrings();
+ initReferences();
+}
+
+void ClothingDebugRenderParams::initReferences(void)
+{
+}
+
+void ClothingDebugRenderParams::freeDynamicArrays(void)
+{
+}
+
+void ClothingDebugRenderParams::freeStrings(void)
+{
+}
+
+void ClothingDebugRenderParams::freeReferences(void)
+{
+}
+
+} // namespace clothing
+} // namespace nvidia
diff --git a/APEX_1.4/module/clothing/src/autogen/ClothingGraphicalLodParameters.cpp b/APEX_1.4/module/clothing/src/autogen/ClothingGraphicalLodParameters.cpp
new file mode 100644
index 00000000..59293e7c
--- /dev/null
+++ b/APEX_1.4/module/clothing/src/autogen/ClothingGraphicalLodParameters.cpp
@@ -0,0 +1,1491 @@
+// 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) 2008-2015 NVIDIA Corporation. All rights reserved.
+
+// This file was generated by NvParameterized/scripts/GenParameterized.pl
+
+
+#include "ClothingGraphicalLodParameters.h"
+#include <string.h>
+#include <stdlib.h>
+
+using namespace NvParameterized;
+
+namespace nvidia
+{
+namespace clothing
+{
+
+using namespace ClothingGraphicalLodParametersNS;
+
+const char* const ClothingGraphicalLodParametersFactory::vptr =
+ NvParameterized::getVptr<ClothingGraphicalLodParameters, ClothingGraphicalLodParameters::ClassAlignment>();
+
+const uint32_t NumParamDefs = 41;
+static NvParameterized::DefinitionImpl* ParamDefTable; // now allocated in buildTree [NumParamDefs];
+
+
+static const size_t ParamLookupChildrenTable[] =
+{
+ 1, 3, 4, 5, 6, 7, 9, 17, 26, 27, 28, 34, 35, 2, 8, 10, 11, 12, 13, 14, 15, 16, 18,
+ 19, 20, 21, 22, 23, 24, 25, 29, 30, 31, 32, 33, 36, 37, 38, 39, 40,
+};
+
+#define TENUM(type) nvidia::##type
+#define CHILDREN(index) &ParamLookupChildrenTable[index]
+static const NvParameterized::ParamLookupNode ParamLookupTable[NumParamDefs] =
+{
+ { TYPE_STRUCT, false, 0, CHILDREN(0), 13 },
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->platforms), CHILDREN(13), 1 }, // platforms
+ { TYPE_STRING, false, 1 * sizeof(NvParameterized::DummyStringStruct), NULL, 0 }, // platforms[]
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->lod), NULL, 0 }, // lod
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->physicalMeshId), NULL, 0 }, // physicalMeshId
+ { TYPE_REF, false, (size_t)(&((ParametersStruct*)0)->renderMeshAsset), NULL, 0 }, // renderMeshAsset
+ { TYPE_POINTER, false, (size_t)(&((ParametersStruct*)0)->renderMeshAssetPointer), NULL, 0 }, // renderMeshAssetPointer
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->immediateClothMap), CHILDREN(14), 1 }, // immediateClothMap
+ { TYPE_U32, false, 1 * sizeof(uint32_t), NULL, 0 }, // immediateClothMap[]
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->skinClothMapB), CHILDREN(15), 1 }, // skinClothMapB
+ { TYPE_STRUCT, false, 1 * sizeof(SkinClothMapB_Type), CHILDREN(16), 6 }, // skinClothMapB[]
+ { TYPE_VEC3, false, (size_t)(&((SkinClothMapB_Type*)0)->vtxTetraBary), NULL, 0 }, // skinClothMapB[].vtxTetraBary
+ { TYPE_U32, false, (size_t)(&((SkinClothMapB_Type*)0)->vertexIndexPlusOffset), NULL, 0 }, // skinClothMapB[].vertexIndexPlusOffset
+ { TYPE_VEC3, false, (size_t)(&((SkinClothMapB_Type*)0)->nrmTetraBary), NULL, 0 }, // skinClothMapB[].nrmTetraBary
+ { TYPE_U32, false, (size_t)(&((SkinClothMapB_Type*)0)->faceIndex0), NULL, 0 }, // skinClothMapB[].faceIndex0
+ { TYPE_U32, false, (size_t)(&((SkinClothMapB_Type*)0)->tetraIndex), NULL, 0 }, // skinClothMapB[].tetraIndex
+ { TYPE_U32, false, (size_t)(&((SkinClothMapB_Type*)0)->submeshIndex), NULL, 0 }, // skinClothMapB[].submeshIndex
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->skinClothMap), CHILDREN(22), 1 }, // skinClothMap
+ { TYPE_STRUCT, false, 1 * sizeof(SkinClothMapD_Type), CHILDREN(23), 7 }, // skinClothMap[]
+ { TYPE_VEC3, false, (size_t)(&((SkinClothMapD_Type*)0)->vertexBary), NULL, 0 }, // skinClothMap[].vertexBary
+ { TYPE_U32, false, (size_t)(&((SkinClothMapD_Type*)0)->vertexIndex0), NULL, 0 }, // skinClothMap[].vertexIndex0
+ { TYPE_VEC3, false, (size_t)(&((SkinClothMapD_Type*)0)->normalBary), NULL, 0 }, // skinClothMap[].normalBary
+ { TYPE_U32, false, (size_t)(&((SkinClothMapD_Type*)0)->vertexIndex1), NULL, 0 }, // skinClothMap[].vertexIndex1
+ { TYPE_VEC3, false, (size_t)(&((SkinClothMapD_Type*)0)->tangentBary), NULL, 0 }, // skinClothMap[].tangentBary
+ { TYPE_U32, false, (size_t)(&((SkinClothMapD_Type*)0)->vertexIndex2), NULL, 0 }, // skinClothMap[].vertexIndex2
+ { TYPE_U32, false, (size_t)(&((SkinClothMapD_Type*)0)->vertexIndexPlusOffset), NULL, 0 }, // skinClothMap[].vertexIndexPlusOffset
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->skinClothMapThickness), NULL, 0 }, // skinClothMapThickness
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->skinClothMapOffset), NULL, 0 }, // skinClothMapOffset
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->tetraMap), CHILDREN(30), 1 }, // tetraMap
+ { TYPE_STRUCT, false, 1 * sizeof(TetraLink_Type), CHILDREN(31), 4 }, // tetraMap[]
+ { TYPE_VEC3, false, (size_t)(&((TetraLink_Type*)0)->vertexBary), NULL, 0 }, // tetraMap[].vertexBary
+ { TYPE_U32, false, (size_t)(&((TetraLink_Type*)0)->tetraIndex0), NULL, 0 }, // tetraMap[].tetraIndex0
+ { TYPE_VEC3, false, (size_t)(&((TetraLink_Type*)0)->normalBary), NULL, 0 }, // tetraMap[].normalBary
+ { TYPE_U32, false, (size_t)(&((TetraLink_Type*)0)->_dummyForAlignment), NULL, 0 }, // tetraMap[]._dummyForAlignment
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->renderMeshAssetSorting), NULL, 0 }, // renderMeshAssetSorting
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->physicsMeshPartitioning), CHILDREN(35), 1 }, // physicsMeshPartitioning
+ { TYPE_STRUCT, false, 1 * sizeof(PhysicsMeshPartitioning_Type), CHILDREN(36), 4 }, // physicsMeshPartitioning[]
+ { TYPE_U32, false, (size_t)(&((PhysicsMeshPartitioning_Type*)0)->graphicalSubmesh), NULL, 0 }, // physicsMeshPartitioning[].graphicalSubmesh
+ { TYPE_U32, false, (size_t)(&((PhysicsMeshPartitioning_Type*)0)->numSimulatedVertices), NULL, 0 }, // physicsMeshPartitioning[].numSimulatedVertices
+ { TYPE_U32, false, (size_t)(&((PhysicsMeshPartitioning_Type*)0)->numSimulatedVerticesAdditional), NULL, 0 }, // physicsMeshPartitioning[].numSimulatedVerticesAdditional
+ { TYPE_U32, false, (size_t)(&((PhysicsMeshPartitioning_Type*)0)->numSimulatedIndices), NULL, 0 }, // physicsMeshPartitioning[].numSimulatedIndices
+};
+
+
+bool ClothingGraphicalLodParameters::mBuiltFlag = false;
+NvParameterized::MutexType ClothingGraphicalLodParameters::mBuiltFlagMutex;
+
+ClothingGraphicalLodParameters::ClothingGraphicalLodParameters(NvParameterized::Traits* traits, void* buf, int32_t* refCount) :
+ NvParameters(traits, buf, refCount)
+{
+ //mParameterizedTraits->registerFactory(className(), &ClothingGraphicalLodParametersFactoryInst);
+
+ if (!buf) //Do not init data if it is inplace-deserialized
+ {
+ initDynamicArrays();
+ initStrings();
+ initReferences();
+ initDefaults();
+ }
+}
+
+ClothingGraphicalLodParameters::~ClothingGraphicalLodParameters()
+{
+ freeStrings();
+ freeReferences();
+ freeDynamicArrays();
+}
+
+void ClothingGraphicalLodParameters::destroy()
+{
+ // We cache these fields here to avoid overwrite in destructor
+ bool doDeallocateSelf = mDoDeallocateSelf;
+ NvParameterized::Traits* traits = mParameterizedTraits;
+ int32_t* refCount = mRefCount;
+ void* buf = mBuffer;
+
+ this->~ClothingGraphicalLodParameters();
+
+ NvParameters::destroy(this, traits, doDeallocateSelf, refCount, buf);
+}
+
+const NvParameterized::DefinitionImpl* ClothingGraphicalLodParameters::getParameterDefinitionTree(void)
+{
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+ if (!mBuiltFlag)
+ {
+ buildTree();
+ }
+ }
+
+ return(&ParamDefTable[0]);
+}
+
+const NvParameterized::DefinitionImpl* ClothingGraphicalLodParameters::getParameterDefinitionTree(void) const
+{
+ ClothingGraphicalLodParameters* tmpParam = const_cast<ClothingGraphicalLodParameters*>(this);
+
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+ if (!mBuiltFlag)
+ {
+ tmpParam->buildTree();
+ }
+ }
+
+ return(&ParamDefTable[0]);
+}
+
+NvParameterized::ErrorType ClothingGraphicalLodParameters::getParameterHandle(const char* long_name, Handle& handle) const
+{
+ ErrorType Ret = NvParameters::getParameterHandle(long_name, handle);
+ if (Ret != ERROR_NONE)
+ {
+ return(Ret);
+ }
+
+ size_t offset;
+ void* ptr;
+
+ getVarPtr(handle, ptr, offset);
+
+ if (ptr == NULL)
+ {
+ return(ERROR_INDEX_OUT_OF_RANGE);
+ }
+
+ return(ERROR_NONE);
+}
+
+NvParameterized::ErrorType ClothingGraphicalLodParameters::getParameterHandle(const char* long_name, Handle& handle)
+{
+ ErrorType Ret = NvParameters::getParameterHandle(long_name, handle);
+ if (Ret != ERROR_NONE)
+ {
+ return(Ret);
+ }
+
+ size_t offset;
+ void* ptr;
+
+ getVarPtr(handle, ptr, offset);
+
+ if (ptr == NULL)
+ {
+ return(ERROR_INDEX_OUT_OF_RANGE);
+ }
+
+ return(ERROR_NONE);
+}
+
+void ClothingGraphicalLodParameters::getVarPtr(const Handle& handle, void*& ptr, size_t& offset) const
+{
+ ptr = getVarPtrHelper(&ParamLookupTable[0], const_cast<ClothingGraphicalLodParameters::ParametersStruct*>(&parameters()), handle, offset);
+}
+
+
+/* Dynamic Handle Indices */
+/* [0] - platforms (not an array of structs) */
+
+void ClothingGraphicalLodParameters::freeParameterDefinitionTable(NvParameterized::Traits* traits)
+{
+ if (!traits)
+ {
+ return;
+ }
+
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ return;
+ }
+
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+
+ if (!mBuiltFlag)
+ {
+ return;
+ }
+
+ for (uint32_t i = 0; i < NumParamDefs; ++i)
+ {
+ ParamDefTable[i].~DefinitionImpl();
+ }
+
+ traits->free(ParamDefTable);
+
+ mBuiltFlag = false;
+}
+
+#define PDEF_PTR(index) (&ParamDefTable[index])
+
+void ClothingGraphicalLodParameters::buildTree(void)
+{
+
+ uint32_t allocSize = sizeof(NvParameterized::DefinitionImpl) * NumParamDefs;
+ ParamDefTable = (NvParameterized::DefinitionImpl*)(mParameterizedTraits->alloc(allocSize));
+ memset(ParamDefTable, 0, allocSize);
+
+ for (uint32_t i = 0; i < NumParamDefs; ++i)
+ {
+ NV_PARAM_PLACEMENT_NEW(ParamDefTable + i, NvParameterized::DefinitionImpl)(*mParameterizedTraits);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=0, longName=""
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[0];
+ ParamDef->init("", TYPE_STRUCT, "STRUCT", true);
+
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=1, longName="platforms"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[1];
+ ParamDef->init("platforms", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "The assets can be prepared for different platforms. This string specifies for which\nplatforms this LOD is kept in the asset.\n", true);
+ HintTable[1].init("shortDescription", "Platforms on this lod is used.", true);
+ ParamDefTable[1].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ static const uint8_t dynHandleIndices[1] = { 0, };
+ ParamDef->setDynamicHandleIndicesMap(dynHandleIndices, 1);
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=2, longName="platforms[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[2];
+ ParamDef->init("platforms", TYPE_STRING, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "The assets can be prepared for different platforms. This string specifies for which\nplatforms this LOD is kept in the asset.\n", true);
+ HintTable[1].init("shortDescription", "Platforms on this lod is used.", true);
+ ParamDefTable[2].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=3, longName="lod"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[3];
+ ParamDef->init("lod", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "Even for a small number of LoDs, the LoD value does not have to be continuous. An Asset\ncan have 3 LoDs at leve 0, 3 and 6.\n", true);
+ HintTable[1].init("shortDescription", "The actual LoD value", true);
+ ParamDefTable[3].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=4, longName="physicalMeshId"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[4];
+ ParamDef->init("physicalMeshId", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "This indexes a physical mesh from the physicalMesh Array in the ClothingAsset. Different\ngraphical LoDs can share a physical mesh.\n", true);
+ HintTable[1].init("shortDescription", "Index of the physical mesh used for this graphical mesh.", true);
+ ParamDefTable[4].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=5, longName="renderMeshAsset"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[5];
+ ParamDef->init("renderMeshAsset", TYPE_REF, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("INCLUDED", uint64_t(1), true);
+ ParamDefTable[5].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("INCLUDED", uint64_t(1), true);
+ HintTable[1].init("longDescription", "Each LoD must have a unique render mesh asset.\n", true);
+ HintTable[2].init("shortDescription", "The render mesh asset used for this LoD level", true);
+ ParamDefTable[5].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+ static const char* const RefVariantVals[] = { "RenderMeshAssetParameters" };
+ ParamDefTable[5].setRefVariantVals((const char**)RefVariantVals, 1);
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=6, longName="renderMeshAssetPointer"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[6];
+ ParamDef->init("renderMeshAssetPointer", TYPE_POINTER, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("DONOTSERIALIZE", uint64_t(1), true);
+ HintTable[1].init("TYPE", "NiApexRenderMeshAsset", true);
+ ParamDefTable[6].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("DONOTSERIALIZE", uint64_t(1), true);
+ HintTable[1].init("TYPE", "NiApexRenderMeshAsset", true);
+ HintTable[2].init("shortDescription", "Render mesh asset pointer", true);
+ ParamDefTable[6].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=7, longName="immediateClothMap"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[7];
+ ParamDef->init("immediateClothMap", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ ParamDefTable[7].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ HintTable[1].init("longDescription", "If some vertices can not be mapped properly, they will use the skinClothMapB to tie to the physical mesh.\n", true);
+ HintTable[2].init("shortDescription", "Directly map some of the physically simulated vertices on the graphical mesh", true);
+ ParamDefTable[7].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=8, longName="immediateClothMap[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[8];
+ ParamDef->init("immediateClothMap", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ ParamDefTable[8].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ HintTable[1].init("longDescription", "If some vertices can not be mapped properly, they will use the skinClothMapB to tie to the physical mesh.\n", true);
+ HintTable[2].init("shortDescription", "Directly map some of the physically simulated vertices on the graphical mesh", true);
+ ParamDefTable[8].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=9, longName="skinClothMapB"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[9];
+ ParamDef->init("skinClothMapB", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ ParamDefTable[9].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ HintTable[1].init("longDescription", "Usually maps only a subset of all vertices to the physical mesh. The others can be done through the immediateClothMap.\n", true);
+ HintTable[2].init("shortDescription", "Map each graphical vertex onto a physically simulated triangle through barycentric coordinates and implicit tetrahedrons.", true);
+ ParamDefTable[9].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=10, longName="skinClothMapB[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[10];
+ ParamDef->init("skinClothMapB", TYPE_STRUCT, "SkinClothMapB", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ ParamDefTable[10].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ HintTable[1].init("longDescription", "Usually maps only a subset of all vertices to the physical mesh. The others can be done through the immediateClothMap.\n", true);
+ HintTable[2].init("shortDescription", "Map each graphical vertex onto a physically simulated triangle through barycentric coordinates and implicit tetrahedrons.", true);
+ ParamDefTable[10].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=11, longName="skinClothMapB[].vtxTetraBary"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[11];
+ ParamDef->init("vtxTetraBary", TYPE_VEC3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The barycentric coordinate into the implicit tetrahedron.", true);
+ ParamDefTable[11].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=12, longName="skinClothMapB[].vertexIndexPlusOffset"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[12];
+ ParamDef->init("vertexIndexPlusOffset", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The vertex index in the graphical mesh (the target index).", true);
+ ParamDefTable[12].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=13, longName="skinClothMapB[].nrmTetraBary"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[13];
+ ParamDef->init("nrmTetraBary", TYPE_VEC3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The barycentric coordinate of (vertex+normal). When vertex is subtracted this will result in the normal again.", true);
+ ParamDefTable[13].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=14, longName="skinClothMapB[].faceIndex0"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[14];
+ ParamDef->init("faceIndex0", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "First index of the 3 consecutive indices making the physical triangle.", true);
+ ParamDefTable[14].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=15, longName="skinClothMapB[].tetraIndex"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[15];
+ ParamDef->init("tetraIndex", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Selects which of the 6 implicit tetrahedrons is used for the mapping.", true);
+ ParamDefTable[15].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=16, longName="skinClothMapB[].submeshIndex"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[16];
+ ParamDef->init("submeshIndex", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("DONOTSERIALIZE", uint64_t(1), true);
+ ParamDefTable[16].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("DONOTSERIALIZE", uint64_t(1), true);
+ HintTable[1].init("longDescription", "This is only needed during the authoring stage and thus does not need to be serialized.", true);
+ HintTable[2].init("shortDescription", "Index into which Physical Submesh/LoD this element of the mapping belongs to.", true);
+ ParamDefTable[16].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=17, longName="skinClothMap"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[17];
+ ParamDef->init("skinClothMap", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ ParamDefTable[17].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ HintTable[1].init("longDescription", "Usually maps only a subset of all vertices to the physical mesh. The others can be done through the immediateClothMap.\n", true);
+ HintTable[2].init("shortDescription", "Map each graphical vertex onto a physically simulated triangle through barycentric coordinates.", true);
+ ParamDefTable[17].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=18, longName="skinClothMap[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[18];
+ ParamDef->init("skinClothMap", TYPE_STRUCT, "SkinClothMapD", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ ParamDefTable[18].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ HintTable[1].init("longDescription", "Usually maps only a subset of all vertices to the physical mesh. The others can be done through the immediateClothMap.\n", true);
+ HintTable[2].init("shortDescription", "Map each graphical vertex onto a physically simulated triangle through barycentric coordinates.", true);
+ ParamDefTable[18].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=19, longName="skinClothMap[].vertexBary"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[19];
+ ParamDef->init("vertexBary", TYPE_VEC3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The barycentric coordinate into the triangle.", true);
+ ParamDefTable[19].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=20, longName="skinClothMap[].vertexIndex0"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[20];
+ ParamDef->init("vertexIndex0", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Vertex index of the physics triangle.", true);
+ ParamDefTable[20].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=21, longName="skinClothMap[].normalBary"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[21];
+ ParamDef->init("normalBary", TYPE_VEC3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The barycentric coordinate of (vertex+normal). When vertex is subtracted this will result in the normal again.", true);
+ ParamDefTable[21].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=22, longName="skinClothMap[].vertexIndex1"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[22];
+ ParamDef->init("vertexIndex1", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Vertex index of the physics triangle.", true);
+ ParamDefTable[22].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=23, longName="skinClothMap[].tangentBary"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[23];
+ ParamDef->init("tangentBary", TYPE_VEC3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The barycentric coordinate of (position+tangent). When position is subtracted this will result in the tangent again.", true);
+ ParamDefTable[23].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=24, longName="skinClothMap[].vertexIndex2"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[24];
+ ParamDef->init("vertexIndex2", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Vertex index of the physics triangle.", true);
+ ParamDefTable[24].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=25, longName="skinClothMap[].vertexIndexPlusOffset"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[25];
+ ParamDef->init("vertexIndexPlusOffset", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The vertex index in the graphical mesh (the target index).", true);
+ ParamDefTable[25].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=26, longName="skinClothMapThickness"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[26];
+ ParamDef->init("skinClothMapThickness", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("READONLY", uint64_t(1), true);
+ ParamDefTable[26].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("READONLY", uint64_t(1), true);
+ HintTable[1].init("longDescription", "The physical mesh is expanded to both directions with this thickness, resulting in the doubled thickness.\nOnly used for Mesh-Mesh Skinning.\n", true);
+ HintTable[2].init("shortDescription", "Thickness of the mesh implicitly defined around the flat physical (triangle) mesh.", true);
+ ParamDefTable[26].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=27, longName="skinClothMapOffset"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[27];
+ ParamDef->init("skinClothMapOffset", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("READONLY", uint64_t(1), true);
+ ParamDefTable[27].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("READONLY", uint64_t(1), true);
+ HintTable[1].init("longDescription", "The length of the normals when added to the vertex to generate the barycentric coordinates.\n", true);
+ HintTable[2].init("shortDescription", "Normal offset of the mesh implicitly defined around the flat physical (triangle) mesh.", true);
+ ParamDefTable[27].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=28, longName="tetraMap"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[28];
+ ParamDef->init("tetraMap", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ ParamDefTable[28].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ HintTable[1].init("longDescription", "This map is only used when the physical mesh is based on tetrahedrons.\n", true);
+ HintTable[2].init("shortDescription", "Map each graphical vertex onto a physically simulated tetrahedron.", true);
+ ParamDefTable[28].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=29, longName="tetraMap[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[29];
+ ParamDef->init("tetraMap", TYPE_STRUCT, "TetraLink", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ ParamDefTable[29].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ HintTable[1].init("longDescription", "This map is only used when the physical mesh is based on tetrahedrons.\n", true);
+ HintTable[2].init("shortDescription", "Map each graphical vertex onto a physically simulated tetrahedron.", true);
+ ParamDefTable[29].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=30, longName="tetraMap[].vertexBary"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[30];
+ ParamDef->init("vertexBary", TYPE_VEC3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The barycentric coordinate into the tetrahedron.", true);
+ ParamDefTable[30].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=31, longName="tetraMap[].tetraIndex0"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[31];
+ ParamDef->init("tetraIndex0", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "First index of the 4 consecutive indices making the physical tetrahedron.", true);
+ ParamDefTable[31].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=32, longName="tetraMap[].normalBary"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[32];
+ ParamDef->init("normalBary", TYPE_VEC3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The barycentric coordinate of (vertex+normal). When vertex is subtracted this will result in the normal again.", true);
+ ParamDefTable[32].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=33, longName="tetraMap[]._dummyForAlignment"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[33];
+ ParamDef->init("_dummyForAlignment", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("DONOTSERIALIZE", uint64_t(1), true);
+ ParamDefTable[33].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("DONOTSERIALIZE", uint64_t(1), true);
+ HintTable[1].init("shortDescription", "Does not hold any data, only helps the alignment of the struct.", true);
+ ParamDefTable[33].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=34, longName="renderMeshAssetSorting"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[34];
+ ParamDef->init("renderMeshAssetSorting", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Render mesh asset sorting", true);
+ ParamDefTable[34].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=35, longName="physicsMeshPartitioning"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[35];
+ ParamDef->init("physicsMeshPartitioning", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Physics mesh partitioning", true);
+ ParamDefTable[35].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=36, longName="physicsMeshPartitioning[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[36];
+ ParamDef->init("physicsMeshPartitioning", TYPE_STRUCT, "PhysicsMeshPartitioning", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Physics mesh partitioning", true);
+ ParamDefTable[36].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=37, longName="physicsMeshPartitioning[].graphicalSubmesh"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[37];
+ ParamDef->init("graphicalSubmesh", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Graphical submesh", true);
+ ParamDefTable[37].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=38, longName="physicsMeshPartitioning[].numSimulatedVertices"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[38];
+ ParamDef->init("numSimulatedVertices", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Simulated vertex count", true);
+ ParamDefTable[38].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=39, longName="physicsMeshPartitioning[].numSimulatedVerticesAdditional"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[39];
+ ParamDef->init("numSimulatedVerticesAdditional", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Simulated additional vertex count", true);
+ ParamDefTable[39].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=40, longName="physicsMeshPartitioning[].numSimulatedIndices"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[40];
+ ParamDef->init("numSimulatedIndices", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Simulated index count", true);
+ ParamDefTable[40].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // SetChildren for: nodeIndex=0, longName=""
+ {
+ static Definition* Children[13];
+ Children[0] = PDEF_PTR(1);
+ Children[1] = PDEF_PTR(3);
+ Children[2] = PDEF_PTR(4);
+ Children[3] = PDEF_PTR(5);
+ Children[4] = PDEF_PTR(6);
+ Children[5] = PDEF_PTR(7);
+ Children[6] = PDEF_PTR(9);
+ Children[7] = PDEF_PTR(17);
+ Children[8] = PDEF_PTR(26);
+ Children[9] = PDEF_PTR(27);
+ Children[10] = PDEF_PTR(28);
+ Children[11] = PDEF_PTR(34);
+ Children[12] = PDEF_PTR(35);
+
+ ParamDefTable[0].setChildren(Children, 13);
+ }
+
+ // SetChildren for: nodeIndex=1, longName="platforms"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(2);
+
+ ParamDefTable[1].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=7, longName="immediateClothMap"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(8);
+
+ ParamDefTable[7].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=9, longName="skinClothMapB"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(10);
+
+ ParamDefTable[9].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=10, longName="skinClothMapB[]"
+ {
+ static Definition* Children[6];
+ Children[0] = PDEF_PTR(11);
+ Children[1] = PDEF_PTR(12);
+ Children[2] = PDEF_PTR(13);
+ Children[3] = PDEF_PTR(14);
+ Children[4] = PDEF_PTR(15);
+ Children[5] = PDEF_PTR(16);
+
+ ParamDefTable[10].setChildren(Children, 6);
+ }
+
+ // SetChildren for: nodeIndex=17, longName="skinClothMap"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(18);
+
+ ParamDefTable[17].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=18, longName="skinClothMap[]"
+ {
+ static Definition* Children[7];
+ Children[0] = PDEF_PTR(19);
+ Children[1] = PDEF_PTR(20);
+ Children[2] = PDEF_PTR(21);
+ Children[3] = PDEF_PTR(22);
+ Children[4] = PDEF_PTR(23);
+ Children[5] = PDEF_PTR(24);
+ Children[6] = PDEF_PTR(25);
+
+ ParamDefTable[18].setChildren(Children, 7);
+ }
+
+ // SetChildren for: nodeIndex=28, longName="tetraMap"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(29);
+
+ ParamDefTable[28].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=29, longName="tetraMap[]"
+ {
+ static Definition* Children[4];
+ Children[0] = PDEF_PTR(30);
+ Children[1] = PDEF_PTR(31);
+ Children[2] = PDEF_PTR(32);
+ Children[3] = PDEF_PTR(33);
+
+ ParamDefTable[29].setChildren(Children, 4);
+ }
+
+ // SetChildren for: nodeIndex=35, longName="physicsMeshPartitioning"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(36);
+
+ ParamDefTable[35].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=36, longName="physicsMeshPartitioning[]"
+ {
+ static Definition* Children[4];
+ Children[0] = PDEF_PTR(37);
+ Children[1] = PDEF_PTR(38);
+ Children[2] = PDEF_PTR(39);
+ Children[3] = PDEF_PTR(40);
+
+ ParamDefTable[36].setChildren(Children, 4);
+ }
+
+ mBuiltFlag = true;
+
+}
+void ClothingGraphicalLodParameters::initStrings(void)
+{
+}
+
+void ClothingGraphicalLodParameters::initDynamicArrays(void)
+{
+ platforms.buf = NULL;
+ platforms.isAllocated = true;
+ platforms.elementSize = sizeof(NvParameterized::DummyStringStruct);
+ platforms.arraySizes[0] = 0;
+ immediateClothMap.buf = NULL;
+ immediateClothMap.isAllocated = true;
+ immediateClothMap.elementSize = sizeof(uint32_t);
+ immediateClothMap.arraySizes[0] = 0;
+ skinClothMapB.buf = NULL;
+ skinClothMapB.isAllocated = true;
+ skinClothMapB.elementSize = sizeof(SkinClothMapB_Type);
+ skinClothMapB.arraySizes[0] = 0;
+ skinClothMap.buf = NULL;
+ skinClothMap.isAllocated = true;
+ skinClothMap.elementSize = sizeof(SkinClothMapD_Type);
+ skinClothMap.arraySizes[0] = 0;
+ tetraMap.buf = NULL;
+ tetraMap.isAllocated = true;
+ tetraMap.elementSize = sizeof(TetraLink_Type);
+ tetraMap.arraySizes[0] = 0;
+ physicsMeshPartitioning.buf = NULL;
+ physicsMeshPartitioning.isAllocated = true;
+ physicsMeshPartitioning.elementSize = sizeof(PhysicsMeshPartitioning_Type);
+ physicsMeshPartitioning.arraySizes[0] = 0;
+}
+
+void ClothingGraphicalLodParameters::initDefaults(void)
+{
+
+ freeStrings();
+ freeReferences();
+ freeDynamicArrays();
+ lod = uint32_t(0);
+ physicalMeshId = uint32_t(-1);
+ renderMeshAssetPointer = NULL;
+ skinClothMapThickness = float(0);
+ skinClothMapOffset = float(0);
+ renderMeshAssetSorting = uint32_t(0);
+
+ initDynamicArrays();
+ initStrings();
+ initReferences();
+}
+
+void ClothingGraphicalLodParameters::initReferences(void)
+{
+ renderMeshAsset = NULL;
+
+}
+
+void ClothingGraphicalLodParameters::freeDynamicArrays(void)
+{
+ if (platforms.isAllocated && platforms.buf)
+ {
+ mParameterizedTraits->free(platforms.buf);
+ }
+ if (immediateClothMap.isAllocated && immediateClothMap.buf)
+ {
+ mParameterizedTraits->free(immediateClothMap.buf);
+ }
+ if (skinClothMapB.isAllocated && skinClothMapB.buf)
+ {
+ mParameterizedTraits->free(skinClothMapB.buf);
+ }
+ if (skinClothMap.isAllocated && skinClothMap.buf)
+ {
+ mParameterizedTraits->free(skinClothMap.buf);
+ }
+ if (tetraMap.isAllocated && tetraMap.buf)
+ {
+ mParameterizedTraits->free(tetraMap.buf);
+ }
+ if (physicsMeshPartitioning.isAllocated && physicsMeshPartitioning.buf)
+ {
+ mParameterizedTraits->free(physicsMeshPartitioning.buf);
+ }
+}
+
+void ClothingGraphicalLodParameters::freeStrings(void)
+{
+
+ for (int i = 0; i < platforms.arraySizes[0]; ++i)
+ {
+ if (platforms.buf[i].isAllocated && platforms.buf[i].buf)
+ {
+ mParameterizedTraits->strfree((char*)platforms.buf[i].buf);
+ }
+ }
+}
+
+void ClothingGraphicalLodParameters::freeReferences(void)
+{
+ if (renderMeshAsset)
+ {
+ renderMeshAsset->destroy();
+ }
+
+}
+
+} // namespace clothing
+} // namespace nvidia
diff --git a/APEX_1.4/module/clothing/src/autogen/ClothingMaterialLibraryParameters.cpp b/APEX_1.4/module/clothing/src/autogen/ClothingMaterialLibraryParameters.cpp
new file mode 100644
index 00000000..5a0bf1c8
--- /dev/null
+++ b/APEX_1.4/module/clothing/src/autogen/ClothingMaterialLibraryParameters.cpp
@@ -0,0 +1,1593 @@
+// 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) 2008-2015 NVIDIA Corporation. All rights reserved.
+
+// This file was generated by NvParameterized/scripts/GenParameterized.pl
+
+
+#include "ClothingMaterialLibraryParameters.h"
+#include <string.h>
+#include <stdlib.h>
+
+using namespace NvParameterized;
+
+namespace nvidia
+{
+namespace clothing
+{
+
+using namespace ClothingMaterialLibraryParametersNS;
+
+const char* const ClothingMaterialLibraryParametersFactory::vptr =
+ NvParameterized::getVptr<ClothingMaterialLibraryParameters, ClothingMaterialLibraryParameters::ClassAlignment>();
+
+const uint32_t NumParamDefs = 43;
+static NvParameterized::DefinitionImpl* ParamDefTable; // now allocated in buildTree [NumParamDefs];
+
+
+static const size_t ParamLookupChildrenTable[] =
+{
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 15, 19, 23, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, 40, 41, 42, 12, 13, 14, 16, 17, 18, 20, 21, 22, 24, 25, 26,
+};
+
+#define TENUM(type) nvidia::##type
+#define CHILDREN(index) &ParamLookupChildrenTable[index]
+static const NvParameterized::ParamLookupNode ParamLookupTable[NumParamDefs] =
+{
+ { TYPE_STRUCT, false, 0, CHILDREN(0), 1 },
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->materials), CHILDREN(1), 1 }, // materials
+ { TYPE_STRUCT, false, 1 * sizeof(ClothingMaterial_Type), CHILDREN(2), 28 }, // materials[]
+ { TYPE_STRING, false, (size_t)(&((ClothingMaterial_Type*)0)->materialName), NULL, 0 }, // materials[].materialName
+ { TYPE_F32, false, (size_t)(&((ClothingMaterial_Type*)0)->verticalStretchingStiffness), NULL, 0 }, // materials[].verticalStretchingStiffness
+ { TYPE_F32, false, (size_t)(&((ClothingMaterial_Type*)0)->horizontalStretchingStiffness), NULL, 0 }, // materials[].horizontalStretchingStiffness
+ { TYPE_F32, false, (size_t)(&((ClothingMaterial_Type*)0)->bendingStiffness), NULL, 0 }, // materials[].bendingStiffness
+ { TYPE_F32, false, (size_t)(&((ClothingMaterial_Type*)0)->shearingStiffness), NULL, 0 }, // materials[].shearingStiffness
+ { TYPE_F32, false, (size_t)(&((ClothingMaterial_Type*)0)->tetherStiffness), NULL, 0 }, // materials[].tetherStiffness
+ { TYPE_F32, false, (size_t)(&((ClothingMaterial_Type*)0)->tetherLimit), NULL, 0 }, // materials[].tetherLimit
+ { TYPE_BOOL, false, (size_t)(&((ClothingMaterial_Type*)0)->orthoBending), NULL, 0 }, // materials[].orthoBending
+ { TYPE_STRUCT, false, (size_t)(&((ClothingMaterial_Type*)0)->verticalStiffnessScaling), CHILDREN(30), 3 }, // materials[].verticalStiffnessScaling
+ { TYPE_F32, false, (size_t)(&((StiffnessScaling_Type*)0)->compressionRange), NULL, 0 }, // materials[].verticalStiffnessScaling.compressionRange
+ { TYPE_F32, false, (size_t)(&((StiffnessScaling_Type*)0)->stretchRange), NULL, 0 }, // materials[].verticalStiffnessScaling.stretchRange
+ { TYPE_F32, false, (size_t)(&((StiffnessScaling_Type*)0)->scale), NULL, 0 }, // materials[].verticalStiffnessScaling.scale
+ { TYPE_STRUCT, false, (size_t)(&((ClothingMaterial_Type*)0)->horizontalStiffnessScaling), CHILDREN(33), 3 }, // materials[].horizontalStiffnessScaling
+ { TYPE_F32, false, (size_t)(&((StiffnessScaling_Type*)0)->compressionRange), NULL, 0 }, // materials[].horizontalStiffnessScaling.compressionRange
+ { TYPE_F32, false, (size_t)(&((StiffnessScaling_Type*)0)->stretchRange), NULL, 0 }, // materials[].horizontalStiffnessScaling.stretchRange
+ { TYPE_F32, false, (size_t)(&((StiffnessScaling_Type*)0)->scale), NULL, 0 }, // materials[].horizontalStiffnessScaling.scale
+ { TYPE_STRUCT, false, (size_t)(&((ClothingMaterial_Type*)0)->bendingStiffnessScaling), CHILDREN(36), 3 }, // materials[].bendingStiffnessScaling
+ { TYPE_F32, false, (size_t)(&((StiffnessScaling_Type*)0)->compressionRange), NULL, 0 }, // materials[].bendingStiffnessScaling.compressionRange
+ { TYPE_F32, false, (size_t)(&((StiffnessScaling_Type*)0)->stretchRange), NULL, 0 }, // materials[].bendingStiffnessScaling.stretchRange
+ { TYPE_F32, false, (size_t)(&((StiffnessScaling_Type*)0)->scale), NULL, 0 }, // materials[].bendingStiffnessScaling.scale
+ { TYPE_STRUCT, false, (size_t)(&((ClothingMaterial_Type*)0)->shearingStiffnessScaling), CHILDREN(39), 3 }, // materials[].shearingStiffnessScaling
+ { TYPE_F32, false, (size_t)(&((StiffnessScaling_Type*)0)->compressionRange), NULL, 0 }, // materials[].shearingStiffnessScaling.compressionRange
+ { TYPE_F32, false, (size_t)(&((StiffnessScaling_Type*)0)->stretchRange), NULL, 0 }, // materials[].shearingStiffnessScaling.stretchRange
+ { TYPE_F32, false, (size_t)(&((StiffnessScaling_Type*)0)->scale), NULL, 0 }, // materials[].shearingStiffnessScaling.scale
+ { TYPE_F32, false, (size_t)(&((ClothingMaterial_Type*)0)->damping), NULL, 0 }, // materials[].damping
+ { TYPE_F32, false, (size_t)(&((ClothingMaterial_Type*)0)->stiffnessFrequency), NULL, 0 }, // materials[].stiffnessFrequency
+ { TYPE_F32, false, (size_t)(&((ClothingMaterial_Type*)0)->drag), NULL, 0 }, // materials[].drag
+ { TYPE_BOOL, false, (size_t)(&((ClothingMaterial_Type*)0)->comDamping), NULL, 0 }, // materials[].comDamping
+ { TYPE_F32, false, (size_t)(&((ClothingMaterial_Type*)0)->friction), NULL, 0 }, // materials[].friction
+ { TYPE_F32, false, (size_t)(&((ClothingMaterial_Type*)0)->massScale), NULL, 0 }, // materials[].massScale
+ { TYPE_U32, false, (size_t)(&((ClothingMaterial_Type*)0)->solverIterations), NULL, 0 }, // materials[].solverIterations
+ { TYPE_F32, false, (size_t)(&((ClothingMaterial_Type*)0)->solverFrequency), NULL, 0 }, // materials[].solverFrequency
+ { TYPE_F32, false, (size_t)(&((ClothingMaterial_Type*)0)->gravityScale), NULL, 0 }, // materials[].gravityScale
+ { TYPE_F32, false, (size_t)(&((ClothingMaterial_Type*)0)->inertiaScale), NULL, 0 }, // materials[].inertiaScale
+ { TYPE_F32, false, (size_t)(&((ClothingMaterial_Type*)0)->hardStretchLimitation), NULL, 0 }, // materials[].hardStretchLimitation
+ { TYPE_F32, false, (size_t)(&((ClothingMaterial_Type*)0)->maxDistanceBias), NULL, 0 }, // materials[].maxDistanceBias
+ { TYPE_U32, false, (size_t)(&((ClothingMaterial_Type*)0)->hierarchicalSolverIterations), NULL, 0 }, // materials[].hierarchicalSolverIterations
+ { TYPE_F32, false, (size_t)(&((ClothingMaterial_Type*)0)->selfcollisionThickness), NULL, 0 }, // materials[].selfcollisionThickness
+ { TYPE_F32, false, (size_t)(&((ClothingMaterial_Type*)0)->selfcollisionSquashScale), NULL, 0 }, // materials[].selfcollisionSquashScale
+ { TYPE_F32, false, (size_t)(&((ClothingMaterial_Type*)0)->selfcollisionStiffness), NULL, 0 }, // materials[].selfcollisionStiffness
+};
+
+
+bool ClothingMaterialLibraryParameters::mBuiltFlag = false;
+NvParameterized::MutexType ClothingMaterialLibraryParameters::mBuiltFlagMutex;
+
+ClothingMaterialLibraryParameters::ClothingMaterialLibraryParameters(NvParameterized::Traits* traits, void* buf, int32_t* refCount) :
+ NvParameters(traits, buf, refCount)
+{
+ //mParameterizedTraits->registerFactory(className(), &ClothingMaterialLibraryParametersFactoryInst);
+
+ if (!buf) //Do not init data if it is inplace-deserialized
+ {
+ initDynamicArrays();
+ initStrings();
+ initReferences();
+ initDefaults();
+ }
+}
+
+ClothingMaterialLibraryParameters::~ClothingMaterialLibraryParameters()
+{
+ freeStrings();
+ freeReferences();
+ freeDynamicArrays();
+}
+
+void ClothingMaterialLibraryParameters::destroy()
+{
+ // We cache these fields here to avoid overwrite in destructor
+ bool doDeallocateSelf = mDoDeallocateSelf;
+ NvParameterized::Traits* traits = mParameterizedTraits;
+ int32_t* refCount = mRefCount;
+ void* buf = mBuffer;
+
+ this->~ClothingMaterialLibraryParameters();
+
+ NvParameters::destroy(this, traits, doDeallocateSelf, refCount, buf);
+}
+
+const NvParameterized::DefinitionImpl* ClothingMaterialLibraryParameters::getParameterDefinitionTree(void)
+{
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+ if (!mBuiltFlag)
+ {
+ buildTree();
+ }
+ }
+
+ return(&ParamDefTable[0]);
+}
+
+const NvParameterized::DefinitionImpl* ClothingMaterialLibraryParameters::getParameterDefinitionTree(void) const
+{
+ ClothingMaterialLibraryParameters* tmpParam = const_cast<ClothingMaterialLibraryParameters*>(this);
+
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+ if (!mBuiltFlag)
+ {
+ tmpParam->buildTree();
+ }
+ }
+
+ return(&ParamDefTable[0]);
+}
+
+NvParameterized::ErrorType ClothingMaterialLibraryParameters::getParameterHandle(const char* long_name, Handle& handle) const
+{
+ ErrorType Ret = NvParameters::getParameterHandle(long_name, handle);
+ if (Ret != ERROR_NONE)
+ {
+ return(Ret);
+ }
+
+ size_t offset;
+ void* ptr;
+
+ getVarPtr(handle, ptr, offset);
+
+ if (ptr == NULL)
+ {
+ return(ERROR_INDEX_OUT_OF_RANGE);
+ }
+
+ return(ERROR_NONE);
+}
+
+NvParameterized::ErrorType ClothingMaterialLibraryParameters::getParameterHandle(const char* long_name, Handle& handle)
+{
+ ErrorType Ret = NvParameters::getParameterHandle(long_name, handle);
+ if (Ret != ERROR_NONE)
+ {
+ return(Ret);
+ }
+
+ size_t offset;
+ void* ptr;
+
+ getVarPtr(handle, ptr, offset);
+
+ if (ptr == NULL)
+ {
+ return(ERROR_INDEX_OUT_OF_RANGE);
+ }
+
+ return(ERROR_NONE);
+}
+
+void ClothingMaterialLibraryParameters::getVarPtr(const Handle& handle, void*& ptr, size_t& offset) const
+{
+ ptr = getVarPtrHelper(&ParamLookupTable[0], const_cast<ClothingMaterialLibraryParameters::ParametersStruct*>(&parameters()), handle, offset);
+}
+
+
+/* Dynamic Handle Indices */
+/* [1,0] - materials.materialName */
+
+void ClothingMaterialLibraryParameters::freeParameterDefinitionTable(NvParameterized::Traits* traits)
+{
+ if (!traits)
+ {
+ return;
+ }
+
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ return;
+ }
+
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+
+ if (!mBuiltFlag)
+ {
+ return;
+ }
+
+ for (uint32_t i = 0; i < NumParamDefs; ++i)
+ {
+ ParamDefTable[i].~DefinitionImpl();
+ }
+
+ traits->free(ParamDefTable);
+
+ mBuiltFlag = false;
+}
+
+#define PDEF_PTR(index) (&ParamDefTable[index])
+
+void ClothingMaterialLibraryParameters::buildTree(void)
+{
+
+ uint32_t allocSize = sizeof(NvParameterized::DefinitionImpl) * NumParamDefs;
+ ParamDefTable = (NvParameterized::DefinitionImpl*)(mParameterizedTraits->alloc(allocSize));
+ memset(ParamDefTable, 0, allocSize);
+
+ for (uint32_t i = 0; i < NumParamDefs; ++i)
+ {
+ NV_PARAM_PLACEMENT_NEW(ParamDefTable + i, NvParameterized::DefinitionImpl)(*mParameterizedTraits);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=0, longName=""
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[0];
+ ParamDef->init("", TYPE_STRUCT, "STRUCT", true);
+
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=1, longName="materials"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[1];
+ ParamDef->init("materials", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Array of materials that are part of this library.", true);
+ ParamDefTable[1].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ static const uint8_t dynHandleIndices[2] = { 1, 0, };
+ ParamDef->setDynamicHandleIndicesMap(dynHandleIndices, 2);
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=2, longName="materials[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[2];
+ ParamDef->init("materials", TYPE_STRUCT, "ClothingMaterial", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Array of materials that are part of this library.", true);
+ ParamDefTable[2].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=3, longName="materials[].materialName"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[3];
+ ParamDef->init("materialName", TYPE_STRING, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Material name", true);
+ ParamDefTable[3].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=4, longName="materials[].verticalStretchingStiffness"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[4];
+ ParamDef->init("verticalStretchingStiffness", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ ParamDefTable[4].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ HintTable[2].init("shortDescription", "Vertical stretching stiffness of the cloth in the range (0, 1]. This parameter is ignored by the PhysX 2.8.4 solver.", true);
+ ParamDefTable[4].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=5, longName="materials[].horizontalStretchingStiffness"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[5];
+ ParamDef->init("horizontalStretchingStiffness", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ ParamDefTable[5].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ HintTable[2].init("shortDescription", "Horizontal Stretching stiffness of the cloth in the range (0, 1].", true);
+ ParamDefTable[5].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=6, longName="materials[].bendingStiffness"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[6];
+ ParamDef->init("bendingStiffness", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ ParamDefTable[6].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ HintTable[2].init("shortDescription", "Bending stiffness of the cloth in the range [0, 1].", true);
+ ParamDefTable[6].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=7, longName="materials[].shearingStiffness"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[7];
+ ParamDef->init("shearingStiffness", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ ParamDefTable[7].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ HintTable[2].init("shortDescription", "Shearing stiffness of the cloth in the range [0, 1].", true);
+ ParamDefTable[7].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=8, longName="materials[].tetherStiffness"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[8];
+ ParamDef->init("tetherStiffness", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ ParamDefTable[8].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ HintTable[2].init("shortDescription", "Range [0, 1], but should be 0. The higher this value, the more the piece of clothing is allowed to stretch.", true);
+ ParamDefTable[8].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=9, longName="materials[].tetherLimit"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[9];
+ ParamDef->init("tetherLimit", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("max", double(4.0), true);
+ HintTable[1].init("min", double(1.0), true);
+ ParamDefTable[9].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("max", double(4.0), true);
+ HintTable[1].init("min", double(1.0), true);
+ HintTable[2].init("shortDescription", "Range [1, 4], but should be 1. This scales the restlength of the tether constraints.", true);
+ ParamDefTable[9].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=10, longName="materials[].orthoBending"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[10];
+ ParamDef->init("orthoBending", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "Bending is modeled via an angular spring between adjacent triangles. This mode is slower but independent of stretching resistance.\n", true);
+ HintTable[1].init("shortDescription", "Enable/disable orthogonal bending resistance.", true);
+ ParamDefTable[10].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=11, longName="materials[].verticalStiffnessScaling"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[11];
+ ParamDef->init("verticalStiffnessScaling", TYPE_STRUCT, "StiffnessScaling", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Vertical stiffness scaling", true);
+ ParamDefTable[11].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=12, longName="materials[].verticalStiffnessScaling.compressionRange"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[12];
+ ParamDef->init("compressionRange", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ ParamDefTable[12].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#else
+
+ static HintImpl HintTable[4];
+ static Hint* HintPtrTable[4] = { &HintTable[0], &HintTable[1], &HintTable[2], &HintTable[3], };
+ HintTable[0].init("longDescription", "For any edge where the simulated length is within the range [restlength, compressionRange*restlength],\nthe scale will be multiplied on top of the regular stiffness.\nThis is can be used to allow the cloth to compress more easily up to a certain limit.\n", true);
+ HintTable[1].init("max", double(1.0), true);
+ HintTable[2].init("min", double(0.0), true);
+ HintTable[3].init("shortDescription", "Multiplier relative to rest length that defines where the stiffness is scaled down to allow compression.", true);
+ ParamDefTable[12].setHints((const NvParameterized::Hint**)HintPtrTable, 4);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=13, longName="materials[].verticalStiffnessScaling.stretchRange"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[13];
+ ParamDef->init("stretchRange", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("min", double(1.0), true);
+ ParamDefTable[13].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("longDescription", "For any edge where the simulated length is within the range [restlength, stretchRange*restlength],\nthe scale will be multiplied on top of the regular stiffness.\nThis is can be used to allow the cloth to stretch more easily up to a certain limit.\n", true);
+ HintTable[1].init("min", double(1.0), true);
+ HintTable[2].init("shortDescription", "Multiplier relative to rest length that defines the range where the stiffness is scaled down to allow stretching.", true);
+ ParamDefTable[13].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=14, longName="materials[].verticalStiffnessScaling.scale"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[14];
+ ParamDef->init("scale", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ ParamDefTable[14].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ HintTable[2].init("shortDescription", "Stiffness scale [0, 1] applied when inside the scaling range.", true);
+ ParamDefTable[14].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=15, longName="materials[].horizontalStiffnessScaling"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[15];
+ ParamDef->init("horizontalStiffnessScaling", TYPE_STRUCT, "StiffnessScaling", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Horizontal stiffness scaling", true);
+ ParamDefTable[15].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=16, longName="materials[].horizontalStiffnessScaling.compressionRange"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[16];
+ ParamDef->init("compressionRange", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ ParamDefTable[16].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#else
+
+ static HintImpl HintTable[4];
+ static Hint* HintPtrTable[4] = { &HintTable[0], &HintTable[1], &HintTable[2], &HintTable[3], };
+ HintTable[0].init("longDescription", "For any edge where the simulated length is within the range [restlength, compressionRange*restlength],\nthe scale will be multiplied on top of the regular stiffness.\nThis is can be used to allow the cloth to compress more easily up to a certain limit.\n", true);
+ HintTable[1].init("max", double(1.0), true);
+ HintTable[2].init("min", double(0.0), true);
+ HintTable[3].init("shortDescription", "Multiplier relative to rest length that defines where the stiffness is scaled down to allow compression.", true);
+ ParamDefTable[16].setHints((const NvParameterized::Hint**)HintPtrTable, 4);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=17, longName="materials[].horizontalStiffnessScaling.stretchRange"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[17];
+ ParamDef->init("stretchRange", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("min", double(1.0), true);
+ ParamDefTable[17].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("longDescription", "For any edge where the simulated length is within the range [restlength, stretchRange*restlength],\nthe scale will be multiplied on top of the regular stiffness.\nThis is can be used to allow the cloth to stretch more easily up to a certain limit.\n", true);
+ HintTable[1].init("min", double(1.0), true);
+ HintTable[2].init("shortDescription", "Multiplier relative to rest length that defines the range where the stiffness is scaled down to allow stretching.", true);
+ ParamDefTable[17].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=18, longName="materials[].horizontalStiffnessScaling.scale"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[18];
+ ParamDef->init("scale", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ ParamDefTable[18].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ HintTable[2].init("shortDescription", "Stiffness scale [0, 1] applied when inside the scaling range.", true);
+ ParamDefTable[18].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=19, longName="materials[].bendingStiffnessScaling"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[19];
+ ParamDef->init("bendingStiffnessScaling", TYPE_STRUCT, "StiffnessScaling", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Bending stiffness scaling", true);
+ ParamDefTable[19].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=20, longName="materials[].bendingStiffnessScaling.compressionRange"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[20];
+ ParamDef->init("compressionRange", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ ParamDefTable[20].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#else
+
+ static HintImpl HintTable[4];
+ static Hint* HintPtrTable[4] = { &HintTable[0], &HintTable[1], &HintTable[2], &HintTable[3], };
+ HintTable[0].init("longDescription", "For any edge where the simulated length is within the range [restlength, compressionRange*restlength],\nthe scale will be multiplied on top of the regular stiffness.\nThis is can be used to allow the cloth to compress more easily up to a certain limit.\n", true);
+ HintTable[1].init("max", double(1.0), true);
+ HintTable[2].init("min", double(0.0), true);
+ HintTable[3].init("shortDescription", "Multiplier relative to rest length that defines where the stiffness is scaled down to allow compression.", true);
+ ParamDefTable[20].setHints((const NvParameterized::Hint**)HintPtrTable, 4);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=21, longName="materials[].bendingStiffnessScaling.stretchRange"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[21];
+ ParamDef->init("stretchRange", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("min", double(1.0), true);
+ ParamDefTable[21].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("longDescription", "For any edge where the simulated length is within the range [restlength, stretchRange*restlength],\nthe scale will be multiplied on top of the regular stiffness.\nThis is can be used to allow the cloth to stretch more easily up to a certain limit.\n", true);
+ HintTable[1].init("min", double(1.0), true);
+ HintTable[2].init("shortDescription", "Multiplier relative to rest length that defines the range where the stiffness is scaled down to allow stretching.", true);
+ ParamDefTable[21].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=22, longName="materials[].bendingStiffnessScaling.scale"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[22];
+ ParamDef->init("scale", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ ParamDefTable[22].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ HintTable[2].init("shortDescription", "Stiffness scale [0, 1] applied when inside the scaling range.", true);
+ ParamDefTable[22].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=23, longName="materials[].shearingStiffnessScaling"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[23];
+ ParamDef->init("shearingStiffnessScaling", TYPE_STRUCT, "StiffnessScaling", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Shearing stiffness scaling", true);
+ ParamDefTable[23].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=24, longName="materials[].shearingStiffnessScaling.compressionRange"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[24];
+ ParamDef->init("compressionRange", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ ParamDefTable[24].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#else
+
+ static HintImpl HintTable[4];
+ static Hint* HintPtrTable[4] = { &HintTable[0], &HintTable[1], &HintTable[2], &HintTable[3], };
+ HintTable[0].init("longDescription", "For any edge where the simulated length is within the range [restlength, compressionRange*restlength],\nthe scale will be multiplied on top of the regular stiffness.\nThis is can be used to allow the cloth to compress more easily up to a certain limit.\n", true);
+ HintTable[1].init("max", double(1.0), true);
+ HintTable[2].init("min", double(0.0), true);
+ HintTable[3].init("shortDescription", "Multiplier relative to rest length that defines where the stiffness is scaled down to allow compression.", true);
+ ParamDefTable[24].setHints((const NvParameterized::Hint**)HintPtrTable, 4);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=25, longName="materials[].shearingStiffnessScaling.stretchRange"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[25];
+ ParamDef->init("stretchRange", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("min", double(1.0), true);
+ ParamDefTable[25].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("longDescription", "For any edge where the simulated length is within the range [restlength, stretchRange*restlength],\nthe scale will be multiplied on top of the regular stiffness.\nThis is can be used to allow the cloth to stretch more easily up to a certain limit.\n", true);
+ HintTable[1].init("min", double(1.0), true);
+ HintTable[2].init("shortDescription", "Multiplier relative to rest length that defines the range where the stiffness is scaled down to allow stretching.", true);
+ ParamDefTable[25].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=26, longName="materials[].shearingStiffnessScaling.scale"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[26];
+ ParamDef->init("scale", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ ParamDefTable[26].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ HintTable[2].init("shortDescription", "Stiffness scale [0, 1] applied when inside the scaling range.", true);
+ ParamDefTable[26].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=27, longName="materials[].damping"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[27];
+ ParamDef->init("damping", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ ParamDefTable[27].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ HintTable[2].init("shortDescription", "Spring damping of the cloth in the range [0, 1]", true);
+ ParamDefTable[27].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=28, longName="materials[].stiffnessFrequency"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[28];
+ ParamDef->init("stiffnessFrequency", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("max", double(500.0), true);
+ HintTable[1].init("min", double(10.0), true);
+ ParamDefTable[28].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("max", double(500.0), true);
+ HintTable[1].init("min", double(10.0), true);
+ HintTable[2].init("shortDescription", "Scales linearity of behavior for the varous stiffness values in the interval (0, 1)", true);
+ ParamDefTable[28].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=29, longName="materials[].drag"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[29];
+ ParamDef->init("drag", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ ParamDefTable[29].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#else
+
+ static HintImpl HintTable[4];
+ static Hint* HintPtrTable[4] = { &HintTable[0], &HintTable[1], &HintTable[2], &HintTable[3], };
+ HintTable[0].init("longDescription", "The drag coefficient is the portion of local frame velocity that is applied to each particle.\n", true);
+ HintTable[1].init("max", double(1.0), true);
+ HintTable[2].init("min", double(0.0), true);
+ HintTable[3].init("shortDescription", "Drag coefficient n the range [0, 1]", true);
+ ParamDefTable[29].setHints((const NvParameterized::Hint**)HintPtrTable, 4);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=30, longName="materials[].comDamping"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[30];
+ ParamDef->init("comDamping", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "If set, the global rigid body modes (translation and rotation) are extracted from damping. This way, the cloth\ncan freely move and rotate even under high damping.\n", true);
+ HintTable[1].init("shortDescription", "Enable/disable center of mass damping of internal velocities.", true);
+ ParamDefTable[30].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=31, longName="materials[].friction"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[31];
+ ParamDef->init("friction", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ ParamDefTable[31].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#else
+
+ static HintImpl HintTable[4];
+ static Hint* HintPtrTable[4] = { &HintTable[0], &HintTable[1], &HintTable[2], &HintTable[3], };
+ HintTable[0].init("longDescription", "Currently only spheres and capsules impose friction on the colliding particles.", true);
+ HintTable[1].init("max", double(1.0), true);
+ HintTable[2].init("min", double(0.0), true);
+ HintTable[3].init("shortDescription", "Friction coefficient in the range [0, 1]", true);
+ ParamDefTable[31].setHints((const NvParameterized::Hint**)HintPtrTable, 4);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=32, longName="materials[].massScale"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[32];
+ ParamDef->init("massScale", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("max", double(100.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ ParamDefTable[32].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("max", double(100.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ HintTable[2].init("shortDescription", "Controls the amount of mass scaling during collision [0, 100]", true);
+ ParamDefTable[32].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=33, longName="materials[].solverIterations"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[33];
+ ParamDef->init("solverIterations", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("min", uint64_t(1), true);
+ ParamDefTable[33].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("longDescription", "Small numbers make the simulation faster while the cloth gets less stiff.\n", true);
+ HintTable[1].init("min", uint64_t(1), true);
+ HintTable[2].init("shortDescription", "Number of solver iterations. For 2.x cloth", true);
+ ParamDefTable[33].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=34, longName="materials[].solverFrequency"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[34];
+ ParamDef->init("solverFrequency", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("min", uint64_t(20), true);
+ ParamDefTable[34].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("longDescription", "Small numbers make the simulation faster while the cloth gets less stiff.\n", true);
+ HintTable[1].init("min", uint64_t(20), true);
+ HintTable[2].init("shortDescription", "Number of solver iterations per second. For 3.x cloth", true);
+ ParamDefTable[34].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=35, longName="materials[].gravityScale"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[35];
+ ParamDef->init("gravityScale", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "A value of 0 will make the cloth ignore gravity, a value of 10 will apply 10 times the gravity.\n", true);
+ HintTable[1].init("shortDescription", "Amount of gravity that is applied to the cloth.", true);
+ ParamDefTable[35].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=36, longName="materials[].inertiaScale"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[36];
+ ParamDef->init("inertiaScale", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ ParamDefTable[36].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#else
+
+ static HintImpl HintTable[4];
+ static Hint* HintPtrTable[4] = { &HintTable[0], &HintTable[1], &HintTable[2], &HintTable[3], };
+ HintTable[0].init("longDescription", "A value of 0 will make the cloth move in global space without inertia, a value of 1 will keep all inertia.\n", true);
+ HintTable[1].init("max", double(1.0), true);
+ HintTable[2].init("min", double(0.0), true);
+ HintTable[3].init("shortDescription", "Amount of inertia that is kept when using local space simulation.", true);
+ ParamDefTable[36].setHints((const NvParameterized::Hint**)HintPtrTable, 4);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=37, longName="materials[].hardStretchLimitation"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[37];
+ ParamDef->init("hardStretchLimitation", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("max", double(2.0), true);
+ HintTable[1].init("min", double(0.0), true);
+ ParamDefTable[37].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#else
+
+ static HintImpl HintTable[4];
+ static Hint* HintPtrTable[4] = { &HintTable[0], &HintTable[1], &HintTable[2], &HintTable[3], };
+ HintTable[0].init("longDescription", "Good values are usually between 1 and 1.1. Any value >= 1 will guarantee that a certain set of edges is not longer\nthan that value times the initial rest length.\n", true);
+ HintTable[1].init("max", double(2.0), true);
+ HintTable[2].init("min", double(0.0), true);
+ HintTable[3].init("shortDescription", "Make cloth simulation less stretchy. A value smaller than 1 will turn it off.", true);
+ ParamDefTable[37].setHints((const NvParameterized::Hint**)HintPtrTable, 4);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=38, longName="materials[].maxDistanceBias"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[38];
+ ParamDef->init("maxDistanceBias", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("max", double(1.0), true);
+ HintTable[1].init("min", double(-1.0), true);
+ ParamDefTable[38].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#else
+
+ static HintImpl HintTable[4];
+ static Hint* HintPtrTable[4] = { &HintTable[0], &HintTable[1], &HintTable[2], &HintTable[3], };
+ HintTable[0].init("longDescription", "A value smaller than 0 will turn the sphere into a capsule and eventually a line (at value -1) along the normal of the vertex.\nA value bigger than 0 will turn the sphere into a disc.\n", true);
+ HintTable[1].init("max", double(1.0), true);
+ HintTable[2].init("min", double(-1.0), true);
+ HintTable[3].init("shortDescription", "Deform the max distance sphere into a capsule or a disc.", true);
+ ParamDefTable[38].setHints((const NvParameterized::Hint**)HintPtrTable, 4);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=39, longName="materials[].hierarchicalSolverIterations"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[39];
+ ParamDef->init("hierarchicalSolverIterations", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("min", uint64_t(0), true);
+ ParamDefTable[39].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("min", uint64_t(0), true);
+ HintTable[1].init("shortDescription", "Number of iterations of the hierarchical cloth solver.", true);
+ ParamDefTable[39].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=40, longName="materials[].selfcollisionThickness"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[40];
+ ParamDef->init("selfcollisionThickness", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "This feature prevents meshes from self-intersecting. Only works properly when configured properly.", true);
+ HintTable[1].init("shortDescription", "Minimal amount of distance particles will keep of each other.", true);
+ ParamDefTable[40].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=41, longName="materials[].selfcollisionSquashScale"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[41];
+ ParamDef->init("selfcollisionSquashScale", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "This feature prevents self collision thickness becoming too high for low resolution cloth.", true);
+ HintTable[1].init("shortDescription", "Amount of thickness scaling along surface normal.", true);
+ ParamDefTable[41].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=42, longName="materials[].selfcollisionStiffness"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[42];
+ ParamDef->init("selfcollisionStiffness", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "This feature prevents meshes from self-intersecting. Only works properly when configured properly.", true);
+ HintTable[1].init("shortDescription", "Stiffness of self collision solver.", true);
+ ParamDefTable[42].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // SetChildren for: nodeIndex=0, longName=""
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(1);
+
+ ParamDefTable[0].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=1, longName="materials"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(2);
+
+ ParamDefTable[1].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=2, longName="materials[]"
+ {
+ static Definition* Children[28];
+ Children[0] = PDEF_PTR(3);
+ Children[1] = PDEF_PTR(4);
+ Children[2] = PDEF_PTR(5);
+ Children[3] = PDEF_PTR(6);
+ Children[4] = PDEF_PTR(7);
+ Children[5] = PDEF_PTR(8);
+ Children[6] = PDEF_PTR(9);
+ Children[7] = PDEF_PTR(10);
+ Children[8] = PDEF_PTR(11);
+ Children[9] = PDEF_PTR(15);
+ Children[10] = PDEF_PTR(19);
+ Children[11] = PDEF_PTR(23);
+ Children[12] = PDEF_PTR(27);
+ Children[13] = PDEF_PTR(28);
+ Children[14] = PDEF_PTR(29);
+ Children[15] = PDEF_PTR(30);
+ Children[16] = PDEF_PTR(31);
+ Children[17] = PDEF_PTR(32);
+ Children[18] = PDEF_PTR(33);
+ Children[19] = PDEF_PTR(34);
+ Children[20] = PDEF_PTR(35);
+ Children[21] = PDEF_PTR(36);
+ Children[22] = PDEF_PTR(37);
+ Children[23] = PDEF_PTR(38);
+ Children[24] = PDEF_PTR(39);
+ Children[25] = PDEF_PTR(40);
+ Children[26] = PDEF_PTR(41);
+ Children[27] = PDEF_PTR(42);
+
+ ParamDefTable[2].setChildren(Children, 28);
+ }
+
+ // SetChildren for: nodeIndex=11, longName="materials[].verticalStiffnessScaling"
+ {
+ static Definition* Children[3];
+ Children[0] = PDEF_PTR(12);
+ Children[1] = PDEF_PTR(13);
+ Children[2] = PDEF_PTR(14);
+
+ ParamDefTable[11].setChildren(Children, 3);
+ }
+
+ // SetChildren for: nodeIndex=15, longName="materials[].horizontalStiffnessScaling"
+ {
+ static Definition* Children[3];
+ Children[0] = PDEF_PTR(16);
+ Children[1] = PDEF_PTR(17);
+ Children[2] = PDEF_PTR(18);
+
+ ParamDefTable[15].setChildren(Children, 3);
+ }
+
+ // SetChildren for: nodeIndex=19, longName="materials[].bendingStiffnessScaling"
+ {
+ static Definition* Children[3];
+ Children[0] = PDEF_PTR(20);
+ Children[1] = PDEF_PTR(21);
+ Children[2] = PDEF_PTR(22);
+
+ ParamDefTable[19].setChildren(Children, 3);
+ }
+
+ // SetChildren for: nodeIndex=23, longName="materials[].shearingStiffnessScaling"
+ {
+ static Definition* Children[3];
+ Children[0] = PDEF_PTR(24);
+ Children[1] = PDEF_PTR(25);
+ Children[2] = PDEF_PTR(26);
+
+ ParamDefTable[23].setChildren(Children, 3);
+ }
+
+ mBuiltFlag = true;
+
+}
+void ClothingMaterialLibraryParameters::initStrings(void)
+{
+}
+
+void ClothingMaterialLibraryParameters::initDynamicArrays(void)
+{
+ materials.buf = NULL;
+ materials.isAllocated = true;
+ materials.elementSize = sizeof(ClothingMaterial_Type);
+ materials.arraySizes[0] = 0;
+}
+
+void ClothingMaterialLibraryParameters::initDefaults(void)
+{
+
+ freeStrings();
+ freeReferences();
+ freeDynamicArrays();
+
+ initDynamicArrays();
+ initStrings();
+ initReferences();
+}
+
+void ClothingMaterialLibraryParameters::initReferences(void)
+{
+}
+
+void ClothingMaterialLibraryParameters::freeDynamicArrays(void)
+{
+ if (materials.isAllocated && materials.buf)
+ {
+ mParameterizedTraits->free(materials.buf);
+ }
+}
+
+void ClothingMaterialLibraryParameters::freeStrings(void)
+{
+
+ for (int i = 0; i < materials.arraySizes[0]; ++i)
+ {
+ if (materials.buf[i].materialName.isAllocated && materials.buf[i].materialName.buf)
+ {
+ mParameterizedTraits->strfree((char*)materials.buf[i].materialName.buf);
+ }
+ }
+}
+
+void ClothingMaterialLibraryParameters::freeReferences(void)
+{
+}
+
+} // namespace clothing
+} // namespace nvidia
diff --git a/APEX_1.4/module/clothing/src/autogen/ClothingModuleParameters.cpp b/APEX_1.4/module/clothing/src/autogen/ClothingModuleParameters.cpp
new file mode 100644
index 00000000..b6e4e0e6
--- /dev/null
+++ b/APEX_1.4/module/clothing/src/autogen/ClothingModuleParameters.cpp
@@ -0,0 +1,583 @@
+// 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) 2008-2015 NVIDIA Corporation. All rights reserved.
+
+// This file was generated by NvParameterized/scripts/GenParameterized.pl
+
+
+#include "ClothingModuleParameters.h"
+#include <string.h>
+#include <stdlib.h>
+
+using namespace NvParameterized;
+
+namespace nvidia
+{
+namespace clothing
+{
+
+using namespace ClothingModuleParametersNS;
+
+const char* const ClothingModuleParametersFactory::vptr =
+ NvParameterized::getVptr<ClothingModuleParameters, ClothingModuleParameters::ClassAlignment>();
+
+const uint32_t NumParamDefs = 12;
+static NvParameterized::DefinitionImpl* ParamDefTable; // now allocated in buildTree [NumParamDefs];
+
+
+static const size_t ParamLookupChildrenTable[] =
+{
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+};
+
+#define TENUM(type) nvidia::##type
+#define CHILDREN(index) &ParamLookupChildrenTable[index]
+static const NvParameterized::ParamLookupNode ParamLookupTable[NumParamDefs] =
+{
+ { TYPE_STRUCT, false, 0, CHILDREN(0), 11 },
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->maxNumCompartments), NULL, 0 }, // maxNumCompartments
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->maxUnusedPhysXResources), NULL, 0 }, // maxUnusedPhysXResources
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->allowAsyncCooking), NULL, 0 }, // allowAsyncCooking
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->asyncFetchResults), NULL, 0 }, // asyncFetchResults
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->avgSimFrequencyWindow), NULL, 0 }, // avgSimFrequencyWindow
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->allowApexWorkBetweenSubsteps), NULL, 0 }, // allowApexWorkBetweenSubsteps
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->interCollisionDistance), NULL, 0 }, // interCollisionDistance
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->interCollisionStiffness), NULL, 0 }, // interCollisionStiffness
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->interCollisionIterations), NULL, 0 }, // interCollisionIterations
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->sparseSelfCollision), NULL, 0 }, // sparseSelfCollision
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->maxTimeRenderProxyInPool), NULL, 0 }, // maxTimeRenderProxyInPool
+};
+
+
+bool ClothingModuleParameters::mBuiltFlag = false;
+NvParameterized::MutexType ClothingModuleParameters::mBuiltFlagMutex;
+
+ClothingModuleParameters::ClothingModuleParameters(NvParameterized::Traits* traits, void* buf, int32_t* refCount) :
+ NvParameters(traits, buf, refCount)
+{
+ //mParameterizedTraits->registerFactory(className(), &ClothingModuleParametersFactoryInst);
+
+ if (!buf) //Do not init data if it is inplace-deserialized
+ {
+ initDynamicArrays();
+ initStrings();
+ initReferences();
+ initDefaults();
+ }
+}
+
+ClothingModuleParameters::~ClothingModuleParameters()
+{
+ freeStrings();
+ freeReferences();
+ freeDynamicArrays();
+}
+
+void ClothingModuleParameters::destroy()
+{
+ // We cache these fields here to avoid overwrite in destructor
+ bool doDeallocateSelf = mDoDeallocateSelf;
+ NvParameterized::Traits* traits = mParameterizedTraits;
+ int32_t* refCount = mRefCount;
+ void* buf = mBuffer;
+
+ this->~ClothingModuleParameters();
+
+ NvParameters::destroy(this, traits, doDeallocateSelf, refCount, buf);
+}
+
+const NvParameterized::DefinitionImpl* ClothingModuleParameters::getParameterDefinitionTree(void)
+{
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+ if (!mBuiltFlag)
+ {
+ buildTree();
+ }
+ }
+
+ return(&ParamDefTable[0]);
+}
+
+const NvParameterized::DefinitionImpl* ClothingModuleParameters::getParameterDefinitionTree(void) const
+{
+ ClothingModuleParameters* tmpParam = const_cast<ClothingModuleParameters*>(this);
+
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+ if (!mBuiltFlag)
+ {
+ tmpParam->buildTree();
+ }
+ }
+
+ return(&ParamDefTable[0]);
+}
+
+NvParameterized::ErrorType ClothingModuleParameters::getParameterHandle(const char* long_name, Handle& handle) const
+{
+ ErrorType Ret = NvParameters::getParameterHandle(long_name, handle);
+ if (Ret != ERROR_NONE)
+ {
+ return(Ret);
+ }
+
+ size_t offset;
+ void* ptr;
+
+ getVarPtr(handle, ptr, offset);
+
+ if (ptr == NULL)
+ {
+ return(ERROR_INDEX_OUT_OF_RANGE);
+ }
+
+ return(ERROR_NONE);
+}
+
+NvParameterized::ErrorType ClothingModuleParameters::getParameterHandle(const char* long_name, Handle& handle)
+{
+ ErrorType Ret = NvParameters::getParameterHandle(long_name, handle);
+ if (Ret != ERROR_NONE)
+ {
+ return(Ret);
+ }
+
+ size_t offset;
+ void* ptr;
+
+ getVarPtr(handle, ptr, offset);
+
+ if (ptr == NULL)
+ {
+ return(ERROR_INDEX_OUT_OF_RANGE);
+ }
+
+ return(ERROR_NONE);
+}
+
+void ClothingModuleParameters::getVarPtr(const Handle& handle, void*& ptr, size_t& offset) const
+{
+ ptr = getVarPtrHelper(&ParamLookupTable[0], const_cast<ClothingModuleParameters::ParametersStruct*>(&parameters()), handle, offset);
+}
+
+
+/* Dynamic Handle Indices */
+
+void ClothingModuleParameters::freeParameterDefinitionTable(NvParameterized::Traits* traits)
+{
+ if (!traits)
+ {
+ return;
+ }
+
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ return;
+ }
+
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+
+ if (!mBuiltFlag)
+ {
+ return;
+ }
+
+ for (uint32_t i = 0; i < NumParamDefs; ++i)
+ {
+ ParamDefTable[i].~DefinitionImpl();
+ }
+
+ traits->free(ParamDefTable);
+
+ mBuiltFlag = false;
+}
+
+#define PDEF_PTR(index) (&ParamDefTable[index])
+
+void ClothingModuleParameters::buildTree(void)
+{
+
+ uint32_t allocSize = sizeof(NvParameterized::DefinitionImpl) * NumParamDefs;
+ ParamDefTable = (NvParameterized::DefinitionImpl*)(mParameterizedTraits->alloc(allocSize));
+ memset(ParamDefTable, 0, allocSize);
+
+ for (uint32_t i = 0; i < NumParamDefs; ++i)
+ {
+ NV_PARAM_PLACEMENT_NEW(ParamDefTable + i, NvParameterized::DefinitionImpl)(*mParameterizedTraits);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=0, longName=""
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[0];
+ ParamDef->init("", TYPE_STRUCT, "STRUCT", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "This class is used for initializing the NxModuleClothing.", true);
+ ParamDefTable[0].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=1, longName="maxNumCompartments"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[1];
+ ParamDef->init("maxNumCompartments", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("defaultValueConsoles", uint64_t(0), true);
+ HintTable[1].init("defaultValueWindows", uint64_t(4), true);
+ ParamDefTable[1].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#else
+
+ static HintImpl HintTable[4];
+ static Hint* HintPtrTable[4] = { &HintTable[0], &HintTable[1], &HintTable[2], &HintTable[3], };
+ HintTable[0].init("defaultValueConsoles", uint64_t(0), true);
+ HintTable[1].init("defaultValueWindows", uint64_t(4), true);
+ HintTable[2].init("longDescription", "To parallelize work hw cloth, sw cloth, hw softbodies and sw softbodies are distributed into different compartments. For each type maximally maxNumCompartments compartments are created in a scene.", true);
+ HintTable[3].init("shortDescription", "Maximum number of compartments to distribute the cloths and softbodies of the same type. Works only with PhysX 2.8.4", true);
+ ParamDefTable[1].setHints((const NvParameterized::Hint**)HintPtrTable, 4);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=2, longName="maxUnusedPhysXResources"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[2];
+ ParamDef->init("maxUnusedPhysXResources", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "Not used instances are generated when NxClothingActors are released or their benefit is not high enough to allow simulation. Then they will return the NxCloth/NxSoftBody and the list of NxActors to their asset where it will be cached until another NxClothingActor needs them.", true);
+ HintTable[1].init("shortDescription", "Maximum number of NxCloth/NxSoftBody instances that are not used.", true);
+ ParamDefTable[2].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=3, longName="allowAsyncCooking"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[3];
+ ParamDef->init("allowAsyncCooking", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "This can be turned off if unexpected bugs/crashes occur.", true);
+ HintTable[1].init("shortDescription", "ClothingActors will cook in a background thread to speed up creation time.", true);
+ ParamDefTable[3].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=4, longName="asyncFetchResults"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[4];
+ ParamDef->init("asyncFetchResults", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "Note that ApexPostTickTime from the scene stats will not be correct if true. Caution: Do not set this to false when simulate and/or fetchResults is called from a PxTask. fetchResults can block and wait for other tasks in this case, which can cause a deadlock if the dispatcher is using only 1 workerthread.", true);
+ HintTable[1].init("shortDescription", "Let fetch results tasks run longer than the fetchResults call, they will block at the next updateRenderResource call.", true);
+ ParamDefTable[4].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=5, longName="avgSimFrequencyWindow"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[5];
+ ParamDef->init("avgSimFrequencyWindow", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Average Simulation Frequency is estimated with the last n frames", true);
+ ParamDefTable[5].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=6, longName="allowApexWorkBetweenSubsteps"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[6];
+ ParamDef->init("allowApexWorkBetweenSubsteps", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "The clothing module can interpolate matrices between substeps. However, for this APEX needs to call simulate/fetchResults several times per frame. This causes problems if physX particles are handled by the application in the same scene. The application needs to be able to read particle buffers with deletion IDs after each fetchResults, which is not possible in that case. Use allowApexWorkBetweenSubsteps to enable matrix interpolation between substeps.", true);
+ HintTable[1].init("shortDescription", "Allow APEX SDK to interpolate clothing matrices between the substeps.", true);
+ ParamDefTable[6].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=7, longName="interCollisionDistance"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[7];
+ ParamDef->init("interCollisionDistance", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "Experimental. Set the radius to 0.0 to disable inter-collision.", true);
+ HintTable[1].init("shortDescription", "Experimental. Radius of the collision between different clothing actors. (3.x solver mode)", true);
+ ParamDefTable[7].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=8, longName="interCollisionStiffness"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[8];
+ ParamDef->init("interCollisionStiffness", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Experimental. Stiffness of the collision between different clothing actors. (3.x solver mode)", true);
+ ParamDefTable[8].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=9, longName="interCollisionIterations"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[9];
+ ParamDef->init("interCollisionIterations", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Experimental. Number of Iterations for the collision between different clothing actors. (3.x solver mode)", true);
+ ParamDefTable[9].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=10, longName="sparseSelfCollision"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[10];
+ ParamDef->init("sparseSelfCollision", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "Experimental. The particle subset is part of the cooked data and depends on the assets selfCollision radius.", true);
+ HintTable[1].init("shortDescription", "Experimental. Only use a subset of particles for self-collision. (3.x solver mode)", true);
+ ParamDefTable[10].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=11, longName="maxTimeRenderProxyInPool"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[11];
+ ParamDef->init("maxTimeRenderProxyInPool", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Maximum number of frames a RenderProxy object can stay the object pool before the memory is released", true);
+ ParamDefTable[11].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // SetChildren for: nodeIndex=0, longName=""
+ {
+ static Definition* Children[11];
+ Children[0] = PDEF_PTR(1);
+ Children[1] = PDEF_PTR(2);
+ Children[2] = PDEF_PTR(3);
+ Children[3] = PDEF_PTR(4);
+ Children[4] = PDEF_PTR(5);
+ Children[5] = PDEF_PTR(6);
+ Children[6] = PDEF_PTR(7);
+ Children[7] = PDEF_PTR(8);
+ Children[8] = PDEF_PTR(9);
+ Children[9] = PDEF_PTR(10);
+ Children[10] = PDEF_PTR(11);
+
+ ParamDefTable[0].setChildren(Children, 11);
+ }
+
+ mBuiltFlag = true;
+
+}
+void ClothingModuleParameters::initStrings(void)
+{
+}
+
+void ClothingModuleParameters::initDynamicArrays(void)
+{
+}
+
+void ClothingModuleParameters::initDefaults(void)
+{
+
+ freeStrings();
+ freeReferences();
+ freeDynamicArrays();
+ maxNumCompartments = uint32_t(4);
+ maxUnusedPhysXResources = uint32_t(5);
+ allowAsyncCooking = bool(true);
+ asyncFetchResults = bool(true);
+ avgSimFrequencyWindow = uint32_t(60);
+ allowApexWorkBetweenSubsteps = bool(false);
+ interCollisionDistance = float(0.0);
+ interCollisionStiffness = float(1.0);
+ interCollisionIterations = uint32_t(1);
+ sparseSelfCollision = bool(false);
+ maxTimeRenderProxyInPool = uint32_t(100);
+
+ initDynamicArrays();
+ initStrings();
+ initReferences();
+}
+
+void ClothingModuleParameters::initReferences(void)
+{
+}
+
+void ClothingModuleParameters::freeDynamicArrays(void)
+{
+}
+
+void ClothingModuleParameters::freeStrings(void)
+{
+}
+
+void ClothingModuleParameters::freeReferences(void)
+{
+}
+
+} // namespace clothing
+} // namespace nvidia
diff --git a/APEX_1.4/module/clothing/src/autogen/ClothingPhysicalMeshParameters.cpp b/APEX_1.4/module/clothing/src/autogen/ClothingPhysicalMeshParameters.cpp
new file mode 100644
index 00000000..de67c1a9
--- /dev/null
+++ b/APEX_1.4/module/clothing/src/autogen/ClothingPhysicalMeshParameters.cpp
@@ -0,0 +1,2418 @@
+// 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) 2008-2015 NVIDIA Corporation. All rights reserved.
+
+// This file was generated by NvParameterized/scripts/GenParameterized.pl
+
+
+#include "ClothingPhysicalMeshParameters.h"
+#include <string.h>
+#include <stdlib.h>
+
+using namespace NvParameterized;
+
+namespace nvidia
+{
+namespace clothing
+{
+
+using namespace ClothingPhysicalMeshParametersNS;
+
+const char* const ClothingPhysicalMeshParametersFactory::vptr =
+ NvParameterized::getVptr<ClothingPhysicalMeshParameters, ClothingPhysicalMeshParameters::ClassAlignment>();
+
+const uint32_t NumParamDefs = 74;
+static NvParameterized::DefinitionImpl* ParamDefTable; // now allocated in buildTree [NumParamDefs];
+
+
+static const size_t ParamLookupChildrenTable[] =
+{
+ 1, 35, 43, 52, 53, 54, 62, 71, 72, 73, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 19, 21, 23,
+ 25, 26, 27, 29, 30, 31, 32, 33, 34, 9, 11, 13, 15, 16, 17, 18, 20, 22, 24, 28, 36,
+ 37, 38, 39, 40, 41, 42, 44, 45, 46, 47, 48, 49, 50, 51, 55, 56, 57, 58, 59, 60, 61,
+ 63, 64, 65, 66, 67, 68, 69, 70,
+};
+
+#define TENUM(type) nvidia::##type
+#define CHILDREN(index) &ParamLookupChildrenTable[index]
+static const NvParameterized::ParamLookupNode ParamLookupTable[NumParamDefs] =
+{
+ { TYPE_STRUCT, false, 0, CHILDREN(0), 10 },
+ { TYPE_STRUCT, false, (size_t)(&((ParametersStruct*)0)->physicalMesh), CHILDREN(10), 22 }, // physicalMesh
+ { TYPE_U32, false, (size_t)(&((PhysicalMesh_Type*)0)->numVertices), NULL, 0 }, // physicalMesh.numVertices
+ { TYPE_U32, false, (size_t)(&((PhysicalMesh_Type*)0)->numSimulatedVertices), NULL, 0 }, // physicalMesh.numSimulatedVertices
+ { TYPE_U32, false, (size_t)(&((PhysicalMesh_Type*)0)->numMaxDistance0Vertices), NULL, 0 }, // physicalMesh.numMaxDistance0Vertices
+ { TYPE_U32, false, (size_t)(&((PhysicalMesh_Type*)0)->numIndices), NULL, 0 }, // physicalMesh.numIndices
+ { TYPE_U32, false, (size_t)(&((PhysicalMesh_Type*)0)->numSimulatedIndices), NULL, 0 }, // physicalMesh.numSimulatedIndices
+ { TYPE_U32, false, (size_t)(&((PhysicalMesh_Type*)0)->numBonesPerVertex), NULL, 0 }, // physicalMesh.numBonesPerVertex
+ { TYPE_ARRAY, true, (size_t)(&((PhysicalMesh_Type*)0)->vertices), CHILDREN(32), 1 }, // physicalMesh.vertices
+ { TYPE_VEC3, false, 1 * sizeof(physx::PxVec3), NULL, 0 }, // physicalMesh.vertices[]
+ { TYPE_ARRAY, true, (size_t)(&((PhysicalMesh_Type*)0)->normals), CHILDREN(33), 1 }, // physicalMesh.normals
+ { TYPE_VEC3, false, 1 * sizeof(physx::PxVec3), NULL, 0 }, // physicalMesh.normals[]
+ { TYPE_ARRAY, true, (size_t)(&((PhysicalMesh_Type*)0)->skinningNormals), CHILDREN(34), 1 }, // physicalMesh.skinningNormals
+ { TYPE_VEC3, false, 1 * sizeof(physx::PxVec3), NULL, 0 }, // physicalMesh.skinningNormals[]
+ { TYPE_ARRAY, true, (size_t)(&((PhysicalMesh_Type*)0)->constrainCoefficients), CHILDREN(35), 1 }, // physicalMesh.constrainCoefficients
+ { TYPE_STRUCT, false, 1 * sizeof(ConstrainCoefficient_Type), CHILDREN(36), 3 }, // physicalMesh.constrainCoefficients[]
+ { TYPE_F32, false, (size_t)(&((ConstrainCoefficient_Type*)0)->maxDistance), NULL, 0 }, // physicalMesh.constrainCoefficients[].maxDistance
+ { TYPE_F32, false, (size_t)(&((ConstrainCoefficient_Type*)0)->collisionSphereRadius), NULL, 0 }, // physicalMesh.constrainCoefficients[].collisionSphereRadius
+ { TYPE_F32, false, (size_t)(&((ConstrainCoefficient_Type*)0)->collisionSphereDistance), NULL, 0 }, // physicalMesh.constrainCoefficients[].collisionSphereDistance
+ { TYPE_ARRAY, true, (size_t)(&((PhysicalMesh_Type*)0)->boneIndices), CHILDREN(39), 1 }, // physicalMesh.boneIndices
+ { TYPE_U16, false, 1 * sizeof(uint16_t), NULL, 0 }, // physicalMesh.boneIndices[]
+ { TYPE_ARRAY, true, (size_t)(&((PhysicalMesh_Type*)0)->boneWeights), CHILDREN(40), 1 }, // physicalMesh.boneWeights
+ { TYPE_F32, false, 1 * sizeof(float), NULL, 0 }, // physicalMesh.boneWeights[]
+ { TYPE_ARRAY, true, (size_t)(&((PhysicalMesh_Type*)0)->optimizationData), CHILDREN(41), 1 }, // physicalMesh.optimizationData
+ { TYPE_U8, false, 1 * sizeof(uint8_t), NULL, 0 }, // physicalMesh.optimizationData[]
+ { TYPE_BOOL, false, (size_t)(&((PhysicalMesh_Type*)0)->hasNegativeBackstop), NULL, 0 }, // physicalMesh.hasNegativeBackstop
+ { TYPE_BOOL, false, (size_t)(&((PhysicalMesh_Type*)0)->isClosed), NULL, 0 }, // physicalMesh.isClosed
+ { TYPE_ARRAY, true, (size_t)(&((PhysicalMesh_Type*)0)->indices), CHILDREN(42), 1 }, // physicalMesh.indices
+ { TYPE_U32, false, 1 * sizeof(uint32_t), NULL, 0 }, // physicalMesh.indices[]
+ { TYPE_F32, false, (size_t)(&((PhysicalMesh_Type*)0)->maximumMaxDistance), NULL, 0 }, // physicalMesh.maximumMaxDistance
+ { TYPE_U32, false, (size_t)(&((PhysicalMesh_Type*)0)->physicalMeshSorting), NULL, 0 }, // physicalMesh.physicalMeshSorting
+ { TYPE_F32, false, (size_t)(&((PhysicalMesh_Type*)0)->shortestEdgeLength), NULL, 0 }, // physicalMesh.shortestEdgeLength
+ { TYPE_F32, false, (size_t)(&((PhysicalMesh_Type*)0)->averageEdgeLength), NULL, 0 }, // physicalMesh.averageEdgeLength
+ { TYPE_BOOL, false, (size_t)(&((PhysicalMesh_Type*)0)->isTetrahedralMesh), NULL, 0 }, // physicalMesh.isTetrahedralMesh
+ { TYPE_BOOL, false, (size_t)(&((PhysicalMesh_Type*)0)->flipNormals), NULL, 0 }, // physicalMesh.flipNormals
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->transitionUpB), CHILDREN(43), 1 }, // transitionUpB
+ { TYPE_STRUCT, false, 1 * sizeof(SkinClothMapB_Type), CHILDREN(44), 6 }, // transitionUpB[]
+ { TYPE_VEC3, false, (size_t)(&((SkinClothMapB_Type*)0)->vtxTetraBary), NULL, 0 }, // transitionUpB[].vtxTetraBary
+ { TYPE_U32, false, (size_t)(&((SkinClothMapB_Type*)0)->vertexIndexPlusOffset), NULL, 0 }, // transitionUpB[].vertexIndexPlusOffset
+ { TYPE_VEC3, false, (size_t)(&((SkinClothMapB_Type*)0)->nrmTetraBary), NULL, 0 }, // transitionUpB[].nrmTetraBary
+ { TYPE_U32, false, (size_t)(&((SkinClothMapB_Type*)0)->faceIndex0), NULL, 0 }, // transitionUpB[].faceIndex0
+ { TYPE_U32, false, (size_t)(&((SkinClothMapB_Type*)0)->tetraIndex), NULL, 0 }, // transitionUpB[].tetraIndex
+ { TYPE_U32, false, (size_t)(&((SkinClothMapB_Type*)0)->submeshIndex), NULL, 0 }, // transitionUpB[].submeshIndex
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->transitionUp), CHILDREN(50), 1 }, // transitionUp
+ { TYPE_STRUCT, false, 1 * sizeof(SkinClothMapD_Type), CHILDREN(51), 7 }, // transitionUp[]
+ { TYPE_VEC3, false, (size_t)(&((SkinClothMapD_Type*)0)->vertexBary), NULL, 0 }, // transitionUp[].vertexBary
+ { TYPE_U32, false, (size_t)(&((SkinClothMapD_Type*)0)->vertexIndex0), NULL, 0 }, // transitionUp[].vertexIndex0
+ { TYPE_VEC3, false, (size_t)(&((SkinClothMapD_Type*)0)->normalBary), NULL, 0 }, // transitionUp[].normalBary
+ { TYPE_U32, false, (size_t)(&((SkinClothMapD_Type*)0)->vertexIndex1), NULL, 0 }, // transitionUp[].vertexIndex1
+ { TYPE_VEC3, false, (size_t)(&((SkinClothMapD_Type*)0)->tangentBary), NULL, 0 }, // transitionUp[].tangentBary
+ { TYPE_U32, false, (size_t)(&((SkinClothMapD_Type*)0)->vertexIndex2), NULL, 0 }, // transitionUp[].vertexIndex2
+ { TYPE_U32, false, (size_t)(&((SkinClothMapD_Type*)0)->vertexIndexPlusOffset), NULL, 0 }, // transitionUp[].vertexIndexPlusOffset
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->transitionUpThickness), NULL, 0 }, // transitionUpThickness
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->transitionUpOffset), NULL, 0 }, // transitionUpOffset
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->transitionDownB), CHILDREN(58), 1 }, // transitionDownB
+ { TYPE_STRUCT, false, 1 * sizeof(SkinClothMapB_Type), CHILDREN(59), 6 }, // transitionDownB[]
+ { TYPE_VEC3, false, (size_t)(&((SkinClothMapB_Type*)0)->vtxTetraBary), NULL, 0 }, // transitionDownB[].vtxTetraBary
+ { TYPE_U32, false, (size_t)(&((SkinClothMapB_Type*)0)->vertexIndexPlusOffset), NULL, 0 }, // transitionDownB[].vertexIndexPlusOffset
+ { TYPE_VEC3, false, (size_t)(&((SkinClothMapB_Type*)0)->nrmTetraBary), NULL, 0 }, // transitionDownB[].nrmTetraBary
+ { TYPE_U32, false, (size_t)(&((SkinClothMapB_Type*)0)->faceIndex0), NULL, 0 }, // transitionDownB[].faceIndex0
+ { TYPE_U32, false, (size_t)(&((SkinClothMapB_Type*)0)->tetraIndex), NULL, 0 }, // transitionDownB[].tetraIndex
+ { TYPE_U32, false, (size_t)(&((SkinClothMapB_Type*)0)->submeshIndex), NULL, 0 }, // transitionDownB[].submeshIndex
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->transitionDown), CHILDREN(65), 1 }, // transitionDown
+ { TYPE_STRUCT, false, 1 * sizeof(SkinClothMapD_Type), CHILDREN(66), 7 }, // transitionDown[]
+ { TYPE_VEC3, false, (size_t)(&((SkinClothMapD_Type*)0)->vertexBary), NULL, 0 }, // transitionDown[].vertexBary
+ { TYPE_U32, false, (size_t)(&((SkinClothMapD_Type*)0)->vertexIndex0), NULL, 0 }, // transitionDown[].vertexIndex0
+ { TYPE_VEC3, false, (size_t)(&((SkinClothMapD_Type*)0)->normalBary), NULL, 0 }, // transitionDown[].normalBary
+ { TYPE_U32, false, (size_t)(&((SkinClothMapD_Type*)0)->vertexIndex1), NULL, 0 }, // transitionDown[].vertexIndex1
+ { TYPE_VEC3, false, (size_t)(&((SkinClothMapD_Type*)0)->tangentBary), NULL, 0 }, // transitionDown[].tangentBary
+ { TYPE_U32, false, (size_t)(&((SkinClothMapD_Type*)0)->vertexIndex2), NULL, 0 }, // transitionDown[].vertexIndex2
+ { TYPE_U32, false, (size_t)(&((SkinClothMapD_Type*)0)->vertexIndexPlusOffset), NULL, 0 }, // transitionDown[].vertexIndexPlusOffset
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->transitionDownThickness), NULL, 0 }, // transitionDownThickness
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->transitionDownOffset), NULL, 0 }, // transitionDownOffset
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->referenceCount), NULL, 0 }, // referenceCount
+};
+
+
+bool ClothingPhysicalMeshParameters::mBuiltFlag = false;
+NvParameterized::MutexType ClothingPhysicalMeshParameters::mBuiltFlagMutex;
+
+ClothingPhysicalMeshParameters::ClothingPhysicalMeshParameters(NvParameterized::Traits* traits, void* buf, int32_t* refCount) :
+ NvParameters(traits, buf, refCount)
+{
+ //mParameterizedTraits->registerFactory(className(), &ClothingPhysicalMeshParametersFactoryInst);
+
+ if (!buf) //Do not init data if it is inplace-deserialized
+ {
+ initDynamicArrays();
+ initStrings();
+ initReferences();
+ initDefaults();
+ }
+}
+
+ClothingPhysicalMeshParameters::~ClothingPhysicalMeshParameters()
+{
+ freeStrings();
+ freeReferences();
+ freeDynamicArrays();
+}
+
+void ClothingPhysicalMeshParameters::destroy()
+{
+ // We cache these fields here to avoid overwrite in destructor
+ bool doDeallocateSelf = mDoDeallocateSelf;
+ NvParameterized::Traits* traits = mParameterizedTraits;
+ int32_t* refCount = mRefCount;
+ void* buf = mBuffer;
+
+ this->~ClothingPhysicalMeshParameters();
+
+ NvParameters::destroy(this, traits, doDeallocateSelf, refCount, buf);
+}
+
+const NvParameterized::DefinitionImpl* ClothingPhysicalMeshParameters::getParameterDefinitionTree(void)
+{
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+ if (!mBuiltFlag)
+ {
+ buildTree();
+ }
+ }
+
+ return(&ParamDefTable[0]);
+}
+
+const NvParameterized::DefinitionImpl* ClothingPhysicalMeshParameters::getParameterDefinitionTree(void) const
+{
+ ClothingPhysicalMeshParameters* tmpParam = const_cast<ClothingPhysicalMeshParameters*>(this);
+
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+ if (!mBuiltFlag)
+ {
+ tmpParam->buildTree();
+ }
+ }
+
+ return(&ParamDefTable[0]);
+}
+
+NvParameterized::ErrorType ClothingPhysicalMeshParameters::getParameterHandle(const char* long_name, Handle& handle) const
+{
+ ErrorType Ret = NvParameters::getParameterHandle(long_name, handle);
+ if (Ret != ERROR_NONE)
+ {
+ return(Ret);
+ }
+
+ size_t offset;
+ void* ptr;
+
+ getVarPtr(handle, ptr, offset);
+
+ if (ptr == NULL)
+ {
+ return(ERROR_INDEX_OUT_OF_RANGE);
+ }
+
+ return(ERROR_NONE);
+}
+
+NvParameterized::ErrorType ClothingPhysicalMeshParameters::getParameterHandle(const char* long_name, Handle& handle)
+{
+ ErrorType Ret = NvParameters::getParameterHandle(long_name, handle);
+ if (Ret != ERROR_NONE)
+ {
+ return(Ret);
+ }
+
+ size_t offset;
+ void* ptr;
+
+ getVarPtr(handle, ptr, offset);
+
+ if (ptr == NULL)
+ {
+ return(ERROR_INDEX_OUT_OF_RANGE);
+ }
+
+ return(ERROR_NONE);
+}
+
+void ClothingPhysicalMeshParameters::getVarPtr(const Handle& handle, void*& ptr, size_t& offset) const
+{
+ ptr = getVarPtrHelper(&ParamLookupTable[0], const_cast<ClothingPhysicalMeshParameters::ParametersStruct*>(&parameters()), handle, offset);
+}
+
+
+/* Dynamic Handle Indices */
+
+void ClothingPhysicalMeshParameters::freeParameterDefinitionTable(NvParameterized::Traits* traits)
+{
+ if (!traits)
+ {
+ return;
+ }
+
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ return;
+ }
+
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+
+ if (!mBuiltFlag)
+ {
+ return;
+ }
+
+ for (uint32_t i = 0; i < NumParamDefs; ++i)
+ {
+ ParamDefTable[i].~DefinitionImpl();
+ }
+
+ traits->free(ParamDefTable);
+
+ mBuiltFlag = false;
+}
+
+#define PDEF_PTR(index) (&ParamDefTable[index])
+
+void ClothingPhysicalMeshParameters::buildTree(void)
+{
+
+ uint32_t allocSize = sizeof(NvParameterized::DefinitionImpl) * NumParamDefs;
+ ParamDefTable = (NvParameterized::DefinitionImpl*)(mParameterizedTraits->alloc(allocSize));
+ memset(ParamDefTable, 0, allocSize);
+
+ for (uint32_t i = 0; i < NumParamDefs; ++i)
+ {
+ NV_PARAM_PLACEMENT_NEW(ParamDefTable + i, NvParameterized::DefinitionImpl)(*mParameterizedTraits);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=0, longName=""
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[0];
+ ParamDef->init("", TYPE_STRUCT, "STRUCT", true);
+
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=1, longName="physicalMesh"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[1];
+ ParamDef->init("physicalMesh", TYPE_STRUCT, "PhysicalMesh", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The physical mesh data.", true);
+ ParamDefTable[1].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=2, longName="physicalMesh.numVertices"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[2];
+ ParamDef->init("numVertices", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Number of vertices of this mesh", true);
+ ParamDefTable[2].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=3, longName="physicalMesh.numSimulatedVertices"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[3];
+ ParamDef->init("numSimulatedVertices", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Number of simulated vertices of this mesh", true);
+ ParamDefTable[3].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=4, longName="physicalMesh.numMaxDistance0Vertices"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[4];
+ ParamDef->init("numMaxDistance0Vertices", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Number of vertices that have max distance set to 0", true);
+ ParamDefTable[4].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=5, longName="physicalMesh.numIndices"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[5];
+ ParamDef->init("numIndices", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Number of indices of this mesh", true);
+ ParamDefTable[5].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=6, longName="physicalMesh.numSimulatedIndices"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[6];
+ ParamDef->init("numSimulatedIndices", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Number of simulated indices of this mesh", true);
+ ParamDefTable[6].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=7, longName="physicalMesh.numBonesPerVertex"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[7];
+ ParamDef->init("numBonesPerVertex", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Number of bone weights/indices per vertex", true);
+ ParamDefTable[7].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=8, longName="physicalMesh.vertices"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[8];
+ ParamDef->init("vertices", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ ParamDefTable[8].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ HintTable[1].init("shortDescription", "Array of vertices", true);
+ ParamDefTable[8].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+ ParamDefTable[8].setAlignment(16);
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=9, longName="physicalMesh.vertices[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[9];
+ ParamDef->init("vertices", TYPE_VEC3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ ParamDefTable[9].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ HintTable[1].init("shortDescription", "Array of vertices", true);
+ ParamDefTable[9].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=10, longName="physicalMesh.normals"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[10];
+ ParamDef->init("normals", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ ParamDefTable[10].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ HintTable[1].init("longDescription", "These are the normals provided by the user. The mesh-mesh skinning will try to restore them as good\nas possible throughout simulation. Note, they can differ from the skinningNormals quite drastically.\n", true);
+ HintTable[2].init("shortDescription", "Array of normals", true);
+ ParamDefTable[10].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+ ParamDefTable[10].setAlignment(16);
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=11, longName="physicalMesh.normals[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[11];
+ ParamDef->init("normals", TYPE_VEC3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ ParamDefTable[11].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ HintTable[1].init("longDescription", "These are the normals provided by the user. The mesh-mesh skinning will try to restore them as good\nas possible throughout simulation. Note, they can differ from the skinningNormals quite drastically.\n", true);
+ HintTable[2].init("shortDescription", "Array of normals", true);
+ ParamDefTable[11].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=12, longName="physicalMesh.skinningNormals"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[12];
+ ParamDef->init("skinningNormals", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ ParamDefTable[12].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ HintTable[1].init("longDescription", "These are the normals of the original mesh. They reflect what should come out of physics but the output\ncan be distorted because parts of the simulation mesh are turned off, resulting in wrong normal computation.\nThey are needed for the flags.CorrectSimulationNormals actorflag.\n", true);
+ HintTable[2].init("shortDescription", "Array of skinning normals", true);
+ ParamDefTable[12].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+ ParamDefTable[12].setAlignment(16);
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=13, longName="physicalMesh.skinningNormals[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[13];
+ ParamDef->init("skinningNormals", TYPE_VEC3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ ParamDefTable[13].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ HintTable[1].init("longDescription", "These are the normals of the original mesh. They reflect what should come out of physics but the output\ncan be distorted because parts of the simulation mesh are turned off, resulting in wrong normal computation.\nThey are needed for the flags.CorrectSimulationNormals actorflag.\n", true);
+ HintTable[2].init("shortDescription", "Array of skinning normals", true);
+ ParamDefTable[13].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=14, longName="physicalMesh.constrainCoefficients"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[14];
+ ParamDef->init("constrainCoefficients", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ ParamDefTable[14].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ HintTable[1].init("longDescription", "These are not provided but computed by copying values from the graphical mesh to the physical mesh.\n", true);
+ HintTable[2].init("shortDescription", "The clothing constrain coefficients for this mesh.", true);
+ ParamDefTable[14].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+ ParamDefTable[14].setAlignment(16);
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=15, longName="physicalMesh.constrainCoefficients[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[15];
+ ParamDef->init("constrainCoefficients", TYPE_STRUCT, "ConstrainCoefficient", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ ParamDefTable[15].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ HintTable[1].init("longDescription", "These are not provided but computed by copying values from the graphical mesh to the physical mesh.\n", true);
+ HintTable[2].init("shortDescription", "The clothing constrain coefficients for this mesh.", true);
+ ParamDefTable[15].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=16, longName="physicalMesh.constrainCoefficients[].maxDistance"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[16];
+ ParamDef->init("maxDistance", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Maximum distance this vertex is allowed to travel from its skinned position.", true);
+ ParamDefTable[16].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=17, longName="physicalMesh.constrainCoefficients[].collisionSphereRadius"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[17];
+ ParamDef->init("collisionSphereRadius", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Size of the Backstop collision sphere.", true);
+ ParamDefTable[17].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=18, longName="physicalMesh.constrainCoefficients[].collisionSphereDistance"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[18];
+ ParamDef->init("collisionSphereDistance", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Distance of the Backstop collision sphere.", true);
+ ParamDefTable[18].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=19, longName="physicalMesh.boneIndices"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[19];
+ ParamDef->init("boneIndices", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ ParamDefTable[19].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ HintTable[1].init("longDescription", "Note: contains numVertices * numBonesPerVertex elements.\n", true);
+ HintTable[2].init("shortDescription", "The bone indices per vertex", true);
+ ParamDefTable[19].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+ ParamDefTable[19].setAlignment(16);
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=20, longName="physicalMesh.boneIndices[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[20];
+ ParamDef->init("boneIndices", TYPE_U16, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ ParamDefTable[20].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ HintTable[1].init("longDescription", "Note: contains numVertices * numBonesPerVertex elements.\n", true);
+ HintTable[2].init("shortDescription", "The bone indices per vertex", true);
+ ParamDefTable[20].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=21, longName="physicalMesh.boneWeights"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[21];
+ ParamDef->init("boneWeights", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ ParamDefTable[21].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ HintTable[1].init("longDescription", "Note: contains numVertices * numBonesPerVertex elements.\n", true);
+ HintTable[2].init("shortDescription", "The bone weights per vertex", true);
+ ParamDefTable[21].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+ ParamDefTable[21].setAlignment(16);
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=22, longName="physicalMesh.boneWeights[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[22];
+ ParamDef->init("boneWeights", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ ParamDefTable[22].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ HintTable[1].init("longDescription", "Note: contains numVertices * numBonesPerVertex elements.\n", true);
+ HintTable[2].init("shortDescription", "The bone weights per vertex", true);
+ ParamDefTable[22].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=23, longName="physicalMesh.optimizationData"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[23];
+ ParamDef->init("optimizationData", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ ParamDefTable[23].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ HintTable[1].init("longDescription", "Each byte contains info for 2 vertices.\nbits 0-3: number of actual bones for that vertex (with boneWeight > 0)\nbit 4: set if that vertex has a negative backstop\nbits 5-7: same data for next vertex\n", true);
+ HintTable[2].init("shortDescription", "Per Vertex Number of boneweights > 0, bool if it has negative collision distance", true);
+ ParamDefTable[23].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+ ParamDefTable[23].setAlignment(16);
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=24, longName="physicalMesh.optimizationData[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[24];
+ ParamDef->init("optimizationData", TYPE_U8, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ ParamDefTable[24].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ HintTable[1].init("longDescription", "Each byte contains info for 2 vertices.\nbits 0-3: number of actual bones for that vertex (with boneWeight > 0)\nbit 4: set if that vertex has a negative backstop\nbits 5-7: same data for next vertex\n", true);
+ HintTable[2].init("shortDescription", "Per Vertex Number of boneweights > 0, bool if it has negative collision distance", true);
+ ParamDefTable[24].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=25, longName="physicalMesh.hasNegativeBackstop"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[25];
+ ParamDef->init("hasNegativeBackstop", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "True if at least 1 has negative collision distance", true);
+ ParamDefTable[25].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=26, longName="physicalMesh.isClosed"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[26];
+ ParamDef->init("isClosed", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "True if all edges have two adjacent triangles", true);
+ ParamDefTable[26].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=27, longName="physicalMesh.indices"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[27];
+ ParamDef->init("indices", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ ParamDefTable[27].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ HintTable[1].init("shortDescription", "The index buffer", true);
+ ParamDefTable[27].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+ ParamDefTable[27].setAlignment(16);
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=28, longName="physicalMesh.indices[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[28];
+ ParamDef->init("indices", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ ParamDefTable[28].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("NOPVD", uint64_t(1), true);
+ HintTable[1].init("shortDescription", "The index buffer", true);
+ ParamDefTable[28].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=29, longName="physicalMesh.maximumMaxDistance"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[29];
+ ParamDef->init("maximumMaxDistance", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The maximum max-distance value for all the vertices.", true);
+ ParamDefTable[29].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=30, longName="physicalMesh.physicalMeshSorting"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[30];
+ ParamDef->init("physicalMeshSorting", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Physical mesh sorting", true);
+ ParamDefTable[30].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=31, longName="physicalMesh.shortestEdgeLength"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[31];
+ ParamDef->init("shortestEdgeLength", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Mesh statistic, only needed for debug rendering.", true);
+ ParamDefTable[31].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=32, longName="physicalMesh.averageEdgeLength"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[32];
+ ParamDef->init("averageEdgeLength", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Mesh statistic, useful for selecting the thickness of the mesh-mesh skinning.", true);
+ ParamDefTable[32].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=33, longName="physicalMesh.isTetrahedralMesh"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[33];
+ ParamDef->init("isTetrahedralMesh", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Are we storing triangles or tetrahedrons in this mesh.", true);
+ ParamDefTable[33].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=34, longName="physicalMesh.flipNormals"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[34];
+ ParamDef->init("flipNormals", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "True when the model has been transformed to left-handed space.", true);
+ ParamDefTable[34].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=35, longName="transitionUpB"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[35];
+ ParamDef->init("transitionUpB", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Transition between this and the next graphical LoD.", true);
+ ParamDefTable[35].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+ ParamDefTable[35].setAlignment(16);
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=36, longName="transitionUpB[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[36];
+ ParamDef->init("transitionUpB", TYPE_STRUCT, "SkinClothMapB", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Transition between this and the next graphical LoD.", true);
+ ParamDefTable[36].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=37, longName="transitionUpB[].vtxTetraBary"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[37];
+ ParamDef->init("vtxTetraBary", TYPE_VEC3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The barycentric coordinate into the implicit tetrahedron.", true);
+ ParamDefTable[37].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=38, longName="transitionUpB[].vertexIndexPlusOffset"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[38];
+ ParamDef->init("vertexIndexPlusOffset", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The vertex index in the graphical mesh (the target index).", true);
+ ParamDefTable[38].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=39, longName="transitionUpB[].nrmTetraBary"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[39];
+ ParamDef->init("nrmTetraBary", TYPE_VEC3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The barycentric coordinate of (vertex+normal). When vertex is subtracted this will result in the normal again.", true);
+ ParamDefTable[39].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=40, longName="transitionUpB[].faceIndex0"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[40];
+ ParamDef->init("faceIndex0", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "First index of the 3 consecutive indices making the physical triangle.", true);
+ ParamDefTable[40].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=41, longName="transitionUpB[].tetraIndex"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[41];
+ ParamDef->init("tetraIndex", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Selects which of the 6 implicit tetrahedrons is used for the mapping.", true);
+ ParamDefTable[41].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=42, longName="transitionUpB[].submeshIndex"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[42];
+ ParamDef->init("submeshIndex", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("DONOTSERIALIZE", uint64_t(1), true);
+ ParamDefTable[42].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("DONOTSERIALIZE", uint64_t(1), true);
+ HintTable[1].init("longDescription", "This is only needed during the authoring stage and thus does not need to be serialized.", true);
+ HintTable[2].init("shortDescription", "Index into which Physical Submesh/LoD this element of the mapping belongs to.", true);
+ ParamDefTable[42].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=43, longName="transitionUp"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[43];
+ ParamDef->init("transitionUp", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Transition between this and the next graphical LoD.", true);
+ ParamDefTable[43].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+ ParamDefTable[43].setAlignment(16);
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=44, longName="transitionUp[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[44];
+ ParamDef->init("transitionUp", TYPE_STRUCT, "SkinClothMapD", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Transition between this and the next graphical LoD.", true);
+ ParamDefTable[44].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=45, longName="transitionUp[].vertexBary"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[45];
+ ParamDef->init("vertexBary", TYPE_VEC3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The barycentric coordinate into the triangle.", true);
+ ParamDefTable[45].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=46, longName="transitionUp[].vertexIndex0"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[46];
+ ParamDef->init("vertexIndex0", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Vertex index of the physics triangle.", true);
+ ParamDefTable[46].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=47, longName="transitionUp[].normalBary"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[47];
+ ParamDef->init("normalBary", TYPE_VEC3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The barycentric coordinate of (vertex+normal). When vertex is subtracted this will result in the normal again.", true);
+ ParamDefTable[47].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=48, longName="transitionUp[].vertexIndex1"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[48];
+ ParamDef->init("vertexIndex1", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Vertex index of the physics triangle.", true);
+ ParamDefTable[48].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=49, longName="transitionUp[].tangentBary"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[49];
+ ParamDef->init("tangentBary", TYPE_VEC3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The barycentric coordinate of (position+tangent). When position is subtracted this will result in the tangent again.", true);
+ ParamDefTable[49].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=50, longName="transitionUp[].vertexIndex2"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[50];
+ ParamDef->init("vertexIndex2", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Vertex index of the physics triangle.", true);
+ ParamDefTable[50].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=51, longName="transitionUp[].vertexIndexPlusOffset"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[51];
+ ParamDef->init("vertexIndexPlusOffset", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The vertex index in the graphical mesh (the target index).", true);
+ ParamDefTable[51].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=52, longName="transitionUpThickness"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[52];
+ ParamDef->init("transitionUpThickness", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The thickness of the transition map", true);
+ ParamDefTable[52].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=53, longName="transitionUpOffset"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[53];
+ ParamDef->init("transitionUpOffset", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The normal offset of the transition map", true);
+ ParamDefTable[53].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=54, longName="transitionDownB"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[54];
+ ParamDef->init("transitionDownB", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Transition between this and the previous graphical LoD.", true);
+ ParamDefTable[54].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+ ParamDefTable[54].setAlignment(16);
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=55, longName="transitionDownB[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[55];
+ ParamDef->init("transitionDownB", TYPE_STRUCT, "SkinClothMapB", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Transition between this and the previous graphical LoD.", true);
+ ParamDefTable[55].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=56, longName="transitionDownB[].vtxTetraBary"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[56];
+ ParamDef->init("vtxTetraBary", TYPE_VEC3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The barycentric coordinate into the implicit tetrahedron.", true);
+ ParamDefTable[56].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=57, longName="transitionDownB[].vertexIndexPlusOffset"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[57];
+ ParamDef->init("vertexIndexPlusOffset", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The vertex index in the graphical mesh (the target index).", true);
+ ParamDefTable[57].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=58, longName="transitionDownB[].nrmTetraBary"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[58];
+ ParamDef->init("nrmTetraBary", TYPE_VEC3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The barycentric coordinate of (vertex+normal). When vertex is subtracted this will result in the normal again.", true);
+ ParamDefTable[58].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=59, longName="transitionDownB[].faceIndex0"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[59];
+ ParamDef->init("faceIndex0", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "First index of the 3 consecutive indices making the physical triangle.", true);
+ ParamDefTable[59].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=60, longName="transitionDownB[].tetraIndex"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[60];
+ ParamDef->init("tetraIndex", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Selects which of the 6 implicit tetrahedrons is used for the mapping.", true);
+ ParamDefTable[60].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=61, longName="transitionDownB[].submeshIndex"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[61];
+ ParamDef->init("submeshIndex", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("DONOTSERIALIZE", uint64_t(1), true);
+ ParamDefTable[61].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("DONOTSERIALIZE", uint64_t(1), true);
+ HintTable[1].init("longDescription", "This is only needed during the authoring stage and thus does not need to be serialized.", true);
+ HintTable[2].init("shortDescription", "Index into which Physical Submesh/LoD this element of the mapping belongs to.", true);
+ ParamDefTable[61].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=62, longName="transitionDown"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[62];
+ ParamDef->init("transitionDown", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Transition between this and the previous graphical LoD.", true);
+ ParamDefTable[62].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+ ParamDefTable[62].setAlignment(16);
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=63, longName="transitionDown[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[63];
+ ParamDef->init("transitionDown", TYPE_STRUCT, "SkinClothMapD", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Transition between this and the previous graphical LoD.", true);
+ ParamDefTable[63].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=64, longName="transitionDown[].vertexBary"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[64];
+ ParamDef->init("vertexBary", TYPE_VEC3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The barycentric coordinate into the triangle.", true);
+ ParamDefTable[64].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=65, longName="transitionDown[].vertexIndex0"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[65];
+ ParamDef->init("vertexIndex0", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Vertex index of the physics triangle.", true);
+ ParamDefTable[65].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=66, longName="transitionDown[].normalBary"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[66];
+ ParamDef->init("normalBary", TYPE_VEC3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The barycentric coordinate of (vertex+normal). When vertex is subtracted this will result in the normal again.", true);
+ ParamDefTable[66].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=67, longName="transitionDown[].vertexIndex1"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[67];
+ ParamDef->init("vertexIndex1", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Vertex index of the physics triangle.", true);
+ ParamDefTable[67].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=68, longName="transitionDown[].tangentBary"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[68];
+ ParamDef->init("tangentBary", TYPE_VEC3, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The barycentric coordinate of (position+tangent). When position is subtracted this will result in the tangent again.", true);
+ ParamDefTable[68].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=69, longName="transitionDown[].vertexIndex2"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[69];
+ ParamDef->init("vertexIndex2", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Vertex index of the physics triangle.", true);
+ ParamDefTable[69].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=70, longName="transitionDown[].vertexIndexPlusOffset"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[70];
+ ParamDef->init("vertexIndexPlusOffset", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The vertex index in the graphical mesh (the target index).", true);
+ ParamDefTable[70].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=71, longName="transitionDownThickness"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[71];
+ ParamDef->init("transitionDownThickness", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The thickness of the transition map", true);
+ ParamDefTable[71].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=72, longName="transitionDownOffset"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[72];
+ ParamDef->init("transitionDownOffset", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "The normal offset of the transition map", true);
+ ParamDefTable[72].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=73, longName="referenceCount"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[73];
+ ParamDef->init("referenceCount", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("READONLY", uint64_t(1), true);
+ ParamDefTable[73].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("READONLY", uint64_t(1), true);
+ HintTable[1].init("shortDescription", "Only used internally, do not modify", true);
+ ParamDefTable[73].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // SetChildren for: nodeIndex=0, longName=""
+ {
+ static Definition* Children[10];
+ Children[0] = PDEF_PTR(1);
+ Children[1] = PDEF_PTR(35);
+ Children[2] = PDEF_PTR(43);
+ Children[3] = PDEF_PTR(52);
+ Children[4] = PDEF_PTR(53);
+ Children[5] = PDEF_PTR(54);
+ Children[6] = PDEF_PTR(62);
+ Children[7] = PDEF_PTR(71);
+ Children[8] = PDEF_PTR(72);
+ Children[9] = PDEF_PTR(73);
+
+ ParamDefTable[0].setChildren(Children, 10);
+ }
+
+ // SetChildren for: nodeIndex=1, longName="physicalMesh"
+ {
+ static Definition* Children[22];
+ Children[0] = PDEF_PTR(2);
+ Children[1] = PDEF_PTR(3);
+ Children[2] = PDEF_PTR(4);
+ Children[3] = PDEF_PTR(5);
+ Children[4] = PDEF_PTR(6);
+ Children[5] = PDEF_PTR(7);
+ Children[6] = PDEF_PTR(8);
+ Children[7] = PDEF_PTR(10);
+ Children[8] = PDEF_PTR(12);
+ Children[9] = PDEF_PTR(14);
+ Children[10] = PDEF_PTR(19);
+ Children[11] = PDEF_PTR(21);
+ Children[12] = PDEF_PTR(23);
+ Children[13] = PDEF_PTR(25);
+ Children[14] = PDEF_PTR(26);
+ Children[15] = PDEF_PTR(27);
+ Children[16] = PDEF_PTR(29);
+ Children[17] = PDEF_PTR(30);
+ Children[18] = PDEF_PTR(31);
+ Children[19] = PDEF_PTR(32);
+ Children[20] = PDEF_PTR(33);
+ Children[21] = PDEF_PTR(34);
+
+ ParamDefTable[1].setChildren(Children, 22);
+ }
+
+ // SetChildren for: nodeIndex=8, longName="physicalMesh.vertices"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(9);
+
+ ParamDefTable[8].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=10, longName="physicalMesh.normals"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(11);
+
+ ParamDefTable[10].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=12, longName="physicalMesh.skinningNormals"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(13);
+
+ ParamDefTable[12].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=14, longName="physicalMesh.constrainCoefficients"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(15);
+
+ ParamDefTable[14].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=15, longName="physicalMesh.constrainCoefficients[]"
+ {
+ static Definition* Children[3];
+ Children[0] = PDEF_PTR(16);
+ Children[1] = PDEF_PTR(17);
+ Children[2] = PDEF_PTR(18);
+
+ ParamDefTable[15].setChildren(Children, 3);
+ }
+
+ // SetChildren for: nodeIndex=19, longName="physicalMesh.boneIndices"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(20);
+
+ ParamDefTable[19].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=21, longName="physicalMesh.boneWeights"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(22);
+
+ ParamDefTable[21].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=23, longName="physicalMesh.optimizationData"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(24);
+
+ ParamDefTable[23].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=27, longName="physicalMesh.indices"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(28);
+
+ ParamDefTable[27].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=35, longName="transitionUpB"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(36);
+
+ ParamDefTable[35].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=36, longName="transitionUpB[]"
+ {
+ static Definition* Children[6];
+ Children[0] = PDEF_PTR(37);
+ Children[1] = PDEF_PTR(38);
+ Children[2] = PDEF_PTR(39);
+ Children[3] = PDEF_PTR(40);
+ Children[4] = PDEF_PTR(41);
+ Children[5] = PDEF_PTR(42);
+
+ ParamDefTable[36].setChildren(Children, 6);
+ }
+
+ // SetChildren for: nodeIndex=43, longName="transitionUp"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(44);
+
+ ParamDefTable[43].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=44, longName="transitionUp[]"
+ {
+ static Definition* Children[7];
+ Children[0] = PDEF_PTR(45);
+ Children[1] = PDEF_PTR(46);
+ Children[2] = PDEF_PTR(47);
+ Children[3] = PDEF_PTR(48);
+ Children[4] = PDEF_PTR(49);
+ Children[5] = PDEF_PTR(50);
+ Children[6] = PDEF_PTR(51);
+
+ ParamDefTable[44].setChildren(Children, 7);
+ }
+
+ // SetChildren for: nodeIndex=54, longName="transitionDownB"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(55);
+
+ ParamDefTable[54].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=55, longName="transitionDownB[]"
+ {
+ static Definition* Children[6];
+ Children[0] = PDEF_PTR(56);
+ Children[1] = PDEF_PTR(57);
+ Children[2] = PDEF_PTR(58);
+ Children[3] = PDEF_PTR(59);
+ Children[4] = PDEF_PTR(60);
+ Children[5] = PDEF_PTR(61);
+
+ ParamDefTable[55].setChildren(Children, 6);
+ }
+
+ // SetChildren for: nodeIndex=62, longName="transitionDown"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(63);
+
+ ParamDefTable[62].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=63, longName="transitionDown[]"
+ {
+ static Definition* Children[7];
+ Children[0] = PDEF_PTR(64);
+ Children[1] = PDEF_PTR(65);
+ Children[2] = PDEF_PTR(66);
+ Children[3] = PDEF_PTR(67);
+ Children[4] = PDEF_PTR(68);
+ Children[5] = PDEF_PTR(69);
+ Children[6] = PDEF_PTR(70);
+
+ ParamDefTable[63].setChildren(Children, 7);
+ }
+
+ mBuiltFlag = true;
+
+}
+void ClothingPhysicalMeshParameters::initStrings(void)
+{
+}
+
+void ClothingPhysicalMeshParameters::initDynamicArrays(void)
+{
+ physicalMesh.vertices.buf = NULL;
+ physicalMesh.vertices.isAllocated = true;
+ physicalMesh.vertices.elementSize = sizeof(physx::PxVec3);
+ physicalMesh.vertices.arraySizes[0] = 0;
+ physicalMesh.normals.buf = NULL;
+ physicalMesh.normals.isAllocated = true;
+ physicalMesh.normals.elementSize = sizeof(physx::PxVec3);
+ physicalMesh.normals.arraySizes[0] = 0;
+ physicalMesh.skinningNormals.buf = NULL;
+ physicalMesh.skinningNormals.isAllocated = true;
+ physicalMesh.skinningNormals.elementSize = sizeof(physx::PxVec3);
+ physicalMesh.skinningNormals.arraySizes[0] = 0;
+ physicalMesh.constrainCoefficients.buf = NULL;
+ physicalMesh.constrainCoefficients.isAllocated = true;
+ physicalMesh.constrainCoefficients.elementSize = sizeof(ConstrainCoefficient_Type);
+ physicalMesh.constrainCoefficients.arraySizes[0] = 0;
+ physicalMesh.boneIndices.buf = NULL;
+ physicalMesh.boneIndices.isAllocated = true;
+ physicalMesh.boneIndices.elementSize = sizeof(uint16_t);
+ physicalMesh.boneIndices.arraySizes[0] = 0;
+ physicalMesh.boneWeights.buf = NULL;
+ physicalMesh.boneWeights.isAllocated = true;
+ physicalMesh.boneWeights.elementSize = sizeof(float);
+ physicalMesh.boneWeights.arraySizes[0] = 0;
+ physicalMesh.optimizationData.buf = NULL;
+ physicalMesh.optimizationData.isAllocated = true;
+ physicalMesh.optimizationData.elementSize = sizeof(uint8_t);
+ physicalMesh.optimizationData.arraySizes[0] = 0;
+ physicalMesh.indices.buf = NULL;
+ physicalMesh.indices.isAllocated = true;
+ physicalMesh.indices.elementSize = sizeof(uint32_t);
+ physicalMesh.indices.arraySizes[0] = 0;
+ transitionUpB.buf = NULL;
+ transitionUpB.isAllocated = true;
+ transitionUpB.elementSize = sizeof(SkinClothMapB_Type);
+ transitionUpB.arraySizes[0] = 0;
+ transitionUp.buf = NULL;
+ transitionUp.isAllocated = true;
+ transitionUp.elementSize = sizeof(SkinClothMapD_Type);
+ transitionUp.arraySizes[0] = 0;
+ transitionDownB.buf = NULL;
+ transitionDownB.isAllocated = true;
+ transitionDownB.elementSize = sizeof(SkinClothMapB_Type);
+ transitionDownB.arraySizes[0] = 0;
+ transitionDown.buf = NULL;
+ transitionDown.isAllocated = true;
+ transitionDown.elementSize = sizeof(SkinClothMapD_Type);
+ transitionDown.arraySizes[0] = 0;
+}
+
+void ClothingPhysicalMeshParameters::initDefaults(void)
+{
+
+ freeStrings();
+ freeReferences();
+ freeDynamicArrays();
+ physicalMesh.numVertices = uint32_t(0);
+ physicalMesh.numSimulatedVertices = uint32_t(0);
+ physicalMesh.numIndices = uint32_t(0);
+ physicalMesh.numSimulatedIndices = uint32_t(0);
+ physicalMesh.numBonesPerVertex = uint32_t(0);
+ physicalMesh.hasNegativeBackstop = bool(false);
+ physicalMesh.isClosed = bool(false);
+ physicalMesh.maximumMaxDistance = float(0);
+ physicalMesh.physicalMeshSorting = uint32_t(0);
+ physicalMesh.shortestEdgeLength = float(0);
+ physicalMesh.averageEdgeLength = float(0);
+ physicalMesh.isTetrahedralMesh = bool(false);
+ physicalMesh.flipNormals = bool(false);
+ transitionUpThickness = float(0);
+ transitionUpOffset = float(0);
+ transitionDownThickness = float(0);
+ transitionDownOffset = float(0);
+ referenceCount = uint32_t(0);
+
+ initDynamicArrays();
+ initStrings();
+ initReferences();
+}
+
+void ClothingPhysicalMeshParameters::initReferences(void)
+{
+}
+
+void ClothingPhysicalMeshParameters::freeDynamicArrays(void)
+{
+ if (physicalMesh.vertices.isAllocated && physicalMesh.vertices.buf)
+ {
+ mParameterizedTraits->free(physicalMesh.vertices.buf);
+ }
+ if (physicalMesh.normals.isAllocated && physicalMesh.normals.buf)
+ {
+ mParameterizedTraits->free(physicalMesh.normals.buf);
+ }
+ if (physicalMesh.skinningNormals.isAllocated && physicalMesh.skinningNormals.buf)
+ {
+ mParameterizedTraits->free(physicalMesh.skinningNormals.buf);
+ }
+ if (physicalMesh.constrainCoefficients.isAllocated && physicalMesh.constrainCoefficients.buf)
+ {
+ mParameterizedTraits->free(physicalMesh.constrainCoefficients.buf);
+ }
+ if (physicalMesh.boneIndices.isAllocated && physicalMesh.boneIndices.buf)
+ {
+ mParameterizedTraits->free(physicalMesh.boneIndices.buf);
+ }
+ if (physicalMesh.boneWeights.isAllocated && physicalMesh.boneWeights.buf)
+ {
+ mParameterizedTraits->free(physicalMesh.boneWeights.buf);
+ }
+ if (physicalMesh.optimizationData.isAllocated && physicalMesh.optimizationData.buf)
+ {
+ mParameterizedTraits->free(physicalMesh.optimizationData.buf);
+ }
+ if (physicalMesh.indices.isAllocated && physicalMesh.indices.buf)
+ {
+ mParameterizedTraits->free(physicalMesh.indices.buf);
+ }
+ if (transitionUpB.isAllocated && transitionUpB.buf)
+ {
+ mParameterizedTraits->free(transitionUpB.buf);
+ }
+ if (transitionUp.isAllocated && transitionUp.buf)
+ {
+ mParameterizedTraits->free(transitionUp.buf);
+ }
+ if (transitionDownB.isAllocated && transitionDownB.buf)
+ {
+ mParameterizedTraits->free(transitionDownB.buf);
+ }
+ if (transitionDown.isAllocated && transitionDown.buf)
+ {
+ mParameterizedTraits->free(transitionDown.buf);
+ }
+}
+
+void ClothingPhysicalMeshParameters::freeStrings(void)
+{
+}
+
+void ClothingPhysicalMeshParameters::freeReferences(void)
+{
+}
+
+} // namespace clothing
+} // namespace nvidia
diff --git a/APEX_1.4/module/clothing/src/autogen/ClothingPreviewParam.cpp b/APEX_1.4/module/clothing/src/autogen/ClothingPreviewParam.cpp
new file mode 100644
index 00000000..c1996251
--- /dev/null
+++ b/APEX_1.4/module/clothing/src/autogen/ClothingPreviewParam.cpp
@@ -0,0 +1,506 @@
+// 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) 2008-2015 NVIDIA Corporation. All rights reserved.
+
+// This file was generated by NvParameterized/scripts/GenParameterized.pl
+
+
+#include "ClothingPreviewParam.h"
+#include <string.h>
+#include <stdlib.h>
+
+using namespace NvParameterized;
+
+namespace nvidia
+{
+namespace clothing
+{
+
+using namespace ClothingPreviewParamNS;
+
+const char* const ClothingPreviewParamFactory::vptr =
+ NvParameterized::getVptr<ClothingPreviewParam, ClothingPreviewParam::ClassAlignment>();
+
+const uint32_t NumParamDefs = 8;
+static NvParameterized::DefinitionImpl* ParamDefTable; // now allocated in buildTree [NumParamDefs];
+
+
+static const size_t ParamLookupChildrenTable[] =
+{
+ 1, 2, 3, 4, 5, 6, 7,
+};
+
+#define TENUM(type) nvidia::##type
+#define CHILDREN(index) &ParamLookupChildrenTable[index]
+static const NvParameterized::ParamLookupNode ParamLookupTable[NumParamDefs] =
+{
+ { TYPE_STRUCT, false, 0, CHILDREN(0), 6 },
+ { TYPE_MAT44, false, (size_t)(&((ParametersStruct*)0)->globalPose), NULL, 0 }, // globalPose
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->fallbackSkinning), NULL, 0 }, // fallbackSkinning
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->useInternalBoneOrder), NULL, 0 }, // useInternalBoneOrder
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->updateStateWithGlobalMatrices), NULL, 0 }, // updateStateWithGlobalMatrices
+ { TYPE_U64, false, (size_t)(&((ParametersStruct*)0)->userData), NULL, 0 }, // userData
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->boneMatrices), CHILDREN(6), 1 }, // boneMatrices
+ { TYPE_MAT44, false, 1 * sizeof(physx::PxMat44), NULL, 0 }, // boneMatrices[]
+};
+
+
+bool ClothingPreviewParam::mBuiltFlag = false;
+NvParameterized::MutexType ClothingPreviewParam::mBuiltFlagMutex;
+
+ClothingPreviewParam::ClothingPreviewParam(NvParameterized::Traits* traits, void* buf, int32_t* refCount) :
+ NvParameters(traits, buf, refCount)
+{
+ //mParameterizedTraits->registerFactory(className(), &ClothingPreviewParamFactoryInst);
+
+ if (!buf) //Do not init data if it is inplace-deserialized
+ {
+ initDynamicArrays();
+ initStrings();
+ initReferences();
+ initDefaults();
+ }
+}
+
+ClothingPreviewParam::~ClothingPreviewParam()
+{
+ freeStrings();
+ freeReferences();
+ freeDynamicArrays();
+}
+
+void ClothingPreviewParam::destroy()
+{
+ // We cache these fields here to avoid overwrite in destructor
+ bool doDeallocateSelf = mDoDeallocateSelf;
+ NvParameterized::Traits* traits = mParameterizedTraits;
+ int32_t* refCount = mRefCount;
+ void* buf = mBuffer;
+
+ this->~ClothingPreviewParam();
+
+ NvParameters::destroy(this, traits, doDeallocateSelf, refCount, buf);
+}
+
+const NvParameterized::DefinitionImpl* ClothingPreviewParam::getParameterDefinitionTree(void)
+{
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+ if (!mBuiltFlag)
+ {
+ buildTree();
+ }
+ }
+
+ return(&ParamDefTable[0]);
+}
+
+const NvParameterized::DefinitionImpl* ClothingPreviewParam::getParameterDefinitionTree(void) const
+{
+ ClothingPreviewParam* tmpParam = const_cast<ClothingPreviewParam*>(this);
+
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+ if (!mBuiltFlag)
+ {
+ tmpParam->buildTree();
+ }
+ }
+
+ return(&ParamDefTable[0]);
+}
+
+NvParameterized::ErrorType ClothingPreviewParam::getParameterHandle(const char* long_name, Handle& handle) const
+{
+ ErrorType Ret = NvParameters::getParameterHandle(long_name, handle);
+ if (Ret != ERROR_NONE)
+ {
+ return(Ret);
+ }
+
+ size_t offset;
+ void* ptr;
+
+ getVarPtr(handle, ptr, offset);
+
+ if (ptr == NULL)
+ {
+ return(ERROR_INDEX_OUT_OF_RANGE);
+ }
+
+ return(ERROR_NONE);
+}
+
+NvParameterized::ErrorType ClothingPreviewParam::getParameterHandle(const char* long_name, Handle& handle)
+{
+ ErrorType Ret = NvParameters::getParameterHandle(long_name, handle);
+ if (Ret != ERROR_NONE)
+ {
+ return(Ret);
+ }
+
+ size_t offset;
+ void* ptr;
+
+ getVarPtr(handle, ptr, offset);
+
+ if (ptr == NULL)
+ {
+ return(ERROR_INDEX_OUT_OF_RANGE);
+ }
+
+ return(ERROR_NONE);
+}
+
+void ClothingPreviewParam::getVarPtr(const Handle& handle, void*& ptr, size_t& offset) const
+{
+ ptr = getVarPtrHelper(&ParamLookupTable[0], const_cast<ClothingPreviewParam::ParametersStruct*>(&parameters()), handle, offset);
+}
+
+
+/* Dynamic Handle Indices */
+
+void ClothingPreviewParam::freeParameterDefinitionTable(NvParameterized::Traits* traits)
+{
+ if (!traits)
+ {
+ return;
+ }
+
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ return;
+ }
+
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+
+ if (!mBuiltFlag)
+ {
+ return;
+ }
+
+ for (uint32_t i = 0; i < NumParamDefs; ++i)
+ {
+ ParamDefTable[i].~DefinitionImpl();
+ }
+
+ traits->free(ParamDefTable);
+
+ mBuiltFlag = false;
+}
+
+#define PDEF_PTR(index) (&ParamDefTable[index])
+
+void ClothingPreviewParam::buildTree(void)
+{
+
+ uint32_t allocSize = sizeof(NvParameterized::DefinitionImpl) * NumParamDefs;
+ ParamDefTable = (NvParameterized::DefinitionImpl*)(mParameterizedTraits->alloc(allocSize));
+ memset(ParamDefTable, 0, allocSize);
+
+ for (uint32_t i = 0; i < NumParamDefs; ++i)
+ {
+ NV_PARAM_PLACEMENT_NEW(ParamDefTable + i, NvParameterized::DefinitionImpl)(*mParameterizedTraits);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=0, longName=""
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[0];
+ ParamDef->init("", TYPE_STRUCT, "STRUCT", true);
+
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=1, longName="globalPose"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[1];
+ ParamDef->init("globalPose", TYPE_MAT44, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("editorDisplay", "false", true);
+ ParamDefTable[1].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("editorDisplay", "false", true);
+ HintTable[1].init("shortDescription", "The pose where the clothing asset will be put into the scene", true);
+ ParamDefTable[1].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=2, longName="fallbackSkinning"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[2];
+ ParamDef->init("fallbackSkinning", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "Performs the regular boneweighted skinning on the CPU before giving the\ndata out through the rendering API.\n", true);
+ HintTable[1].init("shortDescription", "Performs skinning in software", true);
+ ParamDefTable[2].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=3, longName="useInternalBoneOrder"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[3];
+ ParamDef->init("useInternalBoneOrder", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("editorDisplay", "false", true);
+ ParamDefTable[3].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("editorDisplay", "false", true);
+ HintTable[1].init("longDescription", "If this is set to true the bone buffers in updateState and the actor\ndescriptor have to be given in the same order as the bones are stored\ninternally in the asset. This can be queried using\nNxClothingAsset::getNumUsedBones and NxClothingAsset::getBoneName or\nNxClothingAsset::getBoneMapping.\n\nIf this is set to false, the bone buffers can be provided in the order as\nthey are stored in the application. This is either the bone order at\nauthoring time, or NxClothingAsset::remapBoneIndex can be called for each\nbone to let APEX know about the current ordering in the game. Note that\nthis is only recommended if the application already uses physx::PxMat44\n(or something binary equivalent) and does not have to convert the matrices.\n", true);
+ HintTable[2].init("shortDescription", "Expect internally ordered bone arrays in updateState call.", true);
+ ParamDefTable[3].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=4, longName="updateStateWithGlobalMatrices"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[4];
+ ParamDef->init("updateStateWithGlobalMatrices", TYPE_BOOL, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "Depending on what matrices are present, the state can be updated using\nglobal world or object space bone matrices or composite matrices. The\ncomposite matrix can be generated by multiplying the world or object space\nmatrix by the inverse bone bine pose.\n\nNote: If there are problems which might be caused by bind poses being\ndifferent in the ClothingAsset and in the game's animation system, changing\nthis to true (and thus providing global pose matrices) might fix the problem.\n", true);
+ HintTable[1].init("shortDescription", "Use world space matrices instead of composite (relative to bind pose) in NxClothingActor::updateState().", true);
+ ParamDefTable[4].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=5, longName="userData"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[5];
+ ParamDef->init("userData", TYPE_U64, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("editorDisplay", "false", true);
+ ParamDefTable[5].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("editorDisplay", "false", true);
+ HintTable[1].init("shortDescription", "Optional user data pointer associated with the clothing actor", true);
+ ParamDefTable[5].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=6, longName="boneMatrices"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[6];
+ ParamDef->init("boneMatrices", TYPE_ARRAY, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("editorDisplay", "false", true);
+ ParamDefTable[6].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("editorDisplay", "false", true);
+ HintTable[1].init("longDescription", "These matrices are sometimes referred to as composite matrices. They are the\nmultiplication of the current world space bone pose with the inverse bind\npose in world space.\nNote: If \'updateStateWithGlobalMatrices\' is set to true, these must be\nglobal poses instead.\n", true);
+ HintTable[2].init("shortDescription", "An Array of matrices with the full transform for each bone", true);
+ ParamDefTable[6].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=7, longName="boneMatrices[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[7];
+ ParamDef->init("boneMatrices", TYPE_MAT44, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("editorDisplay", "false", true);
+ ParamDefTable[7].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#else
+
+ static HintImpl HintTable[3];
+ static Hint* HintPtrTable[3] = { &HintTable[0], &HintTable[1], &HintTable[2], };
+ HintTable[0].init("editorDisplay", "false", true);
+ HintTable[1].init("longDescription", "These matrices are sometimes referred to as composite matrices. They are the\nmultiplication of the current world space bone pose with the inverse bind\npose in world space.\nNote: If \'updateStateWithGlobalMatrices\' is set to true, these must be\nglobal poses instead.\n", true);
+ HintTable[2].init("shortDescription", "An Array of matrices with the full transform for each bone", true);
+ ParamDefTable[7].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // SetChildren for: nodeIndex=0, longName=""
+ {
+ static Definition* Children[6];
+ Children[0] = PDEF_PTR(1);
+ Children[1] = PDEF_PTR(2);
+ Children[2] = PDEF_PTR(3);
+ Children[3] = PDEF_PTR(4);
+ Children[4] = PDEF_PTR(5);
+ Children[5] = PDEF_PTR(6);
+
+ ParamDefTable[0].setChildren(Children, 6);
+ }
+
+ // SetChildren for: nodeIndex=6, longName="boneMatrices"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(7);
+
+ ParamDefTable[6].setChildren(Children, 1);
+ }
+
+ mBuiltFlag = true;
+
+}
+void ClothingPreviewParam::initStrings(void)
+{
+}
+
+void ClothingPreviewParam::initDynamicArrays(void)
+{
+ boneMatrices.buf = NULL;
+ boneMatrices.isAllocated = true;
+ boneMatrices.elementSize = sizeof(physx::PxMat44);
+ boneMatrices.arraySizes[0] = 0;
+}
+
+void ClothingPreviewParam::initDefaults(void)
+{
+
+ freeStrings();
+ freeReferences();
+ freeDynamicArrays();
+ globalPose = physx::PxMat44(physx::PxVec4(1.0f));
+ fallbackSkinning = bool(false);
+ useInternalBoneOrder = bool(false);
+ updateStateWithGlobalMatrices = bool(false);
+ userData = uint64_t(0);
+
+ initDynamicArrays();
+ initStrings();
+ initReferences();
+}
+
+void ClothingPreviewParam::initReferences(void)
+{
+}
+
+void ClothingPreviewParam::freeDynamicArrays(void)
+{
+ if (boneMatrices.isAllocated && boneMatrices.buf)
+ {
+ mParameterizedTraits->free(boneMatrices.buf);
+ }
+}
+
+void ClothingPreviewParam::freeStrings(void)
+{
+}
+
+void ClothingPreviewParam::freeReferences(void)
+{
+}
+
+} // namespace clothing
+} // namespace nvidia