aboutsummaryrefslogtreecommitdiff
path: root/APEX_1.4/common
diff options
context:
space:
mode:
authorgit perforce import user <a@b>2016-10-25 12:29:14 -0600
committerSheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees>2016-10-25 18:56:37 -0500
commit3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch)
treefa6485c169e50d7415a651bf838f5bcd0fd3bfbd /APEX_1.4/common
downloadphysx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz
physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip
Initial commit:
PhysX 3.4.0 Update @ 21294896 APEX 1.4.0 Update @ 21275617 [CL 21300167]
Diffstat (limited to 'APEX_1.4/common')
-rw-r--r--APEX_1.4/common/include/ApexActor.h410
-rw-r--r--APEX_1.4/common/include/ApexAssetAuthoring.h34
-rw-r--r--APEX_1.4/common/include/ApexAssetTracker.h80
-rw-r--r--APEX_1.4/common/include/ApexAuthorableObject.h322
-rw-r--r--APEX_1.4/common/include/ApexBinaryHeap.h141
-rw-r--r--APEX_1.4/common/include/ApexCollision.h69
-rw-r--r--APEX_1.4/common/include/ApexConstrainedDistributor.h170
-rw-r--r--APEX_1.4/common/include/ApexContext.h86
-rw-r--r--APEX_1.4/common/include/ApexCuda.h375
-rw-r--r--APEX_1.4/common/include/ApexCudaDefs.h310
-rw-r--r--APEX_1.4/common/include/ApexCudaProfile.h131
-rw-r--r--APEX_1.4/common/include/ApexCudaSource.h50
-rw-r--r--APEX_1.4/common/include/ApexCudaTest.h363
-rw-r--r--APEX_1.4/common/include/ApexCudaWrapper.h1232
-rw-r--r--APEX_1.4/common/include/ApexCutil.h39
-rw-r--r--APEX_1.4/common/include/ApexFIFO.h136
-rw-r--r--APEX_1.4/common/include/ApexFind.h63
-rw-r--r--APEX_1.4/common/include/ApexGeneralizedCubeTemplates.h133
-rw-r--r--APEX_1.4/common/include/ApexGeneralizedMarchingCubes.h153
-rw-r--r--APEX_1.4/common/include/ApexGroupsFiltering.h158
-rw-r--r--APEX_1.4/common/include/ApexIsoMesh.h206
-rw-r--r--APEX_1.4/common/include/ApexLegacyModule.h170
-rw-r--r--APEX_1.4/common/include/ApexMarchingCubes.h380
-rw-r--r--APEX_1.4/common/include/ApexMath.h69
-rw-r--r--APEX_1.4/common/include/ApexMerge.h84
-rw-r--r--APEX_1.4/common/include/ApexMeshContractor.h133
-rw-r--r--APEX_1.4/common/include/ApexMeshHash.h110
-rw-r--r--APEX_1.4/common/include/ApexMirrored.h507
-rw-r--r--APEX_1.4/common/include/ApexMirroredArray.h259
-rw-r--r--APEX_1.4/common/include/ApexPermute.h69
-rw-r--r--APEX_1.4/common/include/ApexPreview.h54
-rw-r--r--APEX_1.4/common/include/ApexPvdClient.h168
-rw-r--r--APEX_1.4/common/include/ApexQuadricSimplifier.h352
-rw-r--r--APEX_1.4/common/include/ApexQuickSelectSmallestK.h81
-rw-r--r--APEX_1.4/common/include/ApexRWLockable.h126
-rw-r--r--APEX_1.4/common/include/ApexRand.h133
-rw-r--r--APEX_1.4/common/include/ApexRenderable.h79
-rw-r--r--APEX_1.4/common/include/ApexResource.h105
-rw-r--r--APEX_1.4/common/include/ApexResourceHelper.h95
-rw-r--r--APEX_1.4/common/include/ApexSDKCachedDataImpl.h85
-rw-r--r--APEX_1.4/common/include/ApexSDKHelpers.h236
-rw-r--r--APEX_1.4/common/include/ApexSDKIntl.h265
-rw-r--r--APEX_1.4/common/include/ApexShape.h263
-rw-r--r--APEX_1.4/common/include/ApexSharedUtils.h2364
-rw-r--r--APEX_1.4/common/include/ApexSimdMath.h127
-rw-r--r--APEX_1.4/common/include/ApexSubdivider.h200
-rw-r--r--APEX_1.4/common/include/ApexTest.h24
-rw-r--r--APEX_1.4/common/include/ApexTetrahedralizer.h422
-rw-r--r--APEX_1.4/common/include/AuthorableObjectIntl.h92
-rw-r--r--APEX_1.4/common/include/Cof44.h135
-rw-r--r--APEX_1.4/common/include/CurveImpl.h83
-rw-r--r--APEX_1.4/common/include/DebugColorParamsEx.h65
-rw-r--r--APEX_1.4/common/include/DeclareArray.h25
-rw-r--r--APEX_1.4/common/include/FieldBoundaryIntl.h72
-rw-r--r--APEX_1.4/common/include/FieldSamplerIntl.h144
-rw-r--r--APEX_1.4/common/include/FieldSamplerManagerIntl.h57
-rw-r--r--APEX_1.4/common/include/FieldSamplerQueryIntl.h124
-rw-r--r--APEX_1.4/common/include/FieldSamplerSceneIntl.h85
-rw-r--r--APEX_1.4/common/include/InplaceStorage.h985
-rw-r--r--APEX_1.4/common/include/InplaceTypes.h548
-rw-r--r--APEX_1.4/common/include/InplaceTypesBuilder.h86
-rw-r--r--APEX_1.4/common/include/InstancedObjectSimulationIntl.h160
-rw-r--r--APEX_1.4/common/include/IofxManagerIntl.h208
-rw-r--r--APEX_1.4/common/include/ModuleBase.h46
-rw-r--r--APEX_1.4/common/include/ModuleFieldSamplerIntl.h34
-rw-r--r--APEX_1.4/common/include/ModuleIntl.h264
-rw-r--r--APEX_1.4/common/include/ModuleIofxIntl.h35
-rw-r--r--APEX_1.4/common/include/ModuleUpdateLoader.h53
-rw-r--r--APEX_1.4/common/include/P4Info.h45
-rw-r--r--APEX_1.4/common/include/PVDParameterizedHandler.h113
-rw-r--r--APEX_1.4/common/include/PhysXObjectDescIntl.h116
-rw-r--r--APEX_1.4/common/include/ProfilerCallback.h19
-rw-r--r--APEX_1.4/common/include/RandState.h185
-rw-r--r--APEX_1.4/common/include/RandStateHelpers.h60
-rw-r--r--APEX_1.4/common/include/ReadCheck.h57
-rw-r--r--APEX_1.4/common/include/RenderAPIIntl.h515
-rw-r--r--APEX_1.4/common/include/RenderMeshAssetIntl.h124
-rw-r--r--APEX_1.4/common/include/ResourceProviderIntl.h165
-rw-r--r--APEX_1.4/common/include/SceneIntl.h133
-rw-r--r--APEX_1.4/common/include/SimplexNoise.h132
-rw-r--r--APEX_1.4/common/include/Spline.h168
-rw-r--r--APEX_1.4/common/include/TableLookup.h154
-rw-r--r--APEX_1.4/common/include/WriteCheck.h65
-rw-r--r--APEX_1.4/common/include/autogen/ConvexHullParameters.h276
-rw-r--r--APEX_1.4/common/include/autogen/DebugColorParams.h265
-rw-r--r--APEX_1.4/common/include/autogen/DebugRenderParams.h248
-rw-r--r--APEX_1.4/common/include/autogen/ModuleCommonRegistration.h120
-rw-r--r--APEX_1.4/common/include/variable_oscillator.h48
-rw-r--r--APEX_1.4/common/src/ApexActor.cpp94
-rw-r--r--APEX_1.4/common/src/ApexAssetAuthoring.cpp121
-rw-r--r--APEX_1.4/common/src/ApexAssetTracker.cpp303
-rw-r--r--APEX_1.4/common/src/ApexCollision.cpp750
-rw-r--r--APEX_1.4/common/src/ApexContext.cpp330
-rw-r--r--APEX_1.4/common/src/ApexCudaProfile.cpp332
-rw-r--r--APEX_1.4/common/src/ApexCudaTest.cpp1209
-rw-r--r--APEX_1.4/common/src/ApexGeneralizedCubeTemplates.cpp677
-rw-r--r--APEX_1.4/common/src/ApexGeneralizedMarchingCubes.cpp1222
-rw-r--r--APEX_1.4/common/src/ApexIsoMesh.cpp658
-rw-r--r--APEX_1.4/common/src/ApexMath.cpp49
-rw-r--r--APEX_1.4/common/src/ApexMeshContractor.cpp1708
-rw-r--r--APEX_1.4/common/src/ApexMeshHash.cpp297
-rw-r--r--APEX_1.4/common/src/ApexPreview.cpp49
-rw-r--r--APEX_1.4/common/src/ApexPvdClient.cpp378
-rw-r--r--APEX_1.4/common/src/ApexQuadricSimplifier.cpp1073
-rw-r--r--APEX_1.4/common/src/ApexRWLockable.cpp176
-rw-r--r--APEX_1.4/common/src/ApexResource.cpp36
-rw-r--r--APEX_1.4/common/src/ApexSDKCachedDataImpl.cpp116
-rw-r--r--APEX_1.4/common/src/ApexSDKHelpers.cpp310
-rw-r--r--APEX_1.4/common/src/ApexShape.cpp402
-rw-r--r--APEX_1.4/common/src/ApexSharedUtils.cpp4177
-rw-r--r--APEX_1.4/common/src/ApexSubdivider.cpp766
-rw-r--r--APEX_1.4/common/src/ApexTetrahedralizer.cpp1266
-rw-r--r--APEX_1.4/common/src/CurveImpl.cpp182
-rw-r--r--APEX_1.4/common/src/ModuleBase.cpp52
-rw-r--r--APEX_1.4/common/src/ModuleUpdateLoader.cpp57
-rw-r--r--APEX_1.4/common/src/PVDParameterizedHandler.cpp658
-rw-r--r--APEX_1.4/common/src/ReadCheck.cpp63
-rw-r--r--APEX_1.4/common/src/Spline.cpp176
-rw-r--r--APEX_1.4/common/src/WriteCheck.cpp62
-rw-r--r--APEX_1.4/common/src/autogen/ConvexHullParameters.cpp768
-rw-r--r--APEX_1.4/common/src/autogen/DebugColorParams.cpp1184
-rw-r--r--APEX_1.4/common/src/autogen/DebugRenderParams.cpp632
-rw-r--r--APEX_1.4/common/src/variable_oscillator.cpp95
123 files changed, 38358 insertions, 0 deletions
diff --git a/APEX_1.4/common/include/ApexActor.h b/APEX_1.4/common/include/ApexActor.h
new file mode 100644
index 00000000..08ad7b83
--- /dev/null
+++ b/APEX_1.4/common/include/ApexActor.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.
+ */
+
+
+#ifndef APEX_ACTOR_H
+#define APEX_ACTOR_H
+
+#include "ApexContext.h"
+#include "ApexRenderable.h"
+#include "ApexResource.h"
+#include "ResourceProviderIntl.h"
+#include "ApexSDK.h"
+
+#if PX_PHYSICS_VERSION_MAJOR == 3
+#include "PxActor.h"
+#include "PxShape.h"
+#include "PxFiltering.h"
+#include "PxRigidDynamic.h"
+#include "PxTransform.h"
+#include "PxRigidBodyExt.h"
+#include "../../include/Actor.h"
+#endif
+
+#define UNIQUE_ACTOR_ID 1
+
+namespace nvidia
+{
+namespace apex
+{
+
+class ApexContext;
+class RenderDebugInterface;
+class SceneIntl;
+class Asset;
+class Actor;
+
+/**
+Class that implements actor interface with its context(s)
+*/
+class ApexActor : public ApexRenderable, public ApexContext
+{
+public:
+ ApexActor();
+ ~ApexActor();
+
+ void addSelfToContext(ApexContext& ctx, ApexActor* actorPtr = NULL);
+ void updateIndex(ApexContext& ctx, uint32_t index);
+ bool findSelfInContext(ApexContext& ctx);
+
+ // Each class that derives from ApexActor should implement the following functions
+ // if it wants ActorCreationNotification and Deletion callbacks
+ virtual Asset* getAsset(void)
+ {
+ return NULL;
+ }
+ virtual void ContextActorCreationNotification(AuthObjTypeID authorableObjectType,
+ ApexActor* actorPtr)
+ {
+ PX_UNUSED(authorableObjectType);
+ PX_UNUSED(actorPtr);
+ return;
+ }
+ virtual void ContextActorDeletionNotification(AuthObjTypeID authorableObjectType,
+ ApexActor* actorPtr)
+ {
+ PX_UNUSED(authorableObjectType);
+ PX_UNUSED(actorPtr);
+ return;
+ }
+
+ // Each class that derives from ApexActor may optionally implement these functions
+ virtual Renderable* getRenderable()
+ {
+ return NULL;
+ }
+ virtual Actor* getActor()
+ {
+ return NULL;
+ }
+
+ virtual void release() = 0;
+ void destroy();
+
+#if PX_PHYSICS_VERSION_MAJOR == 3
+ virtual void setPhysXScene(PxScene* s) = 0;
+ virtual PxScene* getPhysXScene() const = 0;
+#endif
+
+ enum ActorState
+ {
+ StateEnabled,
+ StateDisabled,
+ StateEnabling,
+ StateDisabling,
+ };
+
+ /**
+ \brief Selectively enables/disables debug visualization of a specific APEX actor. Default value it true.
+ */
+ virtual void setEnableDebugVisualization(bool state)
+ {
+ mEnableDebugVisualization = state;
+ }
+
+protected:
+ bool mInRelease;
+
+ struct ContextTrack
+ {
+ uint32_t index;
+ ApexContext* ctx;
+ };
+ physx::Array<ContextTrack> mContexts;
+
+#if UNIQUE_ACTOR_ID
+ static int32_t mUniqueActorIdCounter;
+ int32_t mUniqueActorId;
+#endif
+
+ bool mEnableDebugVisualization;
+ friend class ApexContext;
+};
+
+
+
+#if PX_PHYSICS_VERSION_MAJOR == 3
+
+#define APEX_ACTOR_TEMPLATE_PARAM(_type, _name, _variable) \
+bool set##_name(_type x) \
+{ \
+ _variable = x; \
+ return is##_name##Valid(x); \
+} \
+_type get##_name() const { return _variable; }
+
+#define APEX_ACTOR_TEMPLATE_PARAM_VALID_OR_RETURN(_name, _variable) \
+if (!is##_name##Valid(_variable)) \
+{ \
+ return false; \
+}
+
+#define APEX_ACTOR_TEMPLATE_PARAM_SET_DEFAULT(_name) set##_name( getDefault##_name() );
+
+// template for PhysX3.0 actor, body and shape.
+class PhysX3DescTemplateImpl : public nvidia::PhysX3DescTemplate, public UserAllocated
+{
+public:
+ PhysX3DescTemplateImpl()
+ {
+ SetToDefault();
+ }
+ void apply(PxActor* actor) const
+ {
+ actor->setActorFlags(static_cast<physx::PxActorFlags>(actorFlags));
+ actor->setDominanceGroup(dominanceGroup);
+ actor->setOwnerClient(ownerClient);
+ PX_ASSERT(clientBehaviorBits < UINT8_MAX);
+ actor->setClientBehaviorFlags(physx::PxActorClientBehaviorFlags((uint8_t)clientBehaviorBits));
+ //actor->contactReportFlags; // must be set via call PhysX3Interface::setContactReportFlags
+ actor->userData = userData;
+ if (name)
+ {
+ actor->setName(name);
+ }
+
+ // body
+ PxRigidBody* rb = actor->is<physx::PxRigidBody>();
+ if (rb)
+ {
+ // density, user should call updateMassAndInertia when shapes are created.
+ }
+
+ PxRigidDynamic* rd = actor->is<physx::PxRigidDynamic>();
+ if (rd)
+ {
+ rd->setRigidBodyFlags(physx::PxRigidBodyFlags(bodyFlags));
+ rd->setWakeCounter(wakeUpCounter);
+ rd->setLinearDamping(linearDamping);
+ rd->setAngularDamping(angularDamping);
+ rd->setMaxAngularVelocity(maxAngularVelocity);
+ // sleepLinearVelocity attribute for deformable/cloth, see below.
+ rd->setSolverIterationCounts(solverIterationCount, velocityIterationCount);
+ rd->setContactReportThreshold(contactReportThreshold);
+ rd->setSleepThreshold(sleepThreshold);
+ }
+ }
+ void apply(PxShape* shape) const
+ {
+ shape->setFlags((physx::PxShapeFlags)shapeFlags);
+ shape->setMaterials(materials.begin(), static_cast<uint16_t>(materials.size()));
+ shape->userData = shapeUserData;
+ if (shapeName)
+ {
+ shape->setName(shapeName);
+ }
+ shape->setSimulationFilterData(simulationFilterData);
+ shape->setQueryFilterData(queryFilterData);
+ shape->setContactOffset(contactOffset);
+ shape->setRestOffset(restOffset);
+ }
+
+ APEX_ACTOR_TEMPLATE_PARAM(physx::PxDominanceGroup, DominanceGroup, dominanceGroup)
+ APEX_ACTOR_TEMPLATE_PARAM(uint8_t, ActorFlags, actorFlags)
+ APEX_ACTOR_TEMPLATE_PARAM(physx::PxClientID, OwnerClient, ownerClient)
+ APEX_ACTOR_TEMPLATE_PARAM(uint32_t, ClientBehaviorBits, clientBehaviorBits)
+ APEX_ACTOR_TEMPLATE_PARAM(uint16_t, ContactReportFlags, contactReportFlags)
+ APEX_ACTOR_TEMPLATE_PARAM(void*, UserData, userData)
+ APEX_ACTOR_TEMPLATE_PARAM(const char*, Name, name)
+
+ APEX_ACTOR_TEMPLATE_PARAM(float, Density, density)
+ APEX_ACTOR_TEMPLATE_PARAM(uint8_t, BodyFlags, bodyFlags)
+ APEX_ACTOR_TEMPLATE_PARAM(float, WakeUpCounter, wakeUpCounter)
+ APEX_ACTOR_TEMPLATE_PARAM(float, LinearDamping, linearDamping)
+ APEX_ACTOR_TEMPLATE_PARAM(float, AngularDamping, angularDamping)
+ APEX_ACTOR_TEMPLATE_PARAM(float, MaxAngularVelocity, maxAngularVelocity)
+ APEX_ACTOR_TEMPLATE_PARAM(float, SleepLinearVelocity, sleepLinearVelocity)
+ APEX_ACTOR_TEMPLATE_PARAM(uint32_t, SolverIterationCount, solverIterationCount)
+ APEX_ACTOR_TEMPLATE_PARAM(uint32_t, VelocityIterationCount, velocityIterationCount)
+ APEX_ACTOR_TEMPLATE_PARAM(float, ContactReportThreshold, contactReportThreshold)
+ APEX_ACTOR_TEMPLATE_PARAM(float, SleepThreshold, sleepLinearVelocity)
+
+ APEX_ACTOR_TEMPLATE_PARAM(uint8_t, ShapeFlags, shapeFlags)
+ APEX_ACTOR_TEMPLATE_PARAM(void*, ShapeUserData, shapeUserData)
+ APEX_ACTOR_TEMPLATE_PARAM(const char*, ShapeName, shapeName)
+ APEX_ACTOR_TEMPLATE_PARAM(physx::PxFilterData, SimulationFilterData, simulationFilterData)
+ APEX_ACTOR_TEMPLATE_PARAM(physx::PxFilterData, QueryFilterData, queryFilterData)
+ APEX_ACTOR_TEMPLATE_PARAM(float, ContactOffset, contactOffset)
+ APEX_ACTOR_TEMPLATE_PARAM(float, RestOffset, restOffset)
+ physx::PxMaterial** getMaterials(uint32_t& materialCount) const
+ {
+ materialCount = materials.size();
+ return const_cast<physx::PxMaterial**>(materials.begin());
+ }
+ bool setMaterials(physx::PxMaterial** materialArray, uint32_t materialCount)
+ {
+ const bool valid = materialArray != NULL && materialCount > 0;
+ if (!valid)
+ {
+ materials.reset();
+ }
+ else
+ {
+ materials = Array<PxMaterial*>(materialArray, materialArray + materialCount);
+ }
+ return valid;
+ }
+
+ bool isValid()
+ {
+ APEX_ACTOR_TEMPLATE_PARAM_VALID_OR_RETURN(DominanceGroup, dominanceGroup)
+ APEX_ACTOR_TEMPLATE_PARAM_VALID_OR_RETURN(ActorFlags, actorFlags)
+ APEX_ACTOR_TEMPLATE_PARAM_VALID_OR_RETURN(OwnerClient, ownerClient)
+ APEX_ACTOR_TEMPLATE_PARAM_VALID_OR_RETURN(ClientBehaviorBits, clientBehaviorBits)
+ APEX_ACTOR_TEMPLATE_PARAM_VALID_OR_RETURN(ContactReportFlags, contactReportFlags)
+ APEX_ACTOR_TEMPLATE_PARAM_VALID_OR_RETURN(UserData, userData)
+ APEX_ACTOR_TEMPLATE_PARAM_VALID_OR_RETURN(Name, name)
+
+ APEX_ACTOR_TEMPLATE_PARAM_VALID_OR_RETURN(Density, density)
+ APEX_ACTOR_TEMPLATE_PARAM_VALID_OR_RETURN(BodyFlags, bodyFlags)
+ APEX_ACTOR_TEMPLATE_PARAM_VALID_OR_RETURN(WakeUpCounter, wakeUpCounter)
+ APEX_ACTOR_TEMPLATE_PARAM_VALID_OR_RETURN(LinearDamping, linearDamping)
+ APEX_ACTOR_TEMPLATE_PARAM_VALID_OR_RETURN(AngularDamping, angularDamping)
+ APEX_ACTOR_TEMPLATE_PARAM_VALID_OR_RETURN(MaxAngularVelocity, maxAngularVelocity)
+ APEX_ACTOR_TEMPLATE_PARAM_VALID_OR_RETURN(SleepLinearVelocity, sleepLinearVelocity)
+ APEX_ACTOR_TEMPLATE_PARAM_VALID_OR_RETURN(SolverIterationCount, solverIterationCount)
+ APEX_ACTOR_TEMPLATE_PARAM_VALID_OR_RETURN(VelocityIterationCount, velocityIterationCount)
+ APEX_ACTOR_TEMPLATE_PARAM_VALID_OR_RETURN(ContactReportThreshold, contactReportThreshold)
+ APEX_ACTOR_TEMPLATE_PARAM_VALID_OR_RETURN(SleepThreshold, sleepLinearVelocity)
+
+ APEX_ACTOR_TEMPLATE_PARAM_VALID_OR_RETURN(ShapeFlags, shapeFlags)
+ APEX_ACTOR_TEMPLATE_PARAM_VALID_OR_RETURN(ShapeUserData, shapeUserData)
+ APEX_ACTOR_TEMPLATE_PARAM_VALID_OR_RETURN(ShapeName, shapeName)
+ APEX_ACTOR_TEMPLATE_PARAM_VALID_OR_RETURN(SimulationFilterData, simulationFilterData)
+ APEX_ACTOR_TEMPLATE_PARAM_VALID_OR_RETURN(QueryFilterData, queryFilterData)
+ APEX_ACTOR_TEMPLATE_PARAM_VALID_OR_RETURN(ContactOffset, contactOffset)
+ APEX_ACTOR_TEMPLATE_PARAM_VALID_OR_RETURN(RestOffset, restOffset)
+ if (materials.size() == 0)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ void SetToDefault()
+ {
+ APEX_ACTOR_TEMPLATE_PARAM_SET_DEFAULT(DominanceGroup)
+ APEX_ACTOR_TEMPLATE_PARAM_SET_DEFAULT(ActorFlags)
+ APEX_ACTOR_TEMPLATE_PARAM_SET_DEFAULT(OwnerClient)
+ APEX_ACTOR_TEMPLATE_PARAM_SET_DEFAULT(ClientBehaviorBits)
+ APEX_ACTOR_TEMPLATE_PARAM_SET_DEFAULT(ContactReportFlags)
+ APEX_ACTOR_TEMPLATE_PARAM_SET_DEFAULT(UserData)
+ APEX_ACTOR_TEMPLATE_PARAM_SET_DEFAULT(Name)
+
+ APEX_ACTOR_TEMPLATE_PARAM_SET_DEFAULT(Density)
+ APEX_ACTOR_TEMPLATE_PARAM_SET_DEFAULT(BodyFlags)
+ APEX_ACTOR_TEMPLATE_PARAM_SET_DEFAULT(WakeUpCounter)
+ APEX_ACTOR_TEMPLATE_PARAM_SET_DEFAULT(LinearDamping)
+ APEX_ACTOR_TEMPLATE_PARAM_SET_DEFAULT(AngularDamping)
+ APEX_ACTOR_TEMPLATE_PARAM_SET_DEFAULT(MaxAngularVelocity)
+ APEX_ACTOR_TEMPLATE_PARAM_SET_DEFAULT(SleepLinearVelocity)
+ APEX_ACTOR_TEMPLATE_PARAM_SET_DEFAULT(SolverIterationCount)
+ APEX_ACTOR_TEMPLATE_PARAM_SET_DEFAULT(VelocityIterationCount)
+ APEX_ACTOR_TEMPLATE_PARAM_SET_DEFAULT(ContactReportThreshold)
+ APEX_ACTOR_TEMPLATE_PARAM_SET_DEFAULT(SleepThreshold)
+
+ APEX_ACTOR_TEMPLATE_PARAM_SET_DEFAULT(ShapeFlags)
+ APEX_ACTOR_TEMPLATE_PARAM_SET_DEFAULT(ShapeUserData)
+ APEX_ACTOR_TEMPLATE_PARAM_SET_DEFAULT(ShapeName)
+ APEX_ACTOR_TEMPLATE_PARAM_SET_DEFAULT(SimulationFilterData)
+ APEX_ACTOR_TEMPLATE_PARAM_SET_DEFAULT(QueryFilterData)
+ APEX_ACTOR_TEMPLATE_PARAM_SET_DEFAULT(ContactOffset)
+ APEX_ACTOR_TEMPLATE_PARAM_SET_DEFAULT(RestOffset)
+ materials.reset();
+ }
+
+ void release()
+ {
+ delete this;
+ }
+
+public:
+ // actor
+ physx::PxDominanceGroup dominanceGroup;
+ uint8_t actorFlags;
+ physx::PxClientID ownerClient;
+ uint32_t clientBehaviorBits;
+ uint16_t contactReportFlags;
+ void* userData;
+ const char* name;
+
+ // body
+ float density;
+
+ uint8_t bodyFlags;
+ float wakeUpCounter;
+ float linearDamping;
+ float angularDamping;
+ float maxAngularVelocity;
+ float sleepLinearVelocity;
+ uint32_t solverIterationCount;
+ uint32_t velocityIterationCount;
+ float contactReportThreshold;
+ float sleepThreshold;
+
+ // shape
+ uint8_t shapeFlags;
+ Array<PxMaterial*> materials;
+ void* shapeUserData;
+ const char* shapeName;
+ PxFilterData simulationFilterData;
+ PxFilterData queryFilterData;
+ float contactOffset;
+ float restOffset;
+}; // PhysX3DescTemplateImpl
+
+class ApexActorSource
+{
+public:
+
+ // ActorSource methods
+
+ void setPhysX3Template(const PhysX3DescTemplate* desc)
+ {
+ physX3Template.set(static_cast<const PhysX3DescTemplateImpl*>(desc));
+ }
+ bool getPhysX3Template(PhysX3DescTemplate& dest) const
+ {
+ return physX3Template.get(static_cast<PhysX3DescTemplateImpl&>(dest));
+ }
+ PhysX3DescTemplate* createPhysX3DescTemplate() const
+ {
+ return PX_NEW(PhysX3DescTemplateImpl);
+ }
+
+ void modifyActor(PxRigidActor* actor) const
+ {
+ if (physX3Template.isSet)
+ {
+ physX3Template.data.apply(actor);
+ }
+ }
+ void modifyShape(PxShape* shape) const
+ {
+ if (physX3Template.isSet)
+ {
+ physX3Template.data.apply(shape);
+ }
+ }
+
+
+
+protected:
+
+ InitTemplate<PhysX3DescTemplateImpl> physX3Template;
+};
+
+#endif // PX_PHYSICS_VERSION_MAJOR == 3
+
+}
+} // end namespace nvidia::apex
+
+#endif // __APEX_ACTOR_H__
diff --git a/APEX_1.4/common/include/ApexAssetAuthoring.h b/APEX_1.4/common/include/ApexAssetAuthoring.h
new file mode 100644
index 00000000..50ab4c12
--- /dev/null
+++ b/APEX_1.4/common/include/ApexAssetAuthoring.h
@@ -0,0 +1,34 @@
+/*
+ * 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 APEX_ASSET_AUTHORING_H
+#define APEX_ASSET_AUTHORING_H
+
+#include "ApexUsingNamespace.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+
+class ApexAssetAuthoring
+{
+public:
+ virtual void setToolString(const char* toolName, const char* toolVersion, uint32_t toolChangelist);
+
+ virtual void setToolString(const char* toolString);
+};
+
+} // namespace apex
+} // namespace nvidia
+
+#endif // APEX_ASSET_AUTHORING_H \ No newline at end of file
diff --git a/APEX_1.4/common/include/ApexAssetTracker.h b/APEX_1.4/common/include/ApexAssetTracker.h
new file mode 100644
index 00000000..d3c3d94f
--- /dev/null
+++ b/APEX_1.4/common/include/ApexAssetTracker.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.
+ */
+
+
+#ifndef APEX_ASSET_TRACKER_H
+#define APEX_ASSET_TRACKER_H
+
+#include "ApexString.h"
+#include "ApexSDKIntl.h"
+#include "ResourceProviderIntl.h"
+#include "PsArray.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+class IosAsset;
+
+/* There are a couple confusing details here:
+ * 1. If you are tracking particle system or material assets, use an *authoringTypeName*
+ * of "".
+ * 2. When loading, this class checks first if the *authoringTypeName* == "" [A], it will
+ * then check the nameIdList.assetTypeName == "" [B]
+ * If A && B, use particle system namespace defined in B
+ * If A && !B, use material namespace
+ * If !A && B, use namespace specified in constructor
+ */
+class ApexAssetTracker
+{
+public:
+ ApexAssetTracker() : mSdk(0) {}
+
+ ApexAssetTracker(ApexSDKIntl* sdk, const char* authoringTypeName)
+ : mAuthoringTypeName(authoringTypeName),
+ mSdk(sdk)
+ {}
+
+ ApexAssetTracker(ApexSDKIntl* sdk)
+ : mAuthoringTypeName(""),
+ mSdk(sdk)
+ {}
+
+ ~ApexAssetTracker();
+
+ IosAsset* getIosAssetFromName(const char* iosTypeName, const char* assetName);
+ Asset* getAssetFromName(const char* assetName);
+ Asset* getMeshAssetFromName(const char* assetName, bool isOpaqueMesh);
+ bool addAssetName(const char* assetName, bool isOpaqueMesh);
+ bool addAssetName(const char* iosTypeName, const char* assetName);
+ void removeAllAssetNames();
+
+ ResID getResourceIdFromName(const char* assetName, bool isOpaqueMesh);
+
+ uint32_t forceLoadAssets();
+
+ /* one function must be implemented to fill in the name to id mappin lists */
+ //virtual void initializeAssetNameTable() = 0;
+
+ physx::Array<AssetNameIDMapping*>& getNameIdList()
+ {
+ return mNameIdList;
+ }
+
+ ApexSimpleString mAuthoringTypeName;
+ ApexSDKIntl* mSdk;
+ physx::Array<AssetNameIDMapping*> mNameIdList;
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif // APEX_ASSET_TRACKER_H
diff --git a/APEX_1.4/common/include/ApexAuthorableObject.h b/APEX_1.4/common/include/ApexAuthorableObject.h
new file mode 100644
index 00000000..6d4f1ebe
--- /dev/null
+++ b/APEX_1.4/common/include/ApexAuthorableObject.h
@@ -0,0 +1,322 @@
+/*
+ * 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 __APEXAUTHORABLEOBJECT_H__
+#define __APEXAUTHORABLEOBJECT_H__
+
+#include "Asset.h"
+
+#include "AuthorableObjectIntl.h"
+#include "nvparameterized/NvParameterizedTraits.h"
+#include "nvparameterized/NvParameterized.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+class ResourceList;
+
+/**
+ * ApexAuthorableObject
+ * This class is the implementation for AuthorableObjectIntl (except for the
+ * ApexResource stuff). It's disappointing that it has to be templated like
+ * this, but there were issues with multiple inheritance (an Resource ptr
+ * cannot be cast to an Asset ptr - Asset should inherit from Resource
+ * in the future.
+ *
+ * Template expectations:
+ * T_Module - must inherit from ModuleIntl
+ * the T_Asset type typically uses T_Module->mSdk
+ *
+ * T_Asset - T_Asset( T_Module *m, ResourceList &list, const char *name )
+ * must inherit from Asset
+ *
+ * T_AssetAuthoring - T_AssetAuthoring( T_Module *m, ResourceList &list )
+ * must inherit from AssetAuthoring
+ */
+
+template <class T_Module, class T_Asset, class T_AssetAuthoring>
+class ApexAuthorableObject : public AuthorableObjectIntl
+{
+public:
+ ApexAuthorableObject(ModuleIntl* m, ResourceList& list)
+ : AuthorableObjectIntl(m, list, T_Asset::getClassName())
+ {
+ // Register the authorable object type name in the NRP
+ mAOResID = GetInternalApexSDK()->getInternalResourceProvider()->createNameSpace(mAOTypeName.c_str());
+ mAOPtrResID = GetInternalApexSDK()->registerAuthObjType(mAOTypeName.c_str(), this);
+
+ PX_ASSERT(!"This constructor is no longer valid, you MUST provide a parameterizedName!");
+ }
+
+ // This constructor is for assets that are based on NvParameterized, they provide the string
+ // defined in the NvParameterized structure. This will be used to map the NvParameterized object
+ // to the AuthorableObject class to create the assets after they are deserialized
+ ApexAuthorableObject(ModuleIntl* m, ResourceList& list, const char* parameterizedName)
+ : AuthorableObjectIntl(m, list, T_Asset::getClassName())
+ {
+ mParameterizedName = parameterizedName;
+
+ // Register the authorable object type name in the NRP
+ mAOResID = GetInternalApexSDK()->getInternalResourceProvider()->createNameSpace(mAOTypeName.c_str());
+ mAOPtrResID = GetInternalApexSDK()->registerAuthObjType(mAOTypeName.c_str(), this);
+
+ // Register the parameterized name in the NRP to point to this authorable object
+ GetInternalApexSDK()->registerNvParamAuthType(mParameterizedName.c_str(), this);
+ }
+
+ virtual Asset* createAsset(AssetAuthoring& author, const char* name);
+ virtual Asset* createAsset(NvParameterized::Interface* params, const char* name);
+ virtual void releaseAsset(Asset& nxasset);
+
+ virtual AssetAuthoring* createAssetAuthoring();
+ virtual AssetAuthoring* createAssetAuthoring(const char* name);
+ virtual AssetAuthoring* createAssetAuthoring(NvParameterized::Interface* params, const char* name);
+ virtual void releaseAssetAuthoring(AssetAuthoring& nxauthor);
+
+ virtual uint32_t forceLoadAssets();
+
+ virtual uint32_t getAssetCount()
+ {
+ return mAssets.getSize();
+ }
+ virtual bool getAssetList(Asset** outAssets, uint32_t& outAssetCount, uint32_t inAssetCount);
+
+ virtual ResID getResID()
+ {
+ return mAOResID;
+ }
+
+ virtual ApexSimpleString& getName()
+ {
+ return mAOTypeName;
+ }
+
+ // Resource methods
+ virtual void release();
+
+ virtual void destroy()
+ {
+ delete this;
+ }
+
+};
+
+template <class T_Module, class T_Asset, class T_AssetAuthoring>
+Asset* ApexAuthorableObject<T_Module, T_Asset, T_AssetAuthoring>::
+createAsset(AssetAuthoring& author, const char* name)
+{
+ if (mParameterizedName.len())
+ {
+ NvParameterized::Interface* params = 0;
+ NvParameterized::Traits* traits = GetInternalApexSDK()->getParameterizedTraits();
+ params = traits->createNvParameterized(mParameterizedName.c_str());
+ PX_ASSERT(params);
+ if (params)
+ {
+ NvParameterized::Interface* authorParams = author.getNvParameterized();
+ PX_ASSERT(authorParams);
+ if (authorParams)
+ {
+ if (NvParameterized::ERROR_NONE != authorParams->callPreSerializeCallback())
+ {
+ return NULL;
+ }
+
+ NvParameterized::ErrorType err = params->copy(*authorParams);
+
+ PX_ASSERT(err == NvParameterized::ERROR_NONE);
+
+ if (err == NvParameterized::ERROR_NONE)
+ {
+ return createAsset(params, name);
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+ else
+ {
+ APEX_INVALID_OPERATION("Authorable Asset needs a parameterized name");
+ return NULL;
+ }
+}
+
+template <class T_Module, class T_Asset, class T_AssetAuthoring>
+void ApexAuthorableObject<T_Module, T_Asset, T_AssetAuthoring>::
+release()
+{
+ // test this by releasing the module before the individual assets
+
+ // remove all assets that we loaded (must do now else we cannot unregister)
+ mAssets.clear();
+ mAssetAuthors.clear();
+
+ // remove this AO's name from the authorable namespace
+ GetInternalApexSDK()->unregisterAuthObjType(mAOTypeName.c_str());
+
+ if (mParameterizedName.len())
+ {
+ GetInternalApexSDK()->unregisterNvParamAuthType(mParameterizedName.c_str());
+ }
+ destroy();
+}
+
+template <class T_Module, class T_Asset, class T_AssetAuthoring>
+Asset* ApexAuthorableObject<T_Module, T_Asset, T_AssetAuthoring>::
+createAsset(NvParameterized::Interface* params, const char* name)
+{
+ T_Asset* asset = PX_NEW(T_Asset)(DYNAMIC_CAST(T_Module*)(mModule), mAssets, params, name);
+ if (asset)
+ {
+ GetInternalApexSDK()->getNamedResourceProvider()->setResource(mAOTypeName.c_str(), name, asset);
+ }
+ return asset;
+}
+
+template <class T_Module, class T_Asset, class T_AssetAuthoring>
+void ApexAuthorableObject<T_Module, T_Asset, T_AssetAuthoring>::
+releaseAsset(Asset& nxasset)
+{
+ T_Asset* asset = DYNAMIC_CAST(T_Asset*)(&nxasset);
+
+ GetInternalApexSDK()->getInternalResourceProvider()->setResource(mAOTypeName.c_str(), nxasset.getName(), NULL, false, false);
+ asset->destroy();
+}
+
+#ifdef WITHOUT_APEX_AUTHORING
+
+// this should no longer be called now that we're auto-assigning names in createAssetAuthoring()
+template <class T_Module, class T_Asset, class T_AssetAuthoring>
+AssetAuthoring* ApexAuthorableObject<T_Module, T_Asset, T_AssetAuthoring>::
+createAssetAuthoring()
+{
+ APEX_INVALID_OPERATION("Asset authoring has been disabled");
+ return NULL;
+}
+
+template <class T_Module, class T_Asset, class T_AssetAuthoring>
+AssetAuthoring* ApexAuthorableObject<T_Module, T_Asset, T_AssetAuthoring>::
+createAssetAuthoring(const char*)
+{
+ APEX_INVALID_OPERATION("Asset authoring has been disabled");
+ return NULL;
+}
+
+template <class T_Module, class T_Asset, class T_AssetAuthoring>
+AssetAuthoring* ApexAuthorableObject<T_Module, T_Asset, T_AssetAuthoring>::
+createAssetAuthoring(NvParameterized::Interface*, const char*)
+{
+ APEX_INVALID_OPERATION("Asset authoring has been disabled");
+ return NULL;
+}
+
+#else // WITHOUT_APEX_AUTHORING
+
+// this should no longer be called now that we're auto-assigning names in createAssetAuthoring()
+template <class T_Module, class T_Asset, class T_AssetAuthoring>
+AssetAuthoring* ApexAuthorableObject<T_Module, T_Asset, T_AssetAuthoring>::
+createAssetAuthoring()
+{
+ return PX_NEW(T_AssetAuthoring)(DYNAMIC_CAST(T_Module*)(mModule), mAssetAuthors);
+}
+
+template <class T_Module, class T_Asset, class T_AssetAuthoring>
+AssetAuthoring* ApexAuthorableObject<T_Module, T_Asset, T_AssetAuthoring>::
+createAssetAuthoring(const char* name)
+{
+ T_AssetAuthoring* assetAuthor = PX_NEW(T_AssetAuthoring)(DYNAMIC_CAST(T_Module*)(mModule), mAssetAuthors, name);
+
+ if (assetAuthor)
+ {
+ GetInternalApexSDK()->getNamedResourceProvider()->setResource(mAOTypeName.c_str(), name, assetAuthor);
+ }
+ return assetAuthor;
+}
+
+template <class T_Module, class T_Asset, class T_AssetAuthoring>
+AssetAuthoring* ApexAuthorableObject<T_Module, T_Asset, T_AssetAuthoring>::
+createAssetAuthoring(NvParameterized::Interface* params, const char* name)
+{
+ T_AssetAuthoring* assetAuthor = PX_NEW(T_AssetAuthoring)(DYNAMIC_CAST(T_Module*)(mModule), mAssetAuthors, params, name);
+
+ if (assetAuthor)
+ {
+ GetInternalApexSDK()->getNamedResourceProvider()->setResource(mAOTypeName.c_str(), name, assetAuthor);
+ }
+ return assetAuthor;
+}
+
+#endif // WITHOUT_APEX_AUTHORING
+
+template <class T_Module, class T_Asset, class T_AssetAuthoring>
+void ApexAuthorableObject<T_Module, T_Asset, T_AssetAuthoring>::
+releaseAssetAuthoring(AssetAuthoring& nxauthor)
+{
+ T_AssetAuthoring* author = DYNAMIC_CAST(T_AssetAuthoring*)(&nxauthor);
+
+ GetInternalApexSDK()->getInternalResourceProvider()->setResource(mAOTypeName.c_str(), nxauthor.getName(), NULL, false, false);
+ author->destroy();
+}
+
+template <class T_Module, class T_Asset, class T_AssetAuthoring>
+uint32_t ApexAuthorableObject<T_Module, T_Asset, T_AssetAuthoring>::
+forceLoadAssets()
+{
+ uint32_t loadedAssetCount = 0;
+
+ for (uint32_t i = 0; i < mAssets.getSize(); i++)
+ {
+ T_Asset* asset = DYNAMIC_CAST(T_Asset*)(mAssets.getResource(i));
+ loadedAssetCount += asset->forceLoadAssets();
+ }
+ return loadedAssetCount;
+}
+
+template <class T_Module, class T_Asset, class T_AssetAuthoring>
+bool ApexAuthorableObject<T_Module, T_Asset, T_AssetAuthoring>::
+getAssetList(Asset** outAssets, uint32_t& outAssetCount, uint32_t inAssetCount)
+{
+ PX_ASSERT(outAssets);
+ PX_ASSERT(inAssetCount >= mAssets.getSize());
+
+ if (!outAssets || inAssetCount < mAssets.getSize())
+ {
+ outAssetCount = 0;
+ return false;
+ }
+
+ outAssetCount = mAssets.getSize();
+ for (uint32_t i = 0; i < mAssets.getSize(); i++)
+ {
+ T_Asset* asset = DYNAMIC_CAST(T_Asset*)(mAssets.getResource(i));
+ outAssets[i] = static_cast<Asset*>(asset);
+ }
+
+ return true;
+}
+
+}
+} // end namespace nvidia::apex
+
+#endif // __APEXAUTHORABLEOBJECT_H__
diff --git a/APEX_1.4/common/include/ApexBinaryHeap.h b/APEX_1.4/common/include/ApexBinaryHeap.h
new file mode 100644
index 00000000..e772b900
--- /dev/null
+++ b/APEX_1.4/common/include/ApexBinaryHeap.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 APEX_BINARY_HEAP_H
+#define APEX_BINARY_HEAP_H
+
+#include "ApexDefs.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+template <class Comparable>
+class ApexBinaryHeap
+{
+public:
+ explicit ApexBinaryHeap(int capacity = 100) : mCurrentSize(0)
+ {
+ if (capacity > 0)
+ {
+ mArray.reserve((uint32_t)capacity + 1);
+ }
+
+ mArray.insert();
+ }
+
+
+
+ bool isEmpty() const
+ {
+ return mCurrentSize == 0;
+ }
+
+
+
+ const Comparable& peek() const
+ {
+ PX_ASSERT(mArray.size() > 1);
+ return mArray[1];
+ }
+
+
+
+ void push(const Comparable& x)
+ {
+ mArray.insert();
+ // Percolate up
+ mCurrentSize++;
+ uint32_t hole = mCurrentSize;
+ while (hole > 1)
+ {
+ uint32_t parent = hole >> 1;
+ if (!(x < mArray[parent]))
+ {
+ break;
+ }
+ mArray[hole] = mArray[parent];
+ hole = parent;
+ }
+ mArray[hole] = x;
+ }
+
+
+
+ void pop()
+ {
+ if (mArray.size() > 1)
+ {
+ mArray[1] = mArray[mCurrentSize--];
+ percolateDown(1);
+ mArray.popBack();
+ }
+ }
+
+
+
+ void pop(Comparable& minItem)
+ {
+ if (mArray.size() > 1)
+ {
+ minItem = mArray[1];
+ mArray[1] = mArray[mCurrentSize--];
+ percolateDown(1);
+ mArray.popBack();
+ }
+ }
+
+private:
+ uint32_t mCurrentSize; // Number of elements in heap
+ physx::Array<Comparable> mArray;
+
+ void buildHeap()
+ {
+ for (uint32_t i = mCurrentSize / 2; i > 0; i--)
+ {
+ percolateDown(i);
+ }
+ }
+
+
+
+ void percolateDown(uint32_t hole)
+ {
+ Comparable tmp = mArray[hole];
+
+ while (hole * 2 <= mCurrentSize)
+ {
+ uint32_t child = hole * 2;
+ if (child != mCurrentSize && mArray[child + 1] < mArray[child])
+ {
+ child++;
+ }
+ if (mArray[child] < tmp)
+ {
+ mArray[hole] = mArray[child];
+ }
+ else
+ {
+ break;
+ }
+
+ hole = child;
+ }
+
+ mArray[hole] = tmp;
+ }
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif // APEX_BINARY_HEAP_H
diff --git a/APEX_1.4/common/include/ApexCollision.h b/APEX_1.4/common/include/ApexCollision.h
new file mode 100644
index 00000000..ccc4b8b4
--- /dev/null
+++ b/APEX_1.4/common/include/ApexCollision.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.
+ */
+
+
+#ifndef APEX_COLLISION_H
+#define APEX_COLLISION_H
+
+#include "ApexDefs.h"
+
+#include "ApexUsingNamespace.h"
+#include "PxVec3.h"
+#include "PxMat33.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+
+
+struct Segment
+{
+ PxVec3 p0;
+ PxVec3 p1;
+};
+
+struct Capsule : Segment
+{
+ float radius;
+};
+
+struct Triangle
+{
+ Triangle(const PxVec3& a, const PxVec3& b, const PxVec3& c) : v0(a), v1(b), v2(c) {}
+ PxVec3 v0;
+ PxVec3 v1;
+ PxVec3 v2;
+};
+
+struct Box
+{
+ PxVec3 center;
+ PxVec3 extents;
+ PxMat33 rot;
+};
+
+
+bool capsuleCapsuleIntersection(const Capsule& worldCaps0, const Capsule& worldCaps1, float tolerance = 1.2);
+bool boxBoxIntersection(const Box& worldBox0, const Box& worldBox1);
+
+float APEX_pointTriangleSqrDst(const Triangle& triangle, const PxVec3& position);
+float APEX_segmentSegmentSqrDist(const Segment& seg0, const Segment& seg1, float* s, float* t);
+float APEX_pointSegmentSqrDist(const Segment& seg, const PxVec3& point, float* param = 0);
+uint32_t APEX_RayCapsuleIntersect(const PxVec3& origin, const PxVec3& dir, const Capsule& capsule, float s[2]);
+
+bool APEX_RayTriangleIntersect(const PxVec3& orig, const PxVec3& dir, const PxVec3& a, const PxVec3& b, const PxVec3& c, float& t, float& u, float& v);
+
+} // namespace apex
+} // namespace nvidia
+
+
+#endif // APEX_COLLISION_H
diff --git a/APEX_1.4/common/include/ApexConstrainedDistributor.h b/APEX_1.4/common/include/ApexConstrainedDistributor.h
new file mode 100644
index 00000000..b9d7474e
--- /dev/null
+++ b/APEX_1.4/common/include/ApexConstrainedDistributor.h
@@ -0,0 +1,170 @@
+/*
+ * 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 __APEX_CONSTRAINED_DISTRIBUTOR_H__
+#define __APEX_CONSTRAINED_DISTRIBUTOR_H__
+
+#include "Apex.h"
+#include "PsUserAllocated.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+template <typename T = uint32_t>
+class ApexConstrainedDistributor
+{
+public:
+ ApexConstrainedDistributor()
+ {
+ }
+
+ PX_INLINE void resize(uint32_t size)
+ {
+ mConstraintDataArray.resize(size);
+ }
+ PX_INLINE void setBenefit(uint32_t index, float benefit)
+ {
+ PX_ASSERT(index < mConstraintDataArray.size());
+ mConstraintDataArray[index].benefit = benefit;
+ }
+ PX_INLINE void setTargetValue(uint32_t index, T targetValue)
+ {
+ PX_ASSERT(index < mConstraintDataArray.size());
+ mConstraintDataArray[index].targetValue = targetValue;
+ }
+ PX_INLINE T getResultValue(uint32_t index) const
+ {
+ PX_ASSERT(index < mConstraintDataArray.size());
+ return mConstraintDataArray[index].resultValue;
+ }
+
+ void solve(T totalValueLimit)
+ {
+ uint32_t size = mConstraintDataArray.size();
+ if (size == 0)
+ {
+ return;
+ }
+ if (size == 1)
+ {
+ ConstraintData& data = mConstraintDataArray.front();
+ data.resultValue = PxMin(data.targetValue, totalValueLimit);
+ return;
+ }
+
+ float totalBenefit = 0;
+ T totalValue = 0;
+ for (uint32_t i = 0; i < size; i++)
+ {
+ ConstraintData& data = mConstraintDataArray[i];
+
+ totalBenefit += data.benefit;
+ totalValue += data.targetValue;
+
+ data.resultValue = data.targetValue;
+ }
+ if (totalValue <= totalValueLimit)
+ {
+ //resultValue was setted in prev. for-scope
+ return;
+ }
+
+ mConstraintSortPairArray.resize(size);
+ for (uint32_t i = 0; i < size; i++)
+ {
+ ConstraintData& data = mConstraintDataArray[i];
+
+ data.weight = (totalValueLimit * data.benefit / totalBenefit);
+ if (data.weight > 0)
+ {
+ mConstraintSortPairArray[i].key = (data.targetValue / data.weight);
+ }
+ else
+ {
+ mConstraintSortPairArray[i].key = FLT_MAX;
+ data.resultValue = 0; //reset resultValue
+ }
+ mConstraintSortPairArray[i].index = i;
+ }
+
+ nvidia::sort(mConstraintSortPairArray.begin(), size, ConstraintSortPredicate());
+
+ for (uint32_t k = 0; k < size; k++)
+ {
+ float firstKey = mConstraintSortPairArray[k].key;
+ if (firstKey == FLT_MAX)
+ {
+ break;
+ }
+ ConstraintData& firstData = mConstraintDataArray[mConstraintSortPairArray[k].index];
+
+ //special case when k == i
+ float sumWeight = firstData.weight;
+ T sum = firstData.targetValue;
+ for (uint32_t i = k + 1; i < size; i++)
+ {
+ const ConstraintData& data = mConstraintDataArray[mConstraintSortPairArray[i].index];
+
+ sumWeight += data.weight;
+ const T value = static_cast<T>(firstKey * data.weight);
+ PX_ASSERT(value <= data.targetValue);
+ sum += value;
+ }
+
+ if (sum > totalValueLimit)
+ {
+ for (uint32_t i = k; i < size; i++)
+ {
+ ConstraintData& data = mConstraintDataArray[mConstraintSortPairArray[i].index];
+
+ const T value = static_cast<T>(totalValueLimit * data.weight / sumWeight);
+ PX_ASSERT(value <= data.targetValue);
+ data.resultValue = value;
+ }
+ break;
+ }
+ //allready here: firstData.resultData = firstData.targetValue
+ totalValueLimit -= firstData.targetValue;
+ }
+ }
+
+private:
+ struct ConstraintData
+ {
+ float benefit; //input benefit
+ T targetValue; //input constraint on value
+ float weight; //temp
+ T resultValue; //output
+ };
+ struct ConstraintSortPair
+ {
+ float key;
+ uint32_t index;
+ };
+ class ConstraintSortPredicate
+ {
+ public:
+ PX_INLINE bool operator()(const ConstraintSortPair& a, const ConstraintSortPair& b) const
+ {
+ return a.key < b.key;
+ }
+ };
+
+ physx::Array<ConstraintData> mConstraintDataArray;
+ physx::Array<ConstraintSortPair> mConstraintSortPairArray;
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif
diff --git a/APEX_1.4/common/include/ApexContext.h b/APEX_1.4/common/include/ApexContext.h
new file mode 100644
index 00000000..d991dd3a
--- /dev/null
+++ b/APEX_1.4/common/include/ApexContext.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.
+ */
+
+
+#ifndef APEX_CONTEXT_H
+#define APEX_CONTEXT_H
+
+#include "ApexUsingNamespace.h"
+#include "Context.h"
+#include "PsMutex.h"
+#include "PsArray.h"
+#include "PsUserAllocated.h"
+#include "ApexRWLockable.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+class ApexActor;
+class ApexRenderableIterator;
+
+class ApexContext
+{
+public:
+ ApexContext() : mIterator(NULL) {}
+ virtual ~ApexContext();
+
+ virtual uint32_t addActor(ApexActor& actor, ApexActor* actorPtr = NULL);
+ virtual void callContextCreationCallbacks(ApexActor* actorPtr);
+ virtual void callContextDeletionCallbacks(ApexActor* actorPtr);
+ virtual void removeActorAtIndex(uint32_t index);
+
+ void renderLockAllActors();
+ void renderUnLockAllActors();
+
+ void removeAllActors();
+ RenderableIterator* createRenderableIterator();
+ void releaseRenderableIterator(RenderableIterator&);
+
+protected:
+ physx::Array<ApexActor*> mActorArray;
+ physx::Array<ApexActor*> mActorArrayCallBacks;
+ nvidia::ReadWriteLock mActorListLock;
+ ApexRenderableIterator* mIterator;
+
+ friend class ApexRenderableIterator;
+ friend class ApexActor;
+};
+
+class ApexRenderableIterator : public RenderableIterator, public ApexRWLockable, public UserAllocated
+{
+public:
+ APEX_RW_LOCKABLE_BOILERPLATE
+
+ Renderable* getFirst();
+ Renderable* getNext();
+ void reset();
+ void release();
+
+protected:
+ void destroy();
+ ApexRenderableIterator(ApexContext&);
+ virtual ~ApexRenderableIterator() {}
+ void removeCachedActor(ApexActor&);
+
+ ApexContext* ctx;
+ uint32_t curActor;
+ ApexActor* mLockedActor;
+ physx::Array<ApexActor*> mCachedActors;
+ physx::Array<ApexActor*> mSkippedActors;
+
+ friend class ApexContext;
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif // APEX_CONTEXT_H \ No newline at end of file
diff --git a/APEX_1.4/common/include/ApexCuda.h b/APEX_1.4/common/include/ApexCuda.h
new file mode 100644
index 00000000..c4c476dd
--- /dev/null
+++ b/APEX_1.4/common/include/ApexCuda.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.
+ */
+
+
+#ifndef APEX_CUDA_H
+#define APEX_CUDA_H
+
+#include <cuda.h>
+#include "ApexCudaDefs.h"
+
+#define APEX_CUDA_CONCAT_I(arg1, arg2) arg1 ## arg2
+#define APEX_CUDA_CONCAT(arg1, arg2) APEX_CUDA_CONCAT_I(arg1, arg2)
+
+#define APEX_CUDA_TO_STR_I(arg) # arg
+#define APEX_CUDA_TO_STR(arg) APEX_CUDA_TO_STR_I(arg)
+
+const unsigned int APEX_CUDA_SINGLE_BLOCK_LAUNCH = 0xFFFFFFFF;
+
+#define APEX_CUDA_KERNEL_DEFAULT_CONFIG ()
+#define APEX_CUDA_KERNEL_2D_CONFIG(x, y) (0, 0, nvidia::apex::DimBlock(x, y, 1))
+#define APEX_CUDA_KERNEL_3D_CONFIG(x, y, z) (0, 0, nvidia::apex::DimBlock(x, y, z))
+
+#define APEX_CUDA_TEX_FILTER_POINT CU_TR_FILTER_MODE_POINT
+#define APEX_CUDA_TEX_FILTER_LINEAR CU_TR_FILTER_MODE_LINEAR
+
+
+#include <boost/preprocessor/seq.hpp>
+#include <boost/preprocessor/seq/for_each.hpp>
+#include <boost/preprocessor/seq/for_each_i.hpp>
+#include <boost/preprocessor/tuple/elem.hpp>
+#include <boost/preprocessor/punctuation/comma_if.hpp>
+#include <boost/preprocessor/cat.hpp>
+
+
+#define __APEX_CUDA_FUNC_ARG_NAME(elem) BOOST_PP_TUPLE_ELEM(2, 1, elem)
+
+#define __APEX_CUDA_FUNC_ARG_I(r, data, i, elem) BOOST_PP_COMMA_IF(i) BOOST_PP_TUPLE_ELEM(2, 0, elem) __APEX_CUDA_FUNC_ARG_NAME(elem)
+#define __APEX_CUDA_FUNC_ARGS(argseq) BOOST_PP_SEQ_FOR_EACH_I(__APEX_CUDA_FUNC_ARG_I, _, argseq)
+
+#define __APEX_CUDA_FUNC_ARG_NAME_I(r, data, i, elem) BOOST_PP_COMMA_IF(i) __APEX_CUDA_FUNC_ARG_NAME(elem)
+#define __APEX_CUDA_FUNC_ARG_NAMES(argseq) BOOST_PP_SEQ_FOR_EACH_I(__APEX_CUDA_FUNC_ARG_NAME_I, _, argseq)
+
+
+#define __APEX_CUDA_FUNC_$ARG_NAME(elem) BOOST_PP_CAT(_$arg_, BOOST_PP_TUPLE_ELEM(2, 1, elem))
+
+#define __APEX_CUDA_FUNC_$ARG_I(r, data, i, elem) BOOST_PP_COMMA_IF(i) BOOST_PP_TUPLE_ELEM(2, 0, elem) __APEX_CUDA_FUNC_$ARG_NAME(elem)
+#define __APEX_CUDA_FUNC_$ARGS(argseq) BOOST_PP_SEQ_FOR_EACH_I(__APEX_CUDA_FUNC_$ARG_I, _, argseq)
+
+#define __APEX_CUDA_FUNC_$ARG_NAME_I(r, data, i, elem) BOOST_PP_COMMA_IF(i) __APEX_CUDA_FUNC_$ARG_NAME(elem)
+#define __APEX_CUDA_FUNC_$ARG_NAMES(argseq) BOOST_PP_SEQ_FOR_EACH_I(__APEX_CUDA_FUNC_$ARG_NAME_I, _, argseq)
+
+
+#define __APEX_CUDA_FUNC_SET_PARAM(r, data, elem) setParam( data, __APEX_CUDA_FUNC_$ARG_NAME(elem) );
+
+#define __APEX_CUDA_FUNC_COPY_PARAM(r, data, elem) copyParam( APEX_CUDA_TO_STR(__APEX_CUDA_FUNC_ARG_NAME(elem)), __APEX_CUDA_FUNC_$ARG_NAME(elem) );
+
+#define APEX_CUDA_NAME(name) APEX_CUDA_CONCAT(APEX_CUDA_MODULE_PREFIX, name)
+#define APEX_CUDA_NAME_STR(name) APEX_CUDA_TO_STR( APEX_CUDA_NAME(name) )
+
+#define APEX_CUDA_TEX_REF_NAME(name) APEX_CUDA_NAME( APEX_CUDA_CONCAT(texRef, name) )
+#define APEX_CUDA_SURF_REF_NAME(name) APEX_CUDA_NAME( APEX_CUDA_CONCAT(surfRef, name) )
+
+#define APEX_CUDA_STORAGE(name) APEX_CUDA_STORAGE_SIZE(name, MAX_CONST_MEM_SIZE)
+
+#ifdef __CUDACC__
+
+#define APEX_MEM_BLOCK(format) format*
+
+#define APEX_CUDA_TEXTURE_1D(name, format) texture<format, cudaTextureType1D, cudaReadModeElementType> APEX_CUDA_NAME(name);
+#define APEX_CUDA_TEXTURE_2D(name, format) texture<format, cudaTextureType2D, cudaReadModeElementType> APEX_CUDA_NAME(name);
+#define APEX_CUDA_TEXTURE_3D(name, format) texture<format, cudaTextureType3D, cudaReadModeElementType> APEX_CUDA_NAME(name);
+#define APEX_CUDA_TEXTURE_3D_FILTER(name, format, filter) APEX_CUDA_TEXTURE_3D(name, format)
+
+#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 200
+
+#define APEX_CUDA_SURFACE_1D(name)
+#define APEX_CUDA_SURFACE_2D(name)
+#define APEX_CUDA_SURFACE_3D(name)
+
+#else
+
+#define APEX_CUDA_SURFACE_1D(name) surface<void, cudaSurfaceType1D> APEX_CUDA_NAME(name);
+#define APEX_CUDA_SURFACE_2D(name) surface<void, cudaSurfaceType2D> APEX_CUDA_NAME(name);
+#define APEX_CUDA_SURFACE_3D(name) surface<void, cudaSurfaceType3D> APEX_CUDA_NAME(name);
+
+#endif
+
+#define APEX_CUDA_STORAGE_SIZE(name, size) \
+ __constant__ unsigned char APEX_CUDA_NAME( APEX_CUDA_CONCAT(name, _ConstMem) )[size]; \
+ texture<int, 1, cudaReadModeElementType> APEX_CUDA_NAME( APEX_CUDA_CONCAT(name, _Texture) );
+
+
+#define APEX_CUDA_FREE_KERNEL(kernelWarps, kernelName, argseq) \
+ extern "C" __global__ void APEX_CUDA_NAME(kernelName)(int* _extMem, uint16_t _kernelEnum, uint32_t _threadCount, __APEX_CUDA_FUNC_ARGS(argseq) );
+
+#define APEX_CUDA_FREE_KERNEL_2D(kernelDim, kernelName, argseq) \
+ extern "C" __global__ void APEX_CUDA_NAME(kernelName)(int* _extMem, uint16_t _kernelEnum, uint32_t _threadCountX, uint32_t _threadCountY, __APEX_CUDA_FUNC_ARGS(argseq) );
+
+#define APEX_CUDA_FREE_KERNEL_3D(kernelDim, kernelName, argseq) \
+ extern "C" __global__ void APEX_CUDA_NAME(kernelName)(int* _extMem, uint16_t _kernelEnum, uint32_t _threadCountX, uint32_t _threadCountY, uint32_t _threadCountZ, uint32_t _blockCountY, __APEX_CUDA_FUNC_ARGS(argseq) );
+
+#define APEX_CUDA_BOUND_KERNEL(kernelWarps, kernelName, argseq) \
+ extern "C" __global__ void APEX_CUDA_NAME(kernelName)(int* _extMem, uint16_t _kernelEnum, uint32_t _threadCount, __APEX_CUDA_FUNC_ARGS(argseq) );
+
+#define APEX_CUDA_SYNC_KERNEL(kernelWarps, kernelName, argseq) \
+ extern "C" __global__ void APEX_CUDA_NAME(kernelName)(int* _extMem, uint16_t _kernelEnum, __APEX_CUDA_FUNC_ARGS(argseq) );
+
+#else
+
+#define APEX_CUDA_CLASS_NAME(name) APEX_CUDA_CONCAT(CudaClass_, APEX_CUDA_NAME(name) )
+#define APEX_CUDA_OBJ_NAME(name) APEX_CUDA_CONCAT(cudaObj_, APEX_CUDA_NAME(name) )
+
+#define APEX_MEM_BLOCK(format) const ApexCudaMemRef<format>&
+
+#define __APEX_CUDA_TEXTURE(name, filter) \
+ class APEX_CUDA_CLASS_NAME(name) : public ApexCudaTexRef { \
+ public: \
+ APEX_CUDA_CLASS_NAME(name) () : ApexCudaTexRef( APEX_CUDA_NAME_STR(name), filter ) {} \
+ } APEX_CUDA_OBJ_NAME(name); \
+
+#define APEX_CUDA_TEXTURE_1D(name, format) __APEX_CUDA_TEXTURE(name, APEX_CUDA_TEX_FILTER_POINT)
+#define APEX_CUDA_TEXTURE_2D(name, format) __APEX_CUDA_TEXTURE(name, APEX_CUDA_TEX_FILTER_POINT)
+#define APEX_CUDA_TEXTURE_3D(name, format) __APEX_CUDA_TEXTURE(name, APEX_CUDA_TEX_FILTER_POINT)
+#define APEX_CUDA_TEXTURE_3D_FILTER(name, format, filter) __APEX_CUDA_TEXTURE(name, filter)
+
+
+#define __APEX_CUDA_SURFACE(name) \
+ class APEX_CUDA_CLASS_NAME(name) : public ApexCudaSurfRef { \
+ public: \
+ APEX_CUDA_CLASS_NAME(name) () : ApexCudaSurfRef( APEX_CUDA_NAME_STR(name) ) {} \
+ } APEX_CUDA_OBJ_NAME(name); \
+
+#define APEX_CUDA_SURFACE_1D(name) __APEX_CUDA_SURFACE(name)
+#define APEX_CUDA_SURFACE_2D(name) __APEX_CUDA_SURFACE(name)
+#define APEX_CUDA_SURFACE_3D(name) __APEX_CUDA_SURFACE(name)
+
+#define APEX_CUDA_STORAGE_SIZE(name, size) \
+ class APEX_CUDA_CLASS_NAME(name) : public ApexCudaConstStorage { \
+ public: \
+ APEX_CUDA_CLASS_NAME(name) () : ApexCudaConstStorage( APEX_CUDA_NAME_STR( APEX_CUDA_CONCAT(name, _ConstMem) ), APEX_CUDA_NAME_STR( APEX_CUDA_CONCAT(name, _Texture) ) ) {} \
+ } APEX_CUDA_OBJ_NAME(name); \
+
+
+#define __APEX_CUDA_KERNEL_START($blocksPerSM, $config, name, argseq) \
+ class APEX_CUDA_CLASS_NAME(name) : public ApexCudaFunc \
+ { \
+ public: \
+ APEX_CUDA_CLASS_NAME(name) () : ApexCudaFunc( APEX_CUDA_NAME_STR(name) ) {} \
+ PX_INLINE bool isSingleBlock(unsigned int threadCount) const \
+ { \
+ const FuncInstData& fid = getFuncInstData(); \
+ return (threadCount <= fid.mWarpsPerBlock * WARP_SIZE); \
+ } \
+ protected: \
+ void launch1(const FuncInstData& fid, ApexCudaFuncParams& params, CUstream stream) \
+ { \
+ PX_UNUSED(fid); \
+ PX_ASSERT( isValid() ); \
+ setParam(params, (int*)NULL); \
+ setParam(params, uint16_t(0)); \
+ mCTContext = mManager->getCudaTestManager()->isTestKernel(mName, mManager->getModule()->getName());\
+ if (mCTContext) \
+ { \
+ mCTContext->setCuStream(stream); \
+ resolveContext(); \
+ } \
+ } \
+ void launch2(const FuncInstData& fid, const DimBlock& blockDim, uint32_t sharedSize, ApexCudaFuncParams& params, CUstream stream, const DimGrid& gridDim, __APEX_CUDA_FUNC_$ARGS(argseq) ) \
+ { \
+ if (mCTContext) { \
+ mCTContext->setGridDim(gridDim.x, gridDim.y); \
+ mCTContext->setBlockDim(blockDim.x, blockDim.y, blockDim.z); \
+ mCTContext->setSharedSize(sharedSize); \
+ mCTContext->setFuncInstId(int(&fid - mFuncInstData)); \
+ BOOST_PP_SEQ_FOR_EACH(__APEX_CUDA_FUNC_COPY_PARAM, , argseq); \
+ } \
+ BOOST_PP_SEQ_FOR_EACH(__APEX_CUDA_FUNC_SET_PARAM, params, argseq); \
+ void *config[5] = { \
+ CU_LAUNCH_PARAM_BUFFER_POINTER, params.mParams, \
+ CU_LAUNCH_PARAM_BUFFER_SIZE, &params.mOffset, \
+ CU_LAUNCH_PARAM_END \
+ }; \
+ onBeforeLaunch(stream); \
+ CUT_SAFE_CALL(cuLaunchKernel(fid.mCuFunc, gridDim.x, gridDim.y, 1, blockDim.x, blockDim.y, blockDim.z, sharedSize, stream, 0, (void **)config)); \
+ onAfterLaunch(stream); \
+ if (mCTContext) mCTContext->setKernelStatus(); \
+ } \
+ PX_INLINE void evalLaunchParams(const ApexKernelConfig& kernelConfig, const FuncInstData& fid, uint32_t &outWarpsPerBlock, uint32_t &outDynamicShared) \
+ { \
+ const ApexCudaDeviceTraits& devTraits = mManager->getDeviceTraits(); \
+ const uint32_t fixedSharedMem = (kernelConfig.fixedSharedMemDWords << 2); \
+ const uint32_t sharedMemPerWarp = (kernelConfig.sharedMemDWordsPerWarp << 2); \
+ const uint32_t staticSharedMem = fid.mStaticSharedSize + fixedSharedMem; \
+ PX_ASSERT(staticSharedMem + sharedMemPerWarp * 1 <= devTraits.mMaxSharedMemPerBlock); \
+ if (kernelConfig.blockDim.x == 0) \
+ { \
+ const uint32_t maxThreadsPerSM = physx::PxMin(devTraits.mMaxRegistersPerSM / fid.mNumRegsPerThread, devTraits.mMaxThreadsPerSM); \
+ outWarpsPerBlock = physx::PxMin(fid.mMaxThreadsPerBlock, maxThreadsPerSM / $blocksPerSM) >> LOG2_WARP_SIZE; \
+ if (sharedMemPerWarp > 0) \
+ { \
+ const uint32_t sharedMemLimit4SM = (devTraits.mMaxSharedMemPerSM - staticSharedMem * $blocksPerSM) / (sharedMemPerWarp * $blocksPerSM); \
+ const uint32_t sharedMemLimit4Block = (devTraits.mMaxSharedMemPerBlock - staticSharedMem) / sharedMemPerWarp; \
+ const uint32_t sharedMemLimit = physx::PxMin(sharedMemLimit4SM, sharedMemLimit4Block); \
+ outWarpsPerBlock = PxMin<uint32_t>(outWarpsPerBlock, sharedMemLimit); \
+ } \
+ PX_ASSERT(outWarpsPerBlock > 0); \
+ } \
+ else \
+ { \
+ outWarpsPerBlock = (kernelConfig.blockDim.x * kernelConfig.blockDim.y * kernelConfig.blockDim.z + WARP_SIZE-1) / WARP_SIZE; \
+ } \
+ outDynamicShared = fixedSharedMem + sharedMemPerWarp * outWarpsPerBlock; \
+ PX_ASSERT(fid.mStaticSharedSize + outDynamicShared <= devTraits.mMaxSharedMemPerBlock); \
+ PX_ASSERT(outWarpsPerBlock * WARP_SIZE <= fid.mMaxThreadsPerBlock); \
+ PX_ASSERT(outWarpsPerBlock >= kernelConfig.minWarpsPerBlock); \
+ } \
+ virtual void init( PxCudaContextManager* ctx, int funcInstIndex ) \
+ { \
+ PX_UNUSED(ctx); \
+ ApexKernelConfig kernelConfig = ApexKernelConfig $config; \
+ FuncInstData& fid = mFuncInstData[(uint32_t)funcInstIndex]; \
+ evalLaunchParams(kernelConfig, fid, fid.mWarpsPerBlock, fid.mDynamicShared); \
+
+
+#define __APEX_CUDA_KERNEL_WARPS_END(name, argseq) \
+ } \
+ private: \
+ uint32_t mMaxBlocksPerGrid; \
+ uint32_t launch(const FuncInstData& fid, uint32_t warpsPerBlock, uint32_t dynamicShared, CUstream stream, unsigned int _threadCount, __APEX_CUDA_FUNC_$ARGS(argseq) ) \
+ { \
+ warpsPerBlock = PxMin(warpsPerBlock, MAX_WARPS_PER_BLOCK); /* TODO: refactor old kernels to avoid this */ \
+ uint32_t threadsPerBlock = warpsPerBlock * WARP_SIZE; \
+ uint32_t blocksPerGrid = 1; \
+ if (_threadCount == APEX_CUDA_SINGLE_BLOCK_LAUNCH) \
+ { \
+ _threadCount = threadsPerBlock; \
+ } \
+ else \
+ { \
+ if (_threadCount > threadsPerBlock) \
+ { \
+ blocksPerGrid = PxMin((_threadCount + threadsPerBlock - 1) / threadsPerBlock, mMaxBlocksPerGrid); \
+ } \
+ else \
+ { \
+ threadsPerBlock = APEX_CUDA_ALIGN_UP(_threadCount, WARP_SIZE); \
+ } \
+ } \
+ ApexCudaFuncParams params; \
+ launch1(fid, params, stream); \
+ if (mCTContext) mCTContext->setBoundKernel(_threadCount); \
+ setParam(params, _threadCount); \
+ launch2(fid, DimBlock(threadsPerBlock), dynamicShared, params, stream, DimGrid(blocksPerGrid), __APEX_CUDA_FUNC_$ARG_NAMES(argseq) ); \
+ return blocksPerGrid; \
+ } \
+ public: \
+ uint32_t operator() ( CUstream stream, unsigned int _threadCount, __APEX_CUDA_FUNC_$ARGS(argseq) ) \
+ { \
+ const FuncInstData& fid = getFuncInstData(); \
+ return launch(fid, fid.mWarpsPerBlock, fid.mDynamicShared, stream, _threadCount, __APEX_CUDA_FUNC_$ARG_NAMES(argseq) ); \
+ } \
+ uint32_t operator() ( const ApexKernelConfig& kernelConfig, CUstream stream, unsigned int _threadCount, __APEX_CUDA_FUNC_$ARGS(argseq) ) \
+ { \
+ const FuncInstData& fid = getFuncInstData(); \
+ uint32_t warpsPerBlock; \
+ uint32_t dynamicShared; \
+ evalLaunchParams(kernelConfig, fid, warpsPerBlock, dynamicShared); \
+ return launch(fid, warpsPerBlock, dynamicShared, stream, _threadCount, __APEX_CUDA_FUNC_$ARG_NAMES(argseq) ); \
+ } \
+ } APEX_CUDA_OBJ_NAME(name); \
+
+
+#define APEX_CUDA_SYNC_KERNEL(config, name, argseq) \
+ __APEX_CUDA_KERNEL_START(1, config, name, argseq) \
+ mBlocksPerGrid = (uint32_t)ctx->getMultiprocessorCount(); \
+ } \
+ private: \
+ uint32_t mBlocksPerGrid; \
+ public: \
+ void operator() ( CUstream stream, __APEX_CUDA_FUNC_$ARGS(argseq) ) \
+ { \
+ const FuncInstData& fid = getFuncInstData(); \
+ ApexCudaFuncParams params; \
+ launch1(fid, params, stream); \
+ if (mCTContext) mCTContext->setSyncKernel(); \
+ /* alloc full dynamic shared memory for correct block distrib. on GF100 */ \
+ uint32_t dynamicSharedSize = mManager->getDeviceTraits().mMaxSharedMemPerBlock - fid.mStaticSharedSize; \
+ launch2(fid, DimBlock(fid.mWarpsPerBlock * WARP_SIZE), dynamicSharedSize, params, stream, DimGrid(mBlocksPerGrid), __APEX_CUDA_FUNC_$ARG_NAMES(argseq) ); \
+ } \
+ } APEX_CUDA_OBJ_NAME(name); \
+
+
+#define APEX_CUDA_BOUND_KERNEL(config, name, argseq) \
+ __APEX_CUDA_KERNEL_START(mManager->getDeviceTraits().mBlocksPerSM, config, name, argseq) \
+ mMaxBlocksPerGrid = PxMin(mManager->getDeviceTraits().mMaxBlocksPerGrid, kernelConfig.maxGridSize); \
+ __APEX_CUDA_KERNEL_WARPS_END(name, argseq) \
+
+
+#define APEX_CUDA_FREE_KERNEL(config, name, argseq) \
+ __APEX_CUDA_KERNEL_START(mManager->getDeviceTraits().mBlocksPerSM, config, name, argseq) \
+ mMaxBlocksPerGrid = UINT_MAX; \
+ __APEX_CUDA_KERNEL_WARPS_END(name, argseq) \
+
+
+#define APEX_CUDA_FREE_KERNEL_2D($config, name, argseq) \
+ __APEX_CUDA_KERNEL_START(mManager->getDeviceTraits().mBlocksPerSM_2D, $config, name, argseq) \
+ } \
+ public: \
+ void operator() ( CUstream stream, unsigned int _threadCountX, unsigned int _threadCountY, __APEX_CUDA_FUNC_$ARGS(argseq) ) \
+ { \
+ const FuncInstData& fid = getFuncInstData(); \
+ DimBlock blockDim = (ApexKernelConfig $config).blockDim; \
+ if (blockDim.x == 0) \
+ { \
+ uint32_t threadsPerBlock = fid.mWarpsPerBlock * WARP_SIZE; \
+ blockDim.x = PxMin(_threadCountX, threadsPerBlock); \
+ threadsPerBlock /= blockDim.x; \
+ blockDim.y = PxMin(_threadCountY, threadsPerBlock); \
+ } \
+ DimGrid gridDim; \
+ gridDim.x = (_threadCountX + blockDim.x - 1) / blockDim.x; \
+ gridDim.y = (_threadCountY + blockDim.y - 1) / blockDim.y; \
+ ApexCudaFuncParams params; \
+ launch1(fid, params, stream); \
+ if (mCTContext) mCTContext->setFreeKernel(_threadCountX, _threadCountY); \
+ setParam(params, _threadCountX); \
+ setParam(params, _threadCountY); \
+ launch2(fid, blockDim, fid.mDynamicShared, params, stream, gridDim, __APEX_CUDA_FUNC_$ARG_NAMES(argseq) ); \
+ } \
+ } APEX_CUDA_OBJ_NAME(name); \
+
+
+#define APEX_CUDA_FREE_KERNEL_3D($config, name, argseq) \
+ __APEX_CUDA_KERNEL_START(mManager->getDeviceTraits().mBlocksPerSM_3D, $config, name, argseq) \
+ } \
+ public: \
+ void operator() ( CUstream stream, unsigned int _threadCountX, unsigned int _threadCountY, unsigned int _threadCountZ, __APEX_CUDA_FUNC_$ARGS(argseq) ) \
+ { \
+ const FuncInstData& fid = getFuncInstData(); \
+ DimBlock blockDim = (ApexKernelConfig $config).blockDim; \
+ if (blockDim.x == 0) \
+ { \
+ uint32_t threadsPerBlock = fid.mWarpsPerBlock * WARP_SIZE; \
+ blockDim.x = PxMin(_threadCountX, threadsPerBlock); \
+ threadsPerBlock /= blockDim.x; \
+ blockDim.y = PxMin(_threadCountY, threadsPerBlock); \
+ threadsPerBlock /= blockDim.y; \
+ blockDim.z = PxMin(_threadCountZ, threadsPerBlock); \
+ } \
+ const uint32_t blockCountX = (_threadCountX + blockDim.x - 1) / blockDim.x; \
+ const uint32_t blockCountY = (_threadCountY + blockDim.y - 1) / blockDim.y; \
+ const uint32_t blockCountZ = (_threadCountZ + blockDim.z - 1) / blockDim.z; \
+ DimGrid gridDim(blockCountX, blockCountY * blockCountZ); \
+ ApexCudaFuncParams params; \
+ launch1(fid, params, stream); \
+ if (mCTContext) mCTContext->setFreeKernel(_threadCountX, _threadCountY, _threadCountZ, blockCountY); \
+ setParam(params, _threadCountX); \
+ setParam(params, _threadCountY); \
+ setParam(params, _threadCountZ); \
+ setParam(params, blockCountY); \
+ launch2(fid, blockDim, fid.mDynamicShared, params, stream, gridDim, __APEX_CUDA_FUNC_$ARG_NAMES(argseq) ); \
+ } \
+ } APEX_CUDA_OBJ_NAME(name); \
+
+
+#endif // #ifdef __CUDACC__
+
+#endif //APEX_CUDA_H
diff --git a/APEX_1.4/common/include/ApexCudaDefs.h b/APEX_1.4/common/include/ApexCudaDefs.h
new file mode 100644
index 00000000..6a089265
--- /dev/null
+++ b/APEX_1.4/common/include/ApexCudaDefs.h
@@ -0,0 +1,310 @@
+/*
+ * 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 APEX_CUDA_DEFS_H
+#define APEX_CUDA_DEFS_H
+
+#include <cuda.h>
+
+const unsigned int MAX_CONST_MEM_SIZE = 65536;
+
+const unsigned int APEX_CUDA_MEM_ALIGNMENT = 256;
+const unsigned int APEX_CUDA_TEX_MEM_ALIGNMENT = 512;
+
+const unsigned int MAX_SMEM_BANKS = 32;
+
+
+#define APEX_CUDA_ALIGN_UP(value, alignment) (((value) + (alignment)-1) & ~((alignment)-1))
+#define APEX_CUDA_MEM_ALIGN_UP_32BIT(count) APEX_CUDA_ALIGN_UP(count, APEX_CUDA_MEM_ALIGNMENT >> 2)
+
+const unsigned int LOG2_WARP_SIZE = 5;
+const unsigned int WARP_SIZE = (1U << LOG2_WARP_SIZE);
+
+//if you would like to make this value larger than 32 for future GPUs,
+//then you'll need to fix some kernels (like reduce and scan) to support more than 32 warps per block!!!
+const unsigned int MAX_WARPS_PER_BLOCK = 32;
+const unsigned int MAX_THREADS_PER_BLOCK = (MAX_WARPS_PER_BLOCK << LOG2_WARP_SIZE);
+
+const unsigned int MAX_BOUND_BLOCKS = 64;
+
+//uncomment this line to force bound kernels to use defined number of CTAs
+//#define APEX_CUDA_FORCED_BLOCKS 60
+
+
+namespace nvidia
+{
+namespace apex
+{
+
+struct ApexCudaMemFlags
+{
+ enum Enum
+ {
+ UNUSED = 0,
+ IN = 0x01,
+ OUT = 0x02,
+ IN_OUT = IN | OUT
+ };
+};
+
+#ifndef __CUDACC__
+
+class ApexCudaArray : public UserAllocated
+{
+ PX_NOCOPY(ApexCudaArray)
+
+ void init()
+ {
+ switch (mDesc.Format)
+ {
+ case CU_AD_FORMAT_UNSIGNED_INT8:
+ case CU_AD_FORMAT_SIGNED_INT8:
+ mElemSize = 1;
+ break;
+ case CU_AD_FORMAT_UNSIGNED_INT16:
+ case CU_AD_FORMAT_SIGNED_INT16:
+ case CU_AD_FORMAT_HALF:
+ mElemSize = 2;
+ break;
+ case CU_AD_FORMAT_UNSIGNED_INT32:
+ case CU_AD_FORMAT_SIGNED_INT32:
+ case CU_AD_FORMAT_FLOAT:
+ mElemSize = 4;
+ break;
+ default:
+ PX_ALWAYS_ASSERT();
+ mElemSize = 0;
+ break;
+ };
+ mElemSize *= mDesc.NumChannels;
+ }
+
+public:
+ ApexCudaArray() : mCuArray(NULL), mHasOwnership(false), mElemSize(0) {}
+ ~ApexCudaArray() { release(); }
+
+ void assign(CUarray cuArray, bool bTakeOwnership)
+ {
+ release();
+
+ mCuArray = cuArray;
+ mHasOwnership = bTakeOwnership;
+ CUT_SAFE_CALL(cuArray3DGetDescriptor(&mDesc, mCuArray));
+ init();
+ }
+
+ void create(CUDA_ARRAY3D_DESCRIPTOR desc)
+ {
+ if (mCuArray != NULL && mHasOwnership &&
+ mDesc.Width == desc.Width && mDesc.Height == desc.Height && mDesc.Depth == desc.Depth &&
+ mDesc.Format == desc.Format && mDesc.NumChannels == desc.NumChannels && mDesc.Flags == desc.Flags)
+ {
+ return;
+ }
+ release();
+
+ // Allocate CUDA 3d array in device memory
+ mDesc = desc;
+ CUT_SAFE_CALL(cuArray3DCreate(&mCuArray, &mDesc));
+ mHasOwnership = true;
+ init();
+ }
+
+ void create(CUarray_format format, unsigned int numChannels, unsigned int width, unsigned int height, unsigned int depth = 0, bool surfUsage = false)
+ {
+ CUDA_ARRAY3D_DESCRIPTOR desc;
+ desc.Format = format;
+ desc.NumChannels = numChannels;
+ desc.Width = width;
+ desc.Height = height;
+ desc.Depth = depth;
+ desc.Flags = surfUsage ? CUDA_ARRAY3D_SURFACE_LDST : 0u;
+
+ create(desc);
+ }
+
+ void release()
+ {
+ if (mCuArray != NULL)
+ {
+ if (mHasOwnership)
+ {
+ CUT_SAFE_CALL(cuArrayDestroy(mCuArray));
+ }
+ mCuArray = NULL;
+ mHasOwnership = false;
+ mElemSize = 0;
+ }
+ }
+
+ void copyToHost(CUstream stream, void* dstHost, size_t dstPitch = 0, size_t dstHeight = 0,
+ size_t copyWidth = 0, size_t copyHeight = 0, size_t copyDepth = 0)
+ {
+ if (mDesc.Width > 0)
+ {
+ if (mDesc.Height > 0)
+ {
+ if (mDesc.Depth > 0)
+ {
+ //3D
+ CUDA_MEMCPY3D copyDesc;
+ copyDesc.WidthInBytes = size_t(copyWidth ? copyWidth : mDesc.Width) * mElemSize;
+ copyDesc.Height = copyHeight ? copyHeight : mDesc.Height;
+ copyDesc.Depth = copyDepth ? copyDepth : mDesc.Depth;
+
+ copyDesc.srcXInBytes = copyDesc.srcY = copyDesc.srcZ = copyDesc.srcLOD = 0;
+ copyDesc.srcMemoryType = CU_MEMORYTYPE_ARRAY;
+ copyDesc.srcArray = mCuArray;
+
+ copyDesc.dstXInBytes = copyDesc.dstY = copyDesc.dstZ = copyDesc.dstLOD = 0;
+ copyDesc.dstMemoryType = CU_MEMORYTYPE_HOST;
+ copyDesc.dstHost = dstHost;
+ copyDesc.dstPitch = (dstPitch > 0) ? dstPitch : copyDesc.WidthInBytes;
+ copyDesc.dstHeight = (dstHeight > 0) ? dstHeight : copyDesc.Height;
+ CUT_SAFE_CALL(cuMemcpy3DAsync(&copyDesc, stream));
+ }
+ else
+ {
+ //2D
+ CUDA_MEMCPY2D copyDesc;
+ copyDesc.WidthInBytes = size_t(copyWidth ? copyWidth : mDesc.Width) * mElemSize;
+ copyDesc.Height = copyHeight ? copyHeight : mDesc.Height;
+
+ copyDesc.srcXInBytes = copyDesc.srcY = 0;
+ copyDesc.srcMemoryType = CU_MEMORYTYPE_ARRAY;
+ copyDesc.srcArray = mCuArray;
+
+ copyDesc.dstXInBytes = copyDesc.dstY = 0;
+ copyDesc.dstMemoryType = CU_MEMORYTYPE_HOST;
+ copyDesc.dstHost = dstHost;
+ copyDesc.dstPitch = (dstPitch > 0) ? dstPitch : copyDesc.WidthInBytes;
+ CUT_SAFE_CALL(cuMemcpy2DAsync(&copyDesc, stream));
+ }
+ }
+ else
+ {
+ //1D
+ CUT_SAFE_CALL(cuMemcpyAtoHAsync(dstHost, mCuArray, 0, size_t(copyWidth ? copyWidth : mDesc.Width) * mElemSize, stream));
+ }
+ }
+ }
+
+ void copyFromHost(CUstream stream, const void* srcHost, size_t srcPitch = 0, size_t srcHeight = 0)
+ {
+ if (mDesc.Width > 0)
+ {
+ if (mDesc.Height > 0)
+ {
+ if (mDesc.Depth > 0)
+ {
+ //3D
+ CUDA_MEMCPY3D copyDesc;
+ copyDesc.WidthInBytes = size_t(mDesc.Width) * mElemSize;
+ copyDesc.Height = mDesc.Height;
+ copyDesc.Depth = mDesc.Depth;
+
+ copyDesc.srcXInBytes = copyDesc.srcY = copyDesc.srcZ = copyDesc.srcLOD = 0;
+ copyDesc.srcMemoryType = CU_MEMORYTYPE_HOST;
+ copyDesc.srcHost = srcHost;
+ copyDesc.srcPitch = (srcPitch > 0) ? srcPitch : copyDesc.WidthInBytes;
+ copyDesc.srcHeight = (srcHeight > 0) ? srcHeight : copyDesc.Height;
+
+ copyDesc.dstXInBytes = copyDesc.dstY = copyDesc.dstZ = copyDesc.dstLOD = 0;
+ copyDesc.dstMemoryType = CU_MEMORYTYPE_ARRAY;
+ copyDesc.dstArray = mCuArray;
+
+ CUT_SAFE_CALL(cuMemcpy3DAsync(&copyDesc, stream));
+ }
+ else
+ {
+ //2D
+ CUDA_MEMCPY2D copyDesc;
+ copyDesc.WidthInBytes = size_t(mDesc.Width) * mElemSize;
+ copyDesc.Height = mDesc.Height;
+
+ copyDesc.srcXInBytes = copyDesc.srcY = 0;
+ copyDesc.srcMemoryType = CU_MEMORYTYPE_HOST;
+ copyDesc.srcHost = srcHost;
+ copyDesc.srcPitch = (srcPitch > 0) ? srcPitch : copyDesc.WidthInBytes;
+
+ copyDesc.dstXInBytes = copyDesc.dstY = 0;
+ copyDesc.dstMemoryType = CU_MEMORYTYPE_ARRAY;
+ copyDesc.dstArray = mCuArray;
+
+ CUT_SAFE_CALL(cuMemcpy2DAsync(&copyDesc, stream));
+ }
+ }
+ else
+ {
+ //1D
+ CUT_SAFE_CALL(cuMemcpyHtoAAsync(mCuArray, 0, srcHost, size_t(mDesc.Width) * mElemSize, stream));
+ }
+ }
+ }
+
+ void copyToArray(CUstream stream, CUarray dstArray)
+ {
+ //copy array to array
+ CUDA_MEMCPY3D desc;
+ desc.srcXInBytes = desc.srcY = desc.srcZ = desc.srcLOD = 0;
+ desc.srcMemoryType = CU_MEMORYTYPE_ARRAY;
+ desc.srcArray = mCuArray;
+
+ desc.dstXInBytes = desc.dstY = desc.dstZ = desc.dstLOD = 0;
+ desc.dstMemoryType = CU_MEMORYTYPE_ARRAY;
+ desc.dstArray = dstArray;
+
+ desc.WidthInBytes = size_t(mDesc.Width) * mElemSize;
+ desc.Height = mDesc.Height;
+ desc.Depth = mDesc.Depth;
+ CUT_SAFE_CALL(cuMemcpy3DAsync(&desc, stream));
+ }
+
+ PX_INLINE CUarray getCuArray() const
+ {
+ return mCuArray;
+ }
+ PX_INLINE bool isValid() const
+ {
+ return (mCuArray != NULL);
+ }
+
+ PX_INLINE unsigned int getWidth() const { return (unsigned int)mDesc.Width; }
+ PX_INLINE unsigned int getHeight() const { return (unsigned int)mDesc.Height; }
+ PX_INLINE unsigned int getDepth() const { return (unsigned int)mDesc.Depth; }
+ PX_INLINE CUarray_format getFormat() const { return mDesc.Format; }
+ PX_INLINE unsigned int getNumChannels() const { return mDesc.NumChannels; }
+
+ PX_INLINE bool hasOwnership() const { return mHasOwnership; }
+
+ PX_INLINE const CUDA_ARRAY3D_DESCRIPTOR& getDesc() const { return mDesc; }
+
+ PX_INLINE size_t getByteSize() const
+ {
+ size_t size = mDesc.Width * mElemSize;
+ if (mDesc.Height > 0) size *= mDesc.Height;
+ if (mDesc.Depth > 0) size *= mDesc.Depth;
+ return size;
+ }
+
+private:
+ CUarray mCuArray;
+ bool mHasOwnership;
+ unsigned int mElemSize;
+ CUDA_ARRAY3D_DESCRIPTOR mDesc;
+};
+
+#endif //__CUDACC__
+
+}
+} // end namespace nvidia::apex
+
+#endif //APEX_CUDA_DEFS_H
diff --git a/APEX_1.4/common/include/ApexCudaProfile.h b/APEX_1.4/common/include/ApexCudaProfile.h
new file mode 100644
index 00000000..05ee188e
--- /dev/null
+++ b/APEX_1.4/common/include/ApexCudaProfile.h
@@ -0,0 +1,131 @@
+/*
+ * 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 __APEX_CUDA_KERNEL_MANAGER__
+#define __APEX_CUDA_KERNEL_MANAGER__
+
+#include "ApexDefs.h"
+#include "CudaProfileManager.h"
+
+#include "PsMemoryBuffer.h"
+#include "ApexString.h"
+#include "SceneIntl.h"
+#include "PsMutex.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+class ApexCudaObj;
+class ApexCudaFunc;
+class ApexCudaProfileManager;
+
+class ApexCudaProfileSession
+{
+ struct ProfileData
+ {
+ uint32_t id;
+ void* start;
+ void* stop;
+ };
+public:
+ ApexCudaProfileSession();
+ ~ApexCudaProfileSession();
+
+ PX_INLINE void init(ApexCudaProfileManager* manager)
+ {
+ mManager = manager;
+ }
+ void nextFrame();
+ void start();
+ bool stopAndSave();
+ uint32_t getProfileId(const char* name, const char* moduleName);
+
+ void onFuncStart(uint32_t id, void* stream);
+ void onFuncFinish(uint32_t id, void* stream);
+
+protected:
+ float flushProfileInfo(ProfileData& pd);
+
+ ApexCudaProfileManager* mManager;
+ void* mTimer;
+ nvidia::PsMemoryBuffer mMemBuf;
+ nvidia::Mutex mLock;
+ Array <ProfileData> mProfileDataList;
+ float mFrameStart;
+ float mFrameFinish;
+};
+
+/**
+ */
+class ApexCudaProfileManager : public CudaProfileManager, public UserAllocated
+{
+public:
+ struct KernelInfo
+ {
+ ApexSimpleString functionName;
+ ApexSimpleString moduleName;
+ uint32_t id;
+
+ KernelInfo(const char* functionName, const char* moduleName, uint32_t id = 0)
+ : functionName(functionName), moduleName(moduleName), id(id) {}
+
+ bool operator!= (const KernelInfo& ki)
+ {
+ return (this->functionName != "*" && this->functionName != ki.functionName)
+ || (this->moduleName != ki.moduleName);
+ }
+ };
+
+ ApexCudaProfileManager();
+
+ virtual ~ApexCudaProfileManager();
+
+ PX_INLINE void setInternalApexScene(SceneIntl* scene)
+ {
+ mApexScene = scene;
+ }
+ void nextFrame();
+
+ // interface for CudaProfileManager
+ PX_INLINE void setPath(const char* path)
+ {
+ mPath = ApexSimpleString(path);
+ enable(false);
+ }
+ void setKernel(const char* functionName, const char* moduleName);
+ PX_INLINE void setTimeFormat(TimeFormat tf)
+ {
+ mTimeFormat = tf;
+ }
+ void enable(bool state);
+ PX_INLINE bool isEnabled() const
+ {
+ return mState;
+ }
+
+private:
+ bool mState;
+ uint32_t mSessionCount;
+ TimeFormat mTimeFormat;
+ uint32_t mReservedId;
+ ApexSimpleString mPath;
+ Array <KernelInfo> mKernels;
+ ApexCudaProfileSession mSession;
+ SceneIntl* mApexScene;
+ friend class ApexCudaProfileSession;
+};
+
+}
+} // namespace nvidia::apex
+
+#endif // __APEX_CUDA_KERNEL_MANAGER__
diff --git a/APEX_1.4/common/include/ApexCudaSource.h b/APEX_1.4/common/include/ApexCudaSource.h
new file mode 100644
index 00000000..a5caeed7
--- /dev/null
+++ b/APEX_1.4/common/include/ApexCudaSource.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 __APEX_CUDA_SOURCE_H__
+#define __APEX_CUDA_SOURCE_H__
+
+
+#undef APEX_CUDA_TEXTURE_1D
+#undef APEX_CUDA_TEXTURE_2D
+#undef APEX_CUDA_TEXTURE_3D
+#undef APEX_CUDA_TEXTURE_3D_FILTER
+#undef APEX_CUDA_SURFACE_1D
+#undef APEX_CUDA_SURFACE_2D
+#undef APEX_CUDA_SURFACE_3D
+#undef APEX_CUDA_STORAGE_SIZE
+#undef APEX_CUDA_FREE_KERNEL
+#undef APEX_CUDA_FREE_KERNEL_2D
+#undef APEX_CUDA_FREE_KERNEL_3D
+#undef APEX_CUDA_SYNC_KERNEL
+#undef APEX_CUDA_BOUND_KERNEL
+
+#define __APEX_CUDA_OBJ(name) initCudaObj( APEX_CUDA_OBJ_NAME(name) );
+
+#define APEX_CUDA_TEXTURE_1D(name, format) __APEX_CUDA_OBJ(name)
+#define APEX_CUDA_TEXTURE_2D(name, format) __APEX_CUDA_OBJ(name)
+#define APEX_CUDA_TEXTURE_3D(name, format) __APEX_CUDA_OBJ(name)
+#define APEX_CUDA_TEXTURE_3D_FILTER(name, format, filter) __APEX_CUDA_OBJ(name)
+
+#define APEX_CUDA_SURFACE_1D(name) __APEX_CUDA_OBJ(name)
+#define APEX_CUDA_SURFACE_2D(name) __APEX_CUDA_OBJ(name)
+#define APEX_CUDA_SURFACE_3D(name) __APEX_CUDA_OBJ(name)
+
+#define APEX_CUDA_STORAGE_SIZE(name, size) __APEX_CUDA_OBJ(name)
+
+#define APEX_CUDA_FREE_KERNEL(warps, name, argseq) __APEX_CUDA_OBJ(name)
+#define APEX_CUDA_FREE_KERNEL_2D(warps, name, argseq) __APEX_CUDA_OBJ(name)
+#define APEX_CUDA_FREE_KERNEL_3D(warps, name, argseq) __APEX_CUDA_OBJ(name)
+#define APEX_CUDA_SYNC_KERNEL(warps, name, argseq) __APEX_CUDA_OBJ(name)
+#define APEX_CUDA_BOUND_KERNEL(warps, name, argseq) __APEX_CUDA_OBJ(name)
+
+
+#endif //__APEX_CUDA_SOURCE_H__
diff --git a/APEX_1.4/common/include/ApexCudaTest.h b/APEX_1.4/common/include/ApexCudaTest.h
new file mode 100644
index 00000000..43a0c6ea
--- /dev/null
+++ b/APEX_1.4/common/include/ApexCudaTest.h
@@ -0,0 +1,363 @@
+/*
+ * 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 __APEX_CUDA_TEST__
+#define __APEX_CUDA_TEST__
+
+#include "ApexDefs.h"
+#include "CudaTestManager.h"
+
+#include "PsMemoryBuffer.h"
+#include "ApexString.h"
+#include "ApexMirroredArray.h"
+#include "SceneIntl.h"
+
+#include "ApexCudaDefs.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+struct ApexCudaMemRefBase;
+class ApexCudaObj;
+class ApexCudaFunc;
+struct ApexCudaFuncParams;
+class ApexCudaTexRef;
+class ApexCudaSurfRef;
+
+const uint32_t ApexCudaTestFileVersion = 103;
+
+namespace apexCudaTest
+{
+
+struct MemRef
+{
+ ApexSimpleString name;
+ const void* gpuPtr;
+ size_t size;
+ int32_t dataOffset;
+ uint32_t bufferOffset;
+ uint32_t fpType; // Floating point type, if 0 - not a float, else if 4 - float, else if 8 - double
+
+ MemRef(const void* gpuPtr, size_t size, int32_t dataOffset, uint32_t bufferOffset, uint32_t fpType = 0)
+ : gpuPtr(gpuPtr), size(size), dataOffset(dataOffset), bufferOffset(bufferOffset), fpType(fpType) {}
+};
+
+enum ObjTypeEnum
+{
+ OBJ_TYPE_NONE = 0,
+ OBJ_TYPE_TEX_REF_MEM = 1,
+ OBJ_TYPE_CONST_MEM = 2,
+ OBJ_TYPE_SURF_REF = 4,
+ OBJ_TYPE_TEX_REF_ARR = 5
+};
+
+enum KernelTypeEnum
+{
+ KT_SYNC,
+ KT_FREE,
+ KT_FREE2D,
+ KT_FREE3D,
+ KT_BOUND
+};
+
+}
+
+/** Read cuda kernel context from specified file. Run kernel ant compare output with results from file
+*/
+class ApexCudaTestKernelContextReader : public UserAllocated
+{
+ struct Dim3
+ {
+ int x,y,z;
+ };
+
+ struct TexRef
+ {
+ ApexCudaTexRef* cudaTexRef;
+ uint32_t memRefIdx;
+ ApexCudaArray* cudaArray;
+ };
+
+ struct SurfRef
+ {
+ ApexCudaSurfRef* cudaSurfRef;
+ ApexCudaArray* cudaArray;
+ ApexCudaMemFlags::Enum flags;
+ };
+
+ struct ArrayRef
+ {
+ ApexSimpleString name;
+ ApexCudaArray* cudaArray;
+ const uint8_t* bufferPtr;
+ uint32_t size;
+
+ ArrayRef(const char* name, ApexCudaArray* cudaArray, const uint8_t* bufferPtr, uint32_t size)
+ {
+ this->name = name;
+ this->cudaArray = cudaArray;
+ this->bufferPtr = bufferPtr;
+ this->size = size;
+ }
+ };
+
+ struct ParamRef
+ {
+ ApexSimpleString name;
+ uint32_t value;
+ };
+
+public:
+ ApexCudaTestKernelContextReader(const char* path, SceneIntl* scene);
+ ~ApexCudaTestKernelContextReader();
+
+ bool runKernel();
+
+private:
+ ApexCudaArray* loadCudaArray();
+
+ void loadContext(ApexCudaFuncParams& params);
+ void loadTexRef(uint32_t& memOffset, bool bBindToArray);
+ void loadSurfRef();
+ void loadConstMem();
+ uint32_t getParamSize();
+ void loadParam(uint32_t& memOffset, ApexCudaFuncParams& params);
+
+ bool compare(const uint8_t* resData, const uint8_t* refData, size_t size, uint32_t fpType, const char* name);
+ void dumpParams(char* str);
+
+ nvidia::PsMemoryBuffer* mMemBuf;
+
+ uint32_t mCudaObjOffset;
+ uint32_t mParamOffset;
+
+ int mCuOffset;
+ void* mCuStream;
+
+ ApexSimpleString mName;
+ ApexSimpleString mModuleName;
+ uint32_t mFrame;
+ uint32_t mCallPerFrame;
+
+ uint32_t mFuncInstId;
+ uint32_t mSharedSize;
+ Dim3 mBlockDim;
+ Dim3 mGridDim;
+ apexCudaTest::KernelTypeEnum mKernelType;
+ uint32_t mThreadCount[3];
+ uint32_t mBlockCountY;
+
+ ApexCudaObj* mHeadCudaObj;
+ ApexCudaFunc* mFunc;
+
+ SceneIntl* mApexScene;
+ Array <uint8_t*> mArgSeq;
+ ApexMirroredArray <uint8_t> mTmpArray;
+ PxGpuCopyDescQueue mCopyQueue;
+
+ Array <apexCudaTest::MemRef> mInMemRefs;
+ Array <apexCudaTest::MemRef> mOutMemRefs;
+ Array <ArrayRef> mInArrayRefs;
+ Array <ArrayRef> mOutArrayRefs;
+
+ Array <TexRef> mTexRefs;
+ Array <SurfRef> mSurfRefs;
+
+ uint32_t mCudaArrayCount;
+ ApexCudaArray* mCudaArrayList;
+
+ Array <ParamRef> mParamRefs;
+};
+
+/** Extract context data from CudaModuleScene about cuda kernel and save it to specified file
+*/
+class ApexCudaTestKernelContext : public UserAllocated
+{
+ struct ArrayRef
+ {
+ CUarray cuArray;
+ uint32_t bufferOffset;
+
+ ArrayRef(CUarray cuArray, uint32_t bufferOffset)
+ {
+ this->cuArray = cuArray;
+ this->bufferOffset = bufferOffset;
+ }
+ };
+
+public:
+ ApexCudaTestKernelContext(const char* path, const char* functionName, const char* moduleName, uint32_t frame, uint32_t callPerFrame, bool isWriteForNonSuccessfulKernel, bool isKernelForSave);
+ ~ApexCudaTestKernelContext();
+
+ bool saveToFile();
+
+ PX_INLINE void setCuStream(void* cuStream)
+ {
+ mCuStream = cuStream;
+ }
+
+ void startObjList();
+ void finishObjList();
+
+ void setFreeKernel(uint32_t threadCount);
+ void setFreeKernel(uint32_t threadCountX, uint32_t threadCountY);
+ void setFreeKernel(uint32_t threadCountX, uint32_t threadCountY, uint32_t threadCountZ, uint32_t blockCountY);
+ void setBoundKernel(uint32_t threadCount);
+ void setSyncKernel();
+
+ void setBlockDim(uint32_t x, uint32_t y, uint32_t z);
+ void setGridDim(uint32_t x, uint32_t y);
+
+ void setSharedSize(uint32_t size);
+ void setFuncInstId(int id);
+
+ void addParam(const char* name, uint32_t align, const void *val, size_t size, int isMemRef = 0, int dataOffset = 0, uint32_t fpType = 0);
+ void addTexRef(const char* name, const void* mem, size_t size, CUarray arr);
+ void addSurfRef(const char* name, CUarray arr, ApexCudaMemFlags::Enum flags);
+ void addConstMem(const char* name, const void* mem, size_t size);
+ void setKernelStatus();
+
+private:
+ void copyMemRefs();
+ void copyArrayRefs();
+
+ uint32_t addCuArray(CUarray cuArray);
+
+ void completeCudaObjsBlock();
+ void completeCallParamsBlock();
+
+ PX_INLINE uint32_t advanceMemBuf(uint32_t size, uint32_t align = 4);
+ PX_INLINE void copyToMemBuf(const apexCudaTest::MemRef& memRef);
+ PX_INLINE void copyToMemBuf(const ArrayRef& arrayRef);
+
+ void* mCuStream;
+
+ uint32_t mVersion;
+ uint32_t mFrame;
+ uint32_t mCallPerFrame;
+ ApexSimpleString mName;
+ ApexSimpleString mErrorCode;
+ ApexSimpleString mModuleName;
+ ApexSimpleString mPath;
+ nvidia::PsMemoryBuffer mMemBuf;
+
+ uint32_t mCudaObjsOffset;
+ uint32_t mCallParamsOffset;
+
+ uint32_t mCudaObjsCounter;
+ uint32_t mCallParamsCounter;
+
+ Array <ArrayRef> mArrayRefs;
+ Array <apexCudaTest::MemRef> mMemRefs;
+
+ bool mIsCompleteContext;
+ bool mIsWriteForNonSuccessfulKernel;
+ bool mIsContextForSave;
+};
+
+
+/** Class get information what kernels should be tested and give directive for creation ApexCudaTestContext
+ */
+class ApexCudaTestManager : public CudaTestManager, public UserAllocated
+{
+ struct KernelInfo
+ {
+ ApexSimpleString functionName;
+ ApexSimpleString moduleName;
+ uint32_t callCount;
+
+ KernelInfo(const char* functionName, const char* moduleName)
+ : functionName(functionName), moduleName(moduleName), callCount(0) {}
+
+ bool operator!= (const KernelInfo& ki)
+ {
+ return this->functionName != ki.functionName || this->moduleName != ki.moduleName;
+ }
+ };
+
+public:
+
+ ApexCudaTestManager();
+ virtual ~ApexCudaTestManager();
+
+ PX_INLINE void setInternalApexScene(SceneIntl* scene)
+ {
+ mApexScene = scene;
+ }
+ void nextFrame();
+ ApexCudaTestKernelContext* isTestKernel(const char* functionName, const char* moduleName);
+
+ // interface for CudaTestManager
+ PX_INLINE void setWritePath(const char* path)
+ {
+ mPath = ApexSimpleString(path);
+ }
+ void setWriteForFunction(const char* functionName, const char* moduleName);
+
+ PX_INLINE void setMaxSamples(uint32_t maxSamples)
+ {
+ mMaxSamples = maxSamples;
+ }
+ void setFrames(uint32_t numFrames, const uint32_t* frames)
+ {
+ for(uint32_t i = 0; i < numFrames && mSampledFrames.size() < mMaxSamples; i++)
+ {
+ if (frames == NULL) // write next numFrames frames after current
+ {
+ mSampledFrames.pushBack(mCurrentFrame + i + 1);
+ }
+ else
+ {
+ mSampledFrames.pushBack(frames[i]);
+ }
+ }
+ }
+ void setFramePeriod(uint32_t period)
+ {
+ mFramePeriod = period;
+ }
+ void setCallPerFrameMaxCount(uint32_t cpfMaxCount)
+ {
+ mCallPerFrameMaxCount = cpfMaxCount;
+ }
+ void setWriteForNotSuccessfulKernel(bool flag)
+ {
+ mIsWriteForNonSuccessfulKernel = flag;
+ }
+/* void setCallPerFrameSeries(uint32_t callsCount, const uint32_t* calls)
+ {
+ for(uint32_t i = 0; i < callsCount && mSampledCallsPerFrame.size() < mCallPerFrameMaxCount; i++)
+ {
+ mSampledCallsPerFrame.pushBack(calls[i]);
+ }
+ }*/
+ bool runKernel(const char* path);
+
+private:
+ SceneIntl* mApexScene;
+ uint32_t mCurrentFrame;
+ uint32_t mMaxSamples;
+ uint32_t mFramePeriod;
+ uint32_t mCallPerFrameMaxCount;
+ bool mIsWriteForNonSuccessfulKernel;
+ ApexSimpleString mPath;
+ Array <uint32_t> mSampledFrames;
+ //Array <uint32_t> mSampledCallsPerFrame;
+ Array <KernelInfo> mKernels;
+ Array <ApexCudaTestKernelContext*> mContexts;
+};
+
+}
+} // namespace nvidia::apex
+
+#endif // __APEX_CUDA_TEST__
diff --git a/APEX_1.4/common/include/ApexCudaWrapper.h b/APEX_1.4/common/include/ApexCudaWrapper.h
new file mode 100644
index 00000000..c455fbaf
--- /dev/null
+++ b/APEX_1.4/common/include/ApexCudaWrapper.h
@@ -0,0 +1,1232 @@
+/*
+ * 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 __APEX_CUDA_WRAPPER_H__
+#define __APEX_CUDA_WRAPPER_H__
+
+#include <cuda.h>
+#include "ApexCutil.h"
+#include "vector_types.h"
+#include "ApexMirroredArray.h"
+#include "InplaceStorage.h"
+#include "PsMutex.h"
+#include "ApexCudaTest.h"
+#include "ApexCudaProfile.h"
+#include "ApexCudaDefs.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+struct DimGrid
+{
+ uint32_t x, y;
+
+ DimGrid() {}
+ DimGrid(uint32_t x, uint32_t y = 1)
+ {
+ this->x = x;
+ this->y = y;
+ }
+};
+struct DimBlock
+{
+ uint32_t x, y, z;
+
+ DimBlock() {}
+ DimBlock(uint32_t x, uint32_t y = 1, uint32_t z = 1)
+ {
+ this->x = x;
+ this->y = y;
+ this->z = z;
+ }
+};
+
+struct ApexKernelConfig
+{
+ uint32_t fixedSharedMemDWords;
+ uint32_t sharedMemDWordsPerWarp;
+ DimBlock blockDim;
+ uint32_t minWarpsPerBlock;
+ uint32_t maxGridSize;
+
+ ApexKernelConfig() { fixedSharedMemDWords = sharedMemDWordsPerWarp = 0; blockDim = DimBlock(0, 0, 0); minWarpsPerBlock = 1; maxGridSize = MAX_BOUND_BLOCKS; }
+ ApexKernelConfig(uint32_t fixedSharedMemDWords, uint32_t sharedMemDWordsPerWarp, int fixedWarpsPerBlock = 0, uint32_t minWarpsPerBlock = 1, uint32_t maxGridSize = MAX_BOUND_BLOCKS)
+ {
+ this->fixedSharedMemDWords = fixedSharedMemDWords;
+ this->sharedMemDWordsPerWarp = sharedMemDWordsPerWarp;
+ this->blockDim = DimBlock(fixedWarpsPerBlock * WARP_SIZE);
+ this->minWarpsPerBlock = minWarpsPerBlock;
+ this->maxGridSize = maxGridSize;
+ }
+ ApexKernelConfig(uint32_t fixedSharedMemDWords, uint32_t sharedMemDWordsPerWarp, const DimBlock& blockDim)
+ {
+ this->fixedSharedMemDWords = fixedSharedMemDWords;
+ this->sharedMemDWordsPerWarp = sharedMemDWordsPerWarp;
+ this->blockDim = blockDim;
+ this->minWarpsPerBlock = 1;
+ this->maxGridSize = MAX_BOUND_BLOCKS;
+ }
+};
+
+struct ApexCudaMemRefBase
+{
+ typedef ApexCudaMemFlags::Enum Intent;
+
+ const void* ptr;
+ size_t size; //size in bytes
+ int32_t offset; //data offset for ptr
+ Intent intent;
+
+ ApexCudaMemRefBase(const void* ptr, size_t byteSize, int32_t offset, Intent intent)
+ : ptr(ptr), size(byteSize), offset(offset), intent(intent) {}
+ virtual ~ApexCudaMemRefBase() {}
+};
+
+template <class T>
+struct ApexCudaMemRef : public ApexCudaMemRefBase
+{
+ ApexCudaMemRef(T* ptr, size_t byteSize, Intent intent = ApexCudaMemFlags::IN_OUT)
+ : ApexCudaMemRefBase(ptr, byteSize, 0, intent) {}
+
+ ApexCudaMemRef(T* ptr, size_t byteSize, int32_t offset, Intent intent)
+ : ApexCudaMemRefBase(ptr, byteSize, offset, intent) {}
+
+ inline T* getPtr() const
+ {
+ return (T*)ptr;
+ }
+
+ virtual ~ApexCudaMemRef() {}
+};
+
+template <class T>
+inline ApexCudaMemRef<T> createApexCudaMemRef(T* ptr, size_t size, ApexCudaMemRefBase::Intent intent = ApexCudaMemFlags::IN_OUT)
+{
+ return ApexCudaMemRef<T>(ptr, sizeof(T) * size, intent);
+}
+
+template <class T>
+inline ApexCudaMemRef<T> createApexCudaMemRef(T* ptr, size_t size, int32_t offset, ApexCudaMemRefBase::Intent intent)
+{
+ return ApexCudaMemRef<T>(ptr, sizeof(T) * size, sizeof(T) * offset, intent);
+}
+
+template <class T>
+inline ApexCudaMemRef<T> createApexCudaMemRef(const ApexMirroredArray<T>& ma, ApexCudaMemRefBase::Intent intent = ApexCudaMemFlags::IN_OUT)
+{
+ return ApexCudaMemRef<T>(ma.getGpuPtr(), ma.getByteSize(), intent);
+}
+
+template <class T>
+inline ApexCudaMemRef<T> createApexCudaMemRef(const ApexMirroredArray<T>& ma, size_t size, ApexCudaMemRefBase::Intent intent = ApexCudaMemFlags::IN_OUT)
+{
+ return ApexCudaMemRef<T>(ma.getGpuPtr(), sizeof(T) * size, intent);
+}
+
+template <class T>
+inline ApexCudaMemRef<T> createApexCudaMemRef(const ApexMirroredArray<T>& ma, size_t size, int32_t offset, ApexCudaMemRefBase::Intent intent = ApexCudaMemFlags::IN_OUT)
+{
+ return ApexCudaMemRef<T>(ma.getGpuPtr(), sizeof(T) * size, sizeof(T) * offset, intent);
+}
+
+#ifndef ALIGN_OFFSET
+#define ALIGN_OFFSET(offset, alignment) (offset) = ((offset) + (alignment) - 1) & ~((alignment) - 1)
+#endif
+
+#define CUDA_MAX_PARAM_SIZE 256
+
+
+class ApexCudaTestKernelContext;
+
+
+class ApexCudaConstStorage;
+
+class ApexCudaModule
+{
+public:
+ ApexCudaModule()
+ : mCuModule(0), mStorage(0)
+ {
+ }
+
+ PX_INLINE void init(const void* image)
+ {
+ if (mCuModule == 0)
+ {
+ CUT_SAFE_CALL(cuModuleLoadDataEx(&mCuModule, image, 0, NULL, NULL));
+ }
+ }
+ PX_INLINE void release()
+ {
+ if (mCuModule != 0)
+ {
+ CUT_SAFE_CALL(cuModuleUnload(mCuModule));
+ mCuModule = 0;
+ }
+ }
+
+ PX_INLINE bool isValid() const
+ {
+ return (mCuModule != 0);
+ }
+
+ PX_INLINE CUmodule getCuModule() const
+ {
+ return mCuModule;
+ }
+
+ PX_INLINE ApexCudaConstStorage* getStorage() const
+ {
+ return mStorage;
+ }
+
+private:
+ CUmodule mCuModule;
+ ApexCudaConstStorage* mStorage;
+
+ friend class ApexCudaConstStorage;
+};
+
+class ApexCudaObjManager;
+
+class ApexCudaObj
+{
+ friend class ApexCudaObjManager;
+ ApexCudaObj* mObjListNext;
+
+protected:
+ const char* mName;
+ ApexCudaModule* mCudaModule;
+ ApexCudaObjManager* mManager;
+
+ ApexCudaObj(const char* name) : mObjListNext(0), mName(name), mCudaModule(NULL), mManager(NULL) {}
+ virtual ~ApexCudaObj() {}
+
+ PX_INLINE void init(ApexCudaObjManager* manager, ApexCudaModule* cudaModule);
+
+public:
+ const char* getName() const
+ {
+ return mName;
+ }
+ const ApexCudaModule* getCudaModule() const
+ {
+ return mCudaModule;
+ }
+
+ enum ApexCudaObjType
+ {
+ UNKNOWN,
+ FUNCTION,
+ TEXTURE,
+ CONST_STORAGE,
+ SURFACE
+ };
+ virtual ApexCudaObjType getType()
+ {
+ return UNKNOWN;
+ }
+
+ PX_INLINE ApexCudaObj* next()
+ {
+ return mObjListNext;
+ }
+ virtual void release() = 0;
+ virtual void formContext(ApexCudaTestKernelContext*) = 0;
+};
+
+struct ApexCudaDeviceTraits
+{
+ uint32_t mMaxSharedMemPerBlock;
+ uint32_t mMaxSharedMemPerSM;
+ uint32_t mMaxRegistersPerSM;
+ uint32_t mMaxThreadsPerSM;
+
+ uint32_t mBlocksPerSM;
+ uint32_t mBlocksPerSM_2D;
+ uint32_t mBlocksPerSM_3D;
+ uint32_t mMaxBlocksPerGrid;
+};
+
+class ApexCudaObjManager
+{
+ ApexCudaObj* mObjListHead;
+
+ Module* mNxModule;
+ ApexCudaTestManager* mCudaTestManager;
+ PxGpuDispatcher* mGpuDispatcher;
+
+ ApexCudaDeviceTraits mDeviceTraits;
+
+protected:
+ friend class ApexCudaFunc;
+ ApexCudaProfileSession* mCudaProfileSession;
+
+public:
+ ApexCudaObjManager() : mObjListHead(0), mNxModule(0), mCudaTestManager(0), mGpuDispatcher(0), mCudaProfileSession(0) {}
+
+ void init(Module* nxModule, ApexCudaTestManager* cudaTestManager, PxGpuDispatcher* gpuDispatcher)
+ {
+ mNxModule = nxModule;
+ mCudaTestManager = cudaTestManager;
+ mGpuDispatcher = gpuDispatcher;
+
+ //get device traits
+ CUdevice device;
+ CUT_SAFE_CALL(cuCtxGetDevice(&device));
+ CUT_SAFE_CALL(cuDeviceGetAttribute((int*)&mDeviceTraits.mMaxSharedMemPerBlock, CU_DEVICE_ATTRIBUTE_MAX_SHARED_MEMORY_PER_BLOCK, device));
+ CUT_SAFE_CALL(cuDeviceGetAttribute((int*)&mDeviceTraits.mMaxSharedMemPerSM, CU_DEVICE_ATTRIBUTE_MAX_SHARED_MEMORY_PER_MULTIPROCESSOR, device));
+ CUT_SAFE_CALL(cuDeviceGetAttribute((int*)&mDeviceTraits.mMaxRegistersPerSM, CU_DEVICE_ATTRIBUTE_MAX_REGISTERS_PER_MULTIPROCESSOR, device));
+ CUT_SAFE_CALL(cuDeviceGetAttribute((int*)&mDeviceTraits.mMaxThreadsPerSM, CU_DEVICE_ATTRIBUTE_MAX_THREADS_PER_MULTIPROCESSOR, device));
+
+#ifdef APEX_CUDA_FORCED_BLOCKS
+ mDeviceTraits.mBlocksPerSM = (APEX_CUDA_FORCED_BLOCKS > 32) ? 2u : 1u;
+ mDeviceTraits.mMaxBlocksPerGrid = APEX_CUDA_FORCED_BLOCKS;
+#else
+ int computeMajor;
+ int smCount;
+ CUT_SAFE_CALL(cuDeviceGetAttribute(&smCount, CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT, device));
+ CUT_SAFE_CALL(cuDeviceGetAttribute(&computeMajor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, device));
+
+ mDeviceTraits.mBlocksPerSM = 2;//(computeMajor >= 5) ? 2u : 1u;
+ mDeviceTraits.mMaxBlocksPerGrid = uint32_t(smCount) * mDeviceTraits.mBlocksPerSM;
+#endif
+ mDeviceTraits.mBlocksPerSM_2D = 4;
+ mDeviceTraits.mBlocksPerSM_3D = 4;
+ }
+
+ PX_INLINE const ApexCudaDeviceTraits& getDeviceTraits() const
+ {
+ return mDeviceTraits;
+ }
+
+ PX_INLINE void addToObjList(ApexCudaObj* obj)
+ {
+ obj->mObjListNext = mObjListHead;
+ mObjListHead = obj;
+ }
+
+ PX_INLINE ApexCudaObj* getObjListHead()
+ {
+ return mObjListHead;
+ }
+
+ void releaseAll()
+ {
+ for (ApexCudaObj* obj = mObjListHead; obj != 0; obj = obj->mObjListNext)
+ {
+ obj->release();
+ }
+ }
+
+ PX_INLINE Module* getModule() const
+ {
+ return mNxModule;
+ }
+ PX_INLINE ApexCudaTestManager* getCudaTestManager() const
+ {
+ return mCudaTestManager;
+ }
+ PX_INLINE PxGpuDispatcher* getGpuDispatcher() const
+ {
+ return mGpuDispatcher;
+ }
+
+public:
+ virtual void onBeforeLaunchApexCudaFunc(const ApexCudaFunc& func, CUstream stream) = 0;
+ virtual void onAfterLaunchApexCudaFunc(const ApexCudaFunc& func, CUstream stream) = 0;
+
+};
+
+PX_INLINE void ApexCudaObj::init(ApexCudaObjManager* manager, ApexCudaModule* cudaModule)
+{
+ mManager = manager;
+ mManager->addToObjList(this);
+ mCudaModule = cudaModule;
+}
+
+
+class ApexCudaTexRef : public ApexCudaObj
+{
+public:
+ void init(ApexCudaObjManager* manager, CUtexref texRef, ApexCudaModule* cudaModule, CUarray_format format, int numChannels, int dim, int flags)
+ {
+ ApexCudaObj::init(manager, cudaModule);
+
+ mTexRef = texRef;
+ mDim = dim;
+ mFormat = format;
+ mNumChannels = numChannels;
+ mFlags = flags;
+ mIsBinded = false;
+
+ CUT_SAFE_CALL(cuTexRefSetFilterMode(mTexRef, mFilterMode));
+
+ for (int d = 0; d < dim; ++d)
+ {
+ CUT_SAFE_CALL(cuTexRefSetAddressMode(mTexRef, d, CU_TR_ADDRESS_MODE_CLAMP));
+ }
+ }
+
+ ApexCudaTexRef(const char* name, CUfilter_mode filterMode = CU_TR_FILTER_MODE_POINT)
+ : ApexCudaObj(name), mTexRef(0), mFilterMode(filterMode)
+ {
+ }
+
+ void setNormalizedCoords()
+ {
+ mFlags |= CU_TRSF_NORMALIZED_COORDINATES;
+ }
+
+ void bindTo(const void* ptr, size_t bytes, size_t* retByteOffset = 0)
+ {
+ CUT_SAFE_CALL(cuTexRefSetFormat(mTexRef, mFormat, mNumChannels));
+ CUT_SAFE_CALL(cuTexRefSetFlags(mTexRef, (uint32_t)mFlags));
+
+ size_t byteOffset;
+ CUT_SAFE_CALL(cuTexRefSetAddress(&byteOffset, mTexRef, CUT_TODEVICE(ptr), static_cast<unsigned int>(bytes)));
+
+ if (retByteOffset != 0)
+ {
+ *retByteOffset = byteOffset;
+ }
+ else
+ {
+ PX_ASSERT(byteOffset == 0);
+ }
+
+ mBindedSize = bytes;
+ mBindedPtr = ptr;
+ mBindedArray = NULL;
+ mIsBinded = true;
+ }
+
+ template <typename T>
+ void bindTo(ApexMirroredArray<T>& mem, size_t* retByteOffset = 0)
+ {
+ bindTo(mem.getGpuPtr(), mem.getByteSize(), retByteOffset);
+ }
+
+ template <typename T>
+ void bindTo(ApexMirroredArray<T>& mem, size_t size, size_t* retByteOffset = 0)
+ {
+ bindTo(mem.getGpuPtr(), sizeof(T) * size, retByteOffset);
+ }
+
+ void bindTo(CUarray cuArray)
+ {
+ CUT_SAFE_CALL(cuTexRefSetFlags(mTexRef, (uint32_t)mFlags));
+
+ CUT_SAFE_CALL(cuTexRefSetArray(mTexRef, cuArray, CU_TRSA_OVERRIDE_FORMAT));
+
+ mBindedSize = 0;
+ mBindedPtr = NULL;
+ mBindedArray = cuArray;
+ mIsBinded = true;
+ }
+
+ void bindTo(const ApexCudaArray& cudaArray)
+ {
+ bindTo(cudaArray.getCuArray());
+ }
+
+ void unbind()
+ {
+ size_t byteOffset;
+ CUT_SAFE_CALL(cuTexRefSetAddress(&byteOffset, mTexRef, CUdeviceptr(0), 0));
+ mIsBinded = false;
+ }
+
+ virtual ApexCudaObjType getType()
+ {
+ return TEXTURE;
+ }
+
+ virtual void release() {}
+
+ virtual void formContext(ApexCudaTestKernelContext* context)
+ {
+ if (mIsBinded)
+ {
+ context->addTexRef(mName, mBindedPtr, mBindedSize, mBindedArray);
+ }
+ }
+
+private:
+ CUtexref mTexRef;
+ CUfilter_mode mFilterMode;
+
+ CUarray_format mFormat;
+ int mNumChannels;
+ int mDim;
+ int mFlags;
+
+ bool mIsBinded;
+ size_t mBindedSize;
+ const void* mBindedPtr;
+ CUarray mBindedArray;
+};
+
+
+class ApexCudaSurfRef : public ApexCudaObj
+{
+public:
+ void init(ApexCudaObjManager* manager, CUsurfref surfRef, ApexCudaModule* cudaModule)
+ {
+ ApexCudaObj::init(manager, cudaModule);
+
+ mSurfRef = surfRef;
+
+ mIsBinded = false;
+ }
+
+ ApexCudaSurfRef(const char* name) : ApexCudaObj(name), mSurfRef(0)
+ {
+ }
+
+ void bindTo(CUarray cuArray, ApexCudaMemFlags::Enum flags)
+ {
+ CUDA_ARRAY3D_DESCRIPTOR desc;
+ CUT_SAFE_CALL(cuArray3DGetDescriptor(&desc, cuArray));
+
+ CUT_SAFE_CALL(cuSurfRefSetArray(mSurfRef, cuArray, 0));
+
+ mIsBinded = true;
+ mBindedArray = cuArray;
+ mBindedFlags = flags;
+ }
+
+ void bindTo(const ApexCudaArray& cudaArray, ApexCudaMemFlags::Enum flags)
+ {
+ bindTo(cudaArray.getCuArray(), flags);
+ }
+
+ void unbind()
+ {
+ mIsBinded = false;
+ }
+
+ virtual ApexCudaObjType getType()
+ {
+ return SURFACE;
+ }
+
+ virtual void release() {}
+
+ virtual void formContext(ApexCudaTestKernelContext* context)
+ {
+ if (mIsBinded)
+ {
+ context->addSurfRef(mName, mBindedArray, mBindedFlags);
+ }
+ }
+
+private:
+ CUsurfref mSurfRef;
+
+ bool mIsBinded;
+ CUarray mBindedArray;
+ ApexCudaMemFlags::Enum mBindedFlags;
+};
+
+class ApexCudaTexRefScopeBind
+{
+private:
+ ApexCudaTexRefScopeBind& operator=(const ApexCudaTexRefScopeBind&);
+ ApexCudaTexRef& mTexRef;
+
+public:
+ ApexCudaTexRefScopeBind(ApexCudaTexRef& texRef, void* ptr, size_t bytes, size_t* retByteOffset = 0)
+ : mTexRef(texRef)
+ {
+ mTexRef.bindTo(ptr, bytes, retByteOffset);
+ }
+ template <typename T>
+ ApexCudaTexRefScopeBind(ApexCudaTexRef& texRef, ApexMirroredArray<T>& mem, size_t* retByteOffset = 0)
+ : mTexRef(texRef)
+ {
+ mTexRef.bindTo(mem, retByteOffset);
+ }
+ template <typename T>
+ ApexCudaTexRefScopeBind(ApexCudaTexRef& texRef, ApexMirroredArray<T>& mem, size_t size, size_t* retByteOffset = 0)
+ : mTexRef(texRef)
+ {
+ mTexRef.bindTo(mem, size, retByteOffset);
+ }
+ ApexCudaTexRefScopeBind(ApexCudaTexRef& texRef, const ApexCudaArray& cudaArray)
+ : mTexRef(texRef)
+ {
+ mTexRef.bindTo(cudaArray);
+ }
+ ~ApexCudaTexRefScopeBind()
+ {
+ mTexRef.unbind();
+ }
+};
+
+#define APEX_CUDA_TEXTURE_SCOPE_BIND(texRef, mem) ApexCudaTexRefScopeBind texRefScopeBind_##texRef (CUDA_OBJ(texRef), mem);
+#define APEX_CUDA_TEXTURE_SCOPE_BIND_SIZE(texRef, mem, size) ApexCudaTexRefScopeBind texRefScopeBind_##texRef (CUDA_OBJ(texRef), mem, size);
+#define APEX_CUDA_TEXTURE_SCOPE_BIND_PTR(texRef, ptr, count) ApexCudaTexRefScopeBind texRefScopeBind_##texRef (CUDA_OBJ(texRef), ptr, sizeof(*ptr) * count);
+#define APEX_CUDA_TEXTURE_BIND(texRef, mem) CUDA_OBJ(texRef).bindTo(mem);
+#define APEX_CUDA_TEXTURE_BIND_PTR(texRef, ptr, count) CUDA_OBJ(texRef).bindTo(ptr, sizeof(*ptr) * count);
+#define APEX_CUDA_TEXTURE_UNBIND(texRef) CUDA_OBJ(texRef).unbind();
+
+
+class ApexCudaSurfRefScopeBind
+{
+private:
+ ApexCudaSurfRefScopeBind& operator=(const ApexCudaSurfRefScopeBind&);
+ ApexCudaSurfRef& mSurfRef;
+
+public:
+ ApexCudaSurfRefScopeBind(ApexCudaSurfRef& surfRef, ApexCudaArray& cudaArray, ApexCudaMemFlags::Enum flags)
+ : mSurfRef(surfRef)
+ {
+ mSurfRef.bindTo(cudaArray, flags);
+ }
+ ApexCudaSurfRefScopeBind(ApexCudaSurfRef& surfRef, CUarray cuArray, ApexCudaMemFlags::Enum flags)
+ : mSurfRef(surfRef)
+ {
+ mSurfRef.bindTo(cuArray, flags);
+ }
+ ~ApexCudaSurfRefScopeBind()
+ {
+ mSurfRef.unbind();
+ }
+};
+
+#define APEX_CUDA_SURFACE_SCOPE_BIND(surfRef, mem, flags) ApexCudaSurfRefScopeBind surfRefScopeBind_##surfRef (CUDA_OBJ(surfRef), mem, flags);
+#define APEX_CUDA_SURFACE_BIND(surfRef, mem, flags) CUDA_OBJ(surfRef).bindTo(mem, flags);
+#define APEX_CUDA_SURFACE_UNBIND(surfRef) CUDA_OBJ(surfRef).unbind();
+
+
+class ApexCudaVar : public ApexCudaObj
+{
+public:
+ size_t getSize() const
+ {
+ return mSize;
+ }
+
+ void init(ApexCudaObjManager* manager, ApexCudaModule* cudaModule, CUdeviceptr devPtr, size_t size, PxCudaContextManager* ctx)
+ {
+ ApexCudaObj::init(manager, cudaModule);
+
+ mDevPtr = devPtr;
+ mSize = size;
+ init(manager, ctx);
+ }
+
+ virtual void release() {}
+ virtual void formContext(ApexCudaTestKernelContext*) {}
+
+protected:
+ virtual void init(ApexCudaObjManager* , PxCudaContextManager*) = 0;
+
+ ApexCudaVar(const char* name) : ApexCudaObj(name), mDevPtr(0), mSize(0)
+ {
+ }
+
+protected:
+ CUdeviceptr mDevPtr;
+ size_t mSize;
+};
+
+
+class ApexCudaConstStorage : public ApexCudaVar, public InplaceStorage
+{
+public:
+ ApexCudaConstStorage(const char* nameVar, const char* nameTexRef)
+ : ApexCudaVar(nameVar), mCudaTexRef(nameTexRef), mStoreInTexture(false)
+ {
+ mStorageSize = 0;
+ mStoragePtr = 0;
+
+ mHostBuffer = 0;
+ mDeviceBuffer = 0;
+ }
+
+ virtual ApexCudaObjType getType()
+ {
+ return CONST_STORAGE;
+ }
+
+ virtual void formContext(ApexCudaTestKernelContext* context)
+ {
+ if (!mStoreInTexture && mHostBuffer != 0)
+ {
+ PX_ASSERT(mHostBuffer->getSize() >= ApexCudaVar::getSize());
+ void* hostPtr = reinterpret_cast<void*>(mHostBuffer->getPtr());
+ context->addConstMem(mName, hostPtr, ApexCudaVar::getSize());
+ }
+ }
+
+ virtual void init(ApexCudaObjManager* manager, PxCudaContextManager* ctx)
+ {
+ PX_ASSERT(mCudaModule != 0);
+ PX_ASSERT(mCudaModule->mStorage == 0);
+ mCudaModule->mStorage = this;
+
+ CUtexref cuTexRef;
+ CUT_SAFE_CALL(cuModuleGetTexRef(&cuTexRef, mCudaModule->getCuModule(), mCudaTexRef.getName()));
+
+ mCudaTexRef.init(manager, cuTexRef, mCudaModule, CU_AD_FORMAT_SIGNED_INT32, 1, 1, CU_TRSF_READ_AS_INTEGER);
+
+ //prealloc. host buffer for Apex Cuda Test framework
+ reallocHostBuffer(ctx, ApexCudaVar::getSize());
+ }
+
+ virtual void release()
+ {
+ InplaceStorage::release();
+
+ if (mDeviceBuffer != 0)
+ {
+ mDeviceBuffer->free();
+ mDeviceBuffer = 0;
+ }
+ if (mHostBuffer != 0)
+ {
+ mHostBuffer->free();
+ mHostBuffer = 0;
+ }
+
+ if (mStoragePtr != 0)
+ {
+ getAllocator().deallocate(mStoragePtr);
+ mStoragePtr = 0;
+ mStorageSize = 0;
+ }
+ }
+
+ bool copyToDevice(PxCudaContextManager* ctx, CUstream stream)
+ {
+ if (mStoragePtr == 0)
+ {
+ return false;
+ }
+
+ bool result = false;
+
+ InplaceStorage* storage = static_cast<InplaceStorage*>(this);
+ mMutex.lock();
+ if (storage->isChanged())
+ {
+ if (!reallocHostBuffer(ctx, mStorageSize))
+ {
+ return false;
+ }
+
+ CUdeviceptr copyDevPtr = 0;
+ if (mStoreInTexture)
+ {
+ if (mDeviceBuffer == 0)
+ {
+ mDeviceBuffer = ctx->getMemoryManager()->alloc(
+ PxCudaBufferType(PxCudaBufferMemorySpace::T_GPU, PxCudaBufferFlags::F_READ_WRITE),
+ mStorageSize);
+ if (mDeviceBuffer == 0)
+ {
+ APEX_INTERNAL_ERROR("ApexCudaConstStorage failed to allocate GPU Memory!");
+ return false;
+ }
+ }
+ else if (mDeviceBuffer->getSize() < mStorageSize)
+ {
+ mDeviceBuffer->realloc(mStorageSize);
+ }
+ copyDevPtr = mDeviceBuffer->getPtr();
+ }
+ else
+ {
+ if (mDeviceBuffer != 0)
+ {
+ mDeviceBuffer->free();
+ mDeviceBuffer = 0;
+ }
+ copyDevPtr = mDevPtr;
+ }
+
+ uint8_t* hostPtr = reinterpret_cast<uint8_t*>(mHostBuffer->getPtr());
+
+ size_t size = storage->mapTo(hostPtr);
+ // padding up to the next dword
+ size = (size + 7) & ~7;
+ if (size > mStorageSize) size = mStorageSize;
+
+ CUT_SAFE_CALL(cuMemcpyHtoDAsync(copyDevPtr, hostPtr, size, stream));
+
+ storage->setUnchanged();
+ result = true;
+ }
+ mMutex.unlock();
+
+ return result;
+ }
+
+ PX_INLINE bool getStoreInTexture() const
+ {
+ return mStoreInTexture;
+ }
+
+ PX_INLINE void onBeforeLaunch()
+ {
+ if (mStoreInTexture)
+ {
+ mCudaTexRef.bindTo( mDeviceBuffer ? reinterpret_cast<void*>(mDeviceBuffer->getPtr()) : 0, mStorageSize );
+ }
+ }
+
+ PX_INLINE void onAfterLaunch()
+ {
+ if (mStoreInTexture)
+ {
+ mCudaTexRef.unbind();
+ }
+ }
+
+protected:
+ bool reallocHostBuffer(PxCudaContextManager* ctx, size_t size)
+ {
+ if (mHostBuffer == 0)
+ {
+ mHostBuffer = ctx->getMemoryManager()->alloc(
+ PxCudaBufferType(PxCudaBufferMemorySpace::T_PINNED_HOST, PxCudaBufferFlags::F_READ_WRITE),
+ size);
+ if (mHostBuffer == 0)
+ {
+ APEX_INTERNAL_ERROR("ApexCudaConstStorage failed to allocate Pinned Host Memory!");
+ return false;
+ }
+ }
+ else if (mHostBuffer->getSize() < size)
+ {
+ mHostBuffer->realloc(size);
+ }
+ return true;
+ }
+
+ virtual uint8_t* storageResizeBuffer(uint32_t newSize)
+ {
+ if (!mStoreInTexture && newSize > ApexCudaVar::getSize())
+ {
+#if 0
+ APEX_INTERNAL_ERROR("Out of CUDA constant memory");
+ PX_ALWAYS_ASSERT();
+ return 0;
+#else
+ //switch to texture
+ mStoreInTexture = true;
+#endif
+ }
+ else if (mStoreInTexture && newSize <= ApexCudaVar::getSize())
+ {
+ //switch back to const mem.
+ mStoreInTexture = false;
+ }
+
+ const uint32_t PageSize = 4096;
+ size_t allocSize = mStoreInTexture ? (newSize + (PageSize - 1)) & ~(PageSize - 1) : ApexCudaVar::getSize();
+
+ if (allocSize > mStorageSize)
+ {
+ uint8_t* allocStoragePtr = static_cast<uint8_t*>(getAllocator().allocate(allocSize, "ApexCudaConstStorage", __FILE__, __LINE__));
+ if (allocStoragePtr == 0)
+ {
+ APEX_INTERNAL_ERROR("ApexCudaConstStorage failed to allocate memory!");
+ return 0;
+ }
+ if (mStoragePtr != 0)
+ {
+ memcpy(allocStoragePtr, mStoragePtr, mStorageSize);
+ getAllocator().deallocate(mStoragePtr);
+ }
+ mStorageSize = allocSize;
+ mStoragePtr = allocStoragePtr;
+ }
+ return mStoragePtr;
+ }
+
+ virtual void storageLock()
+ {
+ mMutex.lock();
+ }
+ virtual void storageUnlock()
+ {
+ mMutex.unlock();
+ }
+
+private:
+ bool mStoreInTexture;
+ ApexCudaTexRef mCudaTexRef;
+
+ size_t mStorageSize;
+ uint8_t* mStoragePtr;
+
+ PxCudaBuffer* mHostBuffer;
+ PxCudaBuffer* mDeviceBuffer;
+
+ nvidia::Mutex mMutex;
+
+ friend class ApexCudaTestKernelContextReader;
+};
+
+typedef InplaceStorageGroup ApexCudaConstMemGroup;
+
+#define APEX_CUDA_CONST_MEM_GROUP_SCOPE(group) INPLACE_STORAGE_GROUP_SCOPE(group)
+
+
+
+struct ApexCudaFuncParams
+{
+ int mOffset;
+ char mParams[CUDA_MAX_PARAM_SIZE];
+
+ ApexCudaFuncParams() : mOffset(0) {}
+
+
+};
+
+class ApexCudaFunc : public ApexCudaObj
+{
+public:
+ PX_INLINE bool testNameMatch(const char* name) const
+ {
+ if (const char* name$ = strrchr(name, '$'))
+ {
+ if (const char* name_ = strrchr(name, '_'))
+ {
+ return (nvidia::strncmp(name, mName, (uint32_t)(name_ - name)) == 0);
+ }
+ }
+ return (nvidia::strcmp(name, mName) == 0);
+ }
+
+ void init(ApexCudaObjManager* manager, const char* name, CUfunction cuFunc, ApexCudaModule* cudaModule)
+ {
+ int funcInstIndex = 0;
+ if (const char* name$ = strrchr(name, '$'))
+ {
+ funcInstIndex = atoi(name$ + 1);
+ }
+ if (funcInstIndex >= MAX_INST_COUNT)
+ {
+ PX_ALWAYS_ASSERT();
+ return;
+ }
+
+ if (mFuncInstCount == 0)
+ {
+ ApexCudaObj::init(manager, cudaModule);
+ }
+
+ PxCudaContextManager* ctx = mManager->mGpuDispatcher->getCudaContextManager();
+ {
+ int funcMaxThreadsPerBlock;
+ cuFuncGetAttribute(&funcMaxThreadsPerBlock, CU_FUNC_ATTRIBUTE_MAX_THREADS_PER_BLOCK, cuFunc);
+
+ int funcNumRegsPerThread;
+ cuFuncGetAttribute(&funcNumRegsPerThread, CU_FUNC_ATTRIBUTE_NUM_REGS, cuFunc);
+
+ int funcSharedMemSize;
+ cuFuncGetAttribute(&funcSharedMemSize, CU_FUNC_ATTRIBUTE_SHARED_SIZE_BYTES, cuFunc);
+ const int sharedMemGranularity = (ctx->supportsArchSM20() ? 128 : 512) - 1;
+ funcSharedMemSize = (funcSharedMemSize + sharedMemGranularity) & ~sharedMemGranularity;
+
+ FuncInstData& fid = mFuncInstData[funcInstIndex];
+ fid.mName = name;
+ fid.mCuFunc = cuFunc;
+ fid.mMaxThreadsPerBlock = (uint32_t)funcMaxThreadsPerBlock;
+
+ fid.mNumRegsPerThread = (uint32_t)funcNumRegsPerThread;
+ fid.mStaticSharedSize = (uint32_t)funcSharedMemSize;
+ PX_ASSERT(fid.mStaticSharedSize <= mManager->getDeviceTraits().mMaxSharedMemPerBlock);
+
+ fid.mWarpsPerBlock = 0;
+ fid.mDynamicShared = 0;
+ }
+
+ init(ctx, funcInstIndex);
+ mFuncInstCount = PxMax(mFuncInstCount, uint32_t(funcInstIndex) + 1);
+ }
+
+ virtual ApexCudaObjType getType()
+ {
+ return FUNCTION;
+ }
+ virtual void release() {}
+
+ virtual void formContext(ApexCudaTestKernelContext*) {}
+
+ /** This function force cuda stream syncronization that may slowdown application
+ */
+ PX_INLINE void setProfileSession(ApexCudaProfileSession* cudaProfileSession)
+ {
+ mManager->mCudaProfileSession = cudaProfileSession;
+ mProfileId = cudaProfileSession ? cudaProfileSession->getProfileId(mName, mManager->mNxModule->getName()) : 0;
+ }
+
+ PX_INLINE uint32_t getProfileId() const
+ {
+ return mProfileId;
+ }
+
+protected:
+ static const int MAX_INST_COUNT = 2;
+
+ struct FuncInstData
+ {
+ const char* mName;
+ CUfunction mCuFunc;
+
+ uint32_t mMaxThreadsPerBlock;
+ uint32_t mNumRegsPerThread;
+ uint32_t mStaticSharedSize;
+
+ uint32_t mWarpsPerBlock;
+ uint32_t mDynamicShared;
+ };
+
+ uint32_t mFuncInstCount;
+ FuncInstData mFuncInstData[MAX_INST_COUNT];
+
+ uint32_t mProfileId;
+ ApexCudaTestKernelContext* mCTContext;
+
+ ApexCudaFunc(const char* name)
+ : ApexCudaObj(name), mFuncInstCount(0), mProfileId(0), mCTContext(0)
+ {
+ }
+ virtual void init(PxCudaContextManager* , int /*funcInstIndex*/) {}
+
+ bool isValid() const
+ {
+ return (mFuncInstCount != 0) && (mCudaModule != 0);
+ }
+
+ const FuncInstData& getFuncInstData() const
+ {
+ PX_ASSERT(isValid());
+
+ ApexCudaConstStorage* storage = mCudaModule->getStorage();
+ if (storage != 0 && mFuncInstCount > 1)
+ {
+ PX_ASSERT(mFuncInstCount == 2);
+ return mFuncInstData[ storage->getStoreInTexture() ? 1 : 0 ];
+ }
+ else
+ {
+ PX_ASSERT(mFuncInstCount == 1);
+ return mFuncInstData[0];
+ }
+ }
+
+ PX_INLINE void onBeforeLaunch(CUstream stream)
+ {
+ if (ApexCudaConstStorage* storage = mCudaModule->getStorage())
+ {
+ storage->onBeforeLaunch();
+ }
+
+ mManager->onBeforeLaunchApexCudaFunc(*this, stream);
+ }
+ PX_INLINE void onAfterLaunch(CUstream stream)
+ {
+ mManager->onAfterLaunchApexCudaFunc(*this, stream);
+
+ if (ApexCudaConstStorage* storage = mCudaModule->getStorage())
+ {
+ storage->onAfterLaunch();
+ }
+ }
+
+ template <typename T>
+ void setParam(ApexCudaFuncParams& params, T* ptr)
+ {
+ ALIGN_OFFSET(params.mOffset, (int)__alignof(ptr));
+ PX_ASSERT(params.mOffset + sizeof(ptr) <= CUDA_MAX_PARAM_SIZE);
+ memcpy(params.mParams + params.mOffset, &ptr, sizeof(ptr));
+ params.mOffset += sizeof(ptr);
+ mCTContext = NULL; // context can't catch pointers, use instead ApexCudaMemRef
+ }
+
+ template <typename T>
+ void setParam(ApexCudaFuncParams& params, const ApexCudaMemRef<T>& memRef)
+ {
+ T* ptr = memRef.getPtr();
+ ALIGN_OFFSET(params.mOffset, (int)__alignof(ptr));
+ PX_ASSERT(params.mOffset + sizeof(ptr) <= CUDA_MAX_PARAM_SIZE);
+ memcpy(params.mParams + params.mOffset, &ptr, sizeof(ptr));
+ params.mOffset += sizeof(ptr);
+ }
+
+ template <typename T>
+ void setParam(ApexCudaFuncParams& params, const T& val)
+ {
+ ALIGN_OFFSET(params.mOffset, (int)__alignof(val));
+ PX_ASSERT(params.mOffset + sizeof(val) <= CUDA_MAX_PARAM_SIZE);
+ memcpy(params.mParams + params.mOffset, (void*)&val, sizeof(val));
+ params.mOffset += sizeof(val);
+ }
+
+ void resolveContext()
+ {
+ mCTContext->startObjList();
+ ApexCudaObj* obj = mManager->getObjListHead();
+ while(obj)
+ {
+ if ((CUmodule)obj->getCudaModule()->getCuModule() == mCudaModule->getCuModule())
+ {
+ obj->formContext(mCTContext);
+ }
+ obj = obj->next();
+ }
+ mCTContext->finishObjList();
+ }
+
+ template <typename T>
+ void copyParam(const char* name, const ApexCudaMemRef<T>& memRef)
+ {
+ mCTContext->addParam(name, __alignof(void*), memRef.ptr, memRef.size, memRef.intent, memRef.offset);
+ }
+
+ template <typename T>
+ void copyParam(const char* name, const T& val)
+ {
+ mCTContext->addParam(name, __alignof(val), (void*)&val, sizeof(val));
+ }
+
+private:
+ template <typename T>
+ void copyParam(const char* name, const ApexCudaMemRef<T>& memRef, uint32_t fpType)
+ {
+ mCTContext->addParam(name, __alignof(void*), memRef.ptr, memRef.size, memRef.intent, memRef.offset, fpType);
+ }
+ void setParam(ApexCudaFuncParams& params, unsigned align, unsigned size, void* ptr)
+ {
+ ALIGN_OFFSET(params.mOffset, (int)align);
+ PX_ASSERT(params.mOffset + size <= CUDA_MAX_PARAM_SIZE);
+ memcpy(params.mParams + params.mOffset, ptr, (uint32_t)size);
+ params.mOffset += size;
+ }
+ friend class ApexCudaTestKernelContextReader;
+};
+
+template <>
+inline void ApexCudaFunc::copyParam<float>(const char* name, const ApexCudaMemRef<float>& memRef)
+{
+ copyParam(name, memRef, 4);
+}
+
+template <>
+inline void ApexCudaFunc::copyParam<float2>(const char* name, const ApexCudaMemRef<float2>& memRef)
+{
+ copyParam(name, memRef, 4);
+}
+
+template <>
+inline void ApexCudaFunc::copyParam<float3>(const char* name, const ApexCudaMemRef<float3>& memRef)
+{
+ copyParam(name, memRef, 4);
+}
+
+template <>
+inline void ApexCudaFunc::copyParam<float4>(const char* name, const ApexCudaMemRef<float4>& memRef)
+{
+ copyParam(name, memRef, 4);
+}
+
+template <>
+inline void ApexCudaFunc::copyParam<double>(const char* name, const ApexCudaMemRef<double>& memRef)
+{
+ copyParam(name, memRef, 8);
+}
+
+
+class ApexCudaTimer
+{
+public:
+ ApexCudaTimer()
+ : mIsStarted(false)
+ , mIsFinished(false)
+ , mStart(NULL)
+ , mFinish(NULL)
+ {
+ }
+ ~ApexCudaTimer()
+ {
+ if (mStart != NULL)
+ {
+ CUT_SAFE_CALL(cuEventDestroy(mStart));
+ }
+ if (mFinish != NULL)
+ {
+ CUT_SAFE_CALL(cuEventDestroy(mFinish));
+ }
+ }
+ void init()
+ {
+ if (mStart == NULL)
+ {
+ CUT_SAFE_CALL(cuEventCreate(&mStart, CU_EVENT_DEFAULT));
+ }
+ if (mFinish == NULL)
+ {
+ CUT_SAFE_CALL(cuEventCreate(&mFinish, CU_EVENT_DEFAULT));
+ }
+ }
+
+ void onStart(CUstream stream)
+ {
+ if (mStart != NULL)
+ {
+ mIsStarted = true;
+ CUT_SAFE_CALL(cuEventRecord(mStart, stream));
+ }
+ }
+ void onFinish(CUstream stream)
+ {
+ if (mFinish != NULL && mIsStarted)
+ {
+ mIsFinished = true;
+ CUT_SAFE_CALL(cuEventRecord(mFinish, stream));
+ }
+ }
+
+ float getElapsedTime()
+ {
+ if (mIsStarted && mIsFinished)
+ {
+ mIsStarted = false;
+ mIsFinished = false;
+ CUT_SAFE_CALL(cuEventSynchronize(mStart));
+ CUT_SAFE_CALL(cuEventSynchronize(mFinish));
+ float time;
+ CUT_SAFE_CALL(cuEventElapsedTime(&time, mStart, mFinish));
+ return time;
+ }
+ else
+ {
+ return 0.0f;
+ }
+ }
+private:
+ CUevent mStart, mFinish;
+ bool mIsStarted;
+ bool mIsFinished;
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif //__APEX_CUDA_WRAPPER_H__
diff --git a/APEX_1.4/common/include/ApexCutil.h b/APEX_1.4/common/include/ApexCutil.h
new file mode 100644
index 00000000..c6a545e1
--- /dev/null
+++ b/APEX_1.4/common/include/ApexCutil.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 APEX_CUTIL_H
+#define APEX_CUTIL_H
+
+#if defined(__CUDACC__)
+# define CUT_SAFE_CALL(call) call
+# define CUT_CHECK_ERROR(errorMessage)
+#else
+# include "ApexSDKIntl.h"
+
+# define CUT_SAFE_CALL(call) { CUresult ret = call; \
+ if( CUDA_SUCCESS != ret ) { \
+ APEX_INTERNAL_ERROR("Cuda Error %d", ret); \
+ PX_ASSERT(!ret); } }
+
+# if _DEBUG
+# define CUT_CHECK_ERROR(errorMessage) \
+ if( CUDA_SUCCESS != cuCtxSynchronize() ) { \
+ APEX_INTERNAL_ERROR(errorMessage); \
+ PX_ASSERT(0); }
+# else
+# define CUT_CHECK_ERROR(errorMessage)
+# endif
+
+#endif
+
+#define CUT_TODEVICE(gpuptr) (CUdeviceptr)(size_t)(gpuptr)
+
+#endif
diff --git a/APEX_1.4/common/include/ApexFIFO.h b/APEX_1.4/common/include/ApexFIFO.h
new file mode 100644
index 00000000..b087ac0e
--- /dev/null
+++ b/APEX_1.4/common/include/ApexFIFO.h
@@ -0,0 +1,136 @@
+/*
+ * 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 __APEX_FIFO_H__
+#define __APEX_FIFO_H__
+
+#include "Apex.h"
+#include "PsUserAllocated.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+template <typename T>
+struct FIFOEntry
+{
+ T data;
+ uint32_t next;
+ bool isValidEntry;
+};
+
+template<typename T>
+class ApexFIFO : public UserAllocated
+{
+public:
+ ApexFIFO() : first((uint32_t) - 1), last((uint32_t) - 1), count(0) {}
+
+ bool popFront(T& frontElement)
+ {
+ if (first == (uint32_t)-1)
+ {
+ return false;
+ }
+
+ PX_ASSERT(first < list.size());
+ frontElement = list[first].data;
+
+ if (first == last)
+ {
+ list.clear();
+ first = (uint32_t) - 1;
+ last = (uint32_t) - 1;
+ }
+ else
+ {
+ list[first].isValidEntry = false;
+
+ if (list[last].next == (uint32_t)-1)
+ {
+ list[last].next = first;
+ }
+ first = list[first].next;
+ }
+
+ count--;
+ return true;
+ }
+
+
+ void pushBack(const T& newElement)
+ {
+ if (list.size() == 0 || list[last].next == (uint32_t)-1)
+ {
+ FIFOEntry<T> newEntry;
+ newEntry.data = newElement;
+ newEntry.next = (uint32_t) - 1;
+ newEntry.isValidEntry = true;
+ list.pushBack(newEntry);
+
+ if (first == (uint32_t) - 1)
+ {
+ PX_ASSERT(last == (uint32_t) - 1);
+ first = list.size() - 1;
+ }
+ else
+ {
+ PX_ASSERT(last != (uint32_t) - 1);
+ list[last].next = list.size() - 1;
+ }
+
+ last = list.size() - 1;
+ }
+ else
+ {
+ uint32_t freeIndex = list[last].next;
+ PX_ASSERT(freeIndex < list.size());
+
+ FIFOEntry<T>& freeEntry = list[freeIndex];
+ freeEntry.data = newElement;
+ freeEntry.isValidEntry = true;
+
+ if (freeEntry.next == first)
+ {
+ freeEntry.next = (uint32_t) - 1;
+ }
+
+ last = freeIndex;
+ }
+ count++;
+ }
+
+ uint32_t size()
+ {
+ return count;
+ }
+
+ PX_INLINE void reserve(const uint32_t capacity)
+ {
+ list.reserve(capacity);
+ }
+
+ PX_INLINE uint32_t capacity() const
+ {
+ return list.capacity();
+ }
+
+private:
+ uint32_t first;
+ uint32_t last;
+ uint32_t count;
+ physx::Array<FIFOEntry<T> > list;
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif \ No newline at end of file
diff --git a/APEX_1.4/common/include/ApexFind.h b/APEX_1.4/common/include/ApexFind.h
new file mode 100644
index 00000000..32801944
--- /dev/null
+++ b/APEX_1.4/common/include/ApexFind.h
@@ -0,0 +1,63 @@
+/*
+ * 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 APEX_FIND_H
+#define APEX_FIND_H
+
+namespace nvidia
+{
+namespace apex
+{
+ // binary search
+ template<class Sortable>
+ int32_t ApexFind(const Sortable* buffer, uint32_t numEntries, const Sortable& element, int (*compare)(const void*, const void*))
+ {
+
+#if PX_CHECKED
+ if (numEntries > 0)
+ {
+ for (uint32_t i = 1; i < numEntries; ++i)
+ {
+ PX_ASSERT(compare(buffer + i - 1, buffer + i) <= 0);
+ }
+ }
+#endif
+
+ int32_t curMin = 0;
+ int32_t curMax = (int32_t)numEntries;
+ int32_t testIndex = 0;
+
+ while (curMin < curMax)
+ {
+ testIndex = (curMin + curMax) / 2;
+ int32_t compResult = compare(&element, buffer+testIndex);
+ if (compResult < 0)
+ {
+ curMax = testIndex;
+ }
+ else if (compResult > 0)
+ {
+ curMin = testIndex;
+ }
+ else
+ {
+ return testIndex;
+ }
+
+ }
+
+ return -1;
+ }
+
+} // namespace apex
+} // namespace nvidia
+
+#endif // APEX_FIND_H
diff --git a/APEX_1.4/common/include/ApexGeneralizedCubeTemplates.h b/APEX_1.4/common/include/ApexGeneralizedCubeTemplates.h
new file mode 100644
index 00000000..c9b18f5a
--- /dev/null
+++ b/APEX_1.4/common/include/ApexGeneralizedCubeTemplates.h
@@ -0,0 +1,133 @@
+/*
+ * 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 __APEX_GENERALIZED_CUBE_TEMPLATES_H__
+#define __APEX_GENERALIZED_CUBE_TEMPLATES_H__
+
+#include "ApexUsingNamespace.h"
+#include "PsUserAllocated.h"
+#include "PsArray.h"
+
+#include "PxVec3.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+class ApexGeneralizedCubeTemplates : public UserAllocated
+{
+public:
+ ApexGeneralizedCubeTemplates();
+
+ void getTriangles(const int groups[8], physx::Array<int32_t> &indices);
+
+private:
+
+ enum AllConsts
+ {
+ GEN_NUM_SUB_CELLS = 6,
+ SUB_GRID_LEN = GEN_NUM_SUB_CELLS,
+ SUB_GRID_LEN_2 = GEN_NUM_SUB_CELLS * GEN_NUM_SUB_CELLS,
+ NUM_SUB_CELLS = GEN_NUM_SUB_CELLS * GEN_NUM_SUB_CELLS * GEN_NUM_SUB_CELLS,
+ NUM_CUBE_VERTS = 19,
+ NUM_CASES_3 = 6561, // 2^8
+ };
+ struct GenSubCell
+ {
+ inline void init()
+ {
+ group = -1;
+ marked = false;
+ }
+ int32_t group;
+ bool marked;
+ };
+
+ struct GenCoord
+ {
+ void init(int32_t xi, int32_t yi, int32_t zi)
+ {
+ this->xi = xi;
+ this->yi = yi;
+ this->zi = zi;
+ }
+ bool operator == (const GenCoord& c) const
+ {
+ return xi == c.xi && yi == c.yi && zi == c.zi;
+ }
+
+ int32_t xi, yi, zi;
+ };
+
+
+ void createLookupTable3();
+ void setCellGroups(const int32_t groups[8]);
+ void splitDisconnectedGroups();
+ void findVertices();
+ void createTriangles(physx::Array<int32_t>& currentIndices);
+ bool isEdge(const GenCoord& c, int32_t dim, int32_t group0, int32_t group1);
+
+
+ inline uint32_t cellNr(uint32_t x, uint32_t y, uint32_t z)
+ {
+ return x * SUB_GRID_LEN_2 + y * SUB_GRID_LEN + z;
+ }
+
+ inline int32_t groupAt(int32_t x, int32_t y, int32_t z)
+ {
+ if (x < 0 || x >= SUB_GRID_LEN || y < 0 || y >= SUB_GRID_LEN || z < 0 || z >= SUB_GRID_LEN)
+ {
+ return -1;
+ }
+ return mSubGrid[x * SUB_GRID_LEN_2 + y * SUB_GRID_LEN + z].group;
+ }
+
+ inline bool vertexMarked(const GenCoord& c)
+ {
+ if (c.xi < 0 || c.xi > SUB_GRID_LEN || c.yi < 0 || c.yi > SUB_GRID_LEN || c.zi < 0 || c.zi > SUB_GRID_LEN)
+ {
+ return false;
+ }
+ return mVertexMarked[c.xi][c.yi][c.zi];
+ }
+
+ inline void markVertex(const GenCoord& c)
+ {
+ if (c.xi < 0 || c.xi > SUB_GRID_LEN || c.yi < 0 || c.yi > SUB_GRID_LEN || c.zi < 0 || c.zi > SUB_GRID_LEN)
+ {
+ return;
+ }
+ mVertexMarked[c.xi][c.yi][c.zi] = true;
+ }
+
+
+
+
+ float mBasis[NUM_SUB_CELLS][8];
+ PxVec3 mVertPos[NUM_CUBE_VERTS];
+ int mVertexAt[SUB_GRID_LEN + 1][SUB_GRID_LEN + 1][SUB_GRID_LEN + 1];
+ bool mVertexMarked[SUB_GRID_LEN + 1][SUB_GRID_LEN + 1][SUB_GRID_LEN + 1];
+
+ GenSubCell mSubGrid[NUM_SUB_CELLS];
+ int32_t mFirst3[NUM_CASES_3]; // 3^8
+
+ physx::Array<int32_t> mLookupIndices3;
+
+ int32_t mFirstPairVertex[8][8];
+ GenCoord mFirstPairCoord[8][8];
+
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif
diff --git a/APEX_1.4/common/include/ApexGeneralizedMarchingCubes.h b/APEX_1.4/common/include/ApexGeneralizedMarchingCubes.h
new file mode 100644
index 00000000..b1b153cf
--- /dev/null
+++ b/APEX_1.4/common/include/ApexGeneralizedMarchingCubes.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.
+ */
+
+
+#ifndef __APEX_GENERALIZED_MARCHING_CUBES_H__
+#define __APEX_GENERALIZED_MARCHING_CUBES_H__
+
+#include "ApexUsingNamespace.h"
+#include "PsUserAllocated.h"
+#include "PsArray.h"
+
+#include "PxBounds3.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+class IProgressListener;
+class ApexGeneralizedCubeTemplates;
+
+class ApexGeneralizedMarchingCubes : public UserAllocated
+{
+public:
+ ApexGeneralizedMarchingCubes(const PxBounds3& bound, uint32_t subdivision);
+ ~ApexGeneralizedMarchingCubes();
+
+ void release();
+
+ void registerTriangle(const PxVec3& p0, const PxVec3& p1, const PxVec3& p2);
+ bool endRegistration(uint32_t bubleSizeToRemove, IProgressListener* progress);
+
+ uint32_t getNumVertices()
+ {
+ return mVertices.size();
+ }
+ uint32_t getNumIndices()
+ {
+ return mIndices.size();
+ }
+ const PxVec3* getVertices()
+ {
+ return mVertices.begin();
+ }
+ const uint32_t* getIndices()
+ {
+ return mIndices.begin();
+ }
+private:
+
+ struct GeneralizedVertRef
+ {
+ void init()
+ {
+ vertNr = -1;
+ dangling = false;
+ deleted = false;
+ }
+ int32_t vertNr;
+ bool dangling;
+ bool deleted;
+ };
+
+ struct GeneralizedCube
+ {
+ void init(int32_t xi, int32_t yi, int32_t zi)
+ {
+ this->xi = xi;
+ this->yi = yi;
+ this->zi = zi;
+ next = -1;
+ vertRefs[0].init();
+ vertRefs[1].init();
+ vertRefs[2].init();
+ sideVertexNr[0] = -1;
+ sideVertexNr[1] = -1;
+ sideVertexNr[2] = -1;
+ sideBounds[0].setEmpty();
+ sideBounds[1].setEmpty();
+ sideBounds[2].setEmpty();
+ firstTriangle = -1;
+ numTriangles = 0;
+ deleted = false;
+ }
+ int32_t xi, yi, zi;
+ int32_t next;
+ GeneralizedVertRef vertRefs[3];
+ int32_t sideVertexNr[3];
+ PxBounds3 sideBounds[3];
+ int32_t firstTriangle;
+ uint32_t numTriangles;
+ bool deleted;
+ };
+
+ inline int hashFunction(int xi, int yi, int zi)
+ {
+ int h = (int)(unsigned int)((xi * 92837111) ^(yi * 689287499) ^(zi * 283923481));
+ return h % HASH_INDEX_SIZE;
+ }
+ int32_t createCube(int32_t xi, int32_t yi, int32_t zi);
+ int32_t findCube(int32_t xi, int32_t yi, int32_t zi);
+ void completeCells();
+ void createTrianglesForCube(int32_t cellNr);
+ void createNeighbourInfo();
+ void getCubeEdgesAndGroups(int32_t cellNr, GeneralizedVertRef* vertRefs[12], int32_t groups[8]);
+ void determineGroups();
+ void removeBubbles(int32_t minGroupSize);
+ void fixOrientations();
+ void compress();
+
+
+ PxBounds3 mBound;
+
+ float mSpacing;
+ float mInvSpacing;
+
+ physx::Array<GeneralizedCube> mCubes;
+
+ enum { HASH_INDEX_SIZE = 170111 };
+
+ int32_t mFirstCube[HASH_INDEX_SIZE];
+
+ physx::Array<PxVec3> mVertices;
+ physx::Array<uint32_t> mIndices;
+
+ physx::Array<int32_t> mFirstNeighbour;
+ physx::Array<int32_t> mNeighbours;
+ physx::Array<uint8_t> mTriangleDeleted;
+ physx::Array<int32_t> mGeneralizedTriangles;
+ physx::Array<int32_t> mCubeQueue;
+
+ physx::Array<int32_t> mTriangleGroup;
+ physx::Array<int32_t> mGroupFirstTriangle;
+ physx::Array<int32_t> mGroupTriangles;
+
+ ApexGeneralizedCubeTemplates* mTemplates;
+
+ // for debugging only
+public:
+ physx::Array<PxVec3> mDebugLines;
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif
diff --git a/APEX_1.4/common/include/ApexGroupsFiltering.h b/APEX_1.4/common/include/ApexGroupsFiltering.h
new file mode 100644
index 00000000..8ea397e1
--- /dev/null
+++ b/APEX_1.4/common/include/ApexGroupsFiltering.h
@@ -0,0 +1,158 @@
+/*
+ * 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 __APEX_GROUPS_FILTERING_H__
+#define __APEX_GROUPS_FILTERING_H__
+
+#include "ApexDefs.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+template <typename G>
+class ApexGroupsFiltering
+{
+ typedef void (*FilterOp)(const G& mask0, const G& mask1, G& result);
+
+ static void filterOp_AND(const G& mask0, const G& mask1, G& result)
+ {
+ result = (mask0 & mask1);
+ }
+ static void filterOp_OR(const G& mask0, const G& mask1, G& result)
+ {
+ result = (mask0 | mask1);
+ }
+ static void filterOp_XOR(const G& mask0, const G& mask1, G& result)
+ {
+ result = (mask0 ^ mask1);
+ }
+ static void filterOp_NAND(const G& mask0, const G& mask1, G& result)
+ {
+ result = ~(mask0 & mask1);
+ }
+ static void filterOp_NOR(const G& mask0, const G& mask1, G& result)
+ {
+ result = ~(mask0 | mask1);
+ }
+ static void filterOp_NXOR(const G& mask0, const G& mask1, G& result)
+ {
+ result = ~(mask0 ^ mask1);
+ }
+ static void filterOp_SWAP_AND(const G& mask0, const G& mask1, G& result)
+ {
+ result = SWAP_AND(mask0, mask1);
+ }
+
+ GroupsFilterOp::Enum mFilterOp0, mFilterOp1, mFilterOp2;
+ bool mFilterBool;
+ G mFilterConstant0;
+ G mFilterConstant1;
+
+public:
+ ApexGroupsFiltering()
+ {
+ mFilterOp0 = mFilterOp1 = mFilterOp2 = GroupsFilterOp::AND;
+ mFilterBool = false;
+ setZero(mFilterConstant0);
+ setZero(mFilterConstant1);
+ }
+
+ bool setFilterOps(GroupsFilterOp::Enum op0, GroupsFilterOp::Enum op1, GroupsFilterOp::Enum op2)
+ {
+ if (mFilterOp0 != op0 || mFilterOp1 != op1 || mFilterOp2 != op2)
+ {
+ mFilterOp0 = op0;
+ mFilterOp1 = op1;
+ mFilterOp2 = op2;
+ return true;
+ }
+ return false;
+ }
+ void getFilterOps(GroupsFilterOp::Enum& op0, GroupsFilterOp::Enum& op1, GroupsFilterOp::Enum& op2) const
+ {
+ op0 = mFilterOp0;
+ op1 = mFilterOp1;
+ op2 = mFilterOp2;
+ }
+
+ bool setFilterBool(bool flag)
+ {
+ if (mFilterBool != flag)
+ {
+ mFilterBool = flag;
+ return true;
+ }
+ return false;
+ }
+ bool getFilterBool() const
+ {
+ return mFilterBool;
+ }
+
+ bool setFilterConstant0(const G& mask)
+ {
+ if (mFilterConstant0 != mask)
+ {
+ mFilterConstant0 = mask;
+ return true;
+ }
+ return false;
+ }
+ G getFilterConstant0() const
+ {
+ return mFilterConstant0;
+ }
+ bool setFilterConstant1(const G& mask)
+ {
+ if (mFilterConstant1 != mask)
+ {
+ mFilterConstant1 = mask;
+ return true;
+ }
+ return false;
+ }
+ G getFilterConstant1() const
+ {
+ return mFilterConstant1;
+ }
+
+ bool operator()(const G& mask0, const G& mask1) const
+ {
+ static const FilterOp sFilterOpList[] =
+ {
+ &filterOp_AND,
+ &filterOp_OR,
+ &filterOp_XOR,
+ &filterOp_NAND,
+ &filterOp_NOR,
+ &filterOp_NXOR,
+ &filterOp_SWAP_AND,
+ };
+
+ if (hasBits(mask0) & hasBits(mask1))
+ {
+ G result0, result1, result;
+ sFilterOpList[mFilterOp0](mask0, mFilterConstant0, result0);
+ sFilterOpList[mFilterOp1](mask1, mFilterConstant1, result1);
+ sFilterOpList[mFilterOp2](result0, result1, result);
+ return (hasBits(result) == mFilterBool);
+ }
+ return true;
+ }
+};
+
+
+}
+} // end namespace nvidia::apex
+
+#endif
diff --git a/APEX_1.4/common/include/ApexIsoMesh.h b/APEX_1.4/common/include/ApexIsoMesh.h
new file mode 100644
index 00000000..d8644e87
--- /dev/null
+++ b/APEX_1.4/common/include/ApexIsoMesh.h
@@ -0,0 +1,206 @@
+/*
+ * 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 APEX_ISO_MESH_H
+#define APEX_ISO_MESH_H
+
+#include "ApexUsingNamespace.h"
+#include "ApexUsingNamespace.h"
+#include "PsUserAllocated.h"
+#include "PsArray.h"
+#include "PxBounds3.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+class IProgressListener;
+
+class ApexIsoMesh : public UserAllocated
+{
+public:
+ ApexIsoMesh(uint32_t isoGridSubdivision, uint32_t keepNBiggestMeshes, bool discardInnerMeshes);
+ ~ApexIsoMesh();
+
+ void setBound(const PxBounds3& bound);
+ void clear();
+ void clearTemp();
+ void addTriangle(const PxVec3& v0, const PxVec3& v1, const PxVec3& v2);
+ bool update(IProgressListener* progress);
+
+
+ uint32_t getNumVertices() const
+ {
+ return mIsoVertices.size();
+ }
+ const PxVec3& getVertex(uint32_t index) const
+ {
+ PX_ASSERT(index < mIsoVertices.size());
+ return mIsoVertices[index];
+ }
+
+ uint32_t getNumTriangles() const
+ {
+ return mIsoTriangles.size();
+ }
+ void getTriangle(uint32_t index, uint32_t& v0, uint32_t& v1, uint32_t& v2) const;
+private:
+ // settable parameters
+ uint32_t mIsoGridSubdivision;
+ uint32_t mKeepNBiggestMeshes;
+ bool mDiscardInnerMeshes;
+ PxBounds3 mBound;
+
+ bool generateMesh(IProgressListener* progress);
+ bool interpolate(float d0, float d1, const PxVec3& pos0, const PxVec3& pos1, PxVec3& pos);
+ bool findNeighbors(IProgressListener* progress);
+ void removeLayers();
+ uint32_t floodFill(uint32_t triangleNr, uint32_t groupNr);
+
+ void removeTrisAndVerts();
+
+ // non-settable parameters (deducted from the ones you can set)
+ float mCellSize;
+ float mThickness;
+ PxVec3 mOrigin;
+ int32_t mNumX, mNumY, mNumZ;
+ const float mIsoValue;
+
+
+ struct IsoCell
+ {
+ void init()
+ {
+ density = 0.0f;
+ vertNrX = -1;
+ vertNrY = -1;
+ vertNrZ = -1;
+ firstTriangle = -1;
+ numTriangles = 0;
+ }
+ float density;
+ int32_t vertNrX;
+ int32_t vertNrY;
+ int32_t vertNrZ;
+ int32_t firstTriangle;
+ int32_t numTriangles;
+ };
+ physx::Array<IsoCell> mGrid;
+ inline IsoCell& cellAt(int xi, int yi, int zi)
+ {
+ uint32_t index = (uint32_t)(((xi * mNumY) + yi) * mNumZ + zi);
+ PX_ASSERT(index < mGrid.size());
+ return mGrid[index];
+ }
+
+
+ struct IsoTriangle
+ {
+ void init()
+ {
+ vertexNr[0] = -1;
+ vertexNr[1] = -1;
+ vertexNr[2] = -1;
+ adjTriangles[0] = -1;
+ adjTriangles[1] = -1;
+ adjTriangles[2] = -1;
+ groupNr = -1;
+ deleted = false;
+ }
+ void set(int32_t v0, int32_t v1, int32_t v2, int32_t cubeX, int32_t cubeY, int32_t cubeZ)
+ {
+ init();
+ vertexNr[0] = v0;
+ vertexNr[1] = v1;
+ vertexNr[2] = v2;
+ this->cubeX = cubeX;
+ this->cubeY = cubeY;
+ this->cubeZ = cubeZ;
+ }
+ void addNeighbor(int32_t triangleNr)
+ {
+ if (adjTriangles[0] == -1)
+ {
+ adjTriangles[0] = triangleNr;
+ }
+ else if (adjTriangles[1] == -1)
+ {
+ adjTriangles[1] = triangleNr;
+ }
+ else if (adjTriangles[2] == -1)
+ {
+ adjTriangles[2] = triangleNr;
+ }
+ }
+
+ int32_t vertexNr[3];
+ int32_t cubeX, cubeY, cubeZ;
+ int32_t adjTriangles[3];
+ int32_t groupNr;
+ bool deleted;
+ };
+
+ struct IsoEdge
+ {
+ void set(int newV0, int newV1, int newTriangle)
+ {
+ if (newV0 < newV1)
+ {
+ v0 = newV0;
+ v1 = newV1;
+ }
+ else
+ {
+ v0 = newV1;
+ v1 = newV0;
+ }
+ triangleNr = newTriangle;
+ }
+ PX_INLINE bool operator < (const IsoEdge& e) const
+ {
+ if (v0 < e.v0)
+ {
+ return true;
+ }
+ if (v0 > e.v0)
+ {
+ return false;
+ }
+ return (v1 < e.v1);
+ }
+
+ PX_INLINE bool operator()(const IsoEdge& e1, const IsoEdge& e2) const
+ {
+ return e1 < e2;
+ }
+
+ PX_INLINE bool operator == (const IsoEdge& e) const
+ {
+ return v0 == e.v0 && v1 == e.v1;
+ }
+
+ int v0, v1;
+ int triangleNr;
+ };
+
+ physx::Array<PxVec3> mIsoVertices;
+ physx::Array<IsoTriangle> mIsoTriangles;
+ physx::Array<IsoEdge> mIsoEdges;
+
+ // evil, should not be used
+ ApexIsoMesh& operator=(const ApexIsoMesh&);
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif // APEX_ISO_MESH_H
diff --git a/APEX_1.4/common/include/ApexLegacyModule.h b/APEX_1.4/common/include/ApexLegacyModule.h
new file mode 100644
index 00000000..fef29118
--- /dev/null
+++ b/APEX_1.4/common/include/ApexLegacyModule.h
@@ -0,0 +1,170 @@
+/*
+ * 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 APEX_LEGACY_MODULE
+#define APEX_LEGACY_MODULE
+
+#include "nvparameterized/NvParameterizedTraits.h"
+
+#include "ModuleIntl.h"
+#include "ModuleBase.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+struct LegacyClassEntry
+{
+ uint32_t version;
+ uint32_t nextVersion;
+ NvParameterized::Factory* factory;
+ void (*freeParameterDefinitionTable)(NvParameterized::Traits* t);
+ NvParameterized::Conversion* (*createConv)(NvParameterized::Traits*);
+ NvParameterized::Conversion* conv;
+};
+
+template<typename IFaceT>
+class TApexLegacyModule : public IFaceT, public ModuleIntl, public ModuleBase
+{
+public:
+ virtual ~TApexLegacyModule() {}
+
+ // base class methods
+ void init(NvParameterized::Interface&) {}
+
+ NvParameterized::Interface* getDefaultModuleDesc()
+ {
+ return 0;
+ }
+
+ void release()
+ {
+ ModuleBase::release();
+ }
+ void destroy()
+ {
+ releaseLegacyObjects();
+ ModuleBase::destroy();
+ delete this;
+ }
+
+ const char* getName() const
+ {
+ return ModuleBase::getName();
+ }
+
+ ModuleSceneIntl* createInternalModuleScene(SceneIntl&, RenderDebugInterface*)
+ {
+ return NULL;
+ }
+ void releaseModuleSceneIntl(ModuleSceneIntl&) {}
+ uint32_t forceLoadAssets()
+ {
+ return 0;
+ }
+ AuthObjTypeID getModuleID() const
+ {
+ return UINT32_MAX;
+ }
+ RenderableIterator* createRenderableIterator(const Scene&)
+ {
+ return NULL;
+ }
+
+protected:
+ virtual void releaseLegacyObjects() = 0;
+
+ void registerLegacyObjects(LegacyClassEntry* e)
+ {
+ NvParameterized::Traits* t = mSdk->getParameterizedTraits();
+ if (!t)
+ {
+ return;
+ }
+
+ for (; e->factory; ++e)
+ {
+ t->registerFactory(*e->factory);
+
+ e->conv = e->createConv(t);
+ t->registerConversion(e->factory->getClassName(), e->version, e->nextVersion, *e->conv);
+ }
+ }
+
+ void unregisterLegacyObjects(LegacyClassEntry* e)
+ {
+ NvParameterized::Traits* t = mSdk->getParameterizedTraits();
+ if (!t)
+ {
+ return;
+ }
+
+ for (; e->factory; ++e)
+ {
+ t->removeConversion(
+ e->factory->getClassName(),
+ e->version,
+ e->nextVersion
+ );
+ e->conv->release();
+
+ t->removeFactory(e->factory->getClassName(), e->factory->getVersion());
+
+ e->freeParameterDefinitionTable(t);
+ }
+ }
+};
+
+typedef TApexLegacyModule<Module> ApexLegacyModule;
+
+} // namespace apex
+} // namespace nvidia
+
+#define DEFINE_CREATE_MODULE(ModuleBase) \
+ 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 != PHYSICS_SDK_VERSION) \
+ { \
+ if (errorCode) *errorCode = APEX_CE_WRONG_VERSION; \
+ return NULL; \
+ } \
+ \
+ gApexSdk = inSdk; \
+ \
+ ModuleBase *impl = PX_NEW(ModuleBase)(inSdk); \
+ *niRef = (ModuleIntl *) impl; \
+ return (Module *) impl; \
+ }
+
+#define DEFINE_INSTANTIATE_MODULE(ModuleBase) \
+ void instantiate##ModuleBase() \
+ { \
+ ApexSDKIntl *sdk = GetInternalApexSDK(); \
+ ModuleBase *impl = PX_NEW(ModuleBase)(sdk); \
+ sdk->registerExternalModule((Module *) impl, (ModuleIntl *) impl); \
+ }
+
+#endif // __APEX_LEGACY_MODULE__
diff --git a/APEX_1.4/common/include/ApexMarchingCubes.h b/APEX_1.4/common/include/ApexMarchingCubes.h
new file mode 100644
index 00000000..4fc59347
--- /dev/null
+++ b/APEX_1.4/common/include/ApexMarchingCubes.h
@@ -0,0 +1,380 @@
+/*
+ * 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 _APEX_MARCHING_CUBES_H__
+#define _APEX_MARCHING_CUBES_H__
+
+namespace MarchingCubes
+{
+
+// point numbering
+
+// 7-----------6
+// /| /|
+// / | / |
+// / | / |
+// 4-----------5 |
+// | | | |
+// | 3-------|---2
+// | / | /
+// | / | /
+// |/ |/
+// 0-----------1
+
+// edge numbering
+
+// *-----6-----*
+// /| /|
+// 7 | 5 |
+// / 11 / 10
+// *-----4-----* |
+// | | | |
+// | *-----2-|---*
+// 8 / 9 /
+// | 3 | 1
+// |/ |/
+// *-----0-----*
+
+
+// z
+// | y
+// | /
+// |/
+// 0---- x
+
+// dirs: 0:+x, 1:-x, 2:+y, 3:-y, 4:+z, 5:-z
+
+static const int cubeAdjacency[8][3][2] =
+{
+ {{3, 3}, {4, 8}, {1, 0}},
+ {{0, 0}, {5, 9}, {2, 1}},
+ {{1, 1}, {6, 10}, {3, 2}},
+ {{2, 2}, {7, 11}, {0, 3}},
+ {{7, 7}, {0, 8}, {5, 4}},
+ {{4, 4}, {1, 9}, {6, 5}},
+ {{5, 5}, {2, 10}, {7, 6}},
+ {{6, 6}, {3, 11}, {4, 7}}
+};
+
+static const int cubeEdges[12][3] =
+{
+ {0, 1}, {1, 2,}, {2, 3}, {3, 0},
+ {4, 5}, {5, 6}, {6, 7}, {7, 4},
+ {0, 4}, {1, 5}, {2, 6}, {3, 7}
+};
+
+static const int cubeEdgeDirs[12][3] =
+{
+ {0, 1}, {2, 3}, {1, 0}, {3, 2},
+ {0, 1}, {2, 3}, {1, 0}, {3, 2},
+ {4, 5}, {4, 5}, {4, 5}, {4, 5}
+};
+
+static const int edgeTable[256] =
+{
+ 0x0 , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,
+ 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
+ 0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,
+ 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
+ 0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c,
+ 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
+ 0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac,
+ 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
+ 0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c,
+ 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
+ 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc,
+ 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
+ 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c,
+ 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
+ 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc ,
+ 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
+ 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc,
+ 0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
+ 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c,
+ 0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
+ 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc,
+ 0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
+ 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c,
+ 0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460,
+ 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,
+ 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0,
+ 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c,
+ 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230,
+ 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c,
+ 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190,
+ 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c,
+ 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0
+};
+
+static const int triTable[256][16] =
+{
+ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1},
+ {3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1},
+ {3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1},
+ {3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1},
+ {9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1},
+ {9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
+ {2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1},
+ {8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1},
+ {9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
+ {4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1},
+ {3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1},
+ {1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1},
+ {4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1},
+ {4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1},
+ {9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
+ {5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1},
+ {2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1},
+ {9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
+ {0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
+ {2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1},
+ {10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1},
+ {4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1},
+ {5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1},
+ {5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1},
+ {9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1},
+ {0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1},
+ {10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1},
+ {8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1},
+ {2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1},
+ {7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1},
+ {9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1},
+ {2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1},
+ {11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1},
+ {9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1},
+ {5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1},
+ {11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1},
+ {11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
+ {1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1},
+ {9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1},
+ {5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1},
+ {2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
+ {0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
+ {5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1},
+ {6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1},
+ {3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1},
+ {6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1},
+ {5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1},
+ {1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
+ {10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1},
+ {6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1},
+ {8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1},
+ {7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1},
+ {3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
+ {5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1},
+ {0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1},
+ {9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1},
+ {8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1},
+ {5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1},
+ {0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1},
+ {6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1},
+ {10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1},
+ {10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1},
+ {8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1},
+ {1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1},
+ {3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1},
+ {0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1},
+ {10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1},
+ {3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1},
+ {6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1},
+ {9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1},
+ {8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1},
+ {3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1},
+ {6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1},
+ {0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1},
+ {10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1},
+ {10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1},
+ {2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1},
+ {7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1},
+ {7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1},
+ {2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1},
+ {1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1},
+ {11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1},
+ {8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1},
+ {0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1},
+ {7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
+ {10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
+ {2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
+ {6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1},
+ {7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1},
+ {2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1},
+ {1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1},
+ {10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1},
+ {10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1},
+ {0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1},
+ {7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1},
+ {6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1},
+ {8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1},
+ {6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1},
+ {4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1},
+ {10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1},
+ {8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1},
+ {0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1},
+ {1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1},
+ {8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1},
+ {10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1},
+ {4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1},
+ {10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
+ {5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
+ {11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1},
+ {9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
+ {6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1},
+ {7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1},
+ {3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1},
+ {7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1},
+ {9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1},
+ {3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1},
+ {6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1},
+ {9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1},
+ {1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1},
+ {4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1},
+ {7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1},
+ {6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1},
+ {3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1},
+ {0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1},
+ {6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1},
+ {0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1},
+ {11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1},
+ {6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1},
+ {5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1},
+ {9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1},
+ {1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1},
+ {10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1},
+ {0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1},
+ {5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1},
+ {10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1},
+ {11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1},
+ {9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1},
+ {7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1},
+ {2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1},
+ {8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1},
+ {9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1},
+ {9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1},
+ {1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1},
+ {9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1},
+ {9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1},
+ {5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1},
+ {0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1},
+ {10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1},
+ {2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1},
+ {0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1},
+ {0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1},
+ {9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1},
+ {5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1},
+ {3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1},
+ {5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1},
+ {8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1},
+ {9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1},
+ {0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1},
+ {1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1},
+ {3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1},
+ {4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1},
+ {9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1},
+ {11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1},
+ {11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1},
+ {2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1},
+ {9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1},
+ {3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1},
+ {1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1},
+ {4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1},
+ {4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1},
+ {0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1},
+ {3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1},
+ {3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1},
+ {0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1},
+ {9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1},
+ {1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}
+};
+
+} // namespace MarchingCubes
+
+
+#endif
diff --git a/APEX_1.4/common/include/ApexMath.h b/APEX_1.4/common/include/ApexMath.h
new file mode 100644
index 00000000..19d4af4c
--- /dev/null
+++ b/APEX_1.4/common/include/ApexMath.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.
+ */
+
+
+#ifndef APEX_MATH_H
+#define APEX_MATH_H
+
+#include "PxMat44.h"
+#include "PsMathUtils.h"
+
+#include "PsVecMath.h"
+namespace nvidia
+{
+
+#define APEX_ALIGN_UP(offset, alignment) (((offset) + (alignment)-1) & ~((alignment)-1))
+
+/**
+ * computes weight * _origin + (1.0f - weight) * _target
+ */
+PX_INLINE PxMat44 interpolateMatrix(float weight, const PxMat44& _origin, const PxMat44& _target)
+{
+ // target: normalize, save scale, transform to quat
+ PxMat33 target(_target.column0.getXYZ(),
+ _target.column1.getXYZ(),
+ _target.column2.getXYZ());
+ PxVec3 axis0 = target.column0;
+ PxVec3 axis1 = target.column1;
+ PxVec3 axis2 = target.column2;
+ const PxVec4 targetScale(axis0.normalize(), axis1.normalize(), axis2.normalize(), 1.0f);
+ target.column0 = axis0;
+ target.column1 = axis1;
+ target.column2 = axis2;
+ const PxQuat targetQ = PxQuat(target);
+
+ // origin: normalize, save scale, transform to quat
+ PxMat33 origin(_origin.column0.getXYZ(),
+ _origin.column1.getXYZ(),
+ _origin.column2.getXYZ());
+ const PxVec4 originScale(axis0.normalize(), axis1.normalize(), axis2.normalize(), 1.0f);
+ origin.column0 = axis0;
+ origin.column1 = axis1;
+ origin.column2 = axis2;
+ const PxQuat originQ = PxQuat(origin);
+
+ // interpolate
+ PxQuat relativeQ = physx::shdfnd::slerp(1.0f - weight, originQ, targetQ);
+ PxMat44 relative(relativeQ);
+ relative.setPosition(weight * _origin.getPosition() + (1.0f - weight) * _target.getPosition());
+
+ PxMat44 _relative = relative;
+ const PxVec4 scale = weight * originScale + (1.0f - weight) * targetScale;
+ _relative.scale(scale);
+
+ return _relative;
+}
+
+bool operator != (const PxMat44& a, const PxMat44& b);
+
+}
+
+
+#endif // APEX_MATH_H
diff --git a/APEX_1.4/common/include/ApexMerge.h b/APEX_1.4/common/include/ApexMerge.h
new file mode 100644
index 00000000..3821d290
--- /dev/null
+++ b/APEX_1.4/common/include/ApexMerge.h
@@ -0,0 +1,84 @@
+/*
+ * 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 APEX_MERGE_H
+#define APEX_MERGE_H
+
+namespace nvidia
+{
+namespace apex
+{
+ // merge 2 increasingly sorted arrays
+ // it's ok if one of the input buffers is also the results array
+ template<class Sortable>
+ bool ApexMerge(Sortable* bufferA, uint32_t numEntriesA, Sortable* bufferB, uint32_t numEntriesB, Sortable* resultBuffer, uint32_t numEntriesResult, int (*compare)(const void*, const void*))
+ {
+ if (numEntriesResult != numEntriesA + numEntriesB)
+ return false;
+
+#if PX_CHECKED
+ if (numEntriesA > 0)
+ {
+ for (uint32_t i = 1; i < numEntriesA; ++i)
+ {
+ PX_ASSERT(compare(bufferA + i - 1, bufferA + i) <= 0);
+ }
+ }
+
+ if (numEntriesB > 0)
+ {
+ for (uint32_t i = 1; i < numEntriesB; ++i)
+ {
+ PX_ASSERT(compare(bufferB + i - 1, bufferB + i) <= 0);
+ }
+ }
+#endif
+
+ int32_t iA = (int32_t)numEntriesA-1;
+ int32_t iB = (int32_t)numEntriesB-1;
+ uint32_t iResult = numEntriesA + numEntriesB - 1;
+
+ while (iA >= 0 && iB >= 0)
+ {
+ if (compare(&bufferA[iA], &bufferB[iB]) > 0)
+ {
+ resultBuffer[iResult] = bufferA[iA--];
+ }
+ else
+ {
+ resultBuffer[iResult] = bufferB[iB--];
+ }
+
+ --iResult;
+ }
+
+ if (iA < 0)
+ {
+ if (resultBuffer != bufferB)
+ {
+ memcpy(resultBuffer, bufferB, (iB + 1) * sizeof(Sortable));
+ }
+ }
+ else
+ {
+ if (resultBuffer != bufferA)
+ {
+ memcpy(resultBuffer, bufferA, (iA + 1) * sizeof(Sortable));
+ }
+ }
+
+ return true;
+ }
+
+} // namespace apex
+} // namespace nvidia
+
+#endif // APEX_MERGE_H
diff --git a/APEX_1.4/common/include/ApexMeshContractor.h b/APEX_1.4/common/include/ApexMeshContractor.h
new file mode 100644
index 00000000..5a638031
--- /dev/null
+++ b/APEX_1.4/common/include/ApexMeshContractor.h
@@ -0,0 +1,133 @@
+/*
+ * 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 APEX_MESH_CONTRACTOR_H
+#define APEX_MESH_CONTRACTOR_H
+
+#include "ApexDefs.h"
+#include "ApexUsingNamespace.h"
+#include "PsArray.h"
+#include "PxVec3.h"
+#include "PsUserAllocated.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+class IProgressListener;
+
+class ApexMeshContractor : public UserAllocated
+{
+public:
+ ApexMeshContractor();
+
+ void registerVertex(const PxVec3& pos);
+ void registerTriangle(uint32_t v0, uint32_t v1, uint32_t v2);
+ bool endRegistration(uint32_t subdivision, IProgressListener* progress);
+
+ uint32_t contract(int32_t steps, float abortionRatio, float& volumeRatio, IProgressListener* progress);
+ void expandBorder();
+
+ uint32_t getNumVertices()
+ {
+ return mVertices.size();
+ }
+ uint32_t getNumIndices()
+ {
+ return mIndices.size();
+ }
+ const PxVec3* getVertices()
+ {
+ return mVertices.begin();
+ }
+ const uint32_t* getIndices()
+ {
+ return mIndices.begin();
+ }
+private:
+
+ void computeNeighbours();
+ void computeSignedDistanceField();
+ void contractionStep();
+ void computeAreaAndVolume(float& area, float& volume);
+
+ void addTriangle(const PxVec3& v0, const PxVec3& v1, const PxVec3& v2);
+ bool updateDistance(uint32_t xi, uint32_t yi, uint32_t zi);
+ void setInsideOutside();
+ void interpolateGradientAt(const PxVec3& pos, PxVec3& grad);
+ void subdivide(float spacing);
+ void collapse(float spacing);
+
+ void getButterfly(uint32_t triNr, uint32_t v0, uint32_t v1, int32_t& adj, int32_t& t0, int32_t& t1, int32_t& t2, int32_t& t3) const;
+ int32_t getOppositeVertex(int32_t t, uint32_t v0, uint32_t v1) const;
+ void replaceVertex(int32_t t, uint32_t vOld, uint32_t vNew);
+ void replaceNeighbor(int32_t t, int32_t nOld, uint32_t nNew);
+ bool triangleContains(int32_t t, uint32_t v) const;
+ bool legalCollapse(int32_t triNr, uint32_t v0, uint32_t v1) const;
+ void advanceAdjTriangle(uint32_t v, int32_t& t, int32_t& prev) const;
+ bool areNeighbors(int32_t t0, int32_t t1) const;
+ float findMin(const PxVec3& p, const PxVec3& maxDisp) const;
+ float interpolateDistanceAt(const PxVec3& pos) const;
+ void collectNeighborhood(int32_t triNr, float radius, uint32_t newMark, physx::Array<int32_t> &tris, physx::Array<float> &dists, uint32_t* triMarks) const;
+ void getTriangleCenter(int32_t triNr, PxVec3& center) const;
+ float curvatureAt(int triNr, int v);
+
+ struct ContractorCell
+ {
+ ContractorCell() : inside(0), distance(PX_MAX_F32), marked(false)
+ {
+ numCuts[0] = numCuts[1] = numCuts[2] = 0;
+ }
+ /*
+ void init() {
+ distance = PX_MAX_F32;
+ inside = 0;
+ marked = false;
+ numCuts[0] = 0;
+ numCuts[1] = 0;
+ numCuts[2] = 0;
+ }
+ */
+ uint32_t inside;
+ float distance;
+ uint8_t numCuts[3];
+ bool marked;
+ };
+ inline ContractorCell& cellAt(int32_t xi, int32_t yi, int32_t zi)
+ {
+ return mGrid[(((uint32_t)xi * mNumY) + (uint32_t)yi) * mNumZ + (uint32_t)zi];
+ }
+
+ inline const ContractorCell& constCellAt(int32_t xi, int32_t yi, int32_t zi) const
+ {
+ return mGrid[(((uint32_t)xi * mNumY) + (uint32_t)yi) * mNumZ + (uint32_t)zi];
+ }
+ float mCellSize;
+ PxVec3 mOrigin;
+
+ uint32_t mNumX, mNumY, mNumZ;
+
+ physx::Array<PxVec3> mVertices;
+ physx::Array<uint32_t> mIndices;
+ physx::Array<int32_t> mNeighbours;
+
+ physx::Array<ContractorCell> mGrid;
+ physx::Array<float> mVertexCurvatures;
+
+ float mInitialVolume;
+ float mCurrentVolume;
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif // APEX_MESH_CONTRACTOR_H
diff --git a/APEX_1.4/common/include/ApexMeshHash.h b/APEX_1.4/common/include/ApexMeshHash.h
new file mode 100644
index 00000000..97a015ad
--- /dev/null
+++ b/APEX_1.4/common/include/ApexMeshHash.h
@@ -0,0 +1,110 @@
+/*
+ * 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 APEX_MESH_HASH_H
+#define APEX_MESH_HASH_H
+
+#include "ApexDefs.h"
+
+#include "ApexUsingNamespace.h"
+#include "PsUserAllocated.h"
+#include "PsArray.h"
+
+#include "PxVec3.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+struct MeshHashRoot
+{
+ int32_t first;
+ uint32_t timeStamp;
+};
+
+struct MeshHashEntry
+{
+ int32_t next;
+ uint32_t itemIndex;
+};
+
+
+class ApexMeshHash : public UserAllocated
+{
+public:
+ ApexMeshHash();
+ ~ApexMeshHash();
+
+ void setGridSpacing(float spacing);
+ float getGridSpacing()
+ {
+ return 1.0f / mInvSpacing;
+ }
+ void reset();
+ void add(const PxBounds3& bounds, uint32_t itemIndex);
+ void add(const PxVec3& pos, uint32_t itemIndex);
+
+ void query(const PxBounds3& bounds, physx::Array<uint32_t>& itemIndices, int32_t maxIndices = -1);
+ void queryUnique(const PxBounds3& bounds, physx::Array<uint32_t>& itemIndices, int32_t maxIndices = -1);
+
+ void query(const PxVec3& pos, physx::Array<uint32_t>& itemIndices, int32_t maxIndices = -1);
+ void queryUnique(const PxVec3& pos, physx::Array<uint32_t>& itemIndices, int32_t maxIndices = -1);
+
+ // applied functions, only work if inserted objects are points!
+ int32_t getClosestPointNr(const PxVec3* points, uint32_t numPoints, uint32_t pointStride, const PxVec3& pos);
+
+private:
+ enum
+ {
+ HashIndexSize = 170111
+ };
+
+ void compressIndices(physx::Array<uint32_t>& itemIndices);
+ float mSpacing;
+ float mInvSpacing;
+ uint32_t mTime;
+
+ inline uint32_t hashFunction(int32_t xi, int32_t yi, int32_t zi)
+ {
+ uint32_t h = (uint32_t)((xi * 92837111) ^(yi * 689287499) ^(zi * 283923481));
+ return h % HashIndexSize;
+ }
+
+ inline void cellCoordOf(const PxVec3& v, int& xi, int& yi, int& zi)
+ {
+ xi = (int)(v.x * mInvSpacing);
+ if (v.x < 0.0f)
+ {
+ xi--;
+ }
+ yi = (int)(v.y * mInvSpacing);
+ if (v.y < 0.0f)
+ {
+ yi--;
+ }
+ zi = (int)(v.z * mInvSpacing);
+ if (v.z < 0.0f)
+ {
+ zi--;
+ }
+ }
+
+ MeshHashRoot* mHashIndex;
+ physx::Array<MeshHashEntry> mEntries;
+
+ physx::Array<uint32_t> mTempIndices;
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif \ No newline at end of file
diff --git a/APEX_1.4/common/include/ApexMirrored.h b/APEX_1.4/common/include/ApexMirrored.h
new file mode 100644
index 00000000..3ae808f7
--- /dev/null
+++ b/APEX_1.4/common/include/ApexMirrored.h
@@ -0,0 +1,507 @@
+/*
+ * 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 APEX_MIRRORED_H
+#define APEX_MIRRORED_H
+
+#include "ApexDefs.h"
+
+#include "Apex.h"
+#include "ApexCutil.h"
+#include "SceneIntl.h"
+
+#include "PxTaskManager.h"
+#include "PxGpuDispatcher.h"
+#include "PxGpuCopyDesc.h"
+#include "PxGpuCopyDescQueue.h"
+#include "PxCudaContextManager.h"
+#include "PxCudaMemoryManager.h"
+//#include <cuda.h>
+
+#if defined(__CUDACC__)
+#error "Mirrored arrays should not be visible to CUDA code. Send device pointers to CUDA kernels."
+#endif
+
+
+#if !PX_SUPPORT_GPU_PHYSX
+#define PX_ALLOC_INFO(name, ID) __FILE__, __LINE__, name, physx::PxAllocId::ID
+#define PX_ALLOC_INFO_PARAMS_DECL(p0, p1, p2, p3) const char* file = p0, int line = p1, const char* allocName = p2, physx::PxAllocId::Enum allocId = physx::PxAllocId::p3
+#define PX_ALLOC_INFO_PARAMS_DEF() const char* file, int line, const char* allocName, physx::PxAllocId::Enum allocId
+#define PX_ALLOC_INFO_PARAMS_INPUT() file, line, allocName, allocId
+#define PX_ALLOC_INFO_PARAMS_INPUT_INFO(info) info.getFileName(), info.getLine(), info.getAllocName(), info.getAllocId()
+
+namespace physx
+{
+
+struct PxAllocId
+{
+ /**
+ * \brief ID of the Feature which owns/allocated memory from the heap
+ */
+ enum Enum
+ {
+ UNASSIGNED, //!< default
+ APEX, //!< APEX stuff not further classified
+ PARTICLES, //!< all particle related
+ GPU_UTIL, //!< e.g. RadixSort (used in SPH and deformable self collision)
+ CLOTH, //!< all cloth related
+ NUM_IDS //!< number of IDs, be aware that ApexHeapStats contains PxAllocIdStats[NUM_IDS]
+ };
+};
+
+/// \brief class to track allocation statistics, see PxgMirrored
+class PxAllocInfo
+{
+public:
+ /**
+ * \brief AllocInfo default constructor
+ */
+ PxAllocInfo() {}
+
+ /**
+ * \brief AllocInfo constructor that initializes all of the members
+ */
+ PxAllocInfo(const char* file, int line, const char* allocName, PxAllocId::Enum allocId)
+ : mFileName(file)
+ , mLine(line)
+ , mAllocName(allocName)
+ , mAllocId(allocId)
+ {
+ }
+
+ /// \brief get the allocation file name
+ inline const char* getFileName() const
+ {
+ return mFileName;
+ }
+
+ /// \brief get the allocation line
+ inline int getLine() const
+ {
+ return mLine;
+ }
+
+ /// \brief get the allocation name
+ inline const char* getAllocName() const
+ {
+ return mAllocName;
+ }
+
+ /// \brief get the allocation ID
+ inline PxAllocId::Enum getAllocId() const
+ {
+ return mAllocId;
+ }
+
+private:
+ const char* mFileName;
+ int mLine;
+ const char* mAllocName;
+ PxAllocId::Enum mAllocId;
+};
+
+}
+
+#endif
+
+namespace nvidia
+{
+namespace apex
+{
+
+struct ApexMirroredPlace
+{
+ enum Enum
+ {
+ DEFAULT = 0,
+ CPU = 0x01,
+#if APEX_CUDA_SUPPORT
+ GPU = 0x02,
+ CPU_GPU = (CPU | GPU),
+#endif
+ };
+};
+
+
+template <class T>
+class ApexMirrored
+{
+ PX_NOCOPY(ApexMirrored);
+
+public:
+ ApexMirrored(SceneIntl& scene, PX_ALLOC_INFO_PARAMS_DECL(NULL, 0, NULL, UNASSIGNED))
+ : mCpuPtr(0)
+ , mByteCount(0)
+ , mPlace(ApexMirroredPlace::CPU)
+ , mAllocInfo(PX_ALLOC_INFO_PARAMS_INPUT())
+#if APEX_CUDA_SUPPORT
+ , mCpuBuffer(NULL)
+ , mGpuPtr(0)
+ , mGpuBuffer(NULL)
+#endif
+ {
+ PX_UNUSED(scene);
+#if APEX_CUDA_SUPPORT
+ PxGpuDispatcher* gd = scene.getTaskManager()->getGpuDispatcher();
+ if (gd)
+ {
+ mCtx = gd->getCudaContextManager();
+ }
+ else
+ {
+ mCtx = NULL;
+ return;
+ }
+#endif
+ };
+
+ ~ApexMirrored()
+ {
+ }
+
+ //Operators for accessing the data pointed to on the host. Using these operators is guaranteed
+ //to maintain the class invariants. Note that these operators are only ever called on the host.
+ //The GPU never sees this class as instances are converted to regular pointers upon kernel
+ //invocation.
+
+ PX_INLINE T& operator*()
+ {
+ return *getCpuPtr();
+ }
+
+ PX_INLINE const T& operator*() const
+ {
+ return *getCpuPtr();
+ }
+
+ PX_INLINE T* operator->()
+ {
+ return getCpuPtr();
+ }
+
+ PX_INLINE const T* operator->() const
+ {
+ return getCpuPtr();
+ }
+
+ PX_INLINE T& operator[](unsigned int i)
+ {
+ return getCpuPtr()[i];
+ }
+
+ //Methods for converting the pointer to a regular pointer for use on
+ //the CPU After a pointer has been obtained with these methods, the
+ //data can be accessed multiple times with no extra cost. This is the
+ //fastest method for accessing the data on the cpu.
+
+ PX_INLINE T* getCpuPtr() const
+ {
+ return mCpuPtr;
+ }
+
+ /*!
+ \return
+ returns whether CPU buffer has been allocated for this array
+ */
+ PX_INLINE bool cpuPtrIsValid() const
+ {
+ return mCpuPtr != 0;
+ }
+
+ PX_INLINE size_t* getCpuHandle() const
+ {
+ return reinterpret_cast<size_t*>(&mCpuPtr);
+ }
+
+ PX_INLINE size_t getByteSize() const
+ {
+ return mByteCount;
+ }
+
+#if APEX_CUDA_SUPPORT
+ /*!
+ \return
+ returns whether GPU buffer has been allocated for this array
+ */
+ PX_INLINE bool gpuPtrIsValid() const
+ {
+ return mGpuPtr != 0;
+ }
+
+ PX_INLINE T* getGpuPtr() const
+ {
+ return mGpuPtr;
+ }
+
+ /*!
+ Get opaque handle to the underlying gpu or cpu memory These must not
+ be cast to a pointer or derefernced, they should only be used to
+ identify the memory region to the allocator
+ */
+ PX_INLINE size_t* getGpuHandle() const
+ {
+ return reinterpret_cast<size_t*>(&mGpuPtr);
+ }
+
+ PX_INLINE void copyDeviceToHostDesc(PxGpuCopyDesc& desc, size_t byteSize, size_t byteOffset) const
+ {
+ PX_ASSERT(mCpuPtr && mGpuPtr && mByteCount);
+ desc.type = PxGpuCopyDesc::DeviceToHost;
+ desc.bytes = byteSize;
+ desc.source = ((size_t) mGpuPtr) + byteOffset;
+ desc.dest = ((size_t) mCpuPtr) + byteOffset;
+ }
+
+ PX_INLINE void copyHostToDeviceDesc(PxGpuCopyDesc& desc, size_t byteSize, size_t byteOffset) const
+ {
+ PX_ASSERT(mCpuPtr && mGpuPtr && mByteCount);
+ desc.type = PxGpuCopyDesc::HostToDevice;
+ desc.bytes = byteSize;
+ desc.source = ((size_t) mCpuPtr) + byteOffset;
+ desc.dest = ((size_t) mGpuPtr) + byteOffset;
+ }
+
+ PX_INLINE void mallocGpu(size_t byteSize)
+ {
+ PxCudaBufferType bufferType(PxCudaBufferMemorySpace::T_GPU, PxCudaBufferFlags::F_READ_WRITE);
+ PxCudaBuffer* buffer = mCtx->getMemoryManager()->alloc(bufferType, (uint32_t)byteSize);
+ if (buffer)
+ {
+ // in case of realloc
+ if (mGpuBuffer)
+ {
+ mGpuBuffer->free();
+ }
+ mGpuBuffer = buffer;
+ mGpuPtr = reinterpret_cast<T*>(mGpuBuffer->getPtr());
+ PX_ASSERT(mGpuPtr);
+ }
+ else
+ {
+ PX_ASSERT(!"Out of GPU Memory!");
+ }
+ }
+
+ PX_INLINE void freeGpu()
+ {
+ if (mGpuBuffer)
+ {
+ bool success = mGpuBuffer->free();
+ mGpuBuffer = NULL;
+ mGpuPtr = NULL;
+ PX_UNUSED(success);
+ PX_ASSERT(success);
+ }
+ }
+
+ PX_INLINE void mallocHost(size_t byteSize)
+ {
+ PxCudaBufferType bufferType(PxCudaBufferMemorySpace::T_PINNED_HOST, PxCudaBufferFlags::F_READ_WRITE);
+ PxCudaBuffer* buffer = mCtx->getMemoryManager()->alloc(bufferType, (uint32_t)byteSize);
+ if (buffer)
+ {
+ // in case of realloc
+ if (mCpuBuffer)
+ {
+ mCpuBuffer->free();
+ }
+ mCpuBuffer = buffer;
+ mCpuPtr = reinterpret_cast<T*>(mCpuBuffer->getPtr());
+ PX_ASSERT(mCpuPtr);
+ }
+ else
+ {
+ PX_ASSERT(!"Out of Pinned Host Memory!");
+ }
+ }
+ PX_INLINE void freeHost()
+ {
+ if (mCpuBuffer)
+ {
+ bool success = mCpuBuffer->free();
+ mCpuBuffer = NULL;
+ mCpuPtr = NULL;
+ PX_UNUSED(success);
+ PX_ASSERT(success);
+ }
+ }
+ PX_INLINE void swapGpuPtr(ApexMirrored<T>& other)
+ {
+ nvidia::swap(mGpuPtr, other.mGpuPtr);
+ nvidia::swap(mGpuBuffer, other.mGpuBuffer);
+ }
+#endif
+
+ PX_INLINE const PxAllocInfo& getAllocInfo() const
+ {
+ return mAllocInfo;
+ }
+
+ PX_INLINE void mallocCpu(size_t byteSize)
+ {
+ mCpuPtr = (T*)getAllocator().allocate(byteSize, mAllocInfo.getAllocName(), mAllocInfo.getFileName(), mAllocInfo.getLine());
+ PX_ASSERT(mCpuPtr && "Out of CPU Memory!");
+ }
+ PX_INLINE void freeCpu()
+ {
+ if (mCpuPtr)
+ {
+ getAllocator().deallocate(mCpuPtr);
+ mCpuPtr = NULL;
+ }
+ }
+
+
+ PX_INLINE const char* getName() const
+ {
+ return mAllocInfo.getAllocName();
+ }
+
+ void realloc(size_t byteCount, ApexMirroredPlace::Enum place)
+ {
+ ApexMirroredPlace::Enum oldPlace = mPlace;
+ ApexMirroredPlace::Enum newPlace = (place != ApexMirroredPlace::DEFAULT) ? place : oldPlace;
+ if (oldPlace == newPlace && byteCount <= mByteCount)
+ {
+ return;
+ }
+
+ size_t newSize = PxMax(byteCount, mByteCount);
+
+#if APEX_CUDA_SUPPORT
+ if (oldPlace != ApexMirroredPlace::CPU && newPlace != ApexMirroredPlace::CPU)
+ {
+ PX_ASSERT(oldPlace != ApexMirroredPlace::CPU);
+ PX_ASSERT(newPlace != ApexMirroredPlace::CPU);
+
+ if ((mCpuPtr != NULL && byteCount > mByteCount) ||
+ (mCpuPtr == NULL && (place & ApexMirroredPlace::CPU) != 0))
+ {
+ PxCudaBuffer* oldCpuBuffer = mCpuBuffer;
+ T* oldCpuPtr = mCpuPtr;
+
+ mCpuBuffer = NULL;
+
+ mallocHost(newSize);
+
+ PxCudaBuffer* newCpuBuffer = mCpuBuffer;
+ T* newCpuPtr = mCpuPtr;
+
+
+ if (oldCpuPtr != NULL && newCpuPtr != NULL && mByteCount > 0)
+ {
+ memcpy(mCpuPtr, oldCpuPtr, mByteCount);
+ }
+
+ mCpuBuffer = oldCpuBuffer;
+ mCpuPtr = newCpuPtr;
+
+ freeHost();
+
+ mCpuBuffer = newCpuBuffer;
+ mCpuPtr = newCpuPtr;
+ }
+ if ((mGpuPtr != NULL && byteCount > mByteCount) ||
+ (mGpuPtr == NULL && (place & ApexMirroredPlace::GPU) != 0))
+ {
+ // we explicitly do not move old data to the new buffer
+
+ freeGpu();
+ mallocGpu(newSize);
+ }
+ }
+ else
+#endif
+ {
+ T* oldCpuPtr = mCpuPtr;
+#if APEX_CUDA_SUPPORT
+ if (newPlace != ApexMirroredPlace::CPU)
+ {
+ if (newPlace == ApexMirroredPlace::CPU_GPU)
+ {
+ mallocHost(newSize);
+ }
+ else
+ {
+ mCpuPtr = NULL;
+ }
+ mallocGpu(newSize);
+ }
+ else
+#endif
+ {
+ mallocCpu(newSize);
+ }
+ T* newCpuPtr = mCpuPtr;
+
+ if (oldCpuPtr != NULL && newCpuPtr != NULL && mByteCount > 0)
+ {
+ memcpy(newCpuPtr, oldCpuPtr, mByteCount);
+ }
+
+ mCpuPtr = oldCpuPtr;
+#if APEX_CUDA_SUPPORT
+ if (oldPlace != ApexMirroredPlace::CPU)
+ {
+ if (oldPlace == ApexMirroredPlace::CPU_GPU)
+ {
+ freeHost();
+ }
+ freeGpu();
+ }
+ else
+#endif
+ {
+ freeCpu();
+ }
+ mCpuPtr = newCpuPtr;
+ }
+ mByteCount = newSize;
+ mPlace = newPlace;
+ }
+
+ void free()
+ {
+ PX_ASSERT(mPlace != ApexMirroredPlace::DEFAULT);
+#if APEX_CUDA_SUPPORT
+ if (mPlace != ApexMirroredPlace::CPU)
+ {
+ freeHost();
+ freeGpu();
+ }
+ else
+#endif
+ {
+ freeCpu();
+ }
+ mByteCount = 0;
+ }
+
+private:
+ mutable T* mCpuPtr;
+ size_t mByteCount;
+
+ ApexMirroredPlace::Enum mPlace;
+ PxAllocInfo mAllocInfo;
+
+#if APEX_CUDA_SUPPORT
+ mutable PxCudaBuffer* mCpuBuffer;
+ mutable T* mGpuPtr;
+ mutable PxCudaBuffer* mGpuBuffer;
+ PxCudaContextManager* mCtx;
+#endif
+};
+
+
+}
+} // end namespace nvidia::apex
+
+#endif
diff --git a/APEX_1.4/common/include/ApexMirroredArray.h b/APEX_1.4/common/include/ApexMirroredArray.h
new file mode 100644
index 00000000..cb34b26b
--- /dev/null
+++ b/APEX_1.4/common/include/ApexMirroredArray.h
@@ -0,0 +1,259 @@
+/*
+ * 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 APEX_MIRRORED_ARRAY_H
+#define APEX_MIRRORED_ARRAY_H
+
+#include "ApexDefs.h"
+
+#include "ApexMirrored.h"
+#include <new>
+
+#if defined(__CUDACC__) || PX_ANDROID || PX_PS4 || PX_LINUX_FAMILY || PX_OSX
+#define DEFAULT_NAME "unassigned"
+#else
+#include <typeinfo>
+#define DEFAULT_NAME typeid(T).name()
+#endif
+
+#pragma warning(push)
+#pragma warning(disable:4348)
+
+
+namespace nvidia
+{
+namespace apex
+{
+
+template <class T>
+class ApexMirroredArray
+{
+ PX_NOCOPY(ApexMirroredArray);
+
+public:
+ /*!
+ Default array constructor.
+ Initialize an empty array
+ */
+ explicit PX_INLINE ApexMirroredArray(SceneIntl& scene, PX_ALLOC_INFO_PARAMS_DECL("", 0, DEFAULT_NAME, UNASSIGNED)) :
+ mData(scene, PX_ALLOC_INFO_PARAMS_INPUT()), mCapacity(0), mSize(0) {};
+
+ /*!
+ Default destructor
+ */
+ PX_INLINE ~ApexMirroredArray()
+ {
+ mData.free();
+ }
+
+ /*!
+ Return an element from this array. Operation is O(1).
+ \param i
+ The index of the element that will be returned.
+ \return
+ Element i in the array.
+ */
+ PX_INLINE const T& get(uint32_t i) const
+ {
+ return mData.getCpuPtr()[i];
+ }
+
+ /*!
+ Return an element from this array. Operation is O(1).
+ \param i
+ The index of the element that will be returned.
+ \return
+ Element i in the array.
+ */
+ PX_INLINE T& get(uint32_t i)
+ {
+ return mData.getCpuPtr()[i];
+ }
+
+ /*!
+ Array indexing operator.
+ \param i
+ The index of the element that will be returned.
+ \return
+ The element i in the array.
+ */
+ PX_INLINE const T& operator[](uint32_t i) const
+ {
+ return get(i);
+ }
+
+ /*!
+ Array indexing operator.
+ \param i
+ The index of the element that will be returned.
+ \return
+ The element i in the array.
+ */
+ PX_INLINE T& operator[](uint32_t i)
+ {
+ return get(i);
+ }
+
+ /*!
+ \return
+ returns whether GPU buffer has been allocated for this array
+ */
+ PX_INLINE bool cpuPtrIsValid() const
+ {
+ return mData.cpuPtrIsValid();
+ }
+
+ /*!
+ Returns the plain array representation.
+ \return
+ The sets representation.
+ */
+ PX_INLINE T* getPtr() const
+ {
+ return mData.getCpuPtr();
+ }
+
+#if APEX_CUDA_SUPPORT
+ /*!
+ \return
+ returns whether GPU buffer has been allocated for this array
+ */
+ PX_INLINE bool gpuPtrIsValid() const
+ {
+ return mData.gpuPtrIsValid();
+ }
+
+ PX_INLINE T* getGpuPtr() const
+ {
+ return mData.getGpuPtr();
+ }
+
+ PX_INLINE void copyDeviceToHostDesc(PxGpuCopyDesc& desc, uint32_t size, uint32_t offset) const
+ {
+ PX_ASSERT(gpuPtrIsValid() && cpuPtrIsValid());
+ if (size == 0)
+ {
+ size = mSize;
+ }
+ mData.copyDeviceToHostDesc(desc, sizeof(T) * size, sizeof(T) * offset);
+ }
+ PX_INLINE void copyDeviceToHostQ(PxGpuCopyDescQueue& queue, uint32_t size = 0, uint32_t offset = 0) const
+ {
+ PxGpuCopyDesc desc;
+ copyDeviceToHostDesc(desc, size, offset);
+ queue.enqueue(desc);
+ }
+
+ PX_INLINE void copyHostToDeviceDesc(PxGpuCopyDesc& desc, uint32_t size, uint32_t offset) const
+ {
+ PX_ASSERT(gpuPtrIsValid() && cpuPtrIsValid());
+ if (size == 0)
+ {
+ size = mSize;
+ }
+ mData.copyHostToDeviceDesc(desc, sizeof(T) * size, sizeof(T) * offset);
+ }
+ PX_INLINE void copyHostToDeviceQ(PxGpuCopyDescQueue& queue, uint32_t size = 0, uint32_t offset = 0) const
+ {
+ PxGpuCopyDesc desc;
+ copyHostToDeviceDesc(desc, size, offset);
+ queue.enqueue(desc);
+ }
+ PX_INLINE void swapGpuPtr(ApexMirroredArray<T>& other)
+ {
+ PX_ASSERT(mCapacity == other.mCapacity);
+
+ mData.swapGpuPtr(other.mData);
+ }
+#endif /* APEX_CUDA_SUPPORT */
+
+ /*!
+ Returns the number of entries in the array. This can, and probably will,
+ differ from the array size.
+ \return
+ The number of of entries in the array.
+ */
+ PX_INLINE uint32_t getSize() const
+ {
+ return mSize;
+ }
+
+ PX_INLINE size_t getByteSize() const
+ {
+ return mData.getByteSize();
+ }
+
+ PX_INLINE char* getName() const
+ {
+ return mData.getName();
+ }
+
+ /*!
+ Clears the array.
+ */
+ PX_INLINE void clear()
+ {
+ mSize = 0;
+ mData.free();
+ mCapacity = 0;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ /*!
+ Resize array
+ */
+ //////////////////////////////////////////////////////////////////////////
+ PX_INLINE void setSize(const uint32_t size, ApexMirroredPlace::Enum place = ApexMirroredPlace::DEFAULT)
+ {
+ if (size > mCapacity)
+ {
+ mCapacity = size;
+ }
+ mData.realloc(sizeof(T) * mCapacity, place);
+ mSize = size;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ /*!
+ Ensure that the array has at least size capacity.
+ */
+ //////////////////////////////////////////////////////////////////////////
+ PX_INLINE void reserve(const uint32_t capacity, ApexMirroredPlace::Enum place = ApexMirroredPlace::DEFAULT)
+ {
+ if (capacity > mCapacity)
+ {
+ mCapacity = capacity;
+ }
+ mData.realloc(sizeof(T) * mCapacity, place);
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ /*!
+ Query the capacity(allocated mem) for the array.
+ */
+ //////////////////////////////////////////////////////////////////////////
+ PX_INLINE uint32_t getCapacity()
+ {
+ return mCapacity;
+ }
+
+private:
+ ApexMirrored<T> mData;
+ uint32_t mCapacity;
+ uint32_t mSize;
+};
+
+}
+} // end namespace nvidia::apex
+
+#pragma warning(pop)
+
+#endif
diff --git a/APEX_1.4/common/include/ApexPermute.h b/APEX_1.4/common/include/ApexPermute.h
new file mode 100644
index 00000000..ef0001f2
--- /dev/null
+++ b/APEX_1.4/common/include/ApexPermute.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.
+ */
+
+
+#ifndef APEX_PERMUTE_H
+#define APEX_PERMUTE_H
+
+namespace nvidia
+{
+namespace apex
+{
+
+// permutationBuffer has to contain the indices that map from the new to the old index
+template<class Sortable>
+inline void ApexPermute(Sortable* sortBuffer, const uint32_t* permutationBuffer, uint32_t numElements, uint32_t numElementsPerPermutation = 1)
+{
+ nvidia::Array<Sortable> temp;
+ temp.resize(numElementsPerPermutation);
+
+ // TODO remove used buffer
+ nvidia::Array<bool> used(numElements, false);
+
+ for (uint32_t i = 0; i < numElements; i++)
+ {
+ //if (permutationBuffer[i] == (uint32_t)-1 || permutationBuffer[i] == i)
+ if (used[i] || permutationBuffer[i] == i)
+ {
+ continue;
+ }
+
+ uint32_t dst = i;
+ uint32_t src = permutationBuffer[i];
+ for (uint32_t j = 0; j < numElementsPerPermutation; j++)
+ {
+ temp[j] = sortBuffer[numElementsPerPermutation * dst + j];
+ }
+ do
+ {
+ for (uint32_t j = 0; j < numElementsPerPermutation; j++)
+ {
+ sortBuffer[numElementsPerPermutation * dst + j] = sortBuffer[numElementsPerPermutation * src + j];
+ }
+ //permutationBuffer[dst] = (uint32_t)-1;
+ used[dst] = true;
+ dst = src;
+ src = permutationBuffer[src];
+ //} while (permutationBuffer[src] != (uint32_t)-1);
+ }
+ while (!used[src]);
+ for (uint32_t j = 0; j < numElementsPerPermutation; j++)
+ {
+ sortBuffer[numElementsPerPermutation * dst + j] = temp[j];
+ }
+ //permutationBuffer[dst] = (uint32_t)-1;
+ used[dst] = true;
+ }
+}
+
+} // namespace apex
+} // namespace nvidia
+
+#endif // APEX_PERMUTE_H
diff --git a/APEX_1.4/common/include/ApexPreview.h b/APEX_1.4/common/include/ApexPreview.h
new file mode 100644
index 00000000..1d8ff77d
--- /dev/null
+++ b/APEX_1.4/common/include/ApexPreview.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.
+ */
+
+
+#ifndef __APEX_PREVIEW_H__
+#define __APEX_PREVIEW_H__
+
+#include "ApexRenderable.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+class ApexContext;
+
+/**
+ Class that implements preview interface
+*/
+class ApexPreview : public ApexRenderable
+{
+public:
+ ApexPreview();
+ virtual ~ApexPreview();
+
+ // Each class that derives from ApexPreview may optionally implement this function
+ virtual Renderable* getRenderable()
+ {
+ return NULL;
+ }
+
+ virtual void setPose(const PxMat44& pose);
+ virtual const PxMat44 getPose() const;
+
+ virtual void release() = 0;
+ void destroy();
+
+protected:
+ bool mInRelease;
+
+ PxMat44 mPose;
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif // __APEX_PREVIEW_H__
diff --git a/APEX_1.4/common/include/ApexPvdClient.h b/APEX_1.4/common/include/ApexPvdClient.h
new file mode 100644
index 00000000..f2da76d3
--- /dev/null
+++ b/APEX_1.4/common/include/ApexPvdClient.h
@@ -0,0 +1,168 @@
+/*
+ * 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 APEX_PVD_CLIENT_H
+#define APEX_PVD_CLIENT_H
+
+#include "Px.h"
+#include "ApexDefs.h"
+
+#define APEX_PVD_NAMESPACE "Apex"
+
+//#define WITHOUT_PVD 1
+#ifdef WITHOUT_PVD
+namespace physx
+{
+ class PxPvd;
+ namespace pvdsdk
+ {
+ class PvdDataStream;
+ class PvdUserRenderer;
+ }
+}
+#else
+#include "PsPvd.h"
+#include "PxPvdClient.h"
+#include "PxPvdObjectModelBaseTypes.h"
+#include "PxPvdDataStream.h"
+#include "PxPvdUserRenderer.h"
+#endif
+
+namespace NvParameterized
+{
+ class Interface;
+ class Definition;
+ class Handle;
+}
+
+namespace physx
+{
+namespace pvdsdk
+{
+ /**
+ \brief Define what action needs to be done when updating pvd with an NvParameterized object.
+ */
+ struct PvdAction
+ {
+ /**
+ \brief Enum
+ */
+ enum Enum
+ {
+ /**
+ \brief Create instances and update properties.
+ */
+ UPDATE,
+
+ /**
+ \brief Destroy instances.
+ */
+ DESTROY
+ };
+ };
+
+
+
+ /**
+ \brief The ApexPvdClient class allows APEX and PhysX to both connect to the PhysX Visual Debugger (PVD)
+ */
+ class ApexPvdClient : public PvdClient
+ {
+ public:
+ /**
+ \brief Check if the PVD connection is active
+ */
+ virtual bool isConnected() const = 0;
+
+ /**
+ \brief Called when PVD connection established
+ */
+ virtual void onPvdConnected() = 0;
+
+ /**
+ \brief Called when PVD connection finished
+ */
+ virtual void onPvdDisconnected() = 0;
+
+ /**
+ \brief Flush data streams etc.
+ */
+ virtual void flush() = 0;
+
+ /**
+ \brief Retrieve the PxPvd
+ */
+ virtual PxPvd& getPxPvd() = 0;
+
+ /**
+ \brief Returns the data stream if Pvd is connected.
+ */
+ virtual PvdDataStream* getDataStream() = 0;
+
+ /**
+ \brief Returns the PvdUserRenderer if Pvd is connected.
+ */
+ virtual PvdUserRenderer* getUserRender() = 0;
+
+ //virtial PvdMetaDataBinding* getMetaDataBinding() = 0;
+
+ /**
+ \brief Initializes the classes sent to pvd.
+ */
+ virtual void initPvdClasses() = 0;
+
+ /**
+ \brief Sends the existing instances to pvd.
+ */
+ virtual void initPvdInstances() = 0;
+
+ /**
+ \brief Adds properties of an NvParameterized object to the provided class and creates necessary subclasses for structs.
+
+ \note The pvd class pvdClassName must already exist. Pvd classes for structs are being created, but not for references.
+ */
+ virtual void initPvdClasses(const NvParameterized::Definition& paramsHandle, const char* pvdClassName) = 0;
+
+ /**
+ \brief Creates or destroys pvdInstances and/or updates properties.
+ */
+ virtual void updatePvd(const void* pvdInstance, NvParameterized::Interface& params, PvdAction::Enum pvdAction = PvdAction::UPDATE) = 0;
+
+ //////////////////
+
+ /**
+ \brief Start the profiling frame
+ \note inInstanceId must *not* be used already by pvd
+ */
+ virtual void beginFrame( void* inInstanceId ) = 0;
+
+ /**
+ \brief End the profiling frame
+ */
+ virtual void endFrame( void* inInstanceId ) = 0;
+
+ /**
+ \brief Destroy this instance
+ */
+ virtual void release() = 0;
+
+ /**
+ * Assumes foundation is already booted up.
+ */
+ static ApexPvdClient* create( PxPvd* pvd );
+ };
+
+}
+}
+
+
+
+#endif // APEX_PVD_CLIENT_H
diff --git a/APEX_1.4/common/include/ApexQuadricSimplifier.h b/APEX_1.4/common/include/ApexQuadricSimplifier.h
new file mode 100644
index 00000000..75b050cf
--- /dev/null
+++ b/APEX_1.4/common/include/ApexQuadricSimplifier.h
@@ -0,0 +1,352 @@
+/*
+ * 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 __APEX_QUADRIC_SIMPLIFIER_H__
+#define __APEX_QUADRIC_SIMPLIFIER_H__
+
+#include "ApexUsingNamespace.h"
+#include "PsArray.h"
+#include "PsUserAllocated.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+class ApexQuadricSimplifier : public UserAllocated
+{
+public:
+ ApexQuadricSimplifier();
+
+ ~ApexQuadricSimplifier();
+ void clear();
+
+ // registration
+ void registerVertex(const PxVec3& pos);
+ void registerTriangle(uint32_t v0, uint32_t v1, uint32_t v2);
+ bool endRegistration(bool mergeCloseVertices, IProgressListener* progress);
+
+ // manipulation
+ uint32_t simplify(uint32_t subdivision, int32_t maxSteps, float maxError, IProgressListener* progress);
+
+ // accessors
+ uint32_t getNumVertices() const
+ {
+ return mVertices.size();
+ }
+ uint32_t getNumDeletedVertices() const
+ {
+ return mNumDeletedVertices;
+ }
+
+ bool getVertexPosition(uint32_t vertexNr, PxVec3& pos) const
+ {
+ PX_ASSERT(vertexNr < mVertices.size());
+ if (mVertices[vertexNr]->bDeleted == 1)
+ {
+ return false;
+ }
+
+ pos = mVertices[vertexNr]->pos;
+ return true;
+ }
+ int32_t getTriangleNr(uint32_t v0, uint32_t v1, uint32_t v2) const;
+ uint32_t getNumTriangles() const
+ {
+ return mTriangles.size() - mNumDeletedTriangles;
+ }
+ bool getTriangle(uint32_t i, uint32_t& v0, uint32_t& v1, uint32_t& v2) const;
+
+private:
+
+ class Quadric
+ {
+ public:
+ void zero()
+ {
+ a00 = 0.0f;
+ a01 = 0.0f;
+ a02 = 0.0f;
+ a03 = 0.0f;
+ a11 = 0.0f;
+ a12 = 0.0f;
+ a13 = 0.0f;
+ a22 = 0.0f;
+ a23 = 0.0f;
+ a33 = 0.0f;
+ }
+
+ // generate quadric from plane
+ void setFromPlane(const PxVec3& v0, const PxVec3& v1, const PxVec3& v2)
+ {
+ PxVec3 n = (v1 - v0).cross(v2 - v0);
+ n.normalize();
+ float d = -n.dot(v0);
+ a00 = n.x * n.x;
+ a01 = n.x * n.y;
+ a02 = n.x * n.z;
+ a03 = n.x * d;
+ a11 = n.y * n.y;
+ a12 = n.y * n.z;
+ a13 = n.y * d;
+ a22 = n.z * n.z;
+ a23 = n.z * d;
+ a33 = d * d;
+ }
+
+ Quadric operator +(const Quadric& q) const
+ {
+ Quadric sum;
+ sum.a00 = a00 + q.a00;
+ sum.a01 = a01 + q.a01;
+ sum.a02 = a02 + q.a02;
+ sum.a03 = a03 + q.a03;
+ sum.a11 = a11 + q.a11;
+ sum.a12 = a12 + q.a12;
+ sum.a13 = a13 + q.a13;
+ sum.a22 = a22 + q.a22;
+ sum.a23 = a23 + q.a23;
+ sum.a33 = a33 + q.a33;
+ return sum;
+ }
+
+ void operator +=(const Quadric& q)
+ {
+ a00 += q.a00;
+ a01 += q.a01;
+ a02 += q.a02;
+ a03 += q.a03;
+ a11 += q.a11;
+ a12 += q.a12;
+ a13 += q.a13;
+ a22 += q.a22;
+ a23 += q.a23;
+ a33 += q.a33;
+ }
+
+ float outerProduct(const PxVec3& v)
+ {
+ return a00 * v.x * v.x + 2.0f * a01 * v.x * v.y + 2.0f * a02 * v.x * v.z + 2.0f * a03 * v.x +
+ a11 * v.y * v.y + 2.0f * a12 * v.y * v.z + 2.0f * a13 * v.y +
+ a22 * v.z * v.z + 2.0f * a23 * v.z + a33;
+ }
+ private:
+ float a00, a01, a02, a03;
+ float a11, a12, a13;
+ float a22, a23;
+ float a33;
+
+ };
+
+ struct QuadricVertex : public UserAllocated
+ {
+ QuadricVertex(const PxVec3& newPos)
+ {
+ pos = newPos;
+ q.zero();
+ bDeleted = 0;
+ bReferenced = 0;
+ bBorder = 0;
+ }
+ void removeEdge(int32_t edgeNr);
+ void addTriangle(int32_t triangleNr);
+ void removeTriangle(int32_t triangleNr);
+ PxVec3 pos;
+ Quadric q;
+ physx::Array<uint32_t> mEdges;
+ physx::Array<uint32_t> mTriangles;
+ uint32_t bDeleted : 1;
+ uint32_t bReferenced : 1;
+ uint32_t bBorder : 1;
+ };
+
+ struct QuadricEdge
+ {
+ void init(int32_t v0, int32_t v1)
+ {
+ vertexNr[0] = (uint32_t)PxMin(v0, v1);
+ vertexNr[1] = (uint32_t)PxMax(v0, v1);
+ cost = -1.0f;
+ lengthSquared = -1.0f;
+ ratio = -1.0f;
+ heapPos = -1;
+ border = false;
+ deleted = false;
+ }
+ bool operator < (QuadricEdge& e) const
+ {
+ if (vertexNr[0] < e.vertexNr[0])
+ {
+ return true;
+ }
+ if (vertexNr[0] > e.vertexNr[0])
+ {
+ return false;
+ }
+ return vertexNr[1] < e.vertexNr[1];
+ }
+ bool operator == (QuadricEdge& e) const
+ {
+ return vertexNr[0] == e.vertexNr[0] && vertexNr[1] == e.vertexNr[1];
+ }
+ uint32_t otherVertex(uint32_t vNr) const
+ {
+ if (vertexNr[0] == vNr)
+ {
+ return vertexNr[1];
+ }
+ else
+ {
+ PX_ASSERT(vertexNr[1] == vNr);
+ return vertexNr[0];
+ }
+ }
+ void replaceVertex(uint32_t vOld, uint32_t vNew)
+ {
+ if (vertexNr[0] == vOld)
+ {
+ vertexNr[0] = vNew;
+ }
+ else if (vertexNr[1] == vOld)
+ {
+ vertexNr[1] = vNew;
+ }
+ else
+ {
+ PX_ASSERT(0);
+ }
+ if (vertexNr[0] > vertexNr[1])
+ {
+ unsigned v = vertexNr[0];
+ vertexNr[0] = vertexNr[1];
+ vertexNr[1] = v;
+ }
+ }
+ uint32_t vertexNr[2];
+ float cost;
+ float lengthSquared;
+ float ratio;
+ int32_t heapPos;
+ bool border;
+ bool deleted;
+ };
+
+ struct QuadricTriangle
+ {
+ void init(uint32_t v0, uint32_t v1, uint32_t v2)
+ {
+ vertexNr[0] = v0;
+ vertexNr[1] = v1;
+ vertexNr[2] = v2;
+ deleted = false;
+ }
+ bool containsVertex(uint32_t vNr) const
+ {
+ return vertexNr[0] == vNr || vertexNr[1] == vNr || vertexNr[2] == vNr;
+ }
+ uint32_t otherVertex(uint32_t v0, uint32_t v1)
+ {
+ if (vertexNr[0] != v0 && vertexNr[0] != v1)
+ {
+ PX_ASSERT(v0 == vertexNr[1] || v0 == vertexNr[2]);
+ PX_ASSERT(v1 == vertexNr[1] || v1 == vertexNr[2]);
+ return vertexNr[0];
+ }
+ else if (vertexNr[1] != v0 && vertexNr[1] != v1)
+ {
+ PX_ASSERT(v0 == vertexNr[0] || v0 == vertexNr[2]);
+ PX_ASSERT(v1 == vertexNr[0] || v1 == vertexNr[2]);
+ return vertexNr[1];
+ }
+ else
+ {
+ PX_ASSERT(vertexNr[2] != v0 && vertexNr[2] != v1);
+ PX_ASSERT(v0 == vertexNr[0] || v0 == vertexNr[1]);
+ PX_ASSERT(v1 == vertexNr[0] || v1 == vertexNr[1]);
+ return vertexNr[2];
+ }
+ }
+ void replaceVertex(uint32_t vOld, uint32_t vNew)
+ {
+ if (vertexNr[0] == vOld)
+ {
+ vertexNr[0] = vNew;
+ }
+ else if (vertexNr[1] == vOld)
+ {
+ vertexNr[1] = vNew;
+ }
+ else if (vertexNr[2] == vOld)
+ {
+ vertexNr[2] = vNew;
+ }
+ else
+ {
+ PX_ASSERT(0);
+ }
+ }
+ bool operator == (QuadricTriangle& t) const
+ {
+ return t.containsVertex(vertexNr[0]) &&
+ t.containsVertex(vertexNr[1]) &&
+ t.containsVertex(vertexNr[2]);
+ }
+ uint32_t vertexNr[3];
+ bool deleted;
+ };
+
+ struct QuadricVertexRef
+ {
+ void init(const PxVec3& p, int32_t vNr)
+ {
+ pos = p;
+ vertexNr = (uint32_t)vNr;
+ }
+ bool operator < (const QuadricVertexRef& vr)
+ {
+ return pos.x < vr.pos.x;
+ }
+ PxVec3 pos;
+ uint32_t vertexNr;
+ };
+
+
+ void computeCost(QuadricEdge& edge);
+ bool legalCollapse(QuadricEdge& edge, float maxLength);
+ void collapseEdge(QuadricEdge& edge);
+ void quickSortEdges(int32_t l, int32_t r);
+ void quickSortVertexRefs(int32_t l, int32_t r);
+ void mergeVertices();
+
+ bool heapElementSmaller(QuadricEdge* e0, QuadricEdge* e1);
+ void heapUpdate(uint32_t i);
+ void heapSift(uint32_t i);
+ void heapRemove(uint32_t i, bool append);
+ void testHeap();
+ void testMesh();
+
+ PxBounds3 mBounds;
+
+ physx::Array<QuadricVertex*> mVertices;
+ physx::Array<QuadricEdge> mEdges;
+ physx::Array<QuadricTriangle> mTriangles;
+ physx::Array<QuadricEdge*> mHeap;
+ physx::Array<QuadricVertexRef> mVertexRefs;
+
+ uint32_t mNumDeletedTriangles;
+ uint32_t mNumDeletedVertices;
+ uint32_t mNumDeletedHeapElements;
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif \ No newline at end of file
diff --git a/APEX_1.4/common/include/ApexQuickSelectSmallestK.h b/APEX_1.4/common/include/ApexQuickSelectSmallestK.h
new file mode 100644
index 00000000..fabd8c88
--- /dev/null
+++ b/APEX_1.4/common/include/ApexQuickSelectSmallestK.h
@@ -0,0 +1,81 @@
+/*
+ * 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 APEX_QUICK_SELECT_SMALLEST_K_H
+#define APEX_QUICK_SELECT_SMALLEST_K_H
+
+namespace nvidia
+{
+namespace apex
+{
+//A variant of quick sort to move the smallest k members of a sequence to its start.
+//Does much less work than a full sort.
+
+template<class Sortable, class Predicate>
+PX_INLINE void ApexQuickSelectSmallestK(Sortable* start, Sortable* end, uint32_t k, const Predicate& p = Predicate())
+{
+ Sortable* origStart = start;
+ Sortable* i;
+ Sortable* j;
+ Sortable m;
+
+ for (;;)
+ {
+ i = start;
+ j = end;
+ m = *(i + ((j - i) >> 1));
+
+ while (i <= j)
+ {
+ while (p(*i, m))
+ {
+ i++;
+ }
+ while (p(m, *j))
+ {
+ j--;
+ }
+ if (i <= j)
+ {
+ if (i != j)
+ {
+ nvidia::swap(*i, *j);
+ }
+ i++;
+ j--;
+ }
+ }
+
+
+
+ if (start < j
+ && k + origStart - 1 < j) //we now have found the (j - start+1) smallest. we need to continue sorting these only if k < (j - start+1)
+ //if we sort this we definitely won't need to sort the right hand side.
+ {
+ end = j;
+ }
+ else if (i < end
+ && k + origStart > i) //only continue sorting these if left side is not larger than k.
+ //we do this instead of recursing
+ {
+ start = i;
+ }
+ else
+ {
+ return;
+ }
+ }
+}
+
+} // namespace apex
+} // namespace nvidia
+
+#endif // APEX_QUICK_SELECT_SMALLEST_K_H
diff --git a/APEX_1.4/common/include/ApexRWLockable.h b/APEX_1.4/common/include/ApexRWLockable.h
new file mode 100644
index 00000000..2820db72
--- /dev/null
+++ b/APEX_1.4/common/include/ApexRWLockable.h
@@ -0,0 +1,126 @@
+/*
+ * 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 APEX_RW_LOCKABLE_H
+#define APEX_RW_LOCKABLE_H
+
+#include "RWLockable.h"
+#include "PsThread.h"
+#include "PsMutex.h"
+#include "PsHashMap.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+struct ThreadReadWriteCount
+{
+ ThreadReadWriteCount() : value(0) {}
+ union {
+ struct {
+ uint8_t readDepth; // depth of re-entrant reads
+ uint8_t writeDepth; // depth of re-entrant writes
+ uint8_t readLockDepth; // depth of read-locks
+ uint8_t writeLockDepth; // depth of write-locks
+ } counters;
+ uint32_t value;
+ };
+};
+
+class ApexRWLockable : public RWLockable
+{
+public:
+ ApexRWLockable();
+ virtual ~ApexRWLockable();
+
+ virtual void acquireReadLock(const char *fileName, const uint32_t lineno) const;
+ virtual void acquireWriteLock(const char *fileName, const uint32_t lineno)const;
+ virtual void releaseReadLock(void) const;
+ virtual void releaseWriteLock(void) const;
+ virtual uint32_t getReadWriteErrorCount() const;
+ bool startWrite(bool allowReentry);
+ void stopWrite(bool allowReentry);
+ nvidia::Thread::Id getCurrentWriter() const;
+
+ bool startRead() const;
+ void stopRead() const;
+
+ void setEnabled(bool);
+ bool isEnabled() const;
+private:
+ bool mEnabled;
+ mutable volatile nvidia::Thread::Id mCurrentWriter;
+ mutable nvidia::ReadWriteLock mRWLock;
+ volatile int32_t mConcurrentWriteCount;
+ mutable volatile int32_t mConcurrentReadCount;
+ mutable volatile int32_t mConcurrentErrorCount;
+ nvidia::Mutex mDataLock;
+ typedef nvidia::HashMap<nvidia::ThreadImpl::Id, ThreadReadWriteCount> DepthsHashMap_t;
+ mutable DepthsHashMap_t mData;
+};
+
+#define APEX_RW_LOCKABLE_BOILERPLATE \
+ virtual void acquireReadLock(const char *fileName, const uint32_t lineno) const \
+ { \
+ ApexRWLockable::acquireReadLock(fileName, lineno); \
+ } \
+ virtual void acquireWriteLock(const char *fileName, const uint32_t lineno) const\
+ { \
+ ApexRWLockable::acquireWriteLock(fileName, lineno); \
+ } \
+ virtual void releaseReadLock(void) const\
+ { \
+ ApexRWLockable::releaseReadLock(); \
+ } \
+ virtual void releaseWriteLock(void) const\
+ { \
+ ApexRWLockable::releaseWriteLock(); \
+ } \
+ virtual uint32_t getReadWriteErrorCount() const \
+ { \
+ return ApexRWLockable::getReadWriteErrorCount(); \
+ } \
+ bool startWrite(bool allowReentry) \
+ { \
+ return ApexRWLockable::startWrite(allowReentry); \
+ } \
+ void stopWrite(bool allowReentry) \
+ { \
+ ApexRWLockable::stopWrite(allowReentry); \
+ } \
+ bool startRead() const \
+ { \
+ return ApexRWLockable::startRead(); \
+ } \
+ void stopRead() const \
+ { \
+ ApexRWLockable::stopRead(); \
+ } \
+
+class ApexRWLockableScopedDisable
+{
+public:
+ ApexRWLockableScopedDisable(RWLockable*);
+ ~ApexRWLockableScopedDisable();
+private:
+ ApexRWLockableScopedDisable(const ApexRWLockableScopedDisable&);
+ ApexRWLockableScopedDisable& operator=(const ApexRWLockableScopedDisable&);
+
+ ApexRWLockable* mLockable;
+};
+
+#define APEX_RW_LOCKABLE_SCOPED_DISABLE(lockable) ApexRWLockableScopedDisable __temporaryDisable(lockable);
+
+}
+}
+
+#endif // APEX_RW_LOCKABLE_H
diff --git a/APEX_1.4/common/include/ApexRand.h b/APEX_1.4/common/include/ApexRand.h
new file mode 100644
index 00000000..1c075f7e
--- /dev/null
+++ b/APEX_1.4/common/include/ApexRand.h
@@ -0,0 +1,133 @@
+/*
+ * 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 APEX_RAND_H
+#define APEX_RAND_H
+
+#include "PxMath.h"
+#include "PxVec3.h"
+#include "ApexUsingNamespace.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+// "Quick and Dirty Symmetric Random number generator" - returns a uniform deviate in [-1.0,1.0)
+class QDSRand
+{
+ uint32_t mSeed;
+
+public:
+
+ PX_CUDA_CALLABLE PX_INLINE QDSRand(uint32_t seed = 0) : mSeed(seed) {}
+
+ PX_CUDA_CALLABLE PX_INLINE void setSeed(uint32_t seed = 0)
+ {
+ mSeed = seed;
+ }
+
+ PX_CUDA_CALLABLE PX_INLINE uint32_t seed() const
+ {
+ return mSeed;
+ }
+
+ PX_CUDA_CALLABLE PX_INLINE uint32_t nextSeed()
+ {
+ mSeed = mSeed * 1664525L + 1013904223L;
+ return mSeed;
+ }
+
+ PX_CUDA_CALLABLE PX_INLINE float getNext()
+ {
+ union U32F32
+ {
+ uint32_t u;
+ float f;
+ } r;
+ r.u = 0x40000000 | (nextSeed() >> 9);
+ return r.f - 3.0f;
+ }
+
+ PX_CUDA_CALLABLE PX_INLINE float getScaled(const float min, const float max)
+ {
+ const float scale = (max - min) / 2.0f;
+ return ((getNext() + 1.0f) * scale) + min;
+ }
+
+ PX_CUDA_CALLABLE PX_INLINE PxVec3 getScaled(const PxVec3& min, const PxVec3& max)
+ {
+ return PxVec3(getScaled(min.x, max.x), getScaled(min.y, max.y), getScaled(min.z, max.z));
+ }
+
+ PX_CUDA_CALLABLE PX_INLINE float getUnit()
+ {
+ union U32F32
+ {
+ uint32_t u;
+ float f;
+ } r;
+ r.u = 0x3F800000 | (nextSeed() >> 9);
+ return r.f - 1.0f;
+ }
+
+};
+
+// "Quick and Dirty Normal Random number generator" - returns normally-distributed values
+class QDNormRand
+{
+ QDSRand mBase;
+
+public:
+
+ PX_CUDA_CALLABLE PX_INLINE QDNormRand(uint32_t seed = 0) : mBase(seed) {}
+
+ PX_CUDA_CALLABLE PX_INLINE void setSeed(uint32_t seed = 0)
+ {
+ mBase.setSeed(seed);
+ }
+
+ PX_CUDA_CALLABLE PX_INLINE uint32_t setSeed() const
+ {
+ return mBase.seed();
+ }
+
+ PX_CUDA_CALLABLE PX_INLINE uint32_t nextSeed()
+ {
+ return mBase.nextSeed();
+ }
+
+ PX_CUDA_CALLABLE PX_INLINE float getNext()
+ {
+ //Using Box-Muller transform (see http://en.wikipedia.org/wiki/Box_Muller_transform)
+
+ float u, v, s;
+ do
+ {
+ u = mBase.getNext();
+ v = mBase.getNext();
+ s = u * u + v * v;
+ }
+ while (s >= 1.0);
+
+ return u * PxSqrt(-2.0f * PxLog(s) / s);
+ }
+
+ PX_CUDA_CALLABLE PX_INLINE float getScaled(const float m, const float s)
+ {
+ return m + s * getNext();
+ }
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif
diff --git a/APEX_1.4/common/include/ApexRenderable.h b/APEX_1.4/common/include/ApexRenderable.h
new file mode 100644
index 00000000..ad4bfdfa
--- /dev/null
+++ b/APEX_1.4/common/include/ApexRenderable.h
@@ -0,0 +1,79 @@
+/*
+ * 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 APEX_RENDERABLE_H
+#define APEX_RENDERABLE_H
+
+#include "ApexUsingNamespace.h"
+#include "PsMutex.h"
+
+#include "PxBounds3.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+/**
+ Base class for implementations of Renderable classes
+*/
+
+class ApexRenderable
+{
+public:
+ ApexRenderable()
+ {
+ mRenderBounds.setEmpty();
+ }
+ ~ApexRenderable()
+ {
+ // the PS3 Mutex cannot be unlocked without first being locked, so grab the lock
+ if (renderDataTryLock())
+ {
+ renderDataUnLock();
+ }
+ else
+ {
+ // someone is holding the lock and should not be, so assert
+ PX_ALWAYS_ASSERT();
+ }
+ }
+ void renderDataLock()
+ {
+ mRenderDataLock.lock();
+ }
+ void renderDataUnLock()
+ {
+ mRenderDataLock.unlock();
+ }
+ bool renderDataTryLock()
+ {
+ return mRenderDataLock.trylock();
+ }
+ const PxBounds3& getBounds() const
+ {
+ return mRenderBounds;
+ }
+
+protected:
+ //nvidia::Mutex mRenderDataLock;
+ // Converting to be a PS3 SPU-friendly lock
+ // On PC this is the same as a Mutex, on PS3 it is a 128b (!) aligned U32. Subclasses might get bigger on PS3 and they
+ // are most likely distributed over more than one cache line.
+ AtomicLock mRenderDataLock;
+
+ PxBounds3 mRenderBounds;
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif // APEX_RENDERABLE_H
diff --git a/APEX_1.4/common/include/ApexResource.h b/APEX_1.4/common/include/ApexResource.h
new file mode 100644
index 00000000..d2ebda70
--- /dev/null
+++ b/APEX_1.4/common/include/ApexResource.h
@@ -0,0 +1,105 @@
+/*
+ * 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 APEX_RESOURCE_H
+#define APEX_RESOURCE_H
+
+#include "ApexUsingNamespace.h"
+#include "PsUserAllocated.h"
+
+namespace physx
+{
+ namespace pvdsdk
+ {
+ class PvdDataStream;
+ }
+}
+namespace nvidia
+{
+namespace apex
+{
+
+/**
+ * Class defines semi-public interface to ApexResource objects
+ * Resource - gets added to a list, will be deleted when the list is deleted
+ */
+class ApexResourceInterface
+{
+public:
+ virtual void release() = 0;
+ virtual void setListIndex(class ResourceList& list, uint32_t index) = 0;
+ virtual uint32_t getListIndex() const = 0;
+ virtual void initPvdInstances(pvdsdk::PvdDataStream& /*pvdStream*/) {};
+};
+
+/**
+Class that implements resource ID and bank
+*/
+class ApexResource : public UserAllocated
+{
+public:
+ ApexResource() : m_listIndex(0xFFFFFFFF), m_list(NULL) {}
+ void removeSelf();
+ virtual ~ApexResource();
+
+ uint32_t m_listIndex;
+ class ResourceList* m_list;
+};
+
+
+/**
+Initialized Template class.
+*/
+template <class DescType>class InitTemplate
+{
+ //gotta make a derived class cause of protected ctor
+public:
+ InitTemplate() : isSet(false) {}
+
+ bool isSet;
+ DescType data;
+
+
+ void set(const DescType* desc)
+ {
+ if (desc)
+ {
+ isSet = true;
+ //memcpy(this,desc, sizeof(DescType));
+ data = *desc;
+ }
+ else
+ {
+ isSet = false;
+ }
+ }
+
+
+ bool get(DescType& dest) const
+ {
+ if (isSet)
+ {
+ //memcpy(&dest,this, sizeof(DescType));
+ dest = data;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+
+ }
+};
+
+} // namespace apex
+} // namespace nvidia
+
+#endif // APEX_RESOURCE_H
diff --git a/APEX_1.4/common/include/ApexResourceHelper.h b/APEX_1.4/common/include/ApexResourceHelper.h
new file mode 100644
index 00000000..c35aced7
--- /dev/null
+++ b/APEX_1.4/common/include/ApexResourceHelper.h
@@ -0,0 +1,95 @@
+/*
+ * 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 __APEX_RESOURCE_HELPER_H__
+#define __APEX_RESOURCE_HELPER_H__
+
+#include "Apex.h"
+#include "ResourceProviderIntl.h"
+
+#if PX_PHYSICS_VERSION_MAJOR == 3
+#include <PxFiltering.h>
+#endif
+
+namespace nvidia
+{
+namespace apex
+{
+
+class ApexResourceHelper
+{
+ ApexResourceHelper() {}
+public:
+
+
+#if PX_PHYSICS_VERSION_MAJOR == 3
+ static PX_INLINE PxFilterData resolveCollisionGroup128(const char* collisionGroup128Name)
+ {
+ PxFilterData result; //default constructor sets all words to 0
+
+ if (collisionGroup128Name)
+ {
+ /* create namespace for Collision Group (if it has not already been created) */
+ ResourceProviderIntl* nrp = GetInternalApexSDK()->getInternalResourceProvider();
+ ResID collisionGroup128NS = GetInternalApexSDK()->getCollisionGroup128NameSpace();
+ ResID id = nrp->createResource(collisionGroup128NS, collisionGroup128Name);
+ const uint32_t* resourcePtr = static_cast<const uint32_t*>(nrp->getResource(id));
+ if (resourcePtr)
+ {
+ result.word0 = resourcePtr[0];
+ result.word1 = resourcePtr[1];
+ result.word2 = resourcePtr[2];
+ result.word3 = resourcePtr[3];
+ }
+ }
+ return result;
+ }
+#endif
+
+ static PX_INLINE GroupsMask64 resolveCollisionGroup64(const char* collisionGroup64Name)
+ {
+ GroupsMask64 result(0, 0);
+
+ if (collisionGroup64Name)
+ {
+ /* create namespace for Collision Group (if it has not already been created) */
+ ResourceProviderIntl* nrp = GetInternalApexSDK()->getInternalResourceProvider();
+ ResID collisionGroup64NS = GetInternalApexSDK()->getCollisionGroup64NameSpace();
+
+ ResID id = nrp->createResource(collisionGroup64NS, collisionGroup64Name);
+ const uint32_t* resourcePtr = static_cast<const uint32_t*>(nrp->getResource(id));
+ if (resourcePtr)
+ {
+ result.bits0 = resourcePtr[0];
+ result.bits1 = resourcePtr[1];
+ }
+ }
+ return result;
+ }
+
+ static PX_INLINE uint32_t resolveCollisionGroupMask(const char* collisionGroupMaskName, uint32_t defGroupMask = 0xFFFFFFFFu)
+ {
+ uint32_t groupMask = defGroupMask;
+ if (collisionGroupMaskName)
+ {
+ ResourceProviderIntl* nrp = GetInternalApexSDK()->getInternalResourceProvider();
+ ResID collisionGroupMaskNS = GetInternalApexSDK()->getCollisionGroupMaskNameSpace();
+ ResID id = nrp->createResource(collisionGroupMaskNS, collisionGroupMaskName);
+ groupMask = (uint32_t)(size_t)(nrp->getResource(id));
+ }
+ return groupMask;
+ }
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif // __APEX_RESOURCE_HELPER_H__
diff --git a/APEX_1.4/common/include/ApexSDKCachedDataImpl.h b/APEX_1.4/common/include/ApexSDKCachedDataImpl.h
new file mode 100644
index 00000000..2f4e27d7
--- /dev/null
+++ b/APEX_1.4/common/include/ApexSDKCachedDataImpl.h
@@ -0,0 +1,85 @@
+/*
+ * 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 __APEX_SCENE_CACHED_DATA_H__
+
+#define __APEX_SCENE_CACHED_DATA_H__
+
+#include "ApexUsingNamespace.h"
+#include "PxSimpleTypes.h"
+#include "PxFileBuf.h"
+#include "PsUserAllocated.h"
+#include "PsArray.h"
+
+#include "ApexSDKCachedData.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+class ApexScene;
+class ModuleSceneIntl;
+
+/**
+ Cached data is stored per-module.
+*/
+class ModuleCachedDataIntl : public ModuleCachedData
+{
+public:
+ virtual AuthObjTypeID getModuleID() const = 0;
+
+ virtual NvParameterized::Interface* getCachedDataForAssetAtScale(Asset& asset, const PxVec3& scale) = 0;
+ virtual PxFileBuf& serialize(PxFileBuf& stream) const = 0;
+ virtual PxFileBuf& deserialize(PxFileBuf& stream) = 0;
+ virtual void clear(bool force = true) = 0; // If force == false, data in use by actors will not be deleted
+};
+
+//**************************************************************************************************************************
+//**************************************************************************************************************************
+//**** APEX SCENE CACHED DATA
+//**************************************************************************************************************************
+//**************************************************************************************************************************
+
+class ApexSDKCachedDataImpl : public ApexSDKCachedData, public UserAllocated
+{
+public:
+ bool registerModuleDataCache(ModuleCachedDataIntl* cache);
+ bool unregisterModuleDataCache(ModuleCachedDataIntl* cache);
+
+ // ApexSDKCachedData interface
+ ApexSDKCachedDataImpl();
+ virtual ~ApexSDKCachedDataImpl();
+
+ virtual ModuleCachedData* getCacheForModule(AuthObjTypeID moduleID);
+ virtual PxFileBuf& serialize(PxFileBuf& stream) const;
+ virtual PxFileBuf& deserialize(PxFileBuf& stream);
+ virtual void clear(bool force = true);
+
+ struct Version
+ {
+ enum Enum
+ {
+ First = 0,
+
+ Count,
+ Current = Count - 1
+ };
+ };
+
+ // Data
+ physx::Array<ModuleCachedDataIntl*> mModuleCaches;
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif // __APEX_SCENE_CACHED_DATA_H__
diff --git a/APEX_1.4/common/include/ApexSDKHelpers.h b/APEX_1.4/common/include/ApexSDKHelpers.h
new file mode 100644
index 00000000..a3ca7529
--- /dev/null
+++ b/APEX_1.4/common/include/ApexSDKHelpers.h
@@ -0,0 +1,236 @@
+/*
+ * 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 __APEXSDKHELPERS_H__
+#define __APEXSDKHELPERS_H__
+
+
+#include "PsArray.h"
+#include "PsSort.h"
+#include "ApexString.h"
+#include "ApexSDKIntl.h"
+#include "ApexResource.h"
+#include "ResourceProviderIntl.h"
+#include "PxMat33.h"
+#include "PsMutex.h"
+
+namespace physx
+{
+ namespace pvdsdk
+ {
+ class PvdDataStream;
+ }
+}
+namespace nvidia
+{
+namespace apex
+{
+
+enum StreamPointerToken
+{
+ SPT_INVALID_PTR,
+ SPT_VALID_PTR
+};
+
+
+/*
+ Resource list - holds a list of ApexResourceInterface objects, for quick removal
+ */
+class ResourceList: public nvidia::UserAllocated
+{
+ physx::Array<ApexResourceInterface*> mArray;
+ nvidia::ReadWriteLock mRWLock;
+
+#ifndef WITHOUT_PVD
+ // for PVD
+ const void* mOwner;
+ ApexSimpleString mListName;
+ ApexSimpleString mEntryName;
+#endif
+
+public:
+
+ ResourceList()
+#ifndef WITHOUT_PVD
+ : mOwner(NULL)
+#endif
+ {}
+ ~ResourceList();
+
+ void clear(); // explicitely free children
+
+ void add(ApexResourceInterface& resource);
+ void remove(uint32_t index);
+ uint32_t getSize() const
+ {
+ ScopedReadLock scopedLock(const_cast<nvidia::ReadWriteLock&>(mRWLock));
+ return mArray.size();
+ }
+ ApexResourceInterface* getResource(uint32_t index) const
+ {
+ ScopedReadLock scopedLock(const_cast<nvidia::ReadWriteLock&>(mRWLock));
+ return mArray[index];
+ }
+
+ template<typename Predicate>
+ void sort(const Predicate& compare)
+ {
+ ScopedWriteLock scopedLock(mRWLock);
+ uint32_t size = mArray.size();
+ if (size > 0)
+ {
+ nvidia::sort(&mArray[0], size, compare);
+ }
+
+ for (uint32_t i = 0; i < size; ++i)
+ {
+ mArray[i]->setListIndex(*this, i);
+ }
+ }
+
+#ifndef WITHOUT_PVD
+ void setupForPvd(const void* owner, const char* listName, const char* entryName);
+ void initPvdInstances(pvdsdk::PvdDataStream& pvdStream);
+#endif
+};
+
+
+#ifndef M_SQRT1_2 //1/sqrt(2)
+#define M_SQRT1_2 double(0.7071067811865475244008443621048490)
+#endif
+
+
+/*
+ Creates a rotation matrix which rotates about the axisAngle vector. The length of
+ the axisAngle vector is the desired rotation angle. In this approximation, however,
+ this is only the case for small angles. As the length of axisAngle grows (is no
+ longer very much less than 1 radian) the approximation becomes worse. As the length
+ of axisAngle approaches infinity, the rotation angle approaches pi. The exact
+ relation is:
+
+ rotation_angle = 2*atan( axisAngle.magnitude()/2 )
+
+ One use for this construction is the rotation applied to mesh particle system particles. With a
+ decent frame rate, the rotation angle should be small, unless the particle is going
+ very fast or has very small radius. In that case, or if the frame rate is poor,
+ the inaccuracy in this construction probably won't be noticed.
+
+ Error: The rotation angle is accurate to:
+ 1% up to 20 degrees
+ 10% up to 70 degrees
+*/
+PX_INLINE void approxAxisAngleToMat33(const PxVec3& axisAngle, PxMat33& rot)
+{
+ const float x = 0.5f * axisAngle.x;
+ const float y = 0.5f * axisAngle.y;
+ const float z = 0.5f * axisAngle.z;
+ const float xx = x * x;
+ const float yy = y * y;
+ const float zz = z * z;
+ const float xy = x * y;
+ const float yz = y * z;
+ const float zx = z * x;
+ const float twoRecipNorm2 = 2.0f / (1.0f + xx + yy + zz); // w = 1
+ rot(0, 0) = 1.0f - twoRecipNorm2 * (yy + zz);
+ rot(0, 1) = twoRecipNorm2 * (xy - z);
+ rot(0, 2) = twoRecipNorm2 * (zx + y);
+ rot(1, 0) = twoRecipNorm2 * (xy + z);
+ rot(1, 1) = 1.0f - twoRecipNorm2 * (zz + xx);
+ rot(1, 2) = twoRecipNorm2 * (yz - x);
+ rot(2, 0) = twoRecipNorm2 * (zx - y);
+ rot(2, 1) = twoRecipNorm2 * (yz + x);
+ rot(2, 2) = 1.0f - twoRecipNorm2 * (xx + yy);
+}
+
+
+// stl hash
+PX_INLINE uint32_t hash(const char* str, uint32_t len)
+{
+ uint32_t hash = 0;
+
+ for (uint32_t i = 0; i < len; i++)
+ {
+ hash = 5 * hash + str[i];
+ }
+
+ return hash;
+}
+
+PX_INLINE uint32_t GetStamp(ApexSimpleString& name)
+{
+ return hash(name.c_str(), name.len());
+}
+
+#if 0
+// these are poison
+void writeStreamHeader(PxFileBuf& stream, ApexSimpleString& streamName, uint32_t versionStamp);
+uint32_t readStreamHeader(const PxFileBuf& stream, ApexSimpleString& streamName);
+#endif
+
+PX_INLINE uint32_t MaxElementIndex(const PxVec3& v)
+{
+ const uint32_t m01 = (uint32_t)(v.y > v.x);
+ const uint32_t m2 = (uint32_t)(v.z > v[m01]);
+ return m2 << 1 | m01 >> m2;
+}
+
+PX_INLINE uint32_t MinElementIndex(const PxVec3& v)
+{
+ const uint32_t m01 = (uint32_t)(v.y < v.x);
+ const uint32_t m2 = (uint32_t)(v.z < v[m01]);
+ return m2 << 1 | m01 >> m2;
+}
+
+PX_INLINE uint32_t MaxAbsElementIndex(const PxVec3& v)
+{
+ const PxVec3 a(PxAbs(v.x), PxAbs(v.y), PxAbs(v.z));
+ const uint32_t m01 = (uint32_t)(a.y > a.x);
+ const uint32_t m2 = (uint32_t)(a.z > a[m01]);
+ return m2 << 1 | m01 >> m2;
+}
+
+PX_INLINE uint32_t MinAbsElementIndex(const PxVec3& v)
+{
+ const PxVec3 a(PxAbs(v.x), PxAbs(v.y), PxAbs(v.z));
+ const uint32_t m01 = (uint32_t)(a.y < a.x);
+ const uint32_t m2 = (uint32_t)(a.z < a[m01]);
+ return m2 << 1 | m01 >> m2;
+}
+
+
+/******************************************************************************
+ * Helper functions for loading assets
+ *****************************************************************************/
+class ApexAssetHelper
+{
+public:
+ static void* getAssetFromName(ApexSDKIntl* sdk,
+ const char* authoringTypeName,
+ const char* assetName,
+ ResID& inOutResID,
+ ResID optionalPsID = INVALID_RESOURCE_ID);
+
+ static void* getAssetFromNameList(ApexSDKIntl* sdk,
+ const char* authoringTypeName,
+ physx::Array<AssetNameIDMapping*>& nameIdList,
+ const char* assetName,
+ ResID assetPsId = INVALID_RESOURCE_ID);
+
+ static void* getIosAssetFromName(ApexSDKIntl* sdk,
+ const char* iosTypeName,
+ const char* iosAssetName);
+
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif // __APEXSDKHELPERS_H__
diff --git a/APEX_1.4/common/include/ApexSDKIntl.h b/APEX_1.4/common/include/ApexSDKIntl.h
new file mode 100644
index 00000000..6bcc91bb
--- /dev/null
+++ b/APEX_1.4/common/include/ApexSDKIntl.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 APEX_SDK_INTL_H
+#define APEX_SDK_INTL_H
+
+/* Framework-internal interface class */
+
+#include "ApexSDK.h"
+#include "ResourceProviderIntl.h"
+#include "PhysXObjectDescIntl.h"
+
+#include "PsString.h"
+#include "PxErrors.h"
+
+#if APEX_CUDA_SUPPORT
+namespace nvidia
+{
+ class PhysXGpuIndicator;
+}
+#endif
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+namespace NvParameterized
+{
+class Traits;
+};
+
+namespace physx
+{
+namespace pvdsdk
+{
+ class ApexPvdClient;
+}
+namespace profile
+{
+ class PxProfileZone;
+}
+}
+
+namespace nvidia
+{
+namespace apex
+{
+
+class ModuleIntl;
+class Actor;
+class ApexActor;
+class AuthorableObjectIntl;
+class UserOpaqueMesh;
+
+/**
+Internal interface to the ApexSDK, available to Modules and Scenes
+*/
+class ApexSDKIntl : public ApexSDK
+{
+public:
+ /**
+ Register an authorable object type with the SDK. These IDs should be accessable
+ from the Module* public interface so users can compare them against game objects
+ in callbacks.
+ */
+ virtual AuthObjTypeID registerAuthObjType(const char*, ResID nsid) = 0;
+ virtual AuthObjTypeID registerAuthObjType(const char*, AuthorableObjectIntl* authObjPtr) = 0;
+ virtual AuthObjTypeID registerNvParamAuthType(const char*, AuthorableObjectIntl* authObjPtr) = 0;
+ virtual void unregisterAuthObjType(const char*) = 0;
+ virtual void unregisterNvParamAuthType(const char*) = 0;
+ /**
+ Query the ResID of an authorable object namespace. This is useful if you have
+ an authorable object class name, but not a module pointer.
+ */
+ virtual AuthorableObjectIntl* getAuthorableObject(const char*) = 0;
+ virtual AuthorableObjectIntl* getParamAuthObject(const char*) = 0;
+
+ virtual AssetAuthoring* createAssetAuthoring(const char* aoTypeName) = 0;
+ virtual AssetAuthoring* createAssetAuthoring(const char* aoTypeName, const char* name) = 0;
+ virtual Asset* createAsset(AssetAuthoring&, const char*) = 0;
+ virtual Asset* createAsset(NvParameterized::Interface*, const char*) = 0;
+ virtual Asset* createAsset(const char* opaqueMeshName, UserOpaqueMesh* om) = 0;
+ virtual void releaseAsset(Asset&) = 0;
+ virtual void releaseAssetAuthoring(AssetAuthoring&) = 0;
+ /**
+ Request an ApexActor pointer for an Actor
+ */
+ virtual ApexActor* getApexActor(Actor*) const = 0;
+
+ /**
+ When APEX creates a PhysX object and injects it into a PhysX scene, it must
+ register that object with the ApexSDK so that the end user can differentiate between
+ their own PhysX objects and those created by APEX. The object descriptor will also
+ provide a method for working their way back to the containing APEX data structure.
+ */
+#if PX_PHYSICS_VERSION_MAJOR == 3
+ virtual PhysXObjectDescIntl* createObjectDesc(const Actor*, const PxActor*) = 0;
+ virtual PhysXObjectDescIntl* createObjectDesc(const Actor*, const PxShape*) = 0;
+ virtual PhysXObjectDescIntl* createObjectDesc(const Actor*, const PxJoint*) = 0;
+ virtual PhysXObjectDescIntl* createObjectDesc(const Actor*, const PxCloth*) = 0;
+#endif // PX_PHYSICS_VERSION_MAJOR == 3
+
+ /**
+ Retrieve an object desc created by createObjectDesc.
+ */
+ virtual PhysXObjectDescIntl* getGenericPhysXObjectInfo(const void*) const = 0;
+
+ /**
+ When APEX deletes a PhysX object or otherwise removes it from the PhysX scene, it must
+ call this function to remove it from the ApexSDK object description cache.
+ */
+ virtual void releaseObjectDesc(void*) = 0;
+
+ /* Utility functions intended to be used internally */
+ virtual void reportError(PxErrorCode::Enum code, const char* file, int line, const char* functionName, const char* message, ...) = 0;
+
+ virtual uint32_t getCookingVersion() const = 0;
+
+ virtual void* getTempMemory(uint32_t size) = 0;
+
+ virtual void releaseTempMemory(void* data) = 0;
+
+ /**
+ * ApexScenes and Modules can query the ModuleIntl interfaces from the ApexSDK
+ */
+ virtual ModuleIntl** getInternalModules() = 0;
+
+ /**
+ * Returns the internal named resource provider. The internal interface allows
+ * resource creation and deletion
+ */
+ virtual ResourceProviderIntl* getInternalResourceProvider() = 0;
+
+ /**
+ * Allow 3rd party modules distributed as static libraries to link
+ * into the ApexSDK such that the normal ApexSDK::createModule()
+ * will still work correctly. The 3rd party lib must export a C
+ * function that instantiates their module and calls this function.
+ * The user must call that instantiation function before calling
+ * createModule() for it.
+ */
+ virtual void registerExternalModule(Module* nx, ModuleIntl* ni) = 0;
+
+ /**
+ * Allow modules to fetch these ApexSDK global name spaces
+ */
+ virtual ResID getMaterialNameSpace() const = 0;
+ virtual ResID getOpaqueMeshNameSpace() const = 0;
+ virtual ResID getCustomVBNameSpace() const = 0;
+ virtual ResID getApexMeshNameSpace() = 0;
+ virtual ResID getCollisionGroupNameSpace() const = 0;
+ virtual ResID getCollisionGroup128NameSpace() const = 0;
+ virtual ResID getCollisionGroup64NameSpace() const = 0;
+ virtual ResID getCollisionGroupMaskNameSpace() const = 0;
+ virtual ResID getPhysicalMaterialNameSpace() const = 0;
+ virtual ResID getAuthorableTypesNameSpace() const = 0;
+
+ /**
+ * Retrieve the user provided render resource manager
+ */
+ virtual UserRenderResourceManager* getUserRenderResourceManager() const = 0;
+
+ virtual NvParameterized::Traits* getParameterizedTraits() = 0;
+
+ virtual ModuleIntl* getInternalModuleByName(const char* name) = 0;
+
+ /**
+ * Update debug renderer color tables in each apex scene with NvParameterized color table.
+ */
+ virtual void updateDebugColorParams(const char* color, uint32_t val) = 0;
+
+ virtual bool getRMALoadMaterialsLazily() = 0;
+
+ virtual pvdsdk::ApexPvdClient* getApexPvdClient() = 0;
+ virtual profile::PxProfileZoneManager * getProfileZoneManager() = 0;
+ virtual profile::PxProfileZone * getProfileZone() = 0;
+
+ // applications can append strings to the APEX DLL filenames
+ virtual const char* getCustomDllNamePostfix() const = 0;
+#if PX_WINDOWS_FAMILY
+ /**
+ * Return the user-provided appGuid, or the default appGuid if the user didn't provide one.
+ */
+ virtual const char* getAppGuid() = 0;
+#endif
+
+#if APEX_CUDA_SUPPORT
+ virtual PhysXGpuIndicator* registerPhysXIndicatorGpuClient() = 0;
+ virtual void unregisterPhysXIndicatorGpuClient(PhysXGpuIndicator* gpuIndicator) = 0;
+#endif
+
+ virtual ModuleIntl *getInternalModule(Module *module) = 0;
+ virtual Module *getModule(ModuleIntl *module) = 0;
+
+ virtual void enterURR() = 0;
+ virtual void leaveURR() = 0;
+ virtual void checkURR() = 0;
+
+ PX_FORCE_INLINE PxU64 getContextId() const { return PxU64(reinterpret_cast<size_t>(this)); }
+
+protected:
+ virtual ~ApexSDKIntl() {}
+
+};
+
+/**
+Returns global SDK pointer. Not sure if we can do this.
+*/
+APEX_API ApexSDKIntl* CALL_CONV GetInternalApexSDK();
+
+}
+} // end namespace nvidia::apex
+
+#define APEX_SPRINTF_S(dest_buf, n, str_fmt, ...) \
+ shdfnd::snprintf((char *) dest_buf, n, str_fmt, ##__VA_ARGS__);
+
+// gcc uses names ...s
+#define APEX_INVALID_PARAMETER(_A, ...) \
+ nvidia::GetInternalApexSDK()->reportError(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, __FUNCTION__, _A, ##__VA_ARGS__)
+#define APEX_INVALID_OPERATION(_A, ...) \
+ nvidia::GetInternalApexSDK()->reportError(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, __FUNCTION__, _A, ##__VA_ARGS__)
+#define APEX_INTERNAL_ERROR(_A, ...) \
+ nvidia::GetInternalApexSDK()->reportError(PxErrorCode::eINTERNAL_ERROR , __FILE__, __LINE__, __FUNCTION__, _A, ##__VA_ARGS__)
+#define APEX_DEBUG_INFO(_A, ...) \
+ nvidia::GetInternalApexSDK()->reportError(PxErrorCode::eDEBUG_INFO , __FILE__, __LINE__, __FUNCTION__, _A, ##__VA_ARGS__)
+#define APEX_DEBUG_WARNING(_A, ...) \
+ nvidia::GetInternalApexSDK()->reportError(PxErrorCode::eDEBUG_WARNING , __FILE__, __LINE__, __FUNCTION__, _A, ##__VA_ARGS__)
+#define APEX_DEPRECATED() \
+ nvidia::GetInternalApexSDK()->reportError(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, __FUNCTION__, "This method is deprecated")
+#define APEX_DEPRECATED_ONCE() \
+ { static bool firstTime = true; if (firstTime) { firstTime = false; APEX_DEPRECATED(); } }
+
+
+#if PX_DEBUG || PX_CHECKED
+
+namespace nvidia
+{
+ namespace apex
+ {
+ class UpdateRenderResourcesScope
+ {
+ public:
+ PX_INLINE UpdateRenderResourcesScope() { GetInternalApexSDK()->enterURR(); }
+ PX_INLINE ~UpdateRenderResourcesScope() { GetInternalApexSDK()->leaveURR(); }
+ };
+ }
+}
+
+# define URR_SCOPE UpdateRenderResourcesScope updateRenderResourcesScope
+# define URR_CHECK GetInternalApexSDK()->checkURR()
+#else
+# define URR_SCOPE
+# define URR_CHECK
+#endif
+
+
+#endif // APEX_SDK_INTL_H
diff --git a/APEX_1.4/common/include/ApexShape.h b/APEX_1.4/common/include/ApexShape.h
new file mode 100644
index 00000000..f0e87b34
--- /dev/null
+++ b/APEX_1.4/common/include/ApexShape.h
@@ -0,0 +1,263 @@
+/*
+ * 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 __APEX_SHAPE_H__
+#define __APEX_SHAPE_H__
+
+#include "Apex.h"
+#include "ApexUsingNamespace.h"
+#include "PsUserAllocated.h"
+#include "Shape.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+class ApexSphereShape : public SphereShape, public UserAllocated
+{
+private:
+ float mRadius;
+ PxMat44 mTransform4x4;
+ PxMat44 mOldTransform4x4;
+ PxBounds3 mBounds;
+
+ void calculateAABB();
+
+public:
+
+ ApexSphereShape();
+
+ virtual ~ApexSphereShape() {};
+
+ virtual void releaseApexShape()
+ {
+ delete this;
+ }
+
+ const ApexSphereShape* isSphereGeom() const
+ {
+ return this;
+ }
+
+ bool intersectAgainstAABB(PxBounds3 bounds);
+
+ PxBounds3 getAABB() const
+ {
+ return mBounds;
+ }
+
+ void setRadius(float radius);
+
+ float getRadius() const
+ {
+ return mRadius;
+ };
+
+ void setPose(PxMat44 pose);
+
+ PxMat44 getPose() const
+ {
+ return mTransform4x4;
+ }
+
+ PxMat44 getPreviousPose() const
+ {
+ return mOldTransform4x4;
+ }
+
+ void visualize(RenderDebugInterface* renderer) const;
+};
+
+//the capsule is oriented along the y axis by default and its total height is height+2*radius
+class ApexCapsuleShape : public CapsuleShape, public UserAllocated
+{
+private:
+
+ float mRadius;
+ float mHeight;
+ PxMat44 mTransform4x4;
+ PxMat44 mOldTransform4x4;
+ PxBounds3 mBounds;
+ void calculateAABB();
+
+public:
+
+ ApexCapsuleShape();
+
+ virtual ~ApexCapsuleShape() {};
+
+ virtual void releaseApexShape()
+ {
+ delete this;
+ }
+
+ const ApexCapsuleShape* isCapsuleGeom() const
+ {
+ return this;
+ }
+
+ bool intersectAgainstAABB(PxBounds3 bounds);
+
+ PxBounds3 getAABB() const
+ {
+ return mBounds;
+ }
+
+ void setDimensions(float height, float radius);
+
+ void getDimensions(float& height, float& radius) const
+ {
+ radius = mRadius;
+ height = mHeight;
+ };
+
+ void setPose(PxMat44 pose);
+
+ PxMat44 getPose() const
+ {
+ return mTransform4x4;
+ }
+
+ PxMat44 getPreviousPose() const
+ {
+ return mOldTransform4x4;
+ }
+
+ void visualize(RenderDebugInterface* renderer) const;
+};
+
+class ApexBoxShape : public BoxShape, public UserAllocated
+{
+private:
+
+ PxVec3 mSize;
+ PxMat44 mTransform4x4;
+ PxMat44 mOldTransform4x4;
+ PxBounds3 mBounds;
+ void calculateAABB();
+
+public:
+
+ ApexBoxShape();
+
+ virtual ~ApexBoxShape() {};
+
+ virtual void releaseApexShape()
+ {
+ delete this;
+ }
+
+ const ApexBoxShape* isBoxGeom() const
+ {
+ return this;
+ }
+
+ bool intersectAgainstAABB(PxBounds3 bounds);
+
+ PxBounds3 getAABB() const
+ {
+ return mBounds;
+ }
+
+ void setSize(PxVec3 size);
+
+ void setPose(PxMat44 pose);
+
+ PxMat44 getPose() const
+ {
+ return mTransform4x4;
+ }
+
+ PxMat44 getPreviousPose() const
+ {
+ return mOldTransform4x4;
+ }
+
+ PxVec3 getSize() const
+ {
+ return mSize;
+ }
+
+ void visualize(RenderDebugInterface* renderer) const;
+};
+
+class ApexHalfSpaceShape : public HalfSpaceShape, public UserAllocated
+{
+private:
+ PxVec3 mOrigin;
+ PxVec3 mPreviousOrigin;
+ PxVec3 mNormal;
+ PxVec3 mPreviousNormal;
+ bool isPointInside(PxVec3 pos);
+
+public:
+ ApexHalfSpaceShape();
+
+ virtual ~ApexHalfSpaceShape() {};
+
+ virtual void releaseApexShape()
+ {
+ delete this;
+ }
+
+ const ApexHalfSpaceShape* isHalfSpaceGeom() const
+ {
+ return this;
+ }
+
+ bool intersectAgainstAABB(PxBounds3 bounds);
+
+ PxBounds3 getAABB() const
+ {
+ return PxBounds3(PxVec3(0), PxVec3(PX_MAX_F32));
+ }
+
+ void setOriginAndNormal(PxVec3 origin, PxVec3 normal);
+
+ PxVec3 getNormal() const
+ {
+ return mNormal;
+ };
+
+ PxVec3 getPreviousNormal() const
+ {
+ return mPreviousNormal;
+ };
+
+ PxVec3 getOrigin() const
+ {
+ return mOrigin;
+ };
+
+ PxVec3 getPreviousOrigin() const
+ {
+ return mPreviousOrigin;
+ };
+
+ PxMat44 getPose() const;
+
+ PxMat44 getPreviousPose() const;
+
+ void visualize(RenderDebugInterface* renderer) const;
+
+ virtual void setPose(PxMat44 pose)
+ {
+ PX_UNUSED(pose);
+ //dummy
+ }
+};
+
+
+}
+} // end namespace nvidia::apex
+
+#endif
diff --git a/APEX_1.4/common/include/ApexSharedUtils.h b/APEX_1.4/common/include/ApexSharedUtils.h
new file mode 100644
index 00000000..337f40cb
--- /dev/null
+++ b/APEX_1.4/common/include/ApexSharedUtils.h
@@ -0,0 +1,2364 @@
+/*
+ * 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 APEXSHAREDUTILS_H
+#define APEXSHAREDUTILS_H
+
+#include "ApexUsingNamespace.h"
+#include "ApexDefs.h"
+#include "IProgressListener.h"
+#include "RenderMeshAsset.h"
+
+#include "PxStreamFromFileBuf.h"
+
+#include "ApexString.h"
+#include "PsArray.h"
+#include "ConvexHullMethod.h"
+#include "PxPlane.h"
+
+#include "ConvexHullParameters.h"
+
+#include "Cof44.h"
+
+#if PX_PHYSICS_VERSION_MAJOR == 3
+namespace physx
+{
+class PxConvexMesh;
+}
+typedef physx::PxConvexMesh ConvexMesh;
+#endif
+
+namespace nvidia
+{
+namespace apex
+{
+
+PX_INLINE PxPlane toPxPlane(const ConvexHullParametersNS::Plane_Type& plane)
+{
+ return PxPlane(plane.normal.x, plane.normal.y, plane.normal.z, plane.d);
+}
+
+/*
+File-local functions and definitions
+*/
+
+
+/*
+Global utilities
+*/
+
+// Diagonalize a symmetric 3x3 matrix. Returns the eigenvectors in the first parameter, eigenvalues as the return value.
+PxVec3 diagonalizeSymmetric(PxMat33& eigenvectors, const PxMat33& m);
+
+
+
+PX_INLINE bool worldToLocalRay(PxVec3& localorig, PxVec3& localdir,
+ const PxVec3& worldorig, const PxVec3& worlddir,
+ const physx::PxTransform& localToWorldRT, const PxVec3& scale)
+{
+ // Invert scales
+ const float detS = scale.x * scale.y * scale.z;
+ if (detS == 0.0f)
+ {
+ return false; // Not handling singular TMs
+ }
+ const float recipDetS = 1.0f / detS;
+
+ // Is it faster to do a bunch of multiplies, or a few divides?
+ const PxVec3 invS(scale.y * scale.z * recipDetS, scale.z * scale.x * recipDetS, scale.x * scale.y * recipDetS);
+
+ // Create hull-local ray
+ localorig = localToWorldRT.transformInv(worldorig);
+ localorig = invS.multiply(localorig);
+ localdir = localToWorldRT.rotateInv(worlddir);
+ localdir = invS.multiply(localdir);
+
+ return true;
+}
+
+// barycentric utilities
+/**
+This function starts recording the number of cycles elapsed.
+\param pa [in] first vertex of triangle
+\param pb [in] second vertex of triangle
+\param pc [in] third vertex of triangle
+\param p [in] vertex to generate barycentric coordinates for
+\param s [out] the first barycentric coordinate
+\param t [out] the second barycentric coordinate
+\note the third barycentric coordinate is defined as (1 - s - t)
+\see EndProfile
+*/
+void generateBarycentricCoordinatesTri(const PxVec3& pa, const PxVec3& pb, const PxVec3& pc, const PxVec3& p, float& s, float& t);
+void generateBarycentricCoordinatesTet(const PxVec3& pa, const PxVec3& pb, const PxVec3& pc, const PxVec3& pd, const PxVec3& p, PxVec3& bary);
+
+struct OverlapLineSegmentAABBCache
+{
+ PxVec3 sgnDir;
+ PxVec3 invDir;
+};
+
+PX_INLINE void computeOverlapLineSegmentAABBCache(OverlapLineSegmentAABBCache& cache, const PxVec3& segmentDisp)
+{
+ cache.sgnDir = PxVec3((float)(1 - (((int)(segmentDisp.x < 0.0f)) << 1)), (float)(1 - (((int)(segmentDisp.y < 0.0f)) << 1)), (float)(1 - (((int)(segmentDisp.z < 0.0f)) << 1)));
+ PxVec3 absDir = cache.sgnDir.multiply(segmentDisp);
+ absDir += PxVec3(PX_EPS_F32); // To avoid divide-by-zero
+ cache.invDir = PxVec3(absDir.y * absDir.z, absDir.z * absDir.x, absDir.x * absDir.y);
+ cache.invDir *= 1.0f / (absDir.x * cache.invDir.x);
+}
+
+PX_INLINE bool overlapLineSegmentAABBCached(const PxVec3& segmentOrig, const OverlapLineSegmentAABBCache& cache, const PxBounds3& aabb)
+{
+ const PxVec3 center = 0.5f * (aabb.maximum + aabb.minimum);
+ const PxVec3 radii = 0.5f * (aabb.maximum - aabb.minimum);
+ PxVec3 disp = (center - segmentOrig).multiply(cache.sgnDir);
+ PxVec3 tMin = (disp - radii).multiply(cache.invDir);
+ PxVec3 tMax = (disp + radii).multiply(cache.invDir);
+ int maxMinIndex = tMin.y > tMin.x;
+ const int maxMinIndexIs2 = tMin.z > tMin[(unsigned int)maxMinIndex];
+ maxMinIndex = (maxMinIndex | maxMinIndexIs2) << maxMinIndexIs2;
+ int minMaxIndex = tMax.y < tMax.x;
+ const int minMaxIndexIs2 = tMax.z > tMax[(unsigned int)minMaxIndex];
+ minMaxIndex = (minMaxIndex | minMaxIndexIs2) << minMaxIndexIs2;
+ const float tIn = tMin[(unsigned int)maxMinIndex];
+ const float tOut = tMax[(unsigned int)minMaxIndex];
+ return tIn < tOut && tOut > 0.0f && tIn < 1.0f;
+}
+
+PX_INLINE bool overlapLineSegmentAABB(const PxVec3& segmentOrig, const PxVec3& segmentDisp, const PxBounds3& aabb)
+{
+ OverlapLineSegmentAABBCache cache;
+ computeOverlapLineSegmentAABBCache(cache, segmentDisp);
+ return overlapLineSegmentAABBCached(segmentOrig, cache, aabb);
+}
+
+struct IntPair
+{
+ void set(int32_t _i0, int32_t _i1)
+ {
+ i0 = _i0;
+ i1 = _i1;
+ }
+
+ int32_t i0, i1;
+
+ static int compare(const void* a, const void* b)
+ {
+ const int32_t diff0 = ((IntPair*)a)->i0 - ((IntPair*)b)->i0;
+ return diff0 ? diff0 : (((IntPair*)a)->i1 - ((IntPair*)b)->i1);
+ }
+};
+
+PX_INLINE PxFileBuf& operator >> (PxFileBuf& stream, IntPair& p)
+{
+ p.i0 = (int32_t)stream.readDword();
+ p.i1 = (int32_t)stream.readDword();
+ return stream;
+}
+PX_INLINE PxFileBuf& operator << (PxFileBuf& stream, const IntPair& p)
+{
+ stream.storeDword((uint32_t)p.i0);
+ stream.storeDword((uint32_t)p.i1);
+ return stream;
+}
+
+struct BoundsRep
+{
+ BoundsRep() : type(0)
+ {
+ aabb.setEmpty();
+ }
+
+ PxBounds3 aabb;
+ uint32_t type; // By default only reports if subtypes are the same, configurable. Valid range {0...7}
+};
+
+struct BoundsInteractions
+{
+ BoundsInteractions() : bits(0x8040201008040201ULL) {}
+ BoundsInteractions(bool setAll) : bits(setAll ? 0xFFFFFFFFFFFFFFFFULL : 0x0000000000000000ULL) {}
+
+ bool set(unsigned group1, unsigned group2, bool interacts)
+ {
+ if (group1 >= 8 || group2 >= 8)
+ {
+ return false;
+ }
+ const uint64_t mask = (uint64_t)1 << ((group1 << 3) + group2) | (uint64_t)1 << ((group2 << 3) + group1);
+ if (interacts)
+ {
+ bits |= mask;
+ }
+ else
+ {
+ bits &= ~mask;
+ }
+ return true;
+ }
+
+ uint64_t bits;
+};
+
+enum Bounds3Axes
+{
+ Bounds3X = 1,
+ Bounds3Y = 2,
+ Bounds3Z = 4,
+
+ Bounds3XY = Bounds3X | Bounds3Y,
+ Bounds3YZ = Bounds3Y | Bounds3Z,
+ Bounds3ZX = Bounds3Z | Bounds3X,
+
+ Bounds3XYZ = Bounds3X | Bounds3Y | Bounds3Z
+};
+
+void boundsCalculateOverlaps(physx::Array<IntPair>& overlaps, Bounds3Axes axesToUse, const BoundsRep* bounds, uint32_t boundsCount, uint32_t boundsByteStride,
+ const BoundsInteractions& interactions = BoundsInteractions(), bool append = false);
+
+
+/*
+Descriptor for building a ConvexHullImpl, below
+*/
+class ConvexHullDesc
+{
+public:
+ const void* vertices;
+ uint32_t numVertices;
+ uint32_t vertexStrideBytes;
+ uint32_t* indices;
+ uint32_t numIndices;
+ uint8_t* faceIndexCounts;
+ uint32_t numFaces;
+
+ ConvexHullDesc() :
+ vertices(NULL),
+ numVertices(0),
+ vertexStrideBytes(0),
+ indices(NULL),
+ numIndices(0),
+ faceIndexCounts(NULL),
+ numFaces(0)
+ {
+ }
+
+ bool isValid() const
+ {
+ return
+ vertices != NULL &&
+ numVertices != 0 &&
+ vertexStrideBytes != 0 &&
+ indices != NULL &&
+ numIndices != 0 &&
+ faceIndexCounts != NULL &&
+ numFaces != 0;
+ }
+};
+
+/*
+ConvexHullImpl - precomputed (redundant) information about a convex hull: vertices, hull planes, etc.
+*/
+class ConvexHullImpl
+{
+public:
+ struct Separation
+ {
+ PxPlane plane;
+ float min0, max0, min1, max1;
+
+ float getDistance()
+ {
+ return PxMax(min0 - max1, min1 - max0);
+ }
+ };
+
+ ConvexHullImpl();
+ ConvexHullImpl(const ConvexHullImpl& hull) : mParams(NULL), mOwnsParams(false)
+ {
+ *this = hull;
+ }
+ virtual ~ConvexHullImpl();
+
+ // If params == NULL, this will build (and own) its own internal parameters
+ void init(NvParameterized::Interface* params = NULL);
+
+ ConvexHullImpl& operator = (const ConvexHullImpl& hull)
+ {
+ mParams = hull.mParams;
+ mOwnsParams = false;
+ return *this;
+ }
+
+ // Only returns non-NULL value if this object owns its parameters.
+ NvParameterized::Interface* giveOwnersipOfNvParameters();
+
+ // Releases parameters if it owns them
+ void term();
+
+ void buildFromDesc(const ConvexHullDesc& desc);
+ void buildFromPoints(const void* points, uint32_t numPoints, uint32_t pointStrideBytes);
+ void buildFromPlanes(const PxPlane* planes, uint32_t numPlanes, float eps);
+#if PX_PHYSICS_VERSION_MAJOR == 3
+ void buildFromConvexMesh(const ConvexMesh* mesh);
+#endif
+ void buildFromAABB(const PxBounds3& aabb);
+ void buildKDOP(const void* points, uint32_t numPoints, uint32_t pointStrideBytes, const PxVec3* directions, uint32_t numDirections);
+
+ void intersectPlaneSide(const PxPlane& plane);
+ void intersectHull(const ConvexHullImpl& hull);
+
+ // If the distance between the hulls exceeds maxDistance, false is returned.
+ // Otherwise, true is returned. In this case, if 'separation' is not NULL, then separation plane
+ // and projected extents are returned in *separation.
+ static bool hullsInProximity(const ConvexHullImpl& hull0, const physx::PxTransform& localToWorldRT0, const PxVec3& scale0,
+ const ConvexHullImpl& hull1, const physx::PxTransform& localToWorldRT1, const PxVec3& scale1,
+ float maxDistance, Separation* separation = NULL);
+
+ // If the distance between this hull and the given sphere exceeds maxDistance, false is returned.
+ // Otherwise, true is returned. In this case, if 'separation' is not NULL, then separation plane
+ // and projected extents are returned in *separation. The '0' values will correspond to the hull,
+ // and the '1' values to the sphere.
+ bool sphereInProximity(const physx::PxTransform& hullLocalToWorldRT, const PxVec3& hullScale,
+ const PxVec3& sphereWorldCenter, float sphereRadius,
+ float maxDistance, Separation* separation = NULL);
+
+#if PX_PHYSICS_VERSION_MAJOR == 3
+ bool intersects(const PxShape& shape, const physx::PxTransform& localToWorldRT, const PxVec3& scale, float padding) const;
+#endif
+
+ // worldRay.dir need not be normalized. in & out times are relative to worldRay.dir length
+ // N.B. in & out are both input and output variables:
+ // input: in = minimum possible ray intersect time
+ // out = maximum possible ray intersect time
+ // output: in = time ray enters hull
+ // out = time ray exits hull
+ bool rayCast(float& in, float& out, const PxVec3& orig, const PxVec3& dir,
+ const physx::PxTransform& localToWorldRT, const PxVec3& scale, PxVec3* normal = NULL) const;
+
+ // in & out times are relative to worldDisp length
+ // N.B. in & out are both input and output variables:
+ // input: in = minimum possible ray intersect time
+ // out = maximum possible ray intersect time
+ // output: in = time ray enters hull
+ // out = time ray exits hull
+ bool obbSweep(float& in, float& out, const PxVec3& worldBoxCenter, const PxVec3& worldBoxExtents, const PxVec3 worldBoxAxes[3],
+ const PxVec3& worldDisp, const physx::PxTransform& localToWorldRT, const PxVec3& scale, PxVec3* normal = NULL) const;
+
+ // Returns the min and max dot product of the vertices with the given normal
+ void extent(float& min, float& max, const PxVec3& normal) const;
+
+ void fill(physx::Array<PxVec3>& outPoints, const physx::PxTransform& localToWorldRT, const PxVec3& scale,
+ float spacing, float jitter, uint32_t maxPoints, bool adjustSpacing) const;
+
+ void setEmpty()
+ {
+ NvParameterized::Handle handle(*mParams);
+ mParams->getParameterHandle("vertices", handle);
+ mParams->resizeArray(handle, 0);
+ mParams->getParameterHandle("uniquePlanes", handle);
+ mParams->resizeArray(handle, 0);
+ mParams->getParameterHandle("widths", handle);
+ mParams->resizeArray(handle, 0);
+ mParams->getParameterHandle("edges", handle);
+ mParams->resizeArray(handle, 0);
+ mParams->bounds.setEmpty();
+ mParams->volume = 0.0f;
+ mParams->uniqueEdgeDirectionCount = 0;
+ mParams->planeCount = 0;
+ }
+
+ bool isEmpty() const
+ {
+ PX_ASSERT(mParams->bounds.isEmpty() == (mParams->vertices.arraySizes[0] == 0));
+ PX_ASSERT(mParams->bounds.isEmpty() == (mParams->uniquePlanes.arraySizes[0] == 0));
+ PX_ASSERT(mParams->bounds.isEmpty() == (mParams->widths.arraySizes[0] == 0));
+ PX_ASSERT(mParams->bounds.isEmpty() == (mParams->edges.arraySizes[0] == 0));
+ PX_ASSERT(mParams->bounds.isEmpty() == (mParams->volume == 0.0f));
+ return mParams->bounds.isEmpty();
+ }
+
+ uint32_t getVertexCount() const
+ {
+ return (uint32_t)mParams->vertices.arraySizes[0];
+ }
+ const PxVec3& getVertex(uint32_t index) const
+ {
+ return mParams->vertices.buf[index];
+ }
+
+ uint32_t getPlaneCount() const
+ {
+ return mParams->planeCount;
+ }
+ uint32_t getUniquePlaneNormalCount() const
+ {
+ return (uint32_t)mParams->uniquePlanes.arraySizes[0];
+ }
+ PxPlane getPlane(uint32_t index) const
+ {
+ PX_ASSERT(index < getPlaneCount());
+ if (index < (uint32_t)mParams->uniquePlanes.arraySizes[0])
+ {
+ return toPxPlane(mParams->uniquePlanes.buf[index]);
+ }
+ index -= mParams->uniquePlanes.arraySizes[0];
+ PxPlane plane = toPxPlane(mParams->uniquePlanes.buf[index]);
+ plane.n = -plane.n;
+ plane.d = -plane.d - mParams->widths.buf[index];
+ return plane;
+ }
+
+ uint32_t getWidthCount() const
+ {
+ return (uint32_t)mParams->widths.arraySizes[0];
+ }
+ float getWidth(uint32_t index) const
+ {
+ return mParams->widths.buf[index];
+ }
+
+ uint32_t getEdgeCount() const
+ {
+ return (uint32_t)mParams->edges.arraySizes[0];
+ }
+ uint32_t getEdgeEndpointIndex(uint32_t edgeIndex, uint32_t endpointIndex) const // endpointIndex = 0 or 1
+ {
+ PX_ASSERT(edgeIndex < getEdgeCount());
+ PX_ASSERT((endpointIndex & 1) == endpointIndex);
+ endpointIndex &= 1;
+ const uint32_t edge = mParams->edges.buf[edgeIndex];
+ return (endpointIndex & 1) ? (edge & 0x0000FFFF) : (edge >> 16);
+ }
+ uint32_t getEdgeAdjacentFaceIndex(uint32_t edgeIndex, uint32_t adjacencyIndex) const // adjacencyIndex = 0 or 1
+ {
+ PX_ASSERT(edgeIndex < getEdgeCount());
+ PX_ASSERT((adjacencyIndex & 1) == adjacencyIndex);
+ adjacencyIndex &= 1;
+ const uint32_t adj = mParams->adjacentFaces.buf[edgeIndex];
+ return (adjacencyIndex & 1) ? (adj & 0x0000FFFF) : (adj >> 16);
+ }
+ uint32_t getUniqueEdgeDirectionCount() const
+ {
+ return mParams->uniqueEdgeDirectionCount;
+ }
+ PxVec3 getEdgeDirection(uint32_t index) const
+ {
+ PX_ASSERT(index < getEdgeCount());
+ uint32_t edge = mParams->edges.buf[index];
+ return mParams->vertices.buf[edge & 0xFFFF] - mParams->vertices.buf[edge >> 16];
+ }
+
+ const PxBounds3& getBounds() const
+ {
+ return mParams->bounds;
+ }
+ float getVolume() const
+ {
+ return (float)mParams->volume;
+ }
+
+ // transform may include an arbitrary 3x3 block and a translation
+ void applyTransformation(const PxMat44& tm)
+ {
+ PX_ASSERT(mParams);
+
+ const float det3 = PxMat33(tm.getBasis(0), tm.getBasis(1), tm.getBasis(2)).getDeterminant();
+ PX_ASSERT(det3 > 0.0f); // mirroring or degeneracy won't work well here
+
+ // planes and slab widths
+ const Cof44 cof(tm);
+ const uint32_t numPlanes = (uint32_t)mParams->uniquePlanes.arraySizes[0];
+ ConvexHullParametersNS::Plane_Type* planes = mParams->uniquePlanes.buf;
+ PX_ASSERT(planes);
+ PX_ASSERT(numPlanes == (uint32_t)mParams->widths.arraySizes[0]);
+ float* widths = mParams->widths.buf;
+ PX_ASSERT(widths);
+ for (uint32_t i = 0; i < numPlanes; i++)
+ {
+ PxPlane src(planes[i].normal, planes[i].d);
+ PxPlane dst;
+ cof.transform(src, dst);
+ planes[i].normal = dst.n;
+ planes[i].d = dst.d;
+ const float n2 = dst.n.magnitudeSquared();
+ if (n2 > 0.0f)
+ {
+ const float recipN = PxRecipSqrt(n2);
+ planes[i].normal *= recipN;
+ planes[i].d *= recipN;
+ widths[i] *= det3*recipN;
+ }
+ }
+
+ // vertices
+ const uint32_t numVertices = (uint32_t)mParams->vertices.arraySizes[0];
+ PxVec3* vertices = mParams->vertices.buf;
+ PX_ASSERT(vertices);
+
+ mParams->bounds.setEmpty();
+ for (uint32_t i = 0; i < numVertices; i++)
+ {
+ vertices[i] = tm.transform(vertices[i]);
+ mParams->bounds.include(vertices[i]);
+ }
+
+ // volume
+ mParams->volume *= det3;
+ }
+
+ // Special case - transformation must be a pure rotation plus translation, and we only allow a positive, uniform scale
+ // Note, we could implement this with applyTransformation(const PxMat44& tm), above, but we will keep this
+ // old implementation to ensure that behavior doesn't change
+ void applyTransformation(const PxMat44& transformation, float scale)
+ {
+ PX_ASSERT(mParams);
+ PX_ASSERT(scale > 0.0f); // negative scale won't work well here
+
+ // planes
+ const uint32_t numPlanes = (uint32_t)mParams->uniquePlanes.arraySizes[0];
+ ConvexHullParametersNS::Plane_Type* planes = mParams->uniquePlanes.buf;
+ PX_ASSERT(planes);
+ for (uint32_t i = 0; i < numPlanes; i++)
+ {
+ planes[i].normal = transformation.rotate(planes[i].normal);
+ planes[i].d *= scale;
+ }
+
+ // slab widths
+ const uint32_t numWidths = (uint32_t)mParams->widths.arraySizes[0];
+ float* widths = mParams->widths.buf;
+ PX_ASSERT(widths);
+ for (uint32_t i = 0; i < numWidths; i++)
+ {
+ widths[i] *= scale;
+ }
+
+ // vertices
+ const uint32_t numVertices = (uint32_t)mParams->vertices.arraySizes[0];
+ PxVec3* vertices = mParams->vertices.buf;
+ PX_ASSERT(vertices);
+
+ mParams->bounds.setEmpty();
+ for (uint32_t i = 0; i < numVertices; i++)
+ {
+ vertices[i] = transformation.transform(vertices[i]) * scale; // Works since scale is uniform
+ mParams->bounds.include(vertices[i]);
+ }
+
+ // volume
+ mParams->volume *= scale*scale*scale;
+ }
+
+#if PX_PHYSICS_VERSION_MAJOR == 3
+ // Returns the number of vertices and faces of the cooked mesh. If inflated = false,
+ // these should be the same as the values returned by getVertexCount() and getPlaneCount().
+ // However, the numerical properties of the cooker could result in different values. If inflated = true,
+ // then sharp edges will be beveled by the cooker, resulting in more vertices and faces.
+ // Note: the number of edges E may be calculated from the number of vertices V and faces F using E = V + F - 2.
+ // Return value = size in bytes of the cooked convex mesh
+ uint32_t calculateCookedSizes(uint32_t& vertexCount, uint32_t& faceCount, bool inflated) const;
+
+ // Removes vertices from the hull until the bounds given in the function's parameters are met.
+ // If inflated = true, then the maximum counts given are compared with the cooked hull, which may have higher counts due to beveling.
+ // Note: a value of zero indicates no limit, effectively infinite.
+ // Return value: true if successful, i.e. the limits were met. False otherwise.
+ bool reduceHull(uint32_t maxVertexCount, uint32_t maxEdgeCount, uint32_t maxFaceCount, bool inflated);
+
+ // Replaces vertices with cooked, un-inflated vertices, if the latter set is smaller. Returns true if the number of vertices is reduced.
+ bool reduceByCooking();
+#endif
+
+ // Utility function
+ static bool createKDOPDirections(physx::Array<PxVec3>& directions, ConvexHullMethod::Enum method);
+
+// DeclareArray(PxVec3) vertices;
+// DeclareArray(PxPlane) uniquePlanes; // These are the unique face directions. If there is an opposite face, the corresponding widths[i] will give its distance
+// physx::Array<float> widths; // Same size as uniquePlanes. Gives width of hull in uniquePlane direction
+// physx::Array<uint32_t> edges; // Vertex indices stored in high/low words. The first uniqueEdgeDirectionCount elements give the unique directions.
+// PxBounds3 bounds;
+// float volume;
+// uint32_t uniqueEdgeDirectionCount;
+// uint32_t planeCount; // Total number of faces. Greater than or equal to size of uniquePlanes.
+
+ ConvexHullParameters* mParams;
+ bool mOwnsParams;
+};
+
+
+/*
+ConvexMeshBuilder - creates triangles for a convex hull defined by a set of planes. Copied from physx samples (RenderClothActor)
+*/
+struct ConvexMeshBuilder
+{
+ ConvexMeshBuilder(const PxVec4* planes)
+ : mPlanes(planes)
+ {}
+
+ void operator()(uint32_t mask, float scale=1.0f);
+
+ const PxVec4* mPlanes;
+ Array<PxVec3> mVertices;
+ Array<uint16_t> mIndices;
+};
+
+
+// Fast implementation for sse
+PX_INLINE float RecipSqrt(float x)
+{
+#if defined( APEX_SUPPORT_SSE )
+ const float three = 3.0f;
+ const float oneHalf = 0.5f;
+ float y;
+ _asm
+ {
+ movss xmm2, three;
+ rsqrtss xmm0, x
+ movss xmm1, xmm0
+ mulss xmm1, oneHalf
+ mulss xmm0, xmm0
+ mulss xmm0, x
+ subss xmm2, xmm0
+ mulss xmm1, xmm2
+ movss y, xmm1
+ }
+ return y;
+#else
+ return 1.0f / sqrtf(x);
+#endif
+}
+
+/*
+ Array find utility
+ */
+
+// If t is found in array, index is set to the array element and the function returns true
+// If t is not found in the array, index is not modified and the function returns false
+template<class T>
+bool arrayFind(uint32_t& index, const T& t, const physx::Array<T>& array)
+{
+ const uint32_t size = array.size();
+ for (uint32_t i = 0; i < size; ++i)
+ {
+ if (array[i] == t)
+ {
+ index = i;
+ return true;
+ }
+ }
+ return false;
+}
+
+#include "ApexUsingNamespace.h"
+#if PX_X64
+#pragma warning(push)
+#pragma warning(disable: 4324) // 'IndexBank<IndexType>' : structure was padded due to __declspec(align())
+#endif
+
+/*
+ Index bank - double-sided free list for O(1) borrow/return of unique IDs
+
+ Type IndexType should be an unsigned integer type or something that can be cast to and from
+ an integer
+ */
+template <class IndexType>
+class IndexBank
+{
+ public:
+ IndexBank<IndexType>(uint32_t capacity = 0) : indexCount(0), capacityLocked(false)
+ {
+ maxCapacity = calculateMaxCapacity();
+ reserve_internal(capacity);
+ }
+
+ // Copy constructor
+ IndexBank<IndexType>(const IndexBank<IndexType>& other)
+ {
+ *this = other;
+ }
+
+ virtual ~IndexBank<IndexType>() {}
+
+ // Assignment operator
+ IndexBank<IndexType>& operator = (const IndexBank<IndexType>& other)
+ {
+ indices = other.indices;
+ ranks = other.ranks;
+ maxCapacity = other.maxCapacity;
+ indexCount = other.indexCount;
+ capacityLocked = other.capacityLocked;
+ return *this;
+ }
+
+ void setIndicesAndRanks(uint16_t* indicesIn, uint16_t* ranksIn, uint32_t capacityIn, uint32_t usedCountIn)
+ {
+ indexCount = usedCountIn;
+ reserve_internal(capacityIn);
+ for (uint32_t i = 0; i < capacityIn; ++i)
+ {
+ indices[i] = indicesIn[i];
+ ranks[i] = ranksIn[i];
+ }
+ }
+
+ void clear(uint32_t capacity = 0, bool used = false)
+ {
+ capacityLocked = false;
+ indices.reset();
+ ranks.reset();
+ reserve_internal(capacity);
+ if (used)
+ {
+ indexCount = capacity;
+ indices.resize(capacity);
+ for (IndexType i = (IndexType)0; i < (IndexType)capacity; ++i)
+ {
+ indices[i] = i;
+ }
+ }
+ else
+ {
+ indexCount = 0;
+ }
+ }
+
+ // Equivalent to calling freeLastUsed() until the used list is empty.
+ void clearFast()
+ {
+ indexCount = 0;
+ }
+
+ // This is the reserve size. The bank can only grow, due to shuffling of indices
+ virtual void reserve(uint32_t capacity)
+ {
+ reserve_internal(capacity);
+ }
+
+ // If lock = true, keeps bank from automatically resizing
+ void lockCapacity(bool lock)
+ {
+ capacityLocked = lock;
+ }
+
+ bool isCapacityLocked() const
+ {
+ return capacityLocked;
+ }
+
+ void setMaxCapacity(uint32_t inMaxCapacity)
+ {
+ // Cannot drop below current capacity, nor above max set by data types
+ maxCapacity = PxClamp(inMaxCapacity, capacity(), calculateMaxCapacity());
+ }
+
+ uint32_t capacity() const
+ {
+ return indices.size();
+ }
+ uint32_t usedCount() const
+ {
+ return indexCount;
+ }
+ uint32_t freeCount() const
+ {
+ return capacity() - usedCount();
+ }
+
+ // valid from [0] to [size()-1]
+ const IndexType* usedIndices() const
+ {
+ return indices.begin();
+ }
+
+ // valid from [0] to [free()-1]
+ const IndexType* freeIndices() const
+ {
+ return indices.begin() + usedCount();
+ }
+
+ bool isValid(IndexType index) const
+ {
+ return index < (IndexType)capacity();
+ }
+ bool isUsed(IndexType index) const
+ {
+ return isValid(index) && (ranks[index] < (IndexType)usedCount());
+ }
+ bool isFree(IndexType index) const
+ {
+ return isValid(index) && !isUsed();
+ }
+
+ IndexType getRank(IndexType index) const
+ {
+ return ranks[index];
+ }
+
+ // Gets the next available index, if any
+ bool useNextFree(IndexType& index)
+ {
+ if (freeCount() == 0)
+ {
+ if (capacityLocked)
+ {
+ return false;
+ }
+ if (capacity() >= maxCapacity)
+ {
+ return false;
+ }
+ reserve(PxClamp(capacity() * 2, (uint32_t)1, maxCapacity));
+ PX_ASSERT(freeCount() > 0);
+ }
+ index = indices[indexCount++];
+ return true;
+ }
+
+ // Frees the last used index, if any
+ bool freeLastUsed(IndexType& index)
+ {
+ if (usedCount() == 0)
+ {
+ return false;
+ }
+ index = indices[--indexCount];
+ return true;
+ }
+
+ // Requests a particular index. If that index is available, it is borrowed and the function
+ // returns true. Otherwise nothing happens and the function returns false.
+ bool use(IndexType index)
+ {
+ if (!indexIsValidForUse(index))
+ {
+ return false;
+ }
+ IndexType oldRank;
+ placeIndexAtRank(index, (IndexType)indexCount++, oldRank);
+ return true;
+ }
+
+ bool free(IndexType index)
+ {
+ if (!indexIsValidForFreeing(index))
+ {
+ return false;
+ }
+ IndexType oldRank;
+ placeIndexAtRank(index, (IndexType)--indexCount, oldRank);
+ return true;
+ }
+
+ bool useAndReturnRanks(IndexType index, IndexType& newRank, IndexType& oldRank)
+ {
+ if (!indexIsValidForUse(index))
+ {
+ return false;
+ }
+ newRank = (IndexType)indexCount++;
+ placeIndexAtRank(index, newRank, oldRank);
+ return true;
+ }
+
+ bool freeAndReturnRanks(IndexType index, IndexType& newRank, IndexType& oldRank)
+ {
+ if (!indexIsValidForFreeing(index))
+ {
+ return false;
+ }
+ newRank = (IndexType)--indexCount;
+ placeIndexAtRank(index, newRank, oldRank);
+ return true;
+ }
+
+ protected:
+
+ bool indexIsValidForUse(IndexType index)
+ {
+ if (!isValid(index))
+ {
+ if (capacityLocked)
+ {
+ return false;
+ }
+ if (capacity() >= maxCapacity)
+ {
+ return false;
+ }
+ reserve(PxClamp(2*(uint32_t)index, (uint32_t)1, maxCapacity));
+ PX_ASSERT(isValid(index));
+ }
+ return !isUsed(index);
+ }
+
+ bool indexIsValidForFreeing(IndexType index)
+ {
+ if (!isValid(index))
+ {
+ // Invalid index
+ return false;
+ }
+ return isUsed(index);
+ }
+
+ // This is the reserve size. The bank can only grow, due to shuffling of indices
+ void reserve_internal(uint32_t capacity)
+ {
+ capacity = PxMin(capacity, maxCapacity);
+ const uint32_t oldCapacity = indices.size();
+ if (capacity > oldCapacity)
+ {
+ indices.resize(capacity);
+ ranks.resize(capacity);
+ for (IndexType i = (IndexType)oldCapacity; i < (IndexType)capacity; ++i)
+ {
+ indices[i] = i;
+ ranks[i] = i;
+ }
+ }
+ }
+
+ private:
+
+ void placeIndexAtRank(IndexType index, IndexType newRank, IndexType& oldRank) // returns old rank
+ {
+ const IndexType replacementIndex = indices[newRank];
+ oldRank = ranks[index];
+ indices[oldRank] = replacementIndex;
+ indices[newRank] = index;
+ ranks[replacementIndex] = oldRank;
+ ranks[index] = newRank;
+ }
+
+ uint32_t calculateMaxCapacity()
+ {
+#pragma warning(push)
+#pragma warning(disable: 4127) // conditional expression is constant
+ if (sizeof(IndexType) >= sizeof(uint32_t))
+ {
+ return 0xFFFFFFFF; // Limited by data type we use to report capacity
+ }
+ else
+ {
+ return (1u << (8 * PxMin((uint32_t)sizeof(IndexType), 3u))) - 1; // Limited by data type we use for indices
+ }
+#pragma warning(pop)
+ }
+
+ protected:
+
+ Array<IndexType> indices;
+ Array<IndexType> ranks;
+ uint32_t maxCapacity;
+ uint32_t indexCount;
+ bool capacityLocked;
+};
+
+#if PX_X64
+#pragma warning(pop)
+#endif
+
+/*
+ Bank - Index bank of type IndexType with an associated object array of type T
+ */
+template <class T, class IndexType>
+class Bank : public IndexBank<IndexType>
+{
+ public:
+ Bank<T, IndexType>(uint32_t capacity = 0) : IndexBank<IndexType>(capacity)
+ {
+ objects = (T*)PX_ALLOC(IndexBank<IndexType>::indices.size() * sizeof(T), PX_DEBUG_EXP("Bank"));
+ if (objects != NULL)
+ {
+ PX_ASSERT(memset(objects, 0, IndexBank<IndexType>::indices.size() * sizeof(T)));
+ }
+ }
+ Bank<T, IndexType>(const Bank<T, IndexType>& bank) : objects(NULL)
+ {
+ *this = bank;
+ }
+
+ ~Bank<T, IndexType>()
+ {
+ clear();
+ }
+
+ Bank<T, IndexType>& operator = (const Bank<T, IndexType>& bank)
+ {
+ if (&bank == this)
+ {
+ return *this;
+ }
+
+ this->clear();
+
+ this->indices = bank.indices;
+ this->ranks = bank.ranks;
+ this->maxCapacity = bank.maxCapacity;
+ this->indexCount = bank.indexCount;
+ this->capacityLocked = bank.capacityLocked;
+
+ if (this->indices.size())
+ {
+ objects = (T*)PX_ALLOC(IndexBank<IndexType>::indices.size() * sizeof(T), PX_DEBUG_EXP("Bank"));
+ PX_ASSERT(memset(objects, 0, IndexBank<IndexType>::indices.size() * sizeof(T)));
+ for (uint32_t i = 0; i < this->indexCount; ++i)
+ {
+ uint32_t index = this->indices[i];
+ new(objects + index) T();
+ objects[index] = bank.objects[index];
+ }
+ }
+ return *this;
+ }
+
+ // This is the reserve size. The bank can only grow, due to shuffling of indices
+ virtual void reserve(uint32_t capacity)
+ {
+ const uint32_t oldSize = IndexBank<IndexType>::indices.size();
+ IndexBank<IndexType>::reserve_internal(capacity);
+ if (IndexBank<IndexType>::indices.size() > oldSize)
+ {
+ T* nb = (T*)PX_ALLOC(IndexBank<IndexType>::indices.size() * sizeof(T), PX_DEBUG_EXP("Bank"));
+ if (nb)
+ {
+ PX_ASSERT(memset(nb, 0, IndexBank<IndexType>::indices.size() * sizeof(T)));
+
+ const IndexType* usedIndices = IndexBank<IndexType>::usedIndices();
+ uint32_t numIndices = IndexBank<IndexType>::usedCount();
+
+ // this copy needs to be correct for nonPOD type T's
+ for (int32_t i = (int32_t)numIndices - 1; i >= 0; i--)
+ {
+ IndexType index = usedIndices[i];
+ new(nb + index) T(objects[index]);
+ objects[index].~T();
+ }
+ //memcpy( nb, objects, IndexBank<IndexType>::indices.size()*sizeof(T) );
+ }
+ PX_FREE(objects);
+ objects = nb;
+ }
+ }
+
+ // Indirect array accessors: rank in [0,usedCount()-1] returns all "used" indexed objects
+ const T& getUsed(IndexType rank) const
+ {
+ return objects[ IndexBank<IndexType>::indices[rank] ];
+ }
+ T& getUsed(IndexType rank)
+ {
+ return objects[ IndexBank<IndexType>::indices[rank] ];
+ }
+
+ // Direct array accessors
+ const T& direct(IndexType index) const
+ {
+ return objects[index];
+ }
+ T& direct(IndexType index)
+ {
+ return objects[index];
+ }
+
+ // Wrappers for base class, which call appropriate constructors and destructors of objects
+ bool useNextFree(IndexType& index)
+ {
+ if (IndexBank<IndexType>::useNextFree(index))
+ {
+ new(objects + index) T();
+ return true;
+ }
+ return false;
+ }
+
+ bool freeLastUsed(IndexType& index)
+ {
+ if (IndexBank<IndexType>::freeLastUsed(index))
+ {
+ objects[index].~T();
+ return true;
+ }
+ return false;
+ }
+
+ bool use(IndexType index)
+ {
+ if (IndexBank<IndexType>::use(index))
+ {
+ new(objects + index) T();
+ return true;
+ }
+ return false;
+ }
+
+ bool free(IndexType index)
+ {
+ if (IndexBank<IndexType>::free(index))
+ {
+ objects[index].~T();
+ return true;
+ }
+ return false;
+ }
+
+ bool useAndReturnRanks(IndexType index, IndexType& newRank, IndexType& oldRank)
+ {
+ if (IndexBank<IndexType>::useAndReturnRanks(index, newRank, oldRank))
+ {
+ new(objects + index) T();
+ return true;
+ }
+ return false;
+ }
+
+ bool freeAndReturnRanks(IndexType index, IndexType& newRank, IndexType& oldRank)
+ {
+ if (IndexBank<IndexType>::freeAndReturnRanks(index, newRank, oldRank))
+ {
+ objects[index].~T();
+ return true;
+ }
+ return false;
+ }
+
+ // Erases all object, index, and rank arrays (complete deallocation)
+ void clear()
+ {
+ const IndexType* usedIndices = IndexBank<IndexType>::usedIndices();
+ uint32_t numIndices = IndexBank<IndexType>::usedCount();
+
+ for (int32_t i = (int32_t)numIndices - 1; i >= 0; i--)
+ {
+ bool test = free(usedIndices[i]);
+ PX_UNUSED(test);
+ PX_ASSERT(test);
+ }
+
+ IndexBank<IndexType>::clear();
+ PX_FREE(objects);
+ objects = NULL;
+ }
+
+ // Re-arranges objects internally into rank-order, afterwards rank = index
+ void clean()
+ {
+ for (IndexType i = 0; i < IndexBank<IndexType>::capacity(); ++i)
+ {
+ const IndexType index = IndexBank<IndexType>::indices[i];
+ if (index != i)
+ {
+ nvidia::swap(objects[i], objects[index]);
+ const IndexType displacedRank = IndexBank<IndexType>::ranks[i];
+ IndexBank<IndexType>::indices[i] = i;
+ IndexBank<IndexType>::ranks[i] = i;
+ IndexBank<IndexType>::indices[displacedRank] = index;
+ IndexBank<IndexType>::ranks[index] = displacedRank;
+ }
+ }
+ }
+
+ protected:
+ T* objects;
+};
+
+
+/*
+ Ring buffer
+*/
+template <class T>
+class RingBuffer
+{
+ public:
+ RingBuffer() : frontIndex(0), backIndex(0xFFFFFFFF), usedSize(0), bufferSize(0), buffer(NULL) {}
+ ~RingBuffer()
+ {
+ erase();
+ }
+
+ uint32_t size() const
+ {
+ return usedSize;
+ }
+
+ T& operator [](uint32_t i)
+ {
+ PX_ASSERT(i < usedSize);
+ i += frontIndex;
+ return buffer[ i < bufferSize ? i : i - bufferSize ];
+ }
+
+ const T& operator [](uint32_t i) const
+ {
+ return (const T&)(const_cast<RingBuffer<T>*>(this)->operator[](i));
+ }
+
+ T& back() const
+ {
+ return buffer[backIndex];
+ }
+ T& front() const
+ {
+ return buffer[frontIndex];
+ }
+
+ T& pushBack()
+ {
+ if (bufferSize == usedSize)
+ {
+ reserve(2 * (bufferSize + 1));
+ }
+ ++usedSize;
+ if (++backIndex == bufferSize)
+ {
+ backIndex = 0;
+ }
+ T& back = buffer[backIndex];
+ PX_PLACEMENT_NEW(&back, T)();
+ return back;
+ }
+
+ void popBack()
+ {
+ PX_ASSERT(size() != 0);
+ if (size() == 0)
+ {
+ return;
+ }
+ buffer[backIndex].~T();
+ --usedSize;
+ if (backIndex-- == 0)
+ {
+ backIndex += bufferSize;
+ }
+ }
+
+ T& pushFront()
+ {
+ if (bufferSize == usedSize)
+ {
+ reserve(2 * (bufferSize + 1));
+ }
+ ++usedSize;
+ if (frontIndex-- == 0)
+ {
+ frontIndex += bufferSize;
+ }
+ T& front = buffer[frontIndex];
+ PX_PLACEMENT_NEW(&front, T)();
+ return front;
+ }
+
+ void popFront()
+ {
+ PX_ASSERT(size() != 0);
+ if (size() == 0)
+ {
+ return;
+ }
+ buffer[frontIndex].~T();
+ --usedSize;
+ if (++frontIndex == bufferSize)
+ {
+ frontIndex = 0;
+ }
+ }
+
+ void clear()
+ {
+ while (size() != 0)
+ {
+ popBack();
+ }
+ frontIndex = 0;
+ backIndex = 0xFFFFFFFF;
+ }
+
+ void erase()
+ {
+ clear();
+ if (buffer != NULL)
+ {
+ PX_FREE(buffer);
+ buffer = NULL;
+ }
+ bufferSize = 0;
+ }
+
+ void reserve(uint32_t newBufferSize)
+ {
+ if (newBufferSize <= bufferSize)
+ {
+ return;
+ }
+ T* newBuffer = (T*)PX_ALLOC(newBufferSize * sizeof(T), PX_DEBUG_EXP("RingBuffer"));
+ const uint32_t lastIndex = frontIndex + usedSize;
+ if (lastIndex <= bufferSize)
+ {
+ for (uint32_t i = 0; i < usedSize; i++)
+ {
+ PX_PLACEMENT_NEW(newBuffer + i, T)(buffer[i]);
+ buffer[i].~T();
+ }
+ //memcpy( newBuffer, buffer+frontIndex, usedSize*sizeof( T ) );
+ }
+ else
+ {
+ for (uint32_t i = 0; i < (bufferSize - frontIndex); i++)
+ {
+ PX_PLACEMENT_NEW(newBuffer + i, T)(buffer[i + frontIndex]);
+ buffer[i + frontIndex].~T();
+ }
+ //memcpy( newBuffer, buffer+frontIndex, (bufferSize-frontIndex)*sizeof( T ) );
+
+ for (uint32_t i = 0; i < (lastIndex - bufferSize); i++)
+ {
+ PX_PLACEMENT_NEW(newBuffer + i + (bufferSize - frontIndex), T)(buffer[i]);
+ buffer[i].~T();
+ }
+ //memcpy( newBuffer + (bufferSize-frontIndex), buffer, (lastIndex-bufferSize)*sizeof( T ) );
+ }
+ bufferSize = newBufferSize;
+ frontIndex = 0;
+ backIndex = frontIndex + usedSize - 1;
+ if (buffer)
+ {
+ PX_FREE(buffer);
+ }
+ buffer = newBuffer;
+ }
+
+ class It
+ {
+ public:
+ It(const RingBuffer<T>& buffer) :
+ m_bufferStart(buffer.buffer), m_bufferStop(buffer.buffer + buffer.bufferSize),
+ m_current(buffer.usedSize > 0 ? buffer.buffer + buffer.frontIndex : NULL), m_remaining(buffer.usedSize) {}
+
+ operator T* () const
+ {
+ return m_current;
+ }
+ T* operator ++ ()
+ {
+ inc();
+ return m_current;
+ }
+ T* operator ++ (int)
+ {
+ T* prev = m_current;
+ inc();
+ return prev;
+ }
+
+ private:
+ void inc()
+ {
+ if (m_remaining > 1)
+ {
+ --m_remaining;
+ if (++m_current == m_bufferStop)
+ {
+ m_current = m_bufferStart;
+ }
+ }
+ else
+ {
+ m_remaining = 0;
+ m_current = NULL;
+ }
+ }
+
+ T* m_bufferStart;
+ T* m_bufferStop;
+ T* m_current;
+ uint32_t m_remaining;
+ };
+
+ friend class It;
+
+ protected:
+ uint32_t frontIndex;
+ uint32_t backIndex;
+ uint32_t usedSize;
+ uint32_t bufferSize;
+ T* buffer;
+};
+
+
+template<class T>
+class Pool
+{
+ enum { DefaultBlockSizeInBytes = 1024 }; // This must be positive
+
+ public:
+ Pool(uint32_t objectsPerBlock = 0) : m_head(NULL), m_inUse(0)
+ {
+ PX_ASSERT(sizeof(T) >= sizeof(void*));
+ setBlockSize(objectsPerBlock);
+ }
+
+ ~Pool()
+ {
+ empty();
+ }
+
+ void setBlockSize(uint32_t objectsPerBlock)
+ {
+ m_objectsPerBlock = objectsPerBlock > 0 ? objectsPerBlock : ((uint32_t)DefaultBlockSizeInBytes + sizeof(T) - 1) / sizeof(T);
+ }
+
+ /* Gives a single object, allocating if necessary */
+ T* borrow()
+ {
+ if (m_head == NULL)
+ {
+ allocateBlock();
+ }
+ T* ptr = (T*)m_head;
+ m_head = *(void**)m_head;
+ new(ptr) T();
+ ++m_inUse;
+ return ptr;
+ }
+
+ /* Return a single object */
+ void replace(T* ptr)
+ {
+ if (ptr != NULL)
+ {
+ ptr->~T();
+ *(void**)ptr = m_head;
+ m_head = (void*)ptr;
+ --m_inUse;
+ }
+ }
+
+ void allocateBlock()
+ {
+ T* block = (T*)PX_ALLOC(sizeof(T) * m_objectsPerBlock, PX_DEBUG_EXP("ApexSharedUtils::Pool"));
+ m_blocks.pushBack(block);
+ for (T* ptr = block + m_objectsPerBlock; ptr-- != block;)
+ {
+ *(void**)ptr = m_head;
+ m_head = (void*)ptr;
+ }
+ }
+
+ int32_t empty()
+ {
+ while (m_blocks.size())
+ {
+ PX_FREE(m_blocks.back());
+ m_blocks.popBack();
+ }
+ m_blocks.reset();
+ m_head = NULL;
+ const int32_t inUse = m_inUse;
+ m_inUse = 0;
+ return inUse;
+ }
+
+ protected:
+
+ void* m_head;
+ uint32_t m_objectsPerBlock;
+ physx::Array<T*>m_blocks;
+ int32_t m_inUse;
+};
+
+
+// Progress listener implementation for hierarchical progress reporting
+class HierarchicalProgressListener : public IProgressListener
+{
+ public:
+ HierarchicalProgressListener(int totalWork, IProgressListener* parent) :
+ m_work(0), m_subtaskWork(1), m_totalWork(PxMax(totalWork, 1)), m_taskName(NULL), m_parent(parent) {}
+
+ void setSubtaskWork(int subtaskWork, const char* taskName = NULL)
+ {
+ if (subtaskWork < 0)
+ {
+ subtaskWork = m_totalWork - m_work;
+ }
+
+ m_subtaskWork = subtaskWork;
+ PX_ASSERT(m_work + m_subtaskWork <= m_totalWork);
+ m_taskName = taskName;
+ setProgress(0, m_taskName);
+ }
+
+ void completeSubtask()
+ {
+ setProgress(100, m_taskName);
+ m_work += m_subtaskWork;
+ }
+
+ void setProgress(int progress, const char* taskName = NULL)
+ {
+ PX_ASSERT(progress >= 0);
+ PX_ASSERT(progress <= 100);
+
+ if (taskName == NULL)
+ {
+ taskName = m_taskName;
+ }
+
+ if (m_parent != NULL)
+ {
+ const int parentProgress = m_totalWork > 0 ? (m_work * 100 + m_subtaskWork * progress) / m_totalWork : 100;
+ m_parent->setProgress(PxClamp(parentProgress, 0, 100), taskName);
+ }
+ }
+
+ protected:
+ int m_work;
+ int m_subtaskWork;
+ int m_totalWork;
+ const char* m_taskName;
+ IProgressListener* m_parent;
+};
+
+void createIndexStartLookup(physx::Array<uint32_t>& lookup, int32_t indexBase, uint32_t indexRange, int32_t* indexSource, uint32_t indexCount, uint32_t indexByteStride);
+
+void findIslands(physx::Array< physx::Array<uint32_t> >& islands, const physx::Array<IntPair>& overlaps, uint32_t indexRange);
+
+// Neighbor-finding utility class
+class NeighborLookup
+{
+public:
+ void setBounds(const BoundsRep* bounds, uint32_t boundsCount, uint32_t boundsByteStride);
+
+ uint32_t getNeighborCount(const uint32_t index) const;
+ const uint32_t* getNeighbors(const uint32_t index) const;
+
+protected:
+ physx::Array<uint32_t> m_neighbors;
+ physx::Array<uint32_t> m_firstNeighbor;
+};
+
+
+// TriangleFrame - calculates interpolation data for triangle quantities
+class TriangleFrame
+{
+ public:
+
+ enum VertexField
+ {
+// Position_x, Position_y, Position_z, // Not interpolating positions
+ Normal_x, Normal_y, Normal_z,
+ Tangent_x, Tangent_y, Tangent_z,
+ Binormal_x, Binormal_y, Binormal_z,
+ UV0_u, UV0_v, UV1_u, UV1_v, UV2_u, UV2_v, UV3_u, UV3_v,
+ Color_r, Color_g, Color_b, Color_a,
+
+ VertexFieldCount
+ };
+
+ TriangleFrame() : m_fieldMask(0) {}
+ TriangleFrame(const ExplicitRenderTriangle& tri, uint64_t fieldMask = 0xFFFFFFFFFFFFFFFFULL)
+ {
+ setFromTriangle(tri, fieldMask);
+ }
+ TriangleFrame(const PxMat44& tm, const PxVec2& uvScale, const PxVec2& uvOffset, uint64_t fieldMask = 0xFFFFFFFFFFFFFFFFULL)
+ {
+ setFlat(tm, uvScale, uvOffset, fieldMask);
+ }
+
+ PX_INLINE void setFromTriangle(const ExplicitRenderTriangle& tri, uint64_t fieldMask = 0xFFFFFFFFFFFFFFFFULL);
+ PX_INLINE void setFlat(const PxMat44& tm, const PxVec2& uvScale, const PxVec2& uvOffset, uint64_t fieldMask = 0xFFFFFFFFFFFFFFFFULL);
+
+ PX_INLINE void interpolateVertexData(Vertex& vertex) const;
+
+ private:
+
+ static size_t s_offsets[VertexFieldCount];
+ PxPlane m_frames[VertexFieldCount];
+ uint64_t m_fieldMask;
+
+ friend class TriangleFrameBuilder;
+};
+
+PX_INLINE void
+TriangleFrame::setFromTriangle(const ExplicitRenderTriangle& tri, uint64_t fieldMask)
+{
+ m_fieldMask = fieldMask;
+
+ PxVec3 p0, p1, p2;
+ p0 = tri.vertices[0].position;
+ p1 = tri.vertices[1].position;
+ p2 = tri.vertices[2].position;
+ const PxVec3 p1xp2 = p1.cross(p2);
+ const PxVec3 p2xp0 = p2.cross(p0);
+ const PxVec3 p0xp1 = p0.cross(p1);
+ const PxVec3 n = p1xp2 + p2xp0 + p0xp1;
+ const float n2 = n.dot(n);
+ if (n2 < PX_EPS_F32 * PX_EPS_F32)
+ {
+ for (uint32_t i = 0; fieldMask != 0 && i < VertexFieldCount; ++i, (fieldMask >>= 1))
+ {
+ if (fieldMask & 1)
+ {
+ m_frames[i] = PxPlane(0, 0, 0, 0);
+ }
+ }
+ return;
+ }
+
+ // Calculate inverse 4x4 matrix (only need first three columns):
+ const PxVec3 nP = n / n2; // determinant is -n2
+ const PxVec3 Q0(nP.z * (p1.y - p2.y) - nP.y * (p1.z - p2.z), nP.z * (p2.y - p0.y) - nP.y * (p2.z - p0.z), nP.z * (p0.y - p1.y) - nP.y * (p0.z - p1.z));
+ const PxVec3 Q1(nP.x * (p1.z - p2.z) - nP.z * (p1.x - p2.x), nP.x * (p2.z - p0.z) - nP.z * (p2.x - p0.x), nP.x * (p0.z - p1.z) - nP.z * (p0.x - p1.x));
+ const PxVec3 Q2(nP.y * (p1.x - p2.x) - nP.x * (p1.y - p2.y), nP.y * (p2.x - p0.x) - nP.x * (p2.y - p0.y), nP.y * (p0.x - p1.x) - nP.x * (p0.y - p1.y));
+ const PxVec3 r(nP.dot(p1xp2), nP.dot(p2xp0), nP.dot(p0xp1));
+
+ for (uint32_t i = 0; fieldMask != 0 && i < VertexFieldCount; ++i, (fieldMask >>= 1))
+ {
+ if (fieldMask & 1)
+ {
+ const size_t offset = s_offsets[i];
+ const PxVec3 vi(*(float*)(((uint8_t*)&tri.vertices[0]) + offset), *(float*)(((uint8_t*)&tri.vertices[1]) + offset), *(float*)(((uint8_t*)&tri.vertices[2]) + offset));
+ m_frames[i] = PxPlane(Q0.dot(vi), Q1.dot(vi), Q2.dot(vi), r.dot(vi));
+ }
+ }
+}
+
+PX_INLINE void
+TriangleFrame::setFlat(const PxMat44& tm, const PxVec2& uvScale, const PxVec2& uvOffset, uint64_t fieldMask)
+{
+ m_fieldMask = fieldMask;
+
+ // Local z ~ normal = tangents[2], x ~ u and tangent = tangents[0], y ~ v and binormal = tangents[1]
+ if ((fieldMask >> Normal_x) & 1)
+ {
+ m_frames[Normal_x] = PxPlane(PxVec3((float)0), tm(0, 2));
+ }
+ if ((fieldMask >> Normal_y) & 1)
+ {
+ m_frames[Normal_y] = PxPlane(PxVec3((float)0), tm(1, 2));
+ }
+ if ((fieldMask >> Normal_z) & 1)
+ {
+ m_frames[Normal_z] = PxPlane(PxVec3((float)0), tm(2, 2));
+ }
+ if ((fieldMask >> Tangent_x) & 1)
+ {
+ m_frames[Tangent_x] = PxPlane(PxVec3((float)0), tm(0, 0));
+ }
+ if ((fieldMask >> Tangent_y) & 1)
+ {
+ m_frames[Tangent_y] = PxPlane(PxVec3((float)0), tm(1, 0));
+ }
+ if ((fieldMask >> Tangent_z) & 1)
+ {
+ m_frames[Tangent_z] = PxPlane(PxVec3((float)0), tm(2, 0));
+ }
+ if ((fieldMask >> Binormal_x) & 1)
+ {
+ m_frames[Binormal_x] = PxPlane(PxVec3((float)0), tm(0, 1));
+ }
+ if ((fieldMask >> Binormal_y) & 1)
+ {
+ m_frames[Binormal_y] = PxPlane(PxVec3((float)0), tm(1, 1));
+ }
+ if ((fieldMask >> Binormal_z) & 1)
+ {
+ m_frames[Binormal_z] = PxPlane(PxVec3((float)0), tm(2, 1));
+ }
+ const PxVec3 psu = (uvScale[0] ? 1 / uvScale[0] : (float)0) * tm.column0.getXYZ();
+ const PxVec3 psv = (uvScale[1] ? 1 / uvScale[1] : (float)0) * tm.column1.getXYZ();
+ if ((fieldMask >> UV0_u) & 1)
+ {
+ m_frames[UV0_u] = PxPlane(psu, uvOffset[0]);
+ }
+ if ((fieldMask >> UV0_v) & 1)
+ {
+ m_frames[UV0_v] = PxPlane(psv, uvOffset[1]);
+ }
+ if ((fieldMask >> UV1_u) & 1)
+ {
+ m_frames[UV1_u] = PxPlane(psu, uvOffset[0]);
+ }
+ if ((fieldMask >> UV1_v) & 1)
+ {
+ m_frames[UV1_v] = PxPlane(psv, uvOffset[1]);
+ }
+ if ((fieldMask >> UV2_u) & 1)
+ {
+ m_frames[UV2_u] = PxPlane(psu, uvOffset[0]);
+ }
+ if ((fieldMask >> UV2_v) & 1)
+ {
+ m_frames[UV2_v] = PxPlane(psv, uvOffset[1]);
+ }
+ if ((fieldMask >> UV3_u) & 1)
+ {
+ m_frames[UV3_u] = PxPlane(psu, uvOffset[0]);
+ }
+ if ((fieldMask >> UV3_v) & 1)
+ {
+ m_frames[UV3_v] = PxPlane(psv, uvOffset[1]);
+ }
+ if ((fieldMask >> Color_r) & 1)
+ {
+ m_frames[Color_r] = PxPlane(PxVec3((float)0), (float)1);
+ }
+ if ((fieldMask >> Color_g) & 1)
+ {
+ m_frames[Color_g] = PxPlane(PxVec3((float)0), (float)1);
+ }
+ if ((fieldMask >> Color_b) & 1)
+ {
+ m_frames[Color_b] = PxPlane(PxVec3((float)0), (float)1);
+ }
+ if ((fieldMask >> Color_a) & 1)
+ {
+ m_frames[Color_a] = PxPlane(PxVec3((float)0), (float)1);
+ }
+}
+
+PX_INLINE void
+TriangleFrame::interpolateVertexData(Vertex& vertex) const
+{
+ uint64_t fieldMask = m_fieldMask;
+ for (uint32_t i = 0; fieldMask != 0 && i < VertexFieldCount; ++i, (fieldMask >>= 1))
+ {
+ if (fieldMask & 1)
+ {
+ float& value = *(float*)(((uint8_t*)&vertex) + s_offsets[i]);
+ value = m_frames[i].distance(vertex.position);
+ }
+ }
+}
+
+class TriangleFrameBuilder
+{
+ public:
+ TriangleFrameBuilder()
+ {
+#define CREATE_TF_OFFSET( field, element ) (size_t)((uintptr_t)&vertex.field.element-(uintptr_t)&vertex)
+#define CREATE_TF_OFFSET_IDX( field, element, index ) (size_t)((uintptr_t)&vertex.field[index].element-(uintptr_t)&vertex)
+
+ Vertex vertex;
+// TriangleFrame::s_offsets[TriangleFrame::Position_x] = CREATE_TF_OFFSET( position, x );
+// TriangleFrame::s_offsets[TriangleFrame::Position_y] = CREATE_TF_OFFSET( position, y );
+// TriangleFrame::s_offsets[TriangleFrame::Position_z] = CREATE_TF_OFFSET( position, z );
+ TriangleFrame::s_offsets[TriangleFrame::Normal_x] = CREATE_TF_OFFSET(normal, x);
+ TriangleFrame::s_offsets[TriangleFrame::Normal_y] = CREATE_TF_OFFSET(normal, y);
+ TriangleFrame::s_offsets[TriangleFrame::Normal_z] = CREATE_TF_OFFSET(normal, z);
+ TriangleFrame::s_offsets[TriangleFrame::Tangent_x] = CREATE_TF_OFFSET(tangent, x);
+ TriangleFrame::s_offsets[TriangleFrame::Tangent_y] = CREATE_TF_OFFSET(tangent, y);
+ TriangleFrame::s_offsets[TriangleFrame::Tangent_z] = CREATE_TF_OFFSET(tangent, z);
+ TriangleFrame::s_offsets[TriangleFrame::Binormal_x] = CREATE_TF_OFFSET(binormal, x);
+ TriangleFrame::s_offsets[TriangleFrame::Binormal_y] = CREATE_TF_OFFSET(binormal, y);
+ TriangleFrame::s_offsets[TriangleFrame::Binormal_z] = CREATE_TF_OFFSET(binormal, z);
+ TriangleFrame::s_offsets[TriangleFrame::UV0_u] = CREATE_TF_OFFSET_IDX(uv, u, 0);
+ TriangleFrame::s_offsets[TriangleFrame::UV0_v] = CREATE_TF_OFFSET_IDX(uv, v, 0);
+ TriangleFrame::s_offsets[TriangleFrame::UV1_u] = CREATE_TF_OFFSET_IDX(uv, u, 1);
+ TriangleFrame::s_offsets[TriangleFrame::UV1_v] = CREATE_TF_OFFSET_IDX(uv, v, 1);
+ TriangleFrame::s_offsets[TriangleFrame::UV2_u] = CREATE_TF_OFFSET_IDX(uv, u, 2);
+ TriangleFrame::s_offsets[TriangleFrame::UV2_v] = CREATE_TF_OFFSET_IDX(uv, v, 2);
+ TriangleFrame::s_offsets[TriangleFrame::UV3_u] = CREATE_TF_OFFSET_IDX(uv, u, 3);
+ TriangleFrame::s_offsets[TriangleFrame::UV3_v] = CREATE_TF_OFFSET_IDX(uv, v, 3);
+ TriangleFrame::s_offsets[TriangleFrame::Color_r] = CREATE_TF_OFFSET(color, r);
+ TriangleFrame::s_offsets[TriangleFrame::Color_g] = CREATE_TF_OFFSET(color, g);
+ TriangleFrame::s_offsets[TriangleFrame::Color_b] = CREATE_TF_OFFSET(color, b);
+ TriangleFrame::s_offsets[TriangleFrame::Color_a] = CREATE_TF_OFFSET(color, a);
+ }
+};
+
+
+// Format conversion utilities
+
+// Explicit data layouts, used for data conversion
+
+typedef uint8_t UBYTE1_TYPE;
+typedef uint8_t UBYTE2_TYPE[2];
+typedef uint8_t UBYTE3_TYPE[3];
+typedef uint8_t UBYTE4_TYPE[4];
+
+typedef uint16_t USHORT1_TYPE;
+typedef uint16_t USHORT2_TYPE[2];
+typedef uint16_t USHORT3_TYPE[3];
+typedef uint16_t USHORT4_TYPE[4];
+
+typedef int16_t SHORT1_TYPE;
+typedef int16_t SHORT2_TYPE[2];
+typedef int16_t SHORT3_TYPE[3];
+typedef int16_t SHORT4_TYPE[4];
+
+typedef uint32_t UINT1_TYPE;
+typedef uint32_t UINT2_TYPE[2];
+typedef uint32_t UINT3_TYPE[3];
+typedef uint32_t UINT4_TYPE[4];
+
+struct R8G8B8A8_TYPE
+{
+ uint8_t r, g, b, a;
+};
+struct B8G8R8A8_TYPE
+{
+ uint8_t b, g, r, a;
+};
+struct R32G32B32A32_FLOAT_TYPE
+{
+ float r, g, b, a;
+};
+struct B32G32R32A32_FLOAT_TYPE
+{
+ float b, g, r, a;
+};
+
+typedef uint8_t BYTE_UNORM1_TYPE;
+typedef uint8_t BYTE_UNORM2_TYPE[2];
+typedef uint8_t BYTE_UNORM3_TYPE[3];
+typedef uint8_t BYTE_UNORM4_TYPE[4];
+
+typedef uint16_t SHORT_UNORM1_TYPE;
+typedef uint16_t SHORT_UNORM2_TYPE[2];
+typedef uint16_t SHORT_UNORM3_TYPE[3];
+typedef uint16_t SHORT_UNORM4_TYPE[4];
+
+typedef int8_t BYTE_SNORM1_TYPE;
+typedef int8_t BYTE_SNORM2_TYPE[2];
+typedef int8_t BYTE_SNORM3_TYPE[3];
+typedef int8_t BYTE_SNORM4_TYPE[4];
+
+typedef int16_t SHORT_SNORM1_TYPE;
+typedef int16_t SHORT_SNORM2_TYPE[2];
+typedef int16_t SHORT_SNORM3_TYPE[3];
+typedef int16_t SHORT_SNORM4_TYPE[4];
+
+typedef uint16_t HALF1_TYPE;
+typedef uint16_t HALF2_TYPE[2];
+typedef uint16_t HALF3_TYPE[3];
+typedef uint16_t HALF4_TYPE[4];
+
+typedef float FLOAT1_TYPE;
+typedef float FLOAT2_TYPE[2];
+typedef float FLOAT3_TYPE[3];
+typedef float FLOAT4_TYPE[4];
+
+typedef PxMat44 FLOAT4x4_TYPE;
+typedef PxMat33 FLOAT3x3_TYPE;
+
+typedef PxQuat FLOAT4_QUAT_TYPE;
+typedef int8_t BYTE_SNORM4_QUATXYZW_TYPE[4];
+typedef int16_t SHORT_SNORM4_QUATXYZW_TYPE[4];
+
+
+// Data converters
+
+// USHORT1_TYPE -> UINT1_TYPE
+PX_INLINE void convert_UINT1_from_USHORT1(UINT1_TYPE& dst, const USHORT1_TYPE& src)
+{
+ dst = (uint32_t)src;
+}
+
+// USHORT2_TYPE -> UINT2_TYPE
+PX_INLINE void convert_UINT2_from_USHORT2(UINT2_TYPE& dst, const USHORT2_TYPE& src)
+{
+ convert_UINT1_from_USHORT1(dst[0], src[0]);
+ convert_UINT1_from_USHORT1(dst[1], src[1]);
+}
+
+// USHORT3_TYPE -> UINT3_TYPE
+PX_INLINE void convert_UINT3_from_USHORT3(UINT3_TYPE& dst, const USHORT3_TYPE& src)
+{
+ convert_UINT1_from_USHORT1(dst[0], src[0]);
+ convert_UINT1_from_USHORT1(dst[1], src[1]);
+ convert_UINT1_from_USHORT1(dst[2], src[2]);
+}
+
+// USHORT4_TYPE -> UINT4_TYPE
+PX_INLINE void convert_UINT4_from_USHORT4(UINT4_TYPE& dst, const USHORT4_TYPE& src)
+{
+ convert_UINT1_from_USHORT1(dst[0], src[0]);
+ convert_UINT1_from_USHORT1(dst[1], src[1]);
+ convert_UINT1_from_USHORT1(dst[2], src[2]);
+ convert_UINT1_from_USHORT1(dst[3], src[3]);
+}
+
+// UINT1_TYPE -> USHORT1_TYPE
+PX_INLINE void convert_USHORT1_from_UINT1(USHORT1_TYPE& dst, const UINT1_TYPE& src)
+{
+ dst = (uint16_t)src;
+}
+
+// UINT2_TYPE -> USHORT2_TYPE
+PX_INLINE void convert_USHORT2_from_UINT2(USHORT2_TYPE& dst, const UINT2_TYPE& src)
+{
+ convert_USHORT1_from_UINT1(dst[0], src[0]);
+ convert_USHORT1_from_UINT1(dst[1], src[1]);
+}
+
+// UINT3_TYPE -> USHORT3_TYPE
+PX_INLINE void convert_USHORT3_from_UINT3(USHORT3_TYPE& dst, const UINT3_TYPE& src)
+{
+ convert_USHORT1_from_UINT1(dst[0], src[0]);
+ convert_USHORT1_from_UINT1(dst[1], src[1]);
+ convert_USHORT1_from_UINT1(dst[2], src[2]);
+}
+
+// UINT4_TYPE -> USHORT4_TYPE
+PX_INLINE void convert_USHORT4_from_UINT4(USHORT4_TYPE& dst, const UINT4_TYPE& src)
+{
+ convert_USHORT1_from_UINT1(dst[0], src[0]);
+ convert_USHORT1_from_UINT1(dst[1], src[1]);
+ convert_USHORT1_from_UINT1(dst[2], src[2]);
+ convert_USHORT1_from_UINT1(dst[3], src[3]);
+}
+
+// BYTE_SNORM1_TYPE -> FLOAT1_TYPE
+PX_INLINE void convert_FLOAT1_from_BYTE_SNORM1(FLOAT1_TYPE& dst, const BYTE_SNORM1_TYPE& src)
+{
+ dst = (float)src / 127.0f;
+}
+
+// BYTE_SNORM2_TYPE -> FLOAT2_TYPE
+PX_INLINE void convert_FLOAT2_from_BYTE_SNORM2(FLOAT2_TYPE& dst, const BYTE_SNORM2_TYPE& src)
+{
+ convert_FLOAT1_from_BYTE_SNORM1(dst[0], src[0]);
+ convert_FLOAT1_from_BYTE_SNORM1(dst[1], src[1]);
+}
+
+// BYTE_SNORM3_TYPE -> FLOAT3_TYPE
+PX_INLINE void convert_FLOAT3_from_BYTE_SNORM3(FLOAT3_TYPE& dst, const BYTE_SNORM3_TYPE& src)
+{
+ convert_FLOAT1_from_BYTE_SNORM1(dst[0], src[0]);
+ convert_FLOAT1_from_BYTE_SNORM1(dst[1], src[1]);
+ convert_FLOAT1_from_BYTE_SNORM1(dst[2], src[2]);
+}
+
+// BYTE_SNORM4_TYPE -> FLOAT4_TYPE
+PX_INLINE void convert_FLOAT4_from_BYTE_SNORM4(FLOAT4_TYPE& dst, const BYTE_SNORM4_TYPE& src)
+{
+ convert_FLOAT1_from_BYTE_SNORM1(dst[0], src[0]);
+ convert_FLOAT1_from_BYTE_SNORM1(dst[1], src[1]);
+ convert_FLOAT1_from_BYTE_SNORM1(dst[2], src[2]);
+ convert_FLOAT1_from_BYTE_SNORM1(dst[3], src[3]);
+}
+
+// BYTE_SNORM4_QUATXYZW_TYPE -> FLOAT4_QUAT_TYPE
+PX_INLINE void convert_FLOAT4_QUAT_from_BYTE_SNORM4_QUATXYZW(FLOAT4_QUAT_TYPE& dst, const BYTE_SNORM4_QUATXYZW_TYPE& src)
+{
+ convert_FLOAT1_from_BYTE_SNORM1(dst.x, src[0]);
+ convert_FLOAT1_from_BYTE_SNORM1(dst.y, src[1]);
+ convert_FLOAT1_from_BYTE_SNORM1(dst.z, src[2]);
+ convert_FLOAT1_from_BYTE_SNORM1(dst.w, src[3]);
+}
+
+// SHORT_SNORM1_TYPE -> FLOAT1_TYPE
+PX_INLINE void convert_FLOAT1_from_SHORT_SNORM1(FLOAT1_TYPE& dst, const SHORT_SNORM1_TYPE& src)
+{
+ dst = (float)src / 32767.0f;
+}
+
+// SHORT_SNORM2_TYPE -> FLOAT2_TYPE
+PX_INLINE void convert_FLOAT2_from_SHORT_SNORM2(FLOAT2_TYPE& dst, const SHORT_SNORM2_TYPE& src)
+{
+ convert_FLOAT1_from_SHORT_SNORM1(dst[0], src[0]);
+ convert_FLOAT1_from_SHORT_SNORM1(dst[1], src[1]);
+}
+
+// SHORT_SNORM3_TYPE -> FLOAT3_TYPE
+PX_INLINE void convert_FLOAT3_from_SHORT_SNORM3(FLOAT3_TYPE& dst, const SHORT_SNORM3_TYPE& src)
+{
+ convert_FLOAT1_from_SHORT_SNORM1(dst[0], src[0]);
+ convert_FLOAT1_from_SHORT_SNORM1(dst[1], src[1]);
+ convert_FLOAT1_from_SHORT_SNORM1(dst[2], src[2]);
+}
+
+// SHORT_SNORM4_TYPE -> FLOAT4_TYPE
+PX_INLINE void convert_FLOAT4_from_SHORT_SNORM4(FLOAT4_TYPE& dst, const SHORT_SNORM4_TYPE& src)
+{
+ convert_FLOAT1_from_SHORT_SNORM1(dst[0], src[0]);
+ convert_FLOAT1_from_SHORT_SNORM1(dst[1], src[1]);
+ convert_FLOAT1_from_SHORT_SNORM1(dst[2], src[2]);
+ convert_FLOAT1_from_SHORT_SNORM1(dst[3], src[3]);
+}
+
+// SHORT_SNORM4_QUATXYZW_TYPE -> FLOAT4_QUAT_TYPE
+PX_INLINE void convert_FLOAT4_QUAT_from_SHORT_SNORM4_QUATXYZW(FLOAT4_QUAT_TYPE& dst, const SHORT_SNORM4_QUATXYZW_TYPE& src)
+{
+ convert_FLOAT1_from_SHORT_SNORM1(dst.x, src[0]);
+ convert_FLOAT1_from_SHORT_SNORM1(dst.y, src[1]);
+ convert_FLOAT1_from_SHORT_SNORM1(dst.z, src[2]);
+ convert_FLOAT1_from_SHORT_SNORM1(dst.w, src[3]);
+}
+
+// FLOAT1_TYPE -> BYTE_SNORM1_TYPE
+PX_INLINE void convert_BYTE_SNORM1_from_FLOAT1(BYTE_SNORM1_TYPE& dst, const FLOAT1_TYPE& src)
+{
+ dst = (int8_t)((int16_t)(src * 127.0f + 127.5f) - 127); // Doing it this way to avoid nonuniform mapping near zero
+}
+
+// FLOAT2_TYPE -> BYTE_SNORM2_TYPE
+PX_INLINE void convert_BYTE_SNORM2_from_FLOAT2(BYTE_SNORM2_TYPE& dst, const FLOAT2_TYPE& src)
+{
+ convert_BYTE_SNORM1_from_FLOAT1(dst[0], src[0]);
+ convert_BYTE_SNORM1_from_FLOAT1(dst[1], src[1]);
+}
+
+// FLOAT3_TYPE -> BYTE_SNORM3_TYPE
+PX_INLINE void convert_BYTE_SNORM3_from_FLOAT3(BYTE_SNORM3_TYPE& dst, const FLOAT3_TYPE& src)
+{
+ convert_BYTE_SNORM1_from_FLOAT1(dst[0], src[0]);
+ convert_BYTE_SNORM1_from_FLOAT1(dst[1], src[1]);
+ convert_BYTE_SNORM1_from_FLOAT1(dst[2], src[2]);
+}
+
+// FLOAT4_TYPE -> BYTE_SNORM4_TYPE
+PX_INLINE void convert_BYTE_SNORM4_from_FLOAT4(BYTE_SNORM4_TYPE& dst, const FLOAT4_TYPE& src)
+{
+ convert_BYTE_SNORM1_from_FLOAT1(dst[0], src[0]);
+ convert_BYTE_SNORM1_from_FLOAT1(dst[1], src[1]);
+ convert_BYTE_SNORM1_from_FLOAT1(dst[2], src[2]);
+ convert_BYTE_SNORM1_from_FLOAT1(dst[3], src[3]);
+}
+
+// FLOAT4_QUAT_TYPE -> BYTE_SNORM4_QUATXYZW_TYPE
+PX_INLINE void convert_BYTE_SNORM4_QUATXYZW_from_FLOAT4_QUAT(BYTE_SNORM4_QUATXYZW_TYPE& dst, const FLOAT4_QUAT_TYPE& src)
+{
+ convert_BYTE_SNORM1_from_FLOAT1(dst[0], src.x);
+ convert_BYTE_SNORM1_from_FLOAT1(dst[1], src.y);
+ convert_BYTE_SNORM1_from_FLOAT1(dst[2], src.z);
+ convert_BYTE_SNORM1_from_FLOAT1(dst[3], src.w);
+}
+
+// FLOAT1_TYPE -> SHORT_SNORM1_TYPE
+PX_INLINE void convert_SHORT_SNORM1_from_FLOAT1(SHORT_SNORM1_TYPE& dst, const FLOAT1_TYPE& src)
+{
+ dst = (int16_t)((int32_t)(src * 32767.0f + 32767.5f) - 32767); // Doing it this way to avoid nonuniform mapping near zero
+}
+
+// FLOAT2_TYPE -> SHORT_SNORM2_TYPE
+PX_INLINE void convert_SHORT_SNORM2_from_FLOAT2(SHORT_SNORM2_TYPE& dst, const FLOAT2_TYPE& src)
+{
+ convert_SHORT_SNORM1_from_FLOAT1(dst[0], src[0]);
+ convert_SHORT_SNORM1_from_FLOAT1(dst[1], src[1]);
+}
+
+// FLOAT3_TYPE -> SHORT_SNORM3_TYPE
+PX_INLINE void convert_SHORT_SNORM3_from_FLOAT3(SHORT_SNORM3_TYPE& dst, const FLOAT3_TYPE& src)
+{
+ convert_SHORT_SNORM1_from_FLOAT1(dst[0], src[0]);
+ convert_SHORT_SNORM1_from_FLOAT1(dst[1], src[1]);
+ convert_SHORT_SNORM1_from_FLOAT1(dst[2], src[2]);
+}
+
+// FLOAT4_TYPE -> SHORT_SNORM4_TYPE
+PX_INLINE void convert_SHORT_SNORM4_from_FLOAT4(SHORT_SNORM4_TYPE& dst, const FLOAT4_TYPE& src)
+{
+ convert_SHORT_SNORM1_from_FLOAT1(dst[0], src[0]);
+ convert_SHORT_SNORM1_from_FLOAT1(dst[1], src[1]);
+ convert_SHORT_SNORM1_from_FLOAT1(dst[2], src[2]);
+ convert_SHORT_SNORM1_from_FLOAT1(dst[3], src[3]);
+}
+
+// FLOAT4_QUAT_TYPE -> SHORT_SNORM4_QUATXYZW_TYPE
+PX_INLINE void convert_SHORT_SNORM4_QUATXYZW_from_FLOAT4_QUAT(SHORT_SNORM4_QUATXYZW_TYPE& dst, const FLOAT4_QUAT_TYPE& src)
+{
+ convert_SHORT_SNORM1_from_FLOAT1(dst[0], src.x);
+ convert_SHORT_SNORM1_from_FLOAT1(dst[1], src.y);
+ convert_SHORT_SNORM1_from_FLOAT1(dst[2], src.z);
+ convert_SHORT_SNORM1_from_FLOAT1(dst[3], src.w);
+}
+
+// Color format conversions
+PX_INLINE void convert_B8G8R8A8_from_R8G8B8A8(B8G8R8A8_TYPE& dst, const R8G8B8A8_TYPE& src)
+{
+ dst.r = src.r;
+ dst.g = src.g;
+ dst.b = src.b;
+ dst.a = src.a;
+}
+
+PX_INLINE void convert_R8G8B8A8_from_B8G8R8A8(R8G8B8A8_TYPE& dst, const B8G8R8A8_TYPE& src)
+{
+ dst.r = src.r;
+ dst.g = src.g;
+ dst.b = src.b;
+ dst.a = src.a;
+}
+
+PX_INLINE void convert_R32G32B32A32_FLOAT_from_R8G8B8A8(R32G32B32A32_FLOAT_TYPE& dst, const R8G8B8A8_TYPE& src)
+{
+ (VertexColor&)dst = VertexColor((const ColorRGBA&)src);
+}
+
+PX_INLINE void convert_R8G8B8A8_from_R32G32B32A32_FLOAT(R8G8B8A8_TYPE& dst, const R32G32B32A32_FLOAT_TYPE& src)
+{
+ (ColorRGBA&)dst = ((const VertexColor&)src).toColorRGBA();
+}
+
+PX_INLINE void convert_B32G32R32A32_FLOAT_from_R8G8B8A8(B32G32R32A32_FLOAT_TYPE& dst, const R8G8B8A8_TYPE& src)
+{
+ (VertexColor&)dst = VertexColor((const ColorRGBA&)src);
+ float t = dst.r;
+ dst.r = dst.b;
+ dst.b = t;
+}
+
+PX_INLINE void convert_R8G8B8A8_from_B32G32R32A32_FLOAT(R8G8B8A8_TYPE& dst, const B32G32R32A32_FLOAT_TYPE& src)
+{
+ (ColorRGBA&)dst = ((const VertexColor&)src).toColorRGBA();
+ uint8_t t = dst.r;
+ dst.r = dst.b;
+ dst.b = t;
+}
+
+PX_INLINE void convert_R32G32B32A32_FLOAT_from_B8G8R8A8(R32G32B32A32_FLOAT_TYPE& dst, const B8G8R8A8_TYPE& src)
+{
+ (VertexColor&)dst = VertexColor((const ColorRGBA&)src);
+ float t = dst.r;
+ dst.r = dst.b;
+ dst.b = t;
+}
+
+PX_INLINE void convert_B8G8R8A8_from_R32G32B32A32_FLOAT(B8G8R8A8_TYPE& dst, const R32G32B32A32_FLOAT_TYPE& src)
+{
+ (ColorRGBA&)dst = ((const VertexColor&)src).toColorRGBA();
+ uint8_t t = dst.r;
+ dst.r = dst.b;
+ dst.b = t;
+}
+
+PX_INLINE void convert_B32G32R32A32_FLOAT_from_B8G8R8A8(B32G32R32A32_FLOAT_TYPE& dst, const B8G8R8A8_TYPE& src)
+{
+ (VertexColor&)dst = VertexColor((const ColorRGBA&)src);
+}
+
+PX_INLINE void convert_B8G8R8A8_from_B32G32R32A32_FLOAT(B8G8R8A8_TYPE& dst, const B32G32R32A32_FLOAT_TYPE& src)
+{
+ (ColorRGBA&)dst = ((const VertexColor&)src).toColorRGBA();
+}
+
+PX_INLINE void convert_B32G32R32A32_FLOAT_from_R32G32B32A32_FLOAT(B32G32R32A32_FLOAT_TYPE& dst, const R32G32B32A32_FLOAT_TYPE& src)
+{
+ dst.r = src.r;
+ dst.g = src.g;
+ dst.b = src.b;
+ dst.a = src.a;
+}
+
+PX_INLINE void convert_R32G32B32A32_FLOAT_from_B32G32R32A32_FLOAT(R32G32B32A32_FLOAT_TYPE& dst, const B32G32R32A32_FLOAT_TYPE& src)
+{
+ dst.r = src.r;
+ dst.g = src.g;
+ dst.b = src.b;
+ dst.a = src.a;
+}
+
+// Data conversion macros
+#define HANDLE_CONVERT1( _DstFormat, _SrcFormat ) \
+ case RenderDataFormat::_DstFormat : \
+ if( srcFormat == RenderDataFormat::_SrcFormat ) \
+ { \
+ convert_##_DstFormat##_from_##_SrcFormat( ((_DstFormat##_TYPE*)dst)[dstIndex], ((const _SrcFormat##_TYPE*)src)[srcIndex] ); \
+ } \
+ break;
+
+#define HANDLE_CONVERT2( _DstFormat, _SrcFormat1, _SrcFormat2 ) \
+ case RenderDataFormat::_DstFormat : \
+ if( srcFormat == RenderDataFormat::_SrcFormat1 ) \
+ { \
+ convert_##_DstFormat##_from_##_SrcFormat1( ((_DstFormat##_TYPE*)dst)[dstIndex], ((const _SrcFormat1##_TYPE*)src)[srcIndex] ); \
+ } \
+ else if( srcFormat == RenderDataFormat::_SrcFormat2 ) \
+ { \
+ convert_##_DstFormat##_from_##_SrcFormat2( ((_DstFormat##_TYPE*)dst)[dstIndex], ((const _SrcFormat2##_TYPE*)src)[srcIndex] ); \
+ } \
+ break;
+
+#define HANDLE_CONVERT3( _DstFormat, _SrcFormat1, _SrcFormat2, _SrcFormat3 ) \
+ case RenderDataFormat::_DstFormat : \
+ if( srcFormat == RenderDataFormat::_SrcFormat1 ) \
+ { \
+ convert_##_DstFormat##_from_##_SrcFormat1( ((_DstFormat##_TYPE*)dst)[dstIndex], ((const _SrcFormat1##_TYPE*)src)[srcIndex] ); \
+ } \
+ else if( srcFormat == RenderDataFormat::_SrcFormat2 ) \
+ { \
+ convert_##_DstFormat##_from_##_SrcFormat2( ((_DstFormat##_TYPE*)dst)[dstIndex], ((const _SrcFormat2##_TYPE*)src)[srcIndex] ); \
+ } \
+ else if( srcFormat == RenderDataFormat::_SrcFormat3 ) \
+ { \
+ convert_##_DstFormat##_from_##_SrcFormat3( ((_DstFormat##_TYPE*)dst)[dstIndex], ((const _SrcFormat3##_TYPE*)src)[srcIndex] ); \
+ } \
+ break;
+
+// ... etc.
+
+PX_INLINE bool copyRenderVertexData(void* dst, RenderDataFormat::Enum dstFormat, uint32_t dstIndex, const void* src, RenderDataFormat::Enum srcFormat, uint32_t srcIndex)
+{
+ if (dstFormat == srcFormat)
+ {
+ // Direct data copy
+ if (dstFormat != RenderDataFormat::UNSPECIFIED)
+ {
+ uint8_t* srcPtr = (uint8_t*)src;
+ uint8_t* dstPtr = (uint8_t*)dst;
+
+ const uint32_t size = RenderDataFormat::getFormatDataSize(dstFormat);
+ memcpy(dstPtr + (dstIndex * size), srcPtr + (srcIndex * size), size);
+ }
+ return true;
+ }
+
+ switch (dstFormat)
+ {
+ case RenderDataFormat::UNSPECIFIED:
+ break; // The simplest case, do nothing
+
+ // Put format converters here
+
+ HANDLE_CONVERT1(USHORT1, UINT1)
+ HANDLE_CONVERT1(USHORT2, UINT2)
+ HANDLE_CONVERT1(USHORT3, UINT3)
+ HANDLE_CONVERT1(USHORT4, UINT4)
+
+ HANDLE_CONVERT1(UINT1, USHORT1)
+ HANDLE_CONVERT1(UINT2, USHORT2)
+ HANDLE_CONVERT1(UINT3, USHORT3)
+ HANDLE_CONVERT1(UINT4, USHORT4)
+
+ HANDLE_CONVERT1(BYTE_SNORM1, FLOAT1)
+ HANDLE_CONVERT1(BYTE_SNORM2, FLOAT2)
+ HANDLE_CONVERT1(BYTE_SNORM3, FLOAT3)
+ HANDLE_CONVERT1(BYTE_SNORM4, FLOAT4)
+ HANDLE_CONVERT1(BYTE_SNORM4_QUATXYZW, FLOAT4_QUAT)
+ HANDLE_CONVERT1(SHORT_SNORM1, FLOAT1)
+ HANDLE_CONVERT1(SHORT_SNORM2, FLOAT2)
+ HANDLE_CONVERT1(SHORT_SNORM3, FLOAT3)
+ HANDLE_CONVERT1(SHORT_SNORM4, FLOAT4)
+ HANDLE_CONVERT1(SHORT_SNORM4_QUATXYZW, FLOAT4_QUAT)
+
+ HANDLE_CONVERT2(FLOAT1, BYTE_SNORM1, SHORT_SNORM1)
+ HANDLE_CONVERT2(FLOAT2, BYTE_SNORM2, SHORT_SNORM2)
+ HANDLE_CONVERT2(FLOAT3, BYTE_SNORM3, SHORT_SNORM3)
+ HANDLE_CONVERT2(FLOAT4, BYTE_SNORM4, SHORT_SNORM4)
+ HANDLE_CONVERT2(FLOAT4_QUAT, BYTE_SNORM4_QUATXYZW, SHORT_SNORM4_QUATXYZW)
+
+ HANDLE_CONVERT3(R8G8B8A8, B8G8R8A8, R32G32B32A32_FLOAT, B32G32R32A32_FLOAT)
+ HANDLE_CONVERT3(B8G8R8A8, R8G8B8A8, R32G32B32A32_FLOAT, B32G32R32A32_FLOAT)
+ HANDLE_CONVERT3(R32G32B32A32_FLOAT, R8G8B8A8, B8G8R8A8, B32G32R32A32_FLOAT)
+ HANDLE_CONVERT3(B32G32R32A32_FLOAT, R8G8B8A8, B8G8R8A8, R32G32B32A32_FLOAT)
+
+ default:
+ {
+ PX_ALWAYS_ASSERT(); // Format conversion not handled
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool copyRenderVertexBuffer(void* dst, RenderDataFormat::Enum dstFormat, uint32_t dstStride, uint32_t dstStart,
+ const void* src, RenderDataFormat::Enum srcFormat, uint32_t srcStride, uint32_t srcStart,
+ uint32_t numVertices, int32_t* invMap = NULL);
+
+/*
+ Local utilities
+ */
+PX_INLINE bool vertexSemanticFormatValid(RenderVertexSemantic::Enum semantic, RenderDataFormat::Enum format)
+{
+ switch (semantic)
+ {
+ case RenderVertexSemantic::POSITION:
+ return format == RenderDataFormat::FLOAT3;
+ case RenderVertexSemantic::NORMAL:
+ case RenderVertexSemantic::BINORMAL:
+ return format == RenderDataFormat::FLOAT3 || format == RenderDataFormat::BYTE_SNORM3;
+ case RenderVertexSemantic::TANGENT:
+ return format == RenderDataFormat::FLOAT3 || format == RenderDataFormat::BYTE_SNORM3 ||
+ format == RenderDataFormat::FLOAT4 || format == RenderDataFormat::BYTE_SNORM4;
+ case RenderVertexSemantic::COLOR:
+ return format == RenderDataFormat::R8G8B8A8 || format == RenderDataFormat::B8G8R8A8;
+ case RenderVertexSemantic::TEXCOORD0:
+ case RenderVertexSemantic::TEXCOORD1:
+ case RenderVertexSemantic::TEXCOORD2:
+ case RenderVertexSemantic::TEXCOORD3:
+ return format == RenderDataFormat::FLOAT2; // Not supporting other formats yet
+ case RenderVertexSemantic::DISPLACEMENT_TEXCOORD:
+ return format == RenderDataFormat::FLOAT2 || format == RenderDataFormat::FLOAT3;
+ case RenderVertexSemantic::DISPLACEMENT_FLAGS:
+ return format == RenderDataFormat::UINT1 || format == RenderDataFormat::USHORT1;
+ case RenderVertexSemantic::BONE_INDEX:
+ return format == RenderDataFormat::USHORT1 ||
+ format == RenderDataFormat::USHORT2 ||
+ format == RenderDataFormat::USHORT3 ||
+ format == RenderDataFormat::USHORT4; // Not supporting other formats yet
+ case RenderVertexSemantic::BONE_WEIGHT:
+ return format == RenderDataFormat::FLOAT1 ||
+ format == RenderDataFormat::FLOAT2 ||
+ format == RenderDataFormat::FLOAT3 ||
+ format == RenderDataFormat::FLOAT4; // Not supporting other formats yet
+ default:
+ return false;
+ }
+}
+
+PX_INLINE uint32_t vertexSemanticFormatElementCount(RenderVertexSemantic::Enum semantic, RenderDataFormat::Enum format)
+{
+ switch (semantic)
+ {
+ case RenderVertexSemantic::CUSTOM:
+ case RenderVertexSemantic::POSITION:
+ case RenderVertexSemantic::NORMAL:
+ case RenderVertexSemantic::TANGENT:
+ case RenderVertexSemantic::BINORMAL:
+ case RenderVertexSemantic::COLOR:
+ case RenderVertexSemantic::TEXCOORD0:
+ case RenderVertexSemantic::TEXCOORD1:
+ case RenderVertexSemantic::TEXCOORD2:
+ case RenderVertexSemantic::TEXCOORD3:
+ case RenderVertexSemantic::DISPLACEMENT_TEXCOORD:
+ case RenderVertexSemantic::DISPLACEMENT_FLAGS:
+ return 1;
+ case RenderVertexSemantic::BONE_INDEX:
+ switch (format)
+ {
+ case RenderDataFormat::USHORT1:
+ return 1;
+ case RenderDataFormat::USHORT2:
+ return 2;
+ case RenderDataFormat::USHORT3:
+ return 3;
+ case RenderDataFormat::USHORT4:
+ return 4;
+ default:
+ break;
+ }
+ return 0;
+ case RenderVertexSemantic::BONE_WEIGHT:
+ switch (format)
+ {
+ case RenderDataFormat::FLOAT1:
+ return 1;
+ case RenderDataFormat::FLOAT2:
+ return 2;
+ case RenderDataFormat::FLOAT3:
+ return 3;
+ case RenderDataFormat::FLOAT4:
+ return 4;
+ default:
+ break;
+ }
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+
+}
+} // end namespace apex
+
+
+#endif // __APEXSHAREDUTILS_H__
diff --git a/APEX_1.4/common/include/ApexSimdMath.h b/APEX_1.4/common/include/ApexSimdMath.h
new file mode 100644
index 00000000..9c807046
--- /dev/null
+++ b/APEX_1.4/common/include/ApexSimdMath.h
@@ -0,0 +1,127 @@
+/*
+ * 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 APEX_SIMD_MATH_H
+#define APEX_SIMD_MATH_H
+
+#include "PxMat44.h"
+#include "PxVec3.h"
+#include "PsMathUtils.h"
+#include "NvSimd4f.h"
+
+namespace nvidia
+{
+ /** Normalization of the (a[0], a[1], a[2]) vector
+ * @param a input vector
+ * @return normalized vector
+ */
+ inline Simd4f normalizeSimd3f(const Simd4f& a)
+ {
+ return a * rsqrt(dot3(a, a));
+ }
+
+ /** Create simd 4-float tuple from vec3 and wComponent
+ * @param vec3 vector with 3 components
+ * @param wComponent with this value final element will be initialized
+ * @return filled simd 4-float tuple
+ */
+ inline Simd4f createSimd3f(const physx::PxVec3& vec3, float wComponent = 0.0f)
+ {
+ return Simd4fLoad3SetWFactory(&vec3.x, wComponent);
+ }
+
+ /** Apply affine transform to position. Algorithm is not sensitive to pos.w.
+ * @param transformAlignMemLayout transform
+ * @param pos input position.
+ * @return transformed position. With pos.w setuped to one.
+ */
+ inline Simd4f applyAffineTransform(const physx::PxMat44& transformAlignMemLayout, const Simd4f& pos)
+ {
+ const physx::PxMat44& tr = transformAlignMemLayout;
+
+ const Simd4f& col0 = Simd4fAlignedLoadFactory(&tr.column0.x);
+ const Simd4f xMultiplier = splat<0>(pos);
+
+ const Simd4f& col1 = Simd4fAlignedLoadFactory(&tr.column1.x);
+ const Simd4f yMultiplier = splat<1>(pos);
+
+ const Simd4f& col2 = Simd4fAlignedLoadFactory(&tr.column2.x);
+ const Simd4f zMultiplier = splat<2>(pos);
+
+ Simd4f result = xMultiplier * col0 + yMultiplier * col1 + zMultiplier * col2 + Simd4fAlignedLoadFactory(&tr.column3.x);
+
+ array(result)[3] = 1.0f;
+
+ return result;
+ }
+
+ /** Apply linear transform to position or more probability to the vector(direction)
+ * @param transformAlignMemLayout transform
+ * @param pos input position. Algo does not sensitive to pos.w.
+ * @return transformed position. With pos.w setuped to zero.
+ */
+ inline Simd4f applyLinearTransform(const physx::PxMat44& transformAlignMemLayout, const Simd4f& direction)
+ {
+ const physx::PxMat44& tr = transformAlignMemLayout;
+ const Simd4f& col0 = Simd4fAlignedLoadFactory(&tr.column0.x);
+ const Simd4f xMultiplier = splat<0>(direction);
+ const Simd4f& col1 = Simd4fAlignedLoadFactory(&tr.column1.x);
+ const Simd4f yMultiplier = splat<1>(direction);
+ const Simd4f& col2 = Simd4fAlignedLoadFactory(&tr.column2.x);
+ const Simd4f zMultiplier = splat<2>(direction);
+ Simd4f result = xMultiplier * col0 + yMultiplier * col1 + zMultiplier * col2;
+ result = result & gSimd4fMaskXYZ;
+
+ return result;
+ }
+
+ /** Apply transpose of matrix consisted of col0, col1, col2, col3.
+ * Ported version of V4Transpose() from PxShared\*\foundation\include\PsVecMathAoSScalarInline.h
+ * @param col0 input column of the matrix, and output column of the result matrix
+ * @param col1 input column of the matrix, and output column of the result matrix
+ * @param col2 input column of the matrix, and output column of the result matrix
+ * @param col3 input column of the matrix, and output column of the result matrix
+ * @return None
+ */
+ inline void applyTranspose(Simd4f& col0, Simd4f& col1, Simd4f& col2, Simd4f& col3)
+ {
+ /*
+ col0 col1 col2 col3
+ 0 col0[0] col0[1] col0[1] col0[1]
+ 1 col0[1] col0[1] col0[1] col0[1]
+ 2 col0[2] col0[1] col0[1] col0[1]
+ 3 col0[3] col0[1] col0[1] col0[1]
+ */
+
+ float* arrayCol0 = array(col0);
+ float* arrayCol1 = array(col1);
+ float* arrayCol2 = array(col2);
+ float* arrayCol3 = array(col3);
+
+ using physx::PxF32;
+ const PxF32 t01 = arrayCol0[1];
+ const PxF32 t02 = arrayCol0[2];
+ const PxF32 t03 = arrayCol0[3];
+ const PxF32 t12 = arrayCol1[2];
+ const PxF32 t13 = arrayCol1[3];
+ const PxF32 t23 = arrayCol2[3];
+
+ // x -- 0, y -- 1, z -- 2, w -- 3
+ arrayCol0[1] = arrayCol1[0]; arrayCol0[2] = arrayCol2[0]; arrayCol0[3] = arrayCol3[0];
+ arrayCol1[2] = arrayCol2[1]; arrayCol1[3] = arrayCol3[1];
+ arrayCol2[3] = arrayCol3[2];
+
+ arrayCol1[0] = t01; arrayCol2[0] = t02; arrayCol3[0] = t03;
+ arrayCol2[1] = t12; arrayCol3[1] = t13;
+ arrayCol3[2] = t23;
+ }
+}
+
+#endif // APEX_SIND_MATH_H
diff --git a/APEX_1.4/common/include/ApexSubdivider.h b/APEX_1.4/common/include/ApexSubdivider.h
new file mode 100644
index 00000000..a91d2a74
--- /dev/null
+++ b/APEX_1.4/common/include/ApexSubdivider.h
@@ -0,0 +1,200 @@
+/*
+ * 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 APEX_SUBDIVIDER_H
+#define APEX_SUBDIVIDER_H
+
+#include "ApexDefs.h"
+#include "PsUserAllocated.h"
+#include "ApexRand.h"
+#include "PsArray.h"
+#include "ApexUsingNamespace.h"
+
+#include "PxBounds3.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+class IProgressListener;
+
+class ApexSubdivider : public UserAllocated
+{
+public:
+ ApexSubdivider();
+
+ void clear();
+
+ void registerVertex(const PxVec3& v, uint32_t bitFlagPayload);
+ void registerTriangle(uint32_t i0, uint32_t i1, uint32_t i2);
+
+ void endRegistration();
+
+ void mergeVertices(IProgressListener* progress);
+ void closeMesh(IProgressListener* progress);
+ void subdivide(uint32_t subdivisionGridSize, IProgressListener* progress);
+
+ uint32_t getNumVertices() const;
+ uint32_t getNumTriangles() const;
+
+ void getVertex(uint32_t i, PxVec3& v, uint32_t& bitFlagPayload) const;
+ void getTriangle(uint32_t i, uint32_t& i0, uint32_t& i1, uint32_t& i2) const;
+
+private:
+ void compress();
+ void closeHole(uint32_t* indices, uint32_t numIndices);
+ float qualityOfTriangle(uint32_t v0, uint32_t v1, uint32_t v2) const;
+ int32_t getTriangleNr(const uint32_t v0, const uint32_t v1, const uint32_t v2) const;
+
+ PxBounds3 mBound;
+
+ struct SubdividerVertex
+ {
+ SubdividerVertex() : pos(0.0f, 0.0f, 0.0f), firstTriangle(-1), payload(0), marked(false) {}
+ SubdividerVertex(const PxVec3& newPos, uint32_t bitFlagPayload) : pos(newPos), firstTriangle(-1), payload(bitFlagPayload), marked(false) {}
+
+ PxVec3 pos;
+ int32_t firstTriangle;
+ uint32_t payload;
+ bool marked;
+ };
+
+ struct SubdividerVertexRef
+ {
+ SubdividerVertexRef() : pos(0.0f, 0.0f, 0.0f), vertexNr(0) {}
+ SubdividerVertexRef(const PxVec3& p, uint32_t vNr) : pos(p), vertexNr(vNr) {}
+ PX_INLINE bool operator < (const SubdividerVertexRef& vr) const
+ {
+ return pos.x < vr.pos.x;
+ }
+
+ PX_INLINE bool operator()(const SubdividerVertexRef& v1, const SubdividerVertexRef& v2) const
+ {
+ return v1 < v2;
+ }
+
+ PxVec3 pos;
+ uint32_t vertexNr;
+ };
+
+
+
+ struct SubdividerEdge
+ {
+ void init(uint32_t newV0, uint32_t newV1, uint32_t newTriangleNr)
+ {
+ v0 = PxMax(newV0, newV1);
+ v1 = PxMin(newV0, newV1);
+ triangleNr = newTriangleNr;
+ }
+ PX_INLINE bool operator < (const SubdividerEdge& e) const
+ {
+ if (v0 < e.v0)
+ {
+ return true;
+ }
+ if (v0 > e.v0)
+ {
+ return false;
+ }
+ return (v1 < e.v1);
+ }
+ PX_INLINE bool operator()(const SubdividerEdge& e1, const SubdividerEdge& e2) const
+ {
+ return e1 < e2;
+ }
+ PX_INLINE bool operator == (const SubdividerEdge& e) const
+ {
+ return v0 == e.v0 && v1 == e.v1;
+ }
+ uint32_t v0, v1;
+ uint32_t triangleNr;
+ };
+
+ int32_t binarySearchEdges(const Array<SubdividerEdge>& edges, uint32_t v0, uint32_t v1, uint32_t triangleNr) const;
+
+ struct SubdividerTriangle
+ {
+ void init(uint32_t v0, uint32_t v1, uint32_t v2)
+ {
+ vertexNr[0] = v0;
+ vertexNr[1] = v1;
+ vertexNr[2] = v2;
+ }
+
+ bool containsVertex(uint32_t vNr) const
+ {
+ return vertexNr[0] == vNr || vertexNr[1] == vNr || vertexNr[2] == vNr;
+ }
+
+ void replaceVertex(uint32_t vOld, uint32_t vNew)
+ {
+ if (vertexNr[0] == vOld)
+ {
+ vertexNr[0] = vNew;
+ }
+ else if (vertexNr[1] == vOld)
+ {
+ vertexNr[1] = vNew;
+ }
+ else if (vertexNr[2] == vOld)
+ {
+ vertexNr[2] = vNew;
+ }
+ else
+ {
+ PX_ASSERT(0 && "replaceVertex failed");
+ }
+ }
+
+ bool operator == (SubdividerTriangle& t) const
+ {
+ return
+ t.containsVertex(vertexNr[0]) &&
+ t.containsVertex(vertexNr[1]) &&
+ t.containsVertex(vertexNr[2]);
+ }
+ bool isValid() const
+ {
+ return (vertexNr[0] != vertexNr[1] && vertexNr[0] != vertexNr[2] && vertexNr[1] != vertexNr[2]);
+ }
+
+ uint32_t vertexNr[3];
+ };
+
+ struct TriangleList
+ {
+ TriangleList() : triangleNumber(0), nextTriangle(-1) {}
+ TriangleList(uint32_t tNr) : triangleNumber(tNr), nextTriangle(-1) {}
+
+ uint32_t triangleNumber;
+ int32_t nextTriangle;
+ };
+
+ Array<SubdividerVertex> mVertices;
+ Array<SubdividerTriangle> mTriangles;
+ uint32_t mMarkedVertices;
+
+ QDSRand mRand;
+
+ Array<TriangleList> mTriangleList;
+ int32_t mTriangleListEmptyElement;
+ void addTriangleToVertex(uint32_t vertexNumber, uint32_t triangleNumber);
+ void removeTriangleFromVertex(uint32_t vertexNumber, uint32_t triangleNumber);
+ TriangleList& allocateTriangleElement();
+ void freeTriangleElement(uint32_t index);
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif
diff --git a/APEX_1.4/common/include/ApexTest.h b/APEX_1.4/common/include/ApexTest.h
new file mode 100644
index 00000000..d20267f7
--- /dev/null
+++ b/APEX_1.4/common/include/ApexTest.h
@@ -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.
+ */
+
+
+#ifndef APEX_TEST_H
+#define APEX_TEST_H
+
+#define WARNING(exp, msg) if (!(exp)) {ret &= (exp); APEX_DEBUG_WARNING(msg);}
+#define EXPECT_TRUE(exp) WARNING(exp, "Expected true: " #exp)
+#define EXPECT_EQ(v1, v2) WARNING(v1 == v2, "Expected: " #v1 " == " #v2)
+#define EXPECT_NE(v1, v2) WARNING(v1 != v2, "Expected: " #v1 " != " #v2)
+#define EXPECT_GE(v1, v2) WARNING(v1 >= v2, "Expected: " #v1 " >= " #v2)
+#define EXPECT_GT(v1, v2) WARNING(v1 > v2, "Expected: " #v1 " > " #v2)
+#define EXPECT_LE(v1, v2) WARNING(v1 <= v2, "Expected: " #v1 " <= " #v2)
+#define EXPECT_LT(v1, v2) WARNING(v1 < v2, "Expected: " #v1 " < " #v2)
+
+#endif //APEX_TEST_H
diff --git a/APEX_1.4/common/include/ApexTetrahedralizer.h b/APEX_1.4/common/include/ApexTetrahedralizer.h
new file mode 100644
index 00000000..77fc67b2
--- /dev/null
+++ b/APEX_1.4/common/include/ApexTetrahedralizer.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 APEX_TETRAHEDRALIZER_H
+#define APEX_TETRAHEDRALIZER_H
+
+#include "ApexDefs.h"
+#include "PxBounds3.h"
+
+#include "ApexUsingNamespace.h"
+#include "PsArray.h"
+#include "PsUserAllocated.h"
+
+#define TETRAHEDRALIZER_DEBUG_RENDERING 0
+
+namespace nvidia
+{
+namespace apex
+{
+
+class ApexMeshHash;
+class IProgressListener;
+
+class ApexTetrahedralizer : public UserAllocated
+{
+public:
+ ApexTetrahedralizer(uint32_t subdivision);
+ ~ApexTetrahedralizer();
+
+
+ void registerVertex(const PxVec3& v);
+ void registerTriangle(uint32_t i0, uint32_t i1, uint32_t i2);
+ void endRegistration(IProgressListener* progress);
+
+ uint32_t getNumVertices() const
+ {
+ return mVertices.size();
+ }
+ void getVertices(PxVec3* data);
+ uint32_t getNumIndices() const
+ {
+ return mTetras.size() * 4;
+ }
+ void getIndices(uint32_t* data);
+
+private:
+ struct FullTetrahedron;
+
+ void weldVertices();
+ void delaunayTetrahedralization(IProgressListener* progress);
+ int32_t findSurroundingTetra(uint32_t startTetra, const PxVec3& p) const;
+ float retriangulate(const uint32_t tetraNr, uint32_t vertexNr);
+ uint32_t swapTetrahedra(uint32_t startTet, IProgressListener* progress);
+ bool swapEdge(uint32_t v0, uint32_t v1);
+ bool removeOuterTetrahedra(IProgressListener* progress);
+
+ void updateCircumSphere(FullTetrahedron& tetra) const;
+ bool pointInCircumSphere(FullTetrahedron& tetra, const PxVec3& p) const;
+ bool pointInTetra(const FullTetrahedron& tetra, const PxVec3& p) const;
+
+ float getTetraVolume(const FullTetrahedron& tetra) const;
+ float getTetraVolume(int32_t v0, int32_t v1, int32_t v2, int32_t v3) const;
+ float getTetraQuality(const FullTetrahedron& tetra) const;
+ float getTetraLongestEdge(const FullTetrahedron& tetra) const;
+
+ bool triangleContainsVertexNr(uint32_t* triangle, uint32_t* vertexNumber, uint32_t nbVertices);
+
+ void compressTetrahedra(bool trashNeighbours);
+ void compressVertices();
+
+ inline bool isFarVertex(uint32_t vertNr) const
+ {
+ return mFirstFarVertex <= vertNr && vertNr <= mLastFarVertex;
+ }
+
+ ApexMeshHash* mMeshHash;
+
+ uint32_t mSubdivision;
+
+ PxBounds3 mBound;
+ float mBoundDiagonal;
+
+ struct TetraVertex
+ {
+ inline void init(const PxVec3& pos, uint32_t flags)
+ {
+ this->pos = pos;
+ this->flags = flags;
+ }
+ inline bool isDeleted() const
+ {
+ return flags == (uint32_t)0xdeadf00d;
+ }
+ inline void markDeleted()
+ {
+ flags = 0xdeadf00d;
+ }
+
+ PxVec3 pos;
+ uint32_t flags;
+ };
+ class LessInOneAxis
+ {
+ uint32_t mAxis;
+ public:
+ LessInOneAxis(uint32_t axis) : mAxis(axis) {}
+ bool operator()(const TetraVertex& v1, const TetraVertex& v2) const
+ {
+ return v1.pos[mAxis] < v2.pos[mAxis];
+ }
+ };
+
+ struct TetraEdge
+ {
+ void init(int32_t v0, int32_t v1, int32_t tetra, int neighborNr = -1)
+ {
+ this->tetraNr = (uint32_t)tetra;
+ this->neighborNr = neighborNr;
+ PX_ASSERT(v0 != v1);
+ vNr0 = (uint32_t)PxMin(v0, v1);
+ vNr1 = (uint32_t)PxMax(v0, v1);
+ }
+ PX_INLINE bool operator <(const TetraEdge& e) const
+ {
+ if (vNr0 < e.vNr0)
+ {
+ return true;
+ }
+ if (vNr0 > e.vNr0)
+ {
+ return false;
+ }
+ if (vNr1 < e.vNr1)
+ {
+ return true;
+ }
+ if (vNr1 > e.vNr1)
+ {
+ return false;
+ }
+ return (neighborNr < e.neighborNr);
+ }
+ PX_INLINE bool operator()(const TetraEdge& e1, const TetraEdge& e2) const
+ {
+ return e1 < e2;
+ }
+ bool operator ==(TetraEdge& e) const
+ {
+ return vNr0 == e.vNr0 && vNr1 == e.vNr1;
+ }
+
+ bool allEqual(TetraEdge& e) const
+ {
+ return (vNr0 == e.vNr0) && (vNr1 == e.vNr1) && (neighborNr == e.neighborNr);
+ }
+ uint32_t vNr0, vNr1;
+ uint32_t tetraNr;
+ int32_t neighborNr;
+ };
+
+
+ struct TetraEdgeList
+ {
+ void add(TetraEdge& edge)
+ {
+ mEdges.pushBack(edge);
+ }
+ void insert(uint32_t pos, TetraEdge& edge);
+ uint32_t numEdges()
+ {
+ return mEdges.size();
+ }
+ void sort();
+ int findEdge(int v0, int v1);
+ int findEdgeTetra(int v0, int v1, int tetraNr);
+ TetraEdge& operator[](unsigned i)
+ {
+ return mEdges[i];
+ }
+ const TetraEdge& operator[](unsigned i) const
+ {
+ return mEdges[i];
+ }
+
+ physx::Array<TetraEdge> mEdges;
+ };
+
+
+ struct FullTetrahedron
+ {
+ void init()
+ {
+ vertexNr[0] = vertexNr[1] = vertexNr[2] = vertexNr[3] = -1;
+ neighborNr[0] = neighborNr[1] = neighborNr[2] = neighborNr[3] = -1;
+ center = PxVec3(0.0f);
+ radiusSquared = 0.0f;
+ quality = 0;
+ bCircumSphereDirty = 1;
+ bDeleted = 0;
+ }
+ void set(int32_t v0, int32_t v1, int32_t v2, int32_t v3)
+ {
+ vertexNr[0] = v0;
+ vertexNr[1] = v1;
+ vertexNr[2] = v2;
+ vertexNr[3] = v3;
+ neighborNr[0] = neighborNr[1] = neighborNr[2] = neighborNr[3] = -1;
+ center = PxVec3(0.0f);
+ radiusSquared = 0.0f;
+ quality = 0;
+ bCircumSphereDirty = 1;
+ bDeleted = 0;
+ }
+ bool operator==(const FullTetrahedron& t) const
+ {
+ return
+ (vertexNr[0] == t.vertexNr[0]) &&
+ (vertexNr[1] == t.vertexNr[1]) &&
+ (vertexNr[2] == t.vertexNr[2]) &&
+ (vertexNr[3] == t.vertexNr[3]);
+ }
+
+ bool containsVertex(int32_t nr) const
+ {
+ return (vertexNr[0] == nr || vertexNr[1] == nr || vertexNr[2] == nr || vertexNr[3] == nr);
+ }
+ void replaceVertex(int nr, int newNr)
+ {
+ if (vertexNr[0] == nr)
+ {
+ vertexNr[0] = newNr;
+ }
+ else if (vertexNr[1] == nr)
+ {
+ vertexNr[1] = newNr;
+ }
+ else if (vertexNr[2] == nr)
+ {
+ vertexNr[2] = newNr;
+ }
+ else if (vertexNr[3] == nr)
+ {
+ vertexNr[3] = newNr;
+ }
+ else
+ {
+ PX_ASSERT(0);
+ }
+ }
+ void get2OppositeVertices(int vNr0, int vNr1, int& vNr2, int& vNr3)
+ {
+ int v[4], p = 0;
+ if (vertexNr[0] != vNr0 && vertexNr[0] != vNr1)
+ {
+ v[p++] = vertexNr[0];
+ }
+ if (vertexNr[1] != vNr0 && vertexNr[1] != vNr1)
+ {
+ v[p++] = vertexNr[1];
+ }
+ if (vertexNr[2] != vNr0 && vertexNr[2] != vNr1)
+ {
+ v[p++] = vertexNr[2];
+ }
+ if (vertexNr[3] != vNr0 && vertexNr[3] != vNr1)
+ {
+ v[p++] = vertexNr[3];
+ }
+ PX_ASSERT(p == 2);
+ vNr2 = v[0];
+ vNr3 = v[1];
+ }
+ void get3OppositeVertices(int vNr, int& vNr0, int& vNr1, int& vNr2)
+ {
+ if (vNr == vertexNr[0])
+ {
+ vNr0 = vertexNr[1];
+ vNr1 = vertexNr[2];
+ vNr2 = vertexNr[3];
+ }
+ else if (vNr == vertexNr[1])
+ {
+ vNr0 = vertexNr[2];
+ vNr1 = vertexNr[0];
+ vNr2 = vertexNr[3];
+ }
+ else if (vNr == vertexNr[2])
+ {
+ vNr0 = vertexNr[0];
+ vNr1 = vertexNr[1];
+ vNr2 = vertexNr[3];
+ }
+ else if (vNr == vertexNr[3])
+ {
+ vNr0 = vertexNr[2];
+ vNr1 = vertexNr[1];
+ vNr2 = vertexNr[0];
+ }
+ else
+ {
+ PX_ASSERT(0);
+ }
+ }
+ int getOppositeVertex(int vNr0, int vNr1, int vNr2)
+ {
+ if (vertexNr[0] != vNr0 && vertexNr[0] != vNr1 && vertexNr[0] != vNr2)
+ {
+ return vertexNr[0];
+ }
+ if (vertexNr[1] != vNr0 && vertexNr[1] != vNr1 && vertexNr[1] != vNr2)
+ {
+ return vertexNr[1];
+ }
+ if (vertexNr[2] != vNr0 && vertexNr[2] != vNr1 && vertexNr[2] != vNr2)
+ {
+ return vertexNr[2];
+ }
+ if (vertexNr[3] != vNr0 && vertexNr[3] != vNr1 && vertexNr[3] != vNr2)
+ {
+ return vertexNr[3];
+ }
+ PX_ASSERT(0);
+ return -1;
+ }
+ int sideOf(int vNr0, int vNr1, int vNr2)
+ {
+ if (vertexNr[0] != vNr0 && vertexNr[0] != vNr1 && vertexNr[0] != vNr2)
+ {
+ return 0;
+ }
+ if (vertexNr[1] != vNr0 && vertexNr[1] != vNr1 && vertexNr[1] != vNr2)
+ {
+ return 1;
+ }
+ if (vertexNr[2] != vNr0 && vertexNr[2] != vNr1 && vertexNr[2] != vNr2)
+ {
+ return 2;
+ }
+ if (vertexNr[3] != vNr0 && vertexNr[3] != vNr1 && vertexNr[3] != vNr2)
+ {
+ return 3;
+ }
+ PX_ASSERT(0);
+ return -1;
+ }
+ inline int neighborNrOf(int vNr0, int vNr1, int vNr2)
+ {
+ PX_ASSERT(containsVertex(vNr0));
+ PX_ASSERT(containsVertex(vNr1));
+ PX_ASSERT(containsVertex(vNr2));
+ if (vertexNr[0] != vNr0 && vertexNr[0] != vNr1 && vertexNr[0] != vNr2)
+ {
+ return 0;
+ }
+ if (vertexNr[1] != vNr0 && vertexNr[1] != vNr1 && vertexNr[1] != vNr2)
+ {
+ return 1;
+ }
+ if (vertexNr[2] != vNr0 && vertexNr[2] != vNr1 && vertexNr[2] != vNr2)
+ {
+ return 2;
+ }
+ if (vertexNr[3] != vNr0 && vertexNr[3] != vNr1 && vertexNr[3] != vNr2)
+ {
+ return 3;
+ }
+ PX_ASSERT(0);
+ return 0;
+ }
+ inline int& neighborOf(int vNr0, int vNr1, int vNr2)
+ {
+ return neighborNr[neighborNrOf(vNr0, vNr1, vNr2)];
+ }
+
+ inline bool onSurface()
+ {
+ return neighborNr[0] < 0 || neighborNr[1] < 0 || neighborNr[2] < 0 || neighborNr[3] < 0;
+ }
+ // representation
+ PxVec3 center;
+ int32_t vertexNr[4];
+ int32_t neighborNr[4];
+ float radiusSquared;
+ uint32_t quality : 10;
+ uint32_t bDeleted : 1;
+ uint32_t bCircumSphereDirty : 1;
+
+ // static
+ static const uint32_t sideIndices[4][3];
+ };
+
+ physx::Array<FullTetrahedron> mTetras;
+
+ uint32_t mFirstFarVertex;
+ uint32_t mLastFarVertex;
+
+ physx::Array<TetraVertex> mVertices;
+ physx::Array<uint32_t> mIndices;
+
+ // temporary indices, that way we don't allocate this buffer all the time
+ physx::Array<uint32_t> mTempItemIndices;
+
+#if TETRAHEDRALIZER_DEBUG_RENDERING
+public:
+ physx::Array<PxVec3> debugLines;
+ physx::Array<PxVec3> debugBounds;
+ physx::Array<PxVec3> debugTetras;
+#endif
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif // APEX_TETRAHEDRALIZER_H
diff --git a/APEX_1.4/common/include/AuthorableObjectIntl.h b/APEX_1.4/common/include/AuthorableObjectIntl.h
new file mode 100644
index 00000000..89012a1d
--- /dev/null
+++ b/APEX_1.4/common/include/AuthorableObjectIntl.h
@@ -0,0 +1,92 @@
+/*
+ * 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 AUTHORABLE_OBJECT_INTL_H
+#define AUTHORABLE_OBJECT_INTL_H
+
+#include "ApexString.h"
+#include "ApexSDKIntl.h"
+#include "ApexSDKHelpers.h"
+#include "ResourceProviderIntl.h"
+#include "ApexResource.h"
+
+class ResourceList;
+
+namespace NvParameterized
+{
+class Interface;
+};
+
+namespace nvidia
+{
+namespace apex
+{
+
+// This class currently contains implementation, this will be removed and put in APEXAuthorableObject
+class AuthorableObjectIntl : public ApexResourceInterface, public ApexResource
+{
+public:
+
+ AuthorableObjectIntl(ModuleIntl* m, ResourceList& list, const char* aoTypeName)
+ : mAOTypeName(aoTypeName),
+ mModule(m)
+ {
+ list.add(*this);
+ }
+
+ virtual Asset* createAsset(AssetAuthoring& author, const char* name) = 0;
+ virtual Asset* createAsset(NvParameterized::Interface* params, const char* name) = 0;
+ virtual void releaseAsset(Asset& nxasset) = 0;
+
+ virtual AssetAuthoring* createAssetAuthoring() = 0;
+ virtual AssetAuthoring* createAssetAuthoring(const char* name) = 0;
+ virtual AssetAuthoring* createAssetAuthoring(NvParameterized::Interface* params, const char* name) = 0;
+ virtual void releaseAssetAuthoring(AssetAuthoring& nxauthor) = 0;
+
+ virtual uint32_t forceLoadAssets() = 0;
+ virtual uint32_t getAssetCount() = 0;
+ virtual bool getAssetList(Asset** outAssets, uint32_t& outAssetCount, uint32_t inAssetCount) = 0;
+
+
+ virtual ResID getResID() = 0;
+ virtual ApexSimpleString& getName() = 0;
+
+ // ApexResourceInterface methods
+ virtual void release() = 0;
+ virtual void destroy() = 0;
+
+ // ApexResourceInterface methods
+ uint32_t getListIndex() const
+ {
+ return m_listIndex;
+ }
+
+ void setListIndex(ResourceList& list, uint32_t index)
+ {
+ m_listIndex = index;
+ m_list = &list;
+ }
+
+ ResID mAOResID;
+ ResID mAOPtrResID;
+ ApexSimpleString mAOTypeName;
+ ApexSimpleString mParameterizedName;
+
+ ResourceList mAssets;
+ ResourceList mAssetAuthors;
+
+ ModuleIntl* mModule;
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif // AUTHORABLE_OBJECT_INTL_H
diff --git a/APEX_1.4/common/include/Cof44.h b/APEX_1.4/common/include/Cof44.h
new file mode 100644
index 00000000..88bcdff3
--- /dev/null
+++ b/APEX_1.4/common/include/Cof44.h
@@ -0,0 +1,135 @@
+/*
+ * 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 COF44_H
+#define COF44_H
+
+#include "Apex.h"
+#include "PxMat44.h"
+#include "PxPlane.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+/**
+\brief Stores the info needed for the cofactor matrix of a 4x4 homogeneous transformation matrix (implicit last row = 0 0 0 1)
+*/
+class Cof44
+{
+public:
+ /**
+ \param [in] m can be an arbitrary homogeneoous transformation matrix
+ */
+ Cof44(const PxMat44& m)
+ {
+ _block33(0, 0) = m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1);
+ _block33(0, 1) = m(1, 2) * m(2, 0) - m(1, 0) * m(2, 2);
+ _block33(0, 2) = m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0);
+ _block33(1, 0) = m(2, 1) * m(0, 2) - m(2, 2) * m(0, 1);
+ _block33(1, 1) = m(2, 2) * m(0, 0) - m(2, 0) * m(0, 2);
+ _block33(1, 2) = m(2, 0) * m(0, 1) - m(2, 1) * m(0, 0);
+ _block33(2, 0) = m(0, 1) * m(1, 2) - m(0, 2) * m(1, 1);
+ _block33(2, 1) = m(0, 2) * m(1, 0) - m(0, 0) * m(1, 2);
+ _block33(2, 2) = m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0);
+ _44 = _block33(0, 0) * m(0, 0) + _block33(0, 1) * m(0, 1) + _block33(0, 2) * m(0, 2);
+
+ initCommon(m.getPosition());
+ }
+
+ /**
+ \param [in] rt must be pure (proper) rotation and translation
+ \param [in] s is any diagonal matrix (typically scale).
+ \note The combined transform is assumed to be (rt)*s, i.e. s is applied first
+ */
+ Cof44(const PxMat44& rt, const PxVec3 s)
+ {
+ const PxVec3 cofS(s.y * s.z, s.z * s.x, s.x * s.y);
+ _block33(0, 0) = rt(0, 0) * cofS.x;
+ _block33(0, 1) = rt(0, 1) * cofS.y;
+ _block33(0, 2) = rt(0, 2) * cofS.z;
+ _block33(1, 0) = rt(1, 0) * cofS.x;
+ _block33(1, 1) = rt(1, 1) * cofS.y;
+ _block33(1, 2) = rt(1, 2) * cofS.z;
+ _block33(2, 0) = rt(2, 0) * cofS.x;
+ _block33(2, 1) = rt(2, 1) * cofS.y;
+ _block33(2, 2) = rt(2, 2) * cofS.z;
+ _44 = cofS.x * s.x;
+
+ initCommon(rt.getPosition());
+ }
+
+ Cof44(const PxTransform rt, const PxVec3 s)
+ {
+ _block33 = PxMat33(rt.q);
+ const PxVec3 cofS(s.y * s.z, s.z * s.x, s.x * s.y);
+ _block33.column0 *= cofS.x;
+ _block33.column1 *= cofS.y;
+ _block33.column2 *= cofS.z;
+ _44 = cofS.x * s.x;
+
+ initCommon(rt.p);
+ }
+
+ /**
+ \brief Transforms a plane equation correctly even when the transformation is not a rotation
+ \note If the transformation is not a rotation then the length of the plane's normal vector is not preserved in general.
+ */
+ void transform(const PxPlane& src, PxPlane& dst) const
+ {
+ dst.n = _block33.transform(src.n);
+ dst.d = (_block13.dot(src.n)) + _44 * src.d;
+ }
+
+ /**
+ \brief Transforms a normal correctly even when the transformation is not a rotation
+ \note If the transformation is not a rotation then the normal's length is not preserved in general.
+ */
+ const PxMat33& getBlock33() const
+ {
+ return _block33;
+ }
+
+ /**
+ \brief The determinant of the original matrix.
+ */
+ float getDeterminant() const
+ {
+ return _44;
+ }
+
+private:
+
+ void initCommon(const PxVec3& pos)
+ {
+ _block13 = _block33.transformTranspose(-pos);
+ if (_44 < 0)
+ {
+ // det is < 0, we need to negate all values
+ // The Cov Matrix divided by the determinant is the same as the inverse transposed of an affine transformation
+ // For rotation normals, dividing by the determinant is useless as it gets renormalized afterwards again.
+ // If the determinant is negative though, it is important that all values are negated to get the right results.
+ _block33 *= -1;
+ _block13 *= -1;
+ _44 = -_44;
+ }
+
+ }
+ PxMat33 _block33;
+ PxVec3 _block13;
+ float _44;
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif \ No newline at end of file
diff --git a/APEX_1.4/common/include/CurveImpl.h b/APEX_1.4/common/include/CurveImpl.h
new file mode 100644
index 00000000..0d58721b
--- /dev/null
+++ b/APEX_1.4/common/include/CurveImpl.h
@@ -0,0 +1,83 @@
+/*
+ * 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 __CURVE_IMPL_H__
+#define __CURVE_IMPL_H__
+
+#include "Apex.h"
+#include "PxAssert.h"
+#include "nvparameterized/NvParameterized.h"
+#include "PsArray.h"
+#include "Curve.h"
+#include <ApexUsingNamespace.h>
+
+namespace nvidia
+{
+namespace apex
+{
+
+typedef physx::Array<Vec2R> Vec2RPointArray;
+
+/**
+ The CurveImpl is a class for storing control points on a curve and evaluating the results later.
+*/
+class CurveImpl : public Curve
+{
+public:
+ CurveImpl()
+ {}
+
+ ~CurveImpl()
+ {}
+
+ /**
+ Retrieve the output Y for the specified input x, based on the properties of the stored curve described
+ by mControlPoints.
+ */
+ float evaluate(float x) const;
+
+ /**
+ Add a control point to the list of control points, returning the index of the new point.
+ */
+ uint32_t addControlPoint(const Vec2R& controlPoint);
+
+ /**
+ Add a control points to the list of control points. Assuming the
+ hPoints points to a list of vec2s
+ */
+ void addControlPoints(::NvParameterized::Interface* param, ::NvParameterized::Handle& hPoints);
+
+ /**
+ Locates the control points that contain x, placing the resulting control points in the two
+ out parameters. Returns true if the points were found, false otherwise. If the points were not
+ found, the output variables are untouched
+ */
+ bool calculateControlPoints(float x, Vec2R& outXPoints, Vec2R& outYPoints) const;
+
+ /**
+ Locates the first control point with x larger than xValue or the nimber of control points if such point doesn't exist
+ */
+ uint32_t calculateFollowingControlPoint(float xValue) const;
+
+ ///get the array of control points
+ const Vec2R* getControlPoints(uint32_t& outCount) const;
+
+private:
+ // mControlPoints is a sorted list of control points for a curve. Currently, the curve is a lame
+ // lirp'd curve. We could add support for other curvetypes in the future, either bezier curves,
+ // splines, etc.
+ Vec2RPointArray mControlPoints;
+};
+
+}
+} // namespace apex
+
+#endif /* __CURVE_IMPL_H__ */
diff --git a/APEX_1.4/common/include/DebugColorParamsEx.h b/APEX_1.4/common/include/DebugColorParamsEx.h
new file mode 100644
index 00000000..9cb6c070
--- /dev/null
+++ b/APEX_1.4/common/include/DebugColorParamsEx.h
@@ -0,0 +1,65 @@
+/*
+ * 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 HEADER_DebugColorParamsListener_h
+#define HEADER_DebugColorParamsListener_h
+
+#include "NvParameters.h"
+#include "nvparameterized/NvParameterized.h"
+#include "nvparameterized/NvParameterizedTraits.h"
+
+#include "DebugColorParams.h"
+#include "ApexSDKIntl.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+#define MAX_COLOR_NAME_LENGTH 32
+
+class DebugColorParamsEx : public DebugColorParams
+{
+public:
+ DebugColorParamsEx(NvParameterized::Traits* traits, ApexSDKIntl* mSdk) :
+ DebugColorParams(traits),
+ mApexSdk(mSdk) {}
+
+ ~DebugColorParamsEx()
+ {
+ }
+
+ void destroy()
+ {
+ this->~DebugColorParamsEx();
+ this->DebugColorParams::destroy();
+ }
+
+ NvParameterized::ErrorType setParamU32(const NvParameterized::Handle& handle, uint32_t val)
+ {
+ NvParameterized::ErrorType err = NvParameterized::NvParameters::setParamU32(handle, val);
+
+ NvParameterized::Handle& h = const_cast<NvParameterized::Handle&>(handle);
+ char color[MAX_COLOR_NAME_LENGTH];
+ h.getLongName(color, MAX_COLOR_NAME_LENGTH);
+ mApexSdk->updateDebugColorParams(color, val);
+
+ return err;
+ }
+
+private:
+ ApexSDKIntl* mApexSdk;
+};
+
+}
+} // namespace nvidia::apex::
+
+#endif \ No newline at end of file
diff --git a/APEX_1.4/common/include/DeclareArray.h b/APEX_1.4/common/include/DeclareArray.h
new file mode 100644
index 00000000..aca822d5
--- /dev/null
+++ b/APEX_1.4/common/include/DeclareArray.h
@@ -0,0 +1,25 @@
+/*
+ * 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 DECLARE_ARRAY_H
+
+#define DECLARE_ARRAY_H
+
+#error "Do not include DeclareArray.h anywhere!"
+// PH: Also, don't use DeclareArray anymore, use physx::Array< > or Array< > directly
+
+#include "ApexUsingNamespace.h"
+#include "PsArray.h"
+
+#define DeclareArray(x) physx::Array< x >
+
+
+#endif
diff --git a/APEX_1.4/common/include/FieldBoundaryIntl.h b/APEX_1.4/common/include/FieldBoundaryIntl.h
new file mode 100644
index 00000000..b799b8ac
--- /dev/null
+++ b/APEX_1.4/common/include/FieldBoundaryIntl.h
@@ -0,0 +1,72 @@
+/*
+ * 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 FIELD_BOUNDARY_INTL_H
+#define FIELD_BOUNDARY_INTL_H
+
+#include "InplaceTypes.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+
+struct FieldShapeTypeIntl
+{
+ enum Enum
+ {
+ NONE = 0,
+ SPHERE,
+ BOX,
+ CAPSULE,
+
+ FORCE_DWORD = 0xFFFFFFFFu
+ };
+};
+
+//struct FieldShapeDescIntl
+//dimensions for
+//SPHERE: x = radius
+//BOX: (x,y,z) = 1/2 size
+//CAPUSE: x = radius, y = height
+#define INPLACE_TYPE_STRUCT_NAME FieldShapeDescIntl
+#define INPLACE_TYPE_STRUCT_FIELDS \
+ INPLACE_TYPE_FIELD(InplaceEnum<FieldShapeTypeIntl::Enum>, type) \
+ INPLACE_TYPE_FIELD(PxTransform, worldToShape) \
+ INPLACE_TYPE_FIELD(PxVec3, dimensions) \
+ INPLACE_TYPE_FIELD(float, weight)
+#include INPLACE_TYPE_BUILD()
+
+
+#ifndef __CUDACC__
+
+struct FieldBoundaryDescIntl
+{
+#if PX_PHYSICS_VERSION_MAJOR == 3
+ PxFilterData boundaryFilterData;
+#endif
+};
+
+class FieldBoundaryIntl
+{
+public:
+ virtual bool updateFieldBoundary(physx::Array<FieldShapeDescIntl>& shapes) = 0;
+
+protected:
+ virtual ~FieldBoundaryIntl() {}
+};
+#endif
+
+}
+} // end namespace nvidia::apex
+
+#endif // #ifndef FIELD_BOUNDARY_INTL_H
diff --git a/APEX_1.4/common/include/FieldSamplerIntl.h b/APEX_1.4/common/include/FieldSamplerIntl.h
new file mode 100644
index 00000000..b4a7cae9
--- /dev/null
+++ b/APEX_1.4/common/include/FieldSamplerIntl.h
@@ -0,0 +1,144 @@
+/*
+ * 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 FIELD_SAMPLER_INTL_H
+#define FIELD_SAMPLER_INTL_H
+
+#include "InplaceTypes.h"
+#include "FieldBoundaryIntl.h"
+
+#ifndef __CUDACC__
+#include "ApexSDKIntl.h"
+#endif
+
+namespace nvidia
+{
+namespace apex
+{
+
+
+struct FieldSamplerTypeIntl
+{
+ enum Enum
+ {
+ FORCE,
+ ACCELERATION,
+ VELOCITY_DRAG,
+ VELOCITY_DIRECT,
+ };
+};
+
+struct FieldSamplerGridSupportTypeIntl
+{
+ enum Enum
+ {
+ NONE = 0,
+ SINGLE_VELOCITY,
+ VELOCITY_PER_CELL,
+ };
+};
+
+#ifndef __CUDACC__
+
+struct FieldSamplerDescIntl
+{
+ FieldSamplerTypeIntl::Enum type;
+ FieldSamplerGridSupportTypeIntl::Enum gridSupportType;
+ bool cpuSimulationSupport;
+#if PX_PHYSICS_VERSION_MAJOR == 3
+ PxFilterData samplerFilterData;
+ PxFilterData boundaryFilterData;
+#endif
+ float boundaryFadePercentage;
+
+ float dragCoeff; //only used then type is VELOCITY_DRAG
+
+ void* userData;
+
+ FieldSamplerDescIntl()
+ {
+ type = FieldSamplerTypeIntl::FORCE;
+ gridSupportType = FieldSamplerGridSupportTypeIntl::NONE;
+ cpuSimulationSupport = true;
+#if PX_PHYSICS_VERSION_MAJOR == 3
+ samplerFilterData.word0 = 0xFFFFFFFF;
+ samplerFilterData.word1 = 0xFFFFFFFF;
+ samplerFilterData.word2 = 0xFFFFFFFF;
+ samplerFilterData.word3 = 0xFFFFFFFF;
+ boundaryFilterData.word0 = 0xFFFFFFFF;
+ boundaryFilterData.word1 = 0xFFFFFFFF;
+ boundaryFilterData.word2 = 0xFFFFFFFF;
+ boundaryFilterData.word3 = 0xFFFFFFFF;
+#endif
+ boundaryFadePercentage = 0.1;
+ dragCoeff = 0;
+ userData = NULL;
+ }
+};
+
+
+class FieldSamplerIntl
+{
+public:
+ //returns true if shape/params was changed
+ //required to return true on first call!
+ virtual bool updateFieldSampler(FieldShapeDescIntl& shapeDesc, bool& isEnabled) = 0;
+
+ struct ExecuteData
+ {
+ uint32_t count;
+ uint32_t positionStride;
+ uint32_t velocityStride;
+ uint32_t massStride;
+ uint32_t indicesMask;
+ const float* position;
+ const float* velocity;
+ const float* mass;
+ const uint32_t* indices;
+ PxVec3* resultField;
+ };
+
+ virtual void executeFieldSampler(const ExecuteData& data)
+ {
+ PX_UNUSED(data);
+ APEX_INVALID_OPERATION("not implemented");
+ }
+
+#if APEX_CUDA_SUPPORT
+ struct CudaExecuteInfo
+ {
+ uint32_t executeType;
+ InplaceHandleBase executeParamsHandle;
+ };
+
+ virtual void getFieldSamplerCudaExecuteInfo(CudaExecuteInfo& info) const
+ {
+ PX_UNUSED(info);
+ APEX_INVALID_OPERATION("not implemented");
+ }
+#endif
+
+ virtual PxVec3 queryFieldSamplerVelocity() const
+ {
+ APEX_INVALID_OPERATION("not implemented");
+ return PxVec3(0.0f);
+ }
+
+protected:
+ virtual ~FieldSamplerIntl() {}
+};
+
+#endif // __CUDACC__
+
+}
+} // end namespace nvidia::apex
+
+#endif // #ifndef FIELD_SAMPLER_INTL_H
diff --git a/APEX_1.4/common/include/FieldSamplerManagerIntl.h b/APEX_1.4/common/include/FieldSamplerManagerIntl.h
new file mode 100644
index 00000000..3822496e
--- /dev/null
+++ b/APEX_1.4/common/include/FieldSamplerManagerIntl.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.
+ */
+
+
+#ifndef FIELD_SAMPLER_MANAGER_INTL_H
+#define FIELD_SAMPLER_MANAGER_INTL_H
+
+#include "Apex.h"
+#include "ApexSDKHelpers.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+struct FieldSamplerQueryDescIntl;
+class FieldSamplerQueryIntl;
+
+class FieldSamplerSceneIntl;
+
+struct FieldSamplerDescIntl;
+class FieldSamplerIntl;
+
+struct FieldBoundaryDescIntl;
+class FieldBoundaryIntl;
+
+class FieldSamplerManagerIntl
+{
+public:
+ virtual FieldSamplerQueryIntl* createFieldSamplerQuery(const FieldSamplerQueryDescIntl&) = 0;
+
+ virtual void registerFieldSampler(FieldSamplerIntl* , const FieldSamplerDescIntl& , FieldSamplerSceneIntl*) = 0;
+ virtual void unregisterFieldSampler(FieldSamplerIntl*) = 0;
+
+ virtual void registerFieldBoundary(FieldBoundaryIntl* , const FieldBoundaryDescIntl&) = 0;
+ virtual void unregisterFieldBoundary(FieldBoundaryIntl*) = 0;
+
+#if PX_PHYSICS_VERSION_MAJOR == 3
+ virtual void registerUnhandledParticleSystem(PxActor*) = 0;
+ virtual void unregisterUnhandledParticleSystem(PxActor*) = 0;
+ virtual bool isUnhandledParticleSystem(PxActor*) = 0;
+
+ virtual bool doFieldSamplerFiltering(const PxFilterData &o1, const PxFilterData &o2, float &weight) const = 0;
+#endif
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif // #ifndef FIELD_SAMPLER_MANAGER_INTL_H
diff --git a/APEX_1.4/common/include/FieldSamplerQueryIntl.h b/APEX_1.4/common/include/FieldSamplerQueryIntl.h
new file mode 100644
index 00000000..a72c7511
--- /dev/null
+++ b/APEX_1.4/common/include/FieldSamplerQueryIntl.h
@@ -0,0 +1,124 @@
+/*
+ * 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 FIELD_SAMPLER_QUERY_INTL_H
+#define FIELD_SAMPLER_QUERY_INTL_H
+
+#include "ApexDefs.h"
+#include "ApexMirroredArray.h"
+
+#include "PxTask.h"
+#include "ApexActor.h"
+#include "PxMat44.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+
+class FieldSamplerSceneIntl;
+
+struct FieldSamplerQueryDescIntl
+{
+ uint32_t maxCount;
+#if PX_PHYSICS_VERSION_MAJOR == 3
+ PxFilterData samplerFilterData;
+#endif
+ FieldSamplerSceneIntl* ownerFieldSamplerScene;
+
+
+ FieldSamplerQueryDescIntl()
+ {
+ maxCount = 0;
+#if PX_PHYSICS_VERSION_MAJOR == 3
+ samplerFilterData.word0 = 0xFFFFFFFF;
+ samplerFilterData.word1 = 0xFFFFFFFF;
+ samplerFilterData.word2 = 0xFFFFFFFF;
+ samplerFilterData.word3 = 0xFFFFFFFF;
+#endif
+ ownerFieldSamplerScene = 0;
+ }
+};
+
+struct FieldSamplerQueryDataIntl
+{
+ float timeStep;
+ uint32_t count;
+ bool isDataOnDevice;
+
+ uint32_t positionStrideBytes; //Stride for position
+ uint32_t velocityStrideBytes; //Stride for velocity
+ float* pmaInPosition;
+ float* pmaInVelocity;
+ PxVec4* pmaOutField;
+
+ uint32_t massStrideBytes; //if massStride set to 0 supposed single mass for all objects
+ float* pmaInMass;
+
+ uint32_t* pmaInIndices;
+};
+
+
+#if APEX_CUDA_SUPPORT
+
+class ApexCudaArray;
+
+struct FieldSamplerQueryGridDataIntl
+{
+ uint32_t numX, numY, numZ;
+
+ PxMat44 gridToWorld;
+
+ float mass;
+
+ float timeStep;
+
+ PxVec3 cellSize;
+
+ ApexCudaArray* resultVelocity; //x, y, z = velocity vector, w = weight
+
+ CUstream stream;
+};
+#endif
+
+class FieldSamplerCallbackIntl
+{
+public:
+ virtual void operator()(void* stream = NULL) = 0;
+};
+
+class FieldSamplerQueryIntl : public ApexActor
+{
+public:
+ virtual PxTaskID submitFieldSamplerQuery(const FieldSamplerQueryDataIntl& data, PxTaskID taskID) = 0;
+
+ //! FieldSamplerCallbackIntl will be called before FieldSampler computations
+ virtual void setOnStartCallback(FieldSamplerCallbackIntl*) = 0;
+ //! FieldSamplerCallbackIntl will be called after FieldSampler computations
+ virtual void setOnFinishCallback(FieldSamplerCallbackIntl*) = 0;
+
+#if APEX_CUDA_SUPPORT
+ virtual PxVec3 executeFieldSamplerQueryOnGrid(const FieldSamplerQueryGridDataIntl&)
+ {
+ APEX_INVALID_OPERATION("not implemented");
+ return PxVec3(0.0f);
+ }
+#endif
+
+protected:
+ virtual ~FieldSamplerQueryIntl() {}
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif // #ifndef FIELD_SAMPLER_QUERY_INTL_H
diff --git a/APEX_1.4/common/include/FieldSamplerSceneIntl.h b/APEX_1.4/common/include/FieldSamplerSceneIntl.h
new file mode 100644
index 00000000..bce7f960
--- /dev/null
+++ b/APEX_1.4/common/include/FieldSamplerSceneIntl.h
@@ -0,0 +1,85 @@
+/*
+ * 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 FIELD_SAMPLER_SCENE_INTL_H
+#define FIELD_SAMPLER_SCENE_INTL_H
+
+#include "ApexDefs.h"
+#include "PxTask.h"
+
+#include "ModuleIntl.h"
+#include "ApexSDKIntl.h"
+
+namespace nvidia
+{
+
+namespace fieldsampler
+{
+ struct FieldSamplerKernelLaunchDataIntl;
+}
+
+namespace apex
+{
+
+class ApexCudaConstStorage;
+
+struct FieldSamplerSceneDescIntl
+{
+ bool isPrimary;
+
+ FieldSamplerSceneDescIntl()
+ {
+ isPrimary = false;
+ }
+};
+
+struct FieldSamplerQueryDataIntl;
+
+class FieldSamplerSceneIntl : public ModuleSceneIntl
+{
+public:
+ virtual void getFieldSamplerSceneDesc(FieldSamplerSceneDescIntl& desc) const = 0;
+
+ virtual const PxTask* onSubmitFieldSamplerQuery(const FieldSamplerQueryDataIntl& data, const PxTask* )
+ {
+ PX_UNUSED(data);
+ return 0;
+ }
+
+#if APEX_CUDA_SUPPORT
+ virtual ApexCudaConstStorage* getFieldSamplerCudaConstStorage()
+ {
+ APEX_INVALID_OPERATION("not implemented");
+ return 0;
+ }
+
+ virtual bool launchFieldSamplerCudaKernel(const nvidia::fieldsampler::FieldSamplerKernelLaunchDataIntl&)
+ {
+ APEX_INVALID_OPERATION("not implemented");
+ return false;
+ }
+#endif
+
+ virtual SceneStats* getStats()
+ {
+ return 0;
+ }
+
+};
+
+#define FSST_PHYSX_MONITOR_LOAD "FieldSamplerScene::PhysXMonitorLoad"
+#define FSST_PHYSX_MONITOR_FETCH "FieldSamplerScene::PhysXMonitorFetch"
+#define FSST_PHYSX_MONITOR_UPDATE "FieldSamplerPhysXMonitor::Update"
+}
+
+} // end namespace nvidia::apex
+
+#endif // FIELD_SAMPLER_SCENE_INTL_H
diff --git a/APEX_1.4/common/include/InplaceStorage.h b/APEX_1.4/common/include/InplaceStorage.h
new file mode 100644
index 00000000..d2d81912
--- /dev/null
+++ b/APEX_1.4/common/include/InplaceStorage.h
@@ -0,0 +1,985 @@
+/*
+ * 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 __APEX_INPLACE_STORAGE_H__
+#define __APEX_INPLACE_STORAGE_H__
+
+#include "ApexUsingNamespace.h"
+#include "PsAllocator.h"
+#include "InplaceTypes.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+
+class InplaceStorage;
+
+class InplaceStorageGroup
+{
+ friend class InplaceStorage;
+
+ InplaceStorage* _storage;
+ uint32_t _lastBlockIndex;
+
+ InplaceStorageGroup* _groupListPrev;
+ InplaceStorageGroup* _groupListNext;
+
+ PX_INLINE void reset(InplaceStorage* storage)
+ {
+ PX_UNUSED(storage);
+ PX_ASSERT(_storage == storage);
+ _storage = 0;
+ }
+
+public:
+ PX_INLINE InplaceStorageGroup() : _storage(0) {}
+ PX_INLINE InplaceStorageGroup(InplaceStorage& storage) : _storage(0)
+ {
+ init(storage);
+ }
+ PX_INLINE ~InplaceStorageGroup()
+ {
+ release();
+ }
+
+ PX_INLINE void init(InplaceStorage& storage);
+ PX_INLINE void release();
+
+ PX_INLINE void begin();
+ PX_INLINE void end();
+
+ PX_INLINE InplaceStorage& getStorage()
+ {
+ PX_ASSERT(_storage != 0);
+ return *_storage;
+ }
+};
+
+class InplaceStorage
+{
+ struct ReflectorArg
+ {
+ };
+
+ class Reflector
+ {
+ InplaceStorage* _storage;
+ uint32_t _blockIndex;
+ uint8_t* _blockPtr;
+
+ public:
+ Reflector(InplaceStorage* storage, uint32_t blockIndex, uint8_t* blockPtr)
+ : _storage(storage), _blockIndex(blockIndex), _blockPtr(blockPtr)
+ {
+ }
+
+ template <int _inplace_offset_, typename MT>
+ PX_INLINE void processType(ReflectorArg, InplaceHandleBase& handle, MT )
+ {
+ size_t offset = size_t(reinterpret_cast<uint8_t*>(&handle) - _blockPtr);
+ _storage->addHandleRef(_blockIndex, offset, MT::AutoFreeValue);
+ }
+ template <int _inplace_offset_, typename T, typename MT>
+ PX_INLINE void processType(ReflectorArg ra, InplaceHandle<T>& handle, MT mt)
+ {
+ processType<_inplace_offset_>(ra, static_cast<InplaceHandleBase&>(handle), mt);
+ }
+ template <int _inplace_offset_, typename T, typename MT>
+ PX_INLINE void processType(ReflectorArg, T& , MT )
+ {
+ ; //do nothing
+ }
+
+ template <int _inplace_offset_, typename T>
+ PX_INLINE void processPrimitiveType(ReflectorArg, T& )
+ {
+ ; //do nothing
+ }
+ };
+ friend class Reflector;
+
+ static const uint32_t NULL_INDEX = InplaceHandleBase::NULL_VALUE;
+
+ struct Block
+ {
+ uint32_t _size;
+ uint32_t _alignment;
+ uint32_t _offset;
+ uint32_t _prevIndex;
+ union
+ {
+ uint32_t _nextIndex;
+ uint32_t _nextFreeBlockIndex;
+ };
+ uint32_t _firstRefIndex;
+ InplaceStorageGroup* _group;
+
+ void reset()
+ {
+ _alignment = 0;
+ _size = 0;
+ _offset = uint32_t(-1);
+ _prevIndex = _nextIndex = NULL_INDEX;
+ _firstRefIndex = NULL_INDEX;
+ _group = NULL;
+ }
+ };
+
+ struct HandleRef
+ {
+ enum Flags
+ {
+ AUTO_FREE = 0x01,
+ };
+ uint32_t flags;
+ uint32_t ownerBlockIndex;
+ uint32_t offsetInBlock;
+ union
+ {
+ uint32_t nextIndex;
+ uint32_t nextFreeRefIndex;
+ };
+
+ void reset()
+ {
+ flags = 0;
+ ownerBlockIndex = NULL_INDEX;
+ offsetInBlock = 0;
+ }
+ };
+
+ void addHandleRef(uint32_t blockIndex, size_t offset, bool autoFree)
+ {
+ //find free handleRef
+ if (_firstFreeRefIndex == NULL_INDEX)
+ {
+ _firstFreeRefIndex = _handleRefs.size();
+ _handleRefs.resize(_firstFreeRefIndex + 1);
+
+ _handleRefs.back().nextFreeRefIndex = NULL_INDEX;
+ }
+ uint32_t thisRefIndex = _firstFreeRefIndex;
+ HandleRef& handleRef = _handleRefs[thisRefIndex];
+ _firstFreeRefIndex = handleRef.nextFreeRefIndex;
+
+ Block& block = _blocks[blockIndex];
+ handleRef.nextIndex = block._firstRefIndex;
+ block._firstRefIndex = thisRefIndex;
+
+ handleRef.ownerBlockIndex = blockIndex;
+ handleRef.offsetInBlock = (uint32_t) offset;
+ handleRef.flags = 0;
+ if (autoFree)
+ {
+ handleRef.flags |= HandleRef::AUTO_FREE;
+ }
+ }
+
+ template <typename F>
+ void removeHandleRefs(F func, uint32_t blockIndex, uint32_t minOffset = 0)
+ {
+ Block& block = _blocks[blockIndex];
+
+ uint32_t prevRefIndex = NULL_INDEX;
+ uint32_t currRefIndex = block._firstRefIndex;
+ while (currRefIndex != NULL_INDEX)
+ {
+ HandleRef& handleRef = _handleRefs[currRefIndex];
+ PX_ASSERT(handleRef.ownerBlockIndex == blockIndex);
+
+ uint32_t nextRefIndex = handleRef.nextIndex;
+ if (handleRef.offsetInBlock >= minOffset)
+ {
+ //remove
+ if (handleRef.flags & HandleRef::AUTO_FREE)
+ {
+ uint32_t blockOffset = block._offset;
+ PX_ASSERT(blockOffset != uint32_t(-1));
+ InplaceHandleBase handle = *reinterpret_cast<InplaceHandleBase*>(getBufferPtr() + blockOffset + handleRef.offsetInBlock);
+
+ (this->*func)(block, handle);
+ }
+
+ if (prevRefIndex != NULL_INDEX)
+ {
+ _handleRefs[prevRefIndex].nextIndex = nextRefIndex;
+ }
+ else
+ {
+ block._firstRefIndex = nextRefIndex;
+ }
+
+ handleRef.nextFreeRefIndex = _firstFreeRefIndex;
+ _firstFreeRefIndex = currRefIndex;
+
+ handleRef.reset();
+ }
+ else
+ {
+ prevRefIndex = currRefIndex;
+ }
+ currRefIndex = nextRefIndex;
+ }
+ }
+
+
+ PX_INLINE void mapHandle(InplaceHandleBase& handle) const
+ {
+ if (handle._value != NULL_INDEX)
+ {
+ handle._value = _blocks[handle._value]._offset;
+ }
+ }
+ PX_INLINE uint8_t* getBufferPtr()
+ {
+ PX_ASSERT(_bufferPtr != 0);
+ _isChanged = true;
+ return _bufferPtr;
+ }
+ PX_INLINE const uint8_t* getBufferPtr() const
+ {
+ PX_ASSERT(_bufferPtr != 0);
+ return _bufferPtr;
+ }
+
+ template <typename T>
+ PX_INLINE const T* resolveType(InplaceHandleBase handle) const
+ {
+ if (handle._value != NULL_INDEX)
+ {
+ const Block& block = _blocks[handle._value];
+ PX_ASSERT(block._offset != uint32_t(-1));
+ return reinterpret_cast<const T*>(getBufferPtr() + block._offset);
+ }
+ return 0;
+ }
+ template <typename T>
+ PX_INLINE T* resolveType(InplaceHandleBase handle)
+ {
+ if (handle._value != NULL_INDEX)
+ {
+ const Block& block = _blocks[handle._value];
+ PX_ASSERT(block._offset != uint32_t(-1));
+ return reinterpret_cast<T*>(getBufferPtr() + block._offset);
+ }
+ return 0;
+ }
+
+protected:
+ //buffer API
+ virtual uint8_t* storageResizeBuffer(uint32_t newSize) = 0;
+
+ virtual void storageLock() {}
+ virtual void storageUnlock() {}
+
+public:
+ InplaceStorage()
+ {
+ _bufferPtr = 0;
+ _isChanged = false;
+
+ _firstFreeBlockIndex = NULL_INDEX;
+ _lastAllocatedBlockIndex = NULL_INDEX;
+ _allocatedSize = 0;
+
+ _groupListHead = 0;
+ _activeGroup = NULL;
+
+ _firstFreeRefIndex = NULL_INDEX;
+ }
+ virtual ~InplaceStorage()
+ {
+ release();
+ }
+
+ void release()
+ {
+ releaseGroups();
+ }
+
+ bool isChanged() const
+ {
+ return _isChanged;
+ }
+ void setUnchanged()
+ {
+ _isChanged = false;
+ }
+
+ template <typename T>
+ PX_INLINE bool fetch(InplaceHandleBase handle, T& out, uint32_t index = 0) const
+ {
+ const T* ptr = resolveType<T>(handle);
+ if (ptr != 0)
+ {
+ out = ptr[index];
+ return true;
+ }
+ return false;
+ }
+ template <typename T>
+ PX_INLINE bool update(InplaceHandleBase handle, const T& in, uint32_t index = 0)
+ {
+ T* ptr = resolveType<T>(handle);
+ if (ptr != 0)
+ {
+ ptr[index] = in;
+ return true;
+ }
+ return false;
+ }
+ template <typename T>
+ PX_INLINE bool updateRange(InplaceHandleBase handle, const T* in, uint32_t count, uint32_t start = 0)
+ {
+ T* ptr = resolveType<T>(handle);
+ if (ptr != 0)
+ {
+ ::memcpy(ptr + start, in, sizeof(T) * count);
+ return true;
+ }
+ return false;
+ }
+
+
+ template <typename T>
+ PX_INLINE bool alloc(InplaceHandleBase& handle, uint32_t count = 1)
+ {
+ PX_ASSERT(count > 0);
+ handle._value = allocBlock(sizeof(T) * count, __alignof(T));
+ if (handle._value != NULL_INDEX)
+ {
+ reflectElems<T>(handle, count);
+ return true;
+ }
+ return false;
+ }
+
+ template <typename T>
+ PX_INLINE bool alloc(InplaceHandle<T>& handle, uint32_t count = 1)
+ {
+ return alloc<T>(static_cast<InplaceHandleBase&>(handle), count);
+ }
+
+ PX_INLINE void free(InplaceHandleBase& handle)
+ {
+ if (handle._value != NULL_INDEX)
+ {
+ freeBlock(handle._value);
+ handle._value = NULL_INDEX;
+ }
+ }
+
+ template <typename T>
+ bool realloc(InplaceHandleBase& handle, uint32_t oldCount, uint32_t newCount)
+ {
+ if (handle._value != NULL_INDEX)
+ {
+ PX_ASSERT(oldCount > 0);
+ if (oldCount != newCount)
+ {
+ if (newCount > 0)
+ {
+ if (resizeBlock(handle._value, sizeof(T) * newCount))
+ {
+ if (newCount > oldCount)
+ {
+ reflectElems<T>(handle, newCount, oldCount);
+ }
+ return true;
+ }
+ return false;
+ }
+ free(handle);
+ }
+ }
+ else
+ {
+ PX_ASSERT(oldCount == 0);
+ if (newCount > 0)
+ {
+ return (alloc<T>(handle, newCount) != 0);
+ }
+ }
+ return true;
+ }
+
+
+ template <typename T>
+ PX_INLINE InplaceHandle<T> mappedHandle(InplaceHandle<T> handle) const
+ {
+ mapHandle(handle);
+ return handle;
+ }
+
+ uint32_t mapTo(uint8_t* destPtr) const
+ {
+ PX_ASSERT(_lastAllocatedBlockIndex == NULL_INDEX || _blocks[_lastAllocatedBlockIndex]._offset + _blocks[_lastAllocatedBlockIndex]._size == _allocatedSize);
+
+ memcpy(destPtr, getBufferPtr(), _allocatedSize);
+
+ //iterate all blocks
+ for (uint32_t blockIndex = _lastAllocatedBlockIndex; blockIndex != NULL_INDEX; blockIndex = _blocks[blockIndex]._prevIndex)
+ {
+ const Block& block = _blocks[blockIndex];
+ //iterate all refs in current block
+ for (uint32_t refIndex = block._firstRefIndex; refIndex != NULL_INDEX; refIndex = _handleRefs[refIndex].nextIndex)
+ {
+ const HandleRef& handleRef = _handleRefs[refIndex];
+ PX_ASSERT(handleRef.ownerBlockIndex == blockIndex);
+
+ uint32_t blockOffset = block._offset;
+ PX_ASSERT(blockOffset != uint32_t(-1));
+ InplaceHandleBase& handle = *reinterpret_cast<InplaceHandleBase*>(destPtr + blockOffset + handleRef.offsetInBlock);
+
+ mapHandle(handle);
+ }
+ }
+ return _allocatedSize;
+ }
+
+ uint32_t getAllocatedSize() const
+ {
+ return _allocatedSize;
+ }
+
+private:
+ template <typename T>
+ T* reflectElems(InplaceHandleBase handle, uint32_t newCount, uint32_t oldCount = 0)
+ {
+ const Block& block = _blocks[handle._value];
+
+ uint8_t* ptr = (getBufferPtr() + block._offset);
+ T* ptrT0 = reinterpret_cast<T*>(ptr);
+ T* ptrT = ptrT0 + oldCount;
+ Reflector r(this, handle._value, ptr);
+ for (uint32_t index = oldCount; index < newCount; ++index)
+ {
+ ::new(ptrT) T;
+ InplaceTypeHelper::reflectType<0>(r, ReflectorArg(), *ptrT, InplaceTypeMemberDefaultTraits());
+ ++ptrT;
+ }
+ return ptrT0;
+ }
+
+ static PX_INLINE uint32_t alignUp(uint32_t size, uint32_t alignment)
+ {
+ PX_ASSERT(alignment > 0);
+ return (size + (alignment - 1)) & ~(alignment - 1);
+ }
+
+ PX_INLINE int32_t getMoveDelta(uint32_t blockIndex, uint32_t moveOffset) const
+ {
+ PX_ASSERT(blockIndex != NULL_INDEX);
+ const uint32_t currOffset = _blocks[blockIndex]._offset;
+
+ //calculate max alignment for all subsequent blocks
+ uint32_t alignment = 0;
+ do
+ {
+ const Block& block = _blocks[blockIndex];
+ alignment = PxMax(alignment, block._alignment);
+
+ blockIndex = block._nextIndex;
+ }
+ while (blockIndex != NULL_INDEX);
+
+ int32_t moveDelta = (int32_t)moveOffset - (int32_t)currOffset;
+ //align moveDelta
+ if (moveDelta >= 0)
+ {
+ moveDelta += (alignment - 1);
+ moveDelta &= ~(alignment - 1);
+ }
+ else
+ {
+ moveDelta = -moveDelta;
+ moveDelta &= ~(alignment - 1);
+ moveDelta = -moveDelta;
+ }
+ PX_ASSERT(currOffset + moveDelta >= moveOffset);
+ return moveDelta;
+ }
+
+ uint32_t getPrevAllocatedSize(uint32_t prevBlockIndex) const
+ {
+ uint32_t prevAllocatedSize = 0;
+ if (prevBlockIndex != NULL_INDEX)
+ {
+ const Block& prevBlock = _blocks[prevBlockIndex];
+ prevAllocatedSize = prevBlock._offset + prevBlock._size;
+ }
+ return prevAllocatedSize;
+ }
+
+ void moveBlocks(uint32_t moveBlockIndex, int32_t moveDelta)
+ {
+ if (moveDelta != 0)
+ {
+ const uint32_t currOffset = _blocks[moveBlockIndex]._offset;
+ const uint32_t moveOffset = currOffset + moveDelta;
+
+ uint32_t moveSize = _allocatedSize - currOffset;
+ uint8_t* moveFromPtr = getBufferPtr() + currOffset;
+ uint8_t* moveToPtr = getBufferPtr() + moveOffset;
+ memmove(moveToPtr, moveFromPtr, moveSize);
+
+ _allocatedSize += moveDelta;
+ //update moved blocks
+ do
+ {
+ Block& moveBlock = _blocks[moveBlockIndex];
+ moveBlock._offset += moveDelta;
+ PX_ASSERT((moveBlock._offset & (moveBlock._alignment - 1)) == 0);
+
+ moveBlockIndex = moveBlock._nextIndex;
+ }
+ while (moveBlockIndex != NULL_INDEX);
+ }
+ }
+
+ void removeBlocks(uint32_t prevBlockIndex, uint32_t nextBlockIndex, uint32_t lastBlockIndex)
+ {
+ PX_UNUSED(lastBlockIndex);
+
+ uint32_t prevAllocatedSize = getPrevAllocatedSize(prevBlockIndex);
+ if (prevBlockIndex != NULL_INDEX)
+ {
+ _blocks[prevBlockIndex]._nextIndex = nextBlockIndex;
+ }
+ if (nextBlockIndex != NULL_INDEX)
+ {
+ _blocks[nextBlockIndex]._prevIndex = prevBlockIndex;
+
+ const int32_t moveDelta = getMoveDelta(nextBlockIndex, prevAllocatedSize);
+ moveBlocks(nextBlockIndex, moveDelta);
+ }
+ else
+ {
+ //last block
+ PX_ASSERT(lastBlockIndex == _lastAllocatedBlockIndex);
+ _lastAllocatedBlockIndex = prevBlockIndex;
+
+ _allocatedSize = prevAllocatedSize;
+ }
+ shrinkBuffer();
+ }
+
+ PX_INLINE bool growBuffer(uint32_t newAllocatedSize)
+ {
+ PX_ASSERT(newAllocatedSize >= _allocatedSize);
+
+ uint8_t* newBufferPtr = storageResizeBuffer(newAllocatedSize);
+ if (newBufferPtr == 0)
+ {
+ PX_ASSERT(0 && "Out of memory!");
+ return false;
+ }
+ _bufferPtr = newBufferPtr;
+ return true;
+ }
+
+ PX_INLINE void shrinkBuffer()
+ {
+ uint8_t* newBufferPtr = storageResizeBuffer(_allocatedSize);
+ PX_ASSERT(newBufferPtr != 0);
+ _bufferPtr = newBufferPtr;
+ }
+
+ uint32_t allocBlock(uint32_t size, uint32_t alignment)
+ {
+ uint32_t insertBlockIndex;
+ uint32_t offset;
+ int32_t moveDelta;
+ uint32_t newAllocatedSize;
+
+ PX_ASSERT(_activeGroup != NULL);
+ if (_activeGroup->_lastBlockIndex == NULL_INDEX || _activeGroup->_lastBlockIndex == _lastAllocatedBlockIndex)
+ {
+ //push_back new block
+ insertBlockIndex = NULL_INDEX;
+ offset = alignUp(_allocatedSize, alignment);
+ moveDelta = 0;
+ newAllocatedSize = offset + size;
+ }
+ else
+ {
+ //insert new block
+ insertBlockIndex = _blocks[_activeGroup->_lastBlockIndex]._nextIndex;
+ PX_ASSERT(insertBlockIndex != NULL_INDEX);
+
+ uint32_t prevAllocatedSize = getPrevAllocatedSize(_blocks[insertBlockIndex]._prevIndex);
+ offset = alignUp(prevAllocatedSize, alignment);
+ const uint32_t moveOffset = offset + size;
+ moveDelta = getMoveDelta(insertBlockIndex, moveOffset);
+ newAllocatedSize = _allocatedSize + moveDelta;
+ }
+
+ if (growBuffer(newAllocatedSize) == false)
+ {
+ return NULL_INDEX;
+ }
+
+ //find free block
+ if (_firstFreeBlockIndex == NULL_INDEX)
+ {
+ _firstFreeBlockIndex = _blocks.size();
+ _blocks.resize(_firstFreeBlockIndex + 1);
+
+ _blocks.back()._nextFreeBlockIndex = NULL_INDEX;
+ }
+ uint32_t blockIndex = _firstFreeBlockIndex;
+ Block& block = _blocks[blockIndex];
+ _firstFreeBlockIndex = block._nextFreeBlockIndex;
+
+ //init block
+ block._size = size;
+ block._alignment = alignment;
+ block._offset = offset;
+ block._firstRefIndex = NULL_INDEX;
+ block._group = _activeGroup;
+
+ PX_ASSERT((block._offset & (block._alignment - 1)) == 0);
+
+ if (insertBlockIndex == NULL_INDEX)
+ {
+ //add new block after the _lastAllocatedBlockIndex
+ block._prevIndex = _lastAllocatedBlockIndex;
+ block._nextIndex = NULL_INDEX;
+
+ if (_lastAllocatedBlockIndex != NULL_INDEX)
+ {
+ PX_ASSERT(_blocks[_lastAllocatedBlockIndex]._nextIndex == NULL_INDEX);
+ _blocks[_lastAllocatedBlockIndex]._nextIndex = blockIndex;
+ }
+ _lastAllocatedBlockIndex = blockIndex;
+ }
+ else
+ {
+ PX_ASSERT(_activeGroup->_lastBlockIndex != NULL_INDEX);
+ //insert new block before the insertBlockIndex
+ block._prevIndex = _activeGroup->_lastBlockIndex;
+ _blocks[_activeGroup->_lastBlockIndex]._nextIndex = blockIndex;
+
+ block._nextIndex = insertBlockIndex;
+ _blocks[insertBlockIndex]._prevIndex = blockIndex;
+
+ moveBlocks(insertBlockIndex, moveDelta);
+ PX_ASSERT(_allocatedSize == newAllocatedSize);
+ }
+ _allocatedSize = newAllocatedSize;
+
+ //update group
+ _activeGroup->_lastBlockIndex = blockIndex;
+
+ return blockIndex;
+ }
+
+
+ PX_INLINE void onRemoveHandle(const Block& block, InplaceHandleBase handle)
+ {
+ PX_UNUSED(block);
+ if (handle._value != InplaceHandleBase::NULL_VALUE)
+ {
+ PX_ASSERT(handle._value < _blocks.size());
+ PX_ASSERT(_blocks[handle._value]._group == block._group);
+
+ freeBlock(handle._value);
+ }
+ }
+ PX_INLINE void onRemoveHandleEmpty(const Block& , InplaceHandleBase )
+ {
+ }
+
+ void freeBlock(uint32_t blockIndex)
+ {
+ PX_ASSERT(blockIndex != NULL_INDEX);
+ PX_ASSERT(_activeGroup != NULL);
+ PX_ASSERT(_blocks[blockIndex]._group == _activeGroup);
+
+ removeHandleRefs(&InplaceStorage::onRemoveHandle, blockIndex);
+
+ Block& block = _blocks[blockIndex];
+
+ removeBlocks(block._prevIndex, block._nextIndex, blockIndex);
+
+ //update group
+ if (_activeGroup->_lastBlockIndex == blockIndex)
+ {
+ _activeGroup->_lastBlockIndex =
+ (block._prevIndex != NULL_INDEX) &&
+ (_blocks[block._prevIndex]._group == _activeGroup) ? block._prevIndex : NULL_INDEX;
+ }
+
+ block.reset();
+ //add block to free list
+ block._nextFreeBlockIndex = _firstFreeBlockIndex;
+ _firstFreeBlockIndex = blockIndex;
+ }
+
+ bool resizeBlock(uint32_t blockIndex, uint32_t newSize)
+ {
+ if (newSize < _blocks[blockIndex]._size)
+ {
+ //remove refs
+ removeHandleRefs(&InplaceStorage::onRemoveHandle, blockIndex, newSize);
+ }
+
+ Block& block = _blocks[blockIndex];
+ const uint32_t nextBlockIndex = block._nextIndex;
+
+ uint32_t newAllocatedSize = block._offset + newSize;
+ int32_t moveDelta = 0;
+ if (nextBlockIndex != NULL_INDEX)
+ {
+ moveDelta = getMoveDelta(nextBlockIndex, newAllocatedSize);
+ newAllocatedSize = _allocatedSize + moveDelta;
+ }
+
+ const bool bGrow = (newAllocatedSize > _allocatedSize);
+ if (bGrow)
+ {
+ if (growBuffer(newAllocatedSize) == false)
+ {
+ return false;
+ }
+ }
+
+ block._size = newSize;
+
+ if (nextBlockIndex != NULL_INDEX)
+ {
+ moveBlocks(nextBlockIndex, moveDelta);
+ PX_ASSERT(_allocatedSize == newAllocatedSize);
+ }
+ _allocatedSize = newAllocatedSize;
+ if (!bGrow)
+ {
+ shrinkBuffer();
+ }
+ return true;
+ }
+
+ void groupInit(InplaceStorageGroup* group)
+ {
+ storageLock();
+
+ //init new group
+ group->_lastBlockIndex = NULL_INDEX;
+ group->_groupListPrev = 0;
+ group->_groupListNext = _groupListHead;
+ if (_groupListHead != NULL)
+ {
+ _groupListHead->_groupListPrev = group;
+ }
+ _groupListHead = group;
+
+ storageUnlock();
+ }
+
+ void groupFree(InplaceStorageGroup* group)
+ {
+ storageLock();
+
+ if (group->_lastBlockIndex != NULL_INDEX)
+ {
+ uint32_t prevBlockIndex = group->_lastBlockIndex;
+ uint32_t nextBlockIndex = _blocks[group->_lastBlockIndex]._nextIndex;
+ do
+ {
+ uint32_t freeBlockIndex = prevBlockIndex;
+ Block& freeBlock = _blocks[freeBlockIndex];
+ prevBlockIndex = freeBlock._prevIndex;
+
+ removeHandleRefs(&InplaceStorage::onRemoveHandleEmpty, freeBlockIndex);
+
+ freeBlock.reset();
+ //add block to free list
+ freeBlock._nextFreeBlockIndex = _firstFreeBlockIndex;
+ _firstFreeBlockIndex = freeBlockIndex;
+ }
+ while (prevBlockIndex != NULL_INDEX && _blocks[prevBlockIndex]._group == group);
+
+ PX_ASSERT(prevBlockIndex == NULL_INDEX || _blocks[prevBlockIndex]._group != group);
+ PX_ASSERT(nextBlockIndex == NULL_INDEX || _blocks[nextBlockIndex]._group != group);
+
+ removeBlocks(prevBlockIndex, nextBlockIndex, group->_lastBlockIndex);
+ }
+
+ //remove from GroupList
+ if (group->_groupListNext != 0)
+ {
+ group->_groupListNext->_groupListPrev = group->_groupListPrev;
+ }
+ if (group->_groupListPrev != 0)
+ {
+ group->_groupListPrev->_groupListNext = group->_groupListNext;
+ }
+ else
+ {
+ PX_ASSERT(_groupListHead == group);
+ _groupListHead = group->_groupListNext;
+ }
+
+ storageUnlock();
+ }
+
+ void groupBegin(InplaceStorageGroup* group)
+ {
+ storageLock();
+
+ PX_ASSERT(_activeGroup == NULL);
+ _activeGroup = group;
+ }
+
+ void groupEnd(InplaceStorageGroup* group)
+ {
+ PX_UNUSED(group);
+ PX_ASSERT(group == _activeGroup);
+ _activeGroup = NULL;
+
+ storageUnlock();
+ }
+
+ void releaseGroups()
+ {
+ storageLock();
+
+ while (_groupListHead != 0)
+ {
+ InplaceStorageGroup* group = _groupListHead;
+ _groupListHead = _groupListHead->_groupListNext;
+
+ group->reset(this);
+ }
+
+ storageUnlock();
+ }
+
+ uint8_t* _bufferPtr;
+ bool _isChanged;
+
+ uint32_t _allocatedSize;
+
+ uint32_t _firstFreeBlockIndex;
+ uint32_t _lastAllocatedBlockIndex;
+ physx::Array<Block> _blocks;
+
+ uint32_t _firstFreeRefIndex;
+ physx::Array<HandleRef> _handleRefs;
+
+ InplaceStorageGroup* _groupListHead;
+ InplaceStorageGroup* _activeGroup;
+
+ friend class InplaceStorageGroup;
+};
+
+PX_INLINE void InplaceStorageGroup::init(InplaceStorage& storage)
+{
+ PX_ASSERT(_storage == 0);
+ _storage = &storage;
+ getStorage().groupInit(this);
+}
+PX_INLINE void InplaceStorageGroup::release()
+{
+ if (_storage != 0)
+ {
+ getStorage().groupFree(this);
+ _storage = 0;
+ }
+}
+PX_INLINE void InplaceStorageGroup::begin()
+{
+ getStorage().groupBegin(this);
+}
+PX_INLINE void InplaceStorageGroup::end()
+{
+ getStorage().groupEnd(this);
+}
+
+class InplaceStorageGroupScope
+{
+private:
+ InplaceStorageGroupScope& operator=(const InplaceStorageGroupScope&);
+ InplaceStorageGroup& _group;
+
+public:
+ InplaceStorageGroupScope(InplaceStorageGroup& group) : _group(group)
+ {
+ _group.begin();
+ }
+ ~InplaceStorageGroupScope()
+ {
+ _group.end();
+ }
+};
+
+#define INPLACE_STORAGE_GROUP_SCOPE(group) InplaceStorageGroupScope scopeAccess_##group ( group ); InplaceStorage& _storage_ = group.getStorage();
+
+////
+class ApexCpuInplaceStorage : public InplaceStorage
+{
+public:
+ ApexCpuInplaceStorage(uint32_t allocStep = 4096)
+ : mAllocStep(allocStep)
+ {
+ mSize = 0;
+ mStoragePtr = 0;
+ }
+ ~ApexCpuInplaceStorage()
+ {
+ release();
+ }
+
+ void release()
+ {
+ if (mStoragePtr)
+ {
+ PX_FREE(mStoragePtr);
+ mSize = 0;
+ mStoragePtr = 0;
+ }
+ }
+
+protected:
+ //interface for InplaceStorage
+ uint8_t* storageResizeBuffer(uint32_t newSize)
+ {
+ if (newSize > mSize)
+ {
+ newSize = ((newSize + mAllocStep - 1) / mAllocStep) * mAllocStep;
+ PX_ASSERT(newSize > mSize && (newSize % mAllocStep) == 0);
+ uint8_t* newStoragePtr = (uint8_t*)PX_ALLOC(newSize, PX_DEBUG_EXP("ApexCpuInplaceStorage"));
+ if (!newStoragePtr)
+ {
+ return 0;
+ }
+ memcpy(newStoragePtr, mStoragePtr, mSize);
+ PX_FREE(mStoragePtr);
+ mSize = newSize;
+ mStoragePtr = newStoragePtr;
+ }
+ return mStoragePtr;
+ }
+
+private:
+ uint32_t mAllocStep;
+ uint32_t mSize;
+ uint8_t* mStoragePtr;
+};
+
+
+
+}
+} // end namespace nvidia::apex
+
+#endif // __APEX_INPLACE_STORAGE_H__
diff --git a/APEX_1.4/common/include/InplaceTypes.h b/APEX_1.4/common/include/InplaceTypes.h
new file mode 100644
index 00000000..31f7d3a3
--- /dev/null
+++ b/APEX_1.4/common/include/InplaceTypes.h
@@ -0,0 +1,548 @@
+/*
+ * 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 __APEX_INPLACE_TYPES_H__
+#define __APEX_INPLACE_TYPES_H__
+
+#include "ApexUsingNamespace.h"
+#include "PxVec3.h"
+#include "PxVec4.h"
+#include "PxBounds3.h"
+#include "PxMat44.h"
+
+
+namespace nvidia
+{
+namespace apex
+{
+
+#define INPLACE_TYPE_BUILD() "InplaceTypesBuilder.h"
+#define INPLACE_TYPE_FIELD(_field_type_, _field_name_) ( (2, (_field_type_, _field_name_)) )
+#define INPLACE_TYPE_FIELD_N(_field_type_, _field_name_, _field_size_) ( (3, (_field_type_, _field_name_, _field_size_)) )
+
+#define APEX_OFFSETOF(type, member) offsetof(type, member)
+
+#ifdef __CUDACC__
+#define APEX_CUDA_CALLABLE __device__
+#else
+#define APEX_CUDA_CALLABLE
+#endif
+
+
+#ifdef __CUDACC__
+#define INPLACE_TEMPL_ARGS_DEF template <bool GpuInplaceStorageTemplArg>
+#define INPLACE_TEMPL_ARGS_VAL <GpuInplaceStorageTemplArg>
+#define INPLACE_TEMPL_VA_ARGS_DEF(...) template <bool GpuInplaceStorageTemplArg, __VA_ARGS__>
+#define INPLACE_TEMPL_VA_ARGS_VAL(...) <GpuInplaceStorageTemplArg, __VA_ARGS__>
+#define INPLACE_STORAGE_SUB_ARGS_DEF const uint8_t* _arg_constMem_, texture<int, 1, cudaReadModeElementType> _arg_texRef_
+#define INPLACE_STORAGE_ARGS_DEF InplaceHandleBase::StorageSelector<GpuInplaceStorageTemplArg> _arg_selector_, INPLACE_STORAGE_SUB_ARGS_DEF
+#define INPLACE_STORAGE_ARGS_VAL _arg_selector_, _arg_constMem_, _arg_texRef_
+#define CPU_INPLACE_STORAGE_ARGS_UNUSED
+#else
+#define INPLACE_TEMPL_ARGS_DEF template <typename CpuInplaceStorageTemplArg>
+#define INPLACE_TEMPL_ARGS_VAL <CpuInplaceStorageTemplArg>
+#define INPLACE_TEMPL_VA_ARGS_DEF(...) template <typename CpuInplaceStorageTemplArg, __VA_ARGS__>
+#define INPLACE_TEMPL_VA_ARGS_VAL(...) <CpuInplaceStorageTemplArg, __VA_ARGS__>
+#define INPLACE_STORAGE_ARGS_DEF const CpuInplaceStorageTemplArg& _arg_storage_
+#define INPLACE_STORAGE_ARGS_VAL _arg_storage_
+#define CPU_INPLACE_STORAGE_ARGS_UNUSED PX_UNUSED(_arg_storage_);
+#endif
+
+
+template <bool AutoFree>
+struct InplaceTypeMemberTraits
+{
+ enum { AutoFreeValue = AutoFree };
+};
+
+typedef InplaceTypeMemberTraits<false> InplaceTypeMemberDefaultTraits;
+
+template <typename T>
+struct InplaceTypeTraits;
+
+class InplaceTypeHelper
+{
+ template <int n>
+ struct ArrayIterator
+ {
+ template <int _inplace_offset_, typename R, typename RA, typename T, int N, typename MT>
+ APEX_CUDA_CALLABLE PX_INLINE static void reflectArray(R& r, RA ra, T (& arr)[N], MT mt)
+ {
+ InplaceTypeHelper::reflectType<(N - n)*sizeof(T) + _inplace_offset_>(r, ra, arr[ (N - n) ], mt);
+
+ ArrayIterator<n - 1>::reflectArray<_inplace_offset_>(r, ra, arr, mt);
+ }
+ };
+
+public:
+ template <int _inplace_offset_, typename R, typename RA, typename T, typename MT>
+ APEX_CUDA_CALLABLE PX_INLINE static void reflectType(R& r, RA ra, T& t, MT mt)
+ {
+ r.processType<_inplace_offset_>(ra, t, mt);
+ InplaceTypeTraits<T>::reflectType<_inplace_offset_>(r, ra, t);
+ }
+
+ template <int _inplace_offset_, typename R, typename RA, typename T, int N, typename MT>
+ APEX_CUDA_CALLABLE PX_INLINE static void reflectType(R& r, RA ra, T (& arr)[N], MT mt)
+ {
+ ArrayIterator<N>::reflectArray<_inplace_offset_>(r, ra, arr, mt);
+ }
+
+#ifdef __CUDACC__
+ class FetchReflector4ConstMem
+ {
+ public:
+ APEX_CUDA_CALLABLE PX_INLINE FetchReflector4ConstMem() {}
+
+ template <int _inplace_offset_, typename T, typename MT>
+ APEX_CUDA_CALLABLE PX_INLINE void processType(const uint8_t* constMem, T const& value, MT )
+ {
+ ; //do nothing
+ }
+
+ template <int _inplace_offset_, typename T>
+ APEX_CUDA_CALLABLE PX_INLINE void processPrimitiveType(const uint8_t* constMem, T& out)
+ {
+ out = *reinterpret_cast<const T*>(constMem + _inplace_offset_);
+ }
+ };
+ template <typename T>
+ APEX_CUDA_CALLABLE PX_INLINE static void fetchType(T& out, const uint8_t* constMem, uint32_t offset0)
+ {
+ FetchReflector4ConstMem r;
+ InplaceTypeHelper::reflectType<0>(r, constMem + offset0, out, InplaceTypeMemberDefaultTraits());
+ }
+
+ class FetchReflector4TexRef
+ {
+ uint32_t texIdx0;
+
+ APEX_CUDA_CALLABLE PX_INLINE void convertValue(int value, int32_t& out)
+ {
+ out = int32_t(value);
+ }
+ APEX_CUDA_CALLABLE PX_INLINE void convertValue(int value, uint32_t& out)
+ {
+ out = uint32_t(value);
+ }
+ APEX_CUDA_CALLABLE PX_INLINE void convertValue(int value, float& out)
+ {
+ out = __int_as_float(value);
+ }
+ template <typename T>
+ APEX_CUDA_CALLABLE PX_INLINE void convertValue(int value, T*& out)
+ {
+ out = reinterpret_cast<T*>(value);
+ }
+
+ template <int _inplace_offset_, typename T>
+ APEX_CUDA_CALLABLE PX_INLINE void processValue(texture<int, 1, cudaReadModeElementType> texRef, T& out)
+ {
+ PX_COMPILE_TIME_ASSERT((_inplace_offset_ & 3) == 0);
+ //PX_COMPILE_TIME_ASSERT(sizeof(T) == 4); this fails to compile
+ const int texIdx = (_inplace_offset_ >> 2);
+
+ const int value = tex1Dfetch(texRef, texIdx0 + texIdx);
+ convertValue(value, out);
+ }
+
+ template <int _inplace_offset_, typename T>
+ APEX_CUDA_CALLABLE PX_INLINE void processValue64(texture<int, 1, cudaReadModeElementType> texRef, T& out)
+ {
+ PX_COMPILE_TIME_ASSERT((_inplace_offset_ & 7) == 0);
+ PX_COMPILE_TIME_ASSERT(sizeof(T) == 8);
+ const int texIdx = (_inplace_offset_ >> 2);
+ union
+ {
+ struct
+ {
+ int value0;
+ int value1;
+ };
+ long long value;
+ } u;
+ u.value0 = tex1Dfetch(texRef, texIdx0 + texIdx + 0);
+ u.value1 = tex1Dfetch(texRef, texIdx0 + texIdx + 1);
+ out = reinterpret_cast<T>(u.value);
+ }
+
+ public:
+ APEX_CUDA_CALLABLE PX_INLINE FetchReflector4TexRef(uint32_t offset0) : texIdx0(offset0 >> 2) {}
+
+ template <int _inplace_offset_, typename T, typename MT>
+ APEX_CUDA_CALLABLE PX_INLINE void processType(texture<int, 1, cudaReadModeElementType> texRef, T const& value, MT )
+ {
+ ; //do nothing
+ }
+
+ template <int _inplace_offset_, typename T>
+ APEX_CUDA_CALLABLE PX_INLINE void processPrimitiveType(texture<int, 1, cudaReadModeElementType> texRef, T& out)
+ {
+ processValue<_inplace_offset_>(texRef, out);
+ }
+
+ template <int _inplace_offset_, typename T>
+ APEX_CUDA_CALLABLE PX_INLINE void processPrimitiveType(texture<int, 1, cudaReadModeElementType> texRef, T*& out)
+ {
+#if PX_X64
+ processValue64<_inplace_offset_>(texRef, out);
+#else
+ processValue<_inplace_offset_>(texRef, out);
+#endif
+ }
+ };
+ template <typename T>
+ APEX_CUDA_CALLABLE PX_INLINE static void fetchType(T& out, texture<int, 1, cudaReadModeElementType> texRef, uint32_t offset0)
+ {
+ FetchReflector4TexRef r(offset0);
+ InplaceTypeHelper::reflectType<0>(r, texRef, out, InplaceTypeMemberDefaultTraits());
+ }
+#endif
+};
+
+template <>
+struct InplaceTypeHelper::ArrayIterator<0>
+{
+ template <int _inplace_offset_, typename R, typename RA, typename T, int N, typename MT>
+ APEX_CUDA_CALLABLE PX_INLINE static void reflectArray(R& , RA , T (& )[N], MT )
+ {
+ ; // do nothing
+ }
+};
+
+template <typename T>
+struct InplaceTypeTraits
+{
+ template <int _inplace_offset_, typename R, typename RA>
+ APEX_CUDA_CALLABLE PX_INLINE static void reflectType(R& r, RA ra, T& t)
+ {
+ t.reflectSelf<_inplace_offset_>(r, ra);
+ }
+};
+
+
+class InplacePrimitive
+{
+protected:
+ int _value;
+
+ APEX_CUDA_CALLABLE PX_INLINE InplacePrimitive() {}
+
+public:
+ template <int _inplace_offset_, typename R, typename RA>
+ APEX_CUDA_CALLABLE PX_INLINE void reflectSelf(R& r, RA ra)
+ {
+ //r.processPrimitiveType<APEX_OFFSETOF(InplacePrimitive, _value) + _inplace_offset_>(ra, _value);
+ InplaceTypeHelper::reflectType<APEX_OFFSETOF(InplacePrimitive, _value) + _inplace_offset_>(r, ra, _value, InplaceTypeMemberDefaultTraits());
+ }
+};
+
+class InplaceBool : public InplacePrimitive
+{
+public:
+ APEX_CUDA_CALLABLE PX_INLINE InplaceBool() {}
+ APEX_CUDA_CALLABLE PX_INLINE InplaceBool(bool b) { _value = (b ? 1 : 0); }
+ APEX_CUDA_CALLABLE PX_INLINE InplaceBool& operator= (bool b) { _value = (b ? 1 : 0); return *this; }
+ APEX_CUDA_CALLABLE PX_INLINE operator bool () const { return (_value != 0); }
+};
+
+template <typename ET>
+class InplaceEnum : public InplacePrimitive
+{
+public:
+ APEX_CUDA_CALLABLE PX_INLINE InplaceEnum() {}
+ APEX_CUDA_CALLABLE PX_INLINE InplaceEnum(ET value) { _value = value; }
+ APEX_CUDA_CALLABLE PX_INLINE InplaceEnum<ET>& operator=(ET value) { _value = value; return *this; }
+ APEX_CUDA_CALLABLE PX_INLINE operator ET () const { return ET(_value); }
+};
+
+
+template <typename T> struct InplaceTypeTraits<T*>
+{
+ template <int _inplace_offset_, typename R, typename RA>
+ APEX_CUDA_CALLABLE PX_INLINE static void reflectType(R& r, RA ra, T*& t) { r.processPrimitiveType<_inplace_offset_>(ra, t); }
+};
+template <> struct InplaceTypeTraits<int32_t>
+{
+ template <int _inplace_offset_, typename R, typename RA>
+ APEX_CUDA_CALLABLE PX_INLINE static void reflectType(R& r, RA ra, int32_t& t) { r.processPrimitiveType<_inplace_offset_>(ra, t); }
+};
+template <> struct InplaceTypeTraits<uint32_t>
+{
+ template <int _inplace_offset_, typename R, typename RA>
+ APEX_CUDA_CALLABLE PX_INLINE static void reflectType(R& r, RA ra, uint32_t& t) { r.processPrimitiveType<_inplace_offset_>(ra, t); }
+};
+template <> struct InplaceTypeTraits<float>
+{
+ template <int _inplace_offset_, typename R, typename RA>
+ APEX_CUDA_CALLABLE PX_INLINE static void reflectType(R& r, RA ra, float& t) { r.processPrimitiveType<_inplace_offset_>(ra, t); }
+};
+template <> struct InplaceTypeTraits<PxVec3>
+{
+ template <int _inplace_offset_, typename R, typename RA>
+ APEX_CUDA_CALLABLE PX_INLINE static void reflectType(R& r, RA ra, PxVec3& t)
+ {
+ InplaceTypeHelper::reflectType<APEX_OFFSETOF(PxVec3, x) + _inplace_offset_>(r, ra, t.x, InplaceTypeMemberDefaultTraits());
+ InplaceTypeHelper::reflectType<APEX_OFFSETOF(PxVec3, y) + _inplace_offset_>(r, ra, t.y, InplaceTypeMemberDefaultTraits());
+ InplaceTypeHelper::reflectType<APEX_OFFSETOF(PxVec3, z) + _inplace_offset_>(r, ra, t.z, InplaceTypeMemberDefaultTraits());
+ }
+};
+template <> struct InplaceTypeTraits<PxVec4>
+{
+ template <int _inplace_offset_, typename R, typename RA>
+ APEX_CUDA_CALLABLE PX_INLINE static void reflectType(R& r, RA ra, PxVec4& t)
+ {
+ InplaceTypeHelper::reflectType<APEX_OFFSETOF(PxVec4, x) + _inplace_offset_>(r, ra, t.x, InplaceTypeMemberDefaultTraits());
+ InplaceTypeHelper::reflectType<APEX_OFFSETOF(PxVec4, y) + _inplace_offset_>(r, ra, t.y, InplaceTypeMemberDefaultTraits());
+ InplaceTypeHelper::reflectType<APEX_OFFSETOF(PxVec4, z) + _inplace_offset_>(r, ra, t.z, InplaceTypeMemberDefaultTraits());
+ InplaceTypeHelper::reflectType<APEX_OFFSETOF(PxVec4, w) + _inplace_offset_>(r, ra, t.w, InplaceTypeMemberDefaultTraits());
+ }
+};
+template <> struct InplaceTypeTraits<PxTransform>
+{
+ template <int _inplace_offset_, typename R, typename RA>
+ APEX_CUDA_CALLABLE PX_INLINE static void reflectType(R& r, RA ra, PxTransform& t)
+ {
+ InplaceTypeHelper::reflectType<APEX_OFFSETOF(PxTransform, q) + _inplace_offset_>(r, ra, t.q, InplaceTypeMemberDefaultTraits());
+ InplaceTypeHelper::reflectType<APEX_OFFSETOF(PxTransform, p) + _inplace_offset_>(r, ra, t.p, InplaceTypeMemberDefaultTraits());
+ }
+};
+template <> struct InplaceTypeTraits<PxQuat>
+{
+ template <int _inplace_offset_, typename R, typename RA>
+ APEX_CUDA_CALLABLE PX_INLINE static void reflectType(R& r, RA ra, PxQuat& t)
+ {
+ InplaceTypeHelper::reflectType<APEX_OFFSETOF(PxQuat, x) + _inplace_offset_>(r, ra, t.x, InplaceTypeMemberDefaultTraits());
+ InplaceTypeHelper::reflectType<APEX_OFFSETOF(PxQuat, y) + _inplace_offset_>(r, ra, t.y, InplaceTypeMemberDefaultTraits());
+ InplaceTypeHelper::reflectType<APEX_OFFSETOF(PxQuat, z) + _inplace_offset_>(r, ra, t.z, InplaceTypeMemberDefaultTraits());
+ InplaceTypeHelper::reflectType<APEX_OFFSETOF(PxQuat, w) + _inplace_offset_>(r, ra, t.w, InplaceTypeMemberDefaultTraits());
+ }
+};
+template <> struct InplaceTypeTraits<PxBounds3>
+{
+ template <int _inplace_offset_, typename R, typename RA>
+ APEX_CUDA_CALLABLE PX_INLINE static void reflectType(R& r, RA ra, PxBounds3& t)
+ {
+ InplaceTypeHelper::reflectType<APEX_OFFSETOF(PxBounds3, minimum) + _inplace_offset_>(r, ra, t.minimum, InplaceTypeMemberDefaultTraits());
+ InplaceTypeHelper::reflectType<APEX_OFFSETOF(PxBounds3, maximum) + _inplace_offset_>(r, ra, t.maximum, InplaceTypeMemberDefaultTraits());
+ }
+};
+template <> struct InplaceTypeTraits<PxPlane>
+{
+ template <int _inplace_offset_, typename R, typename RA>
+ APEX_CUDA_CALLABLE PX_INLINE static void reflectType(R& r, RA ra, PxPlane& t)
+ {
+ InplaceTypeHelper::reflectType<APEX_OFFSETOF(PxPlane, n) + _inplace_offset_>(r, ra, t.n, InplaceTypeMemberDefaultTraits());
+ InplaceTypeHelper::reflectType<APEX_OFFSETOF(PxPlane, d) + _inplace_offset_>(r, ra, t.d, InplaceTypeMemberDefaultTraits());
+ }
+};
+template <> struct InplaceTypeTraits<PxMat33>
+{
+ template <int _inplace_offset_, typename R, typename RA>
+ APEX_CUDA_CALLABLE PX_INLINE static void reflectType(R& r, RA ra, PxMat33& t)
+ {
+ InplaceTypeHelper::reflectType<APEX_OFFSETOF(PxMat33, column0) + _inplace_offset_>(r, ra, t.column0, InplaceTypeMemberDefaultTraits());
+ InplaceTypeHelper::reflectType<APEX_OFFSETOF(PxMat33, column1) + _inplace_offset_>(r, ra, t.column1, InplaceTypeMemberDefaultTraits());
+ InplaceTypeHelper::reflectType<APEX_OFFSETOF(PxMat33, column2) + _inplace_offset_>(r, ra, t.column2, InplaceTypeMemberDefaultTraits());
+ }
+};
+template <> struct InplaceTypeTraits<PxMat44>
+{
+ template <int _inplace_offset_, typename R, typename RA>
+ APEX_CUDA_CALLABLE PX_INLINE static void reflectType(R& r, RA ra, PxMat44& t)
+ {
+ InplaceTypeHelper::reflectType<APEX_OFFSETOF(PxMat44, column0) + _inplace_offset_>(r, ra, t.column0, InplaceTypeMemberDefaultTraits());
+ InplaceTypeHelper::reflectType<APEX_OFFSETOF(PxMat44, column1) + _inplace_offset_>(r, ra, t.column1, InplaceTypeMemberDefaultTraits());
+ InplaceTypeHelper::reflectType<APEX_OFFSETOF(PxMat44, column2) + _inplace_offset_>(r, ra, t.column2, InplaceTypeMemberDefaultTraits());
+ InplaceTypeHelper::reflectType<APEX_OFFSETOF(PxMat44, column3) + _inplace_offset_>(r, ra, t.column3, InplaceTypeMemberDefaultTraits());
+ }
+};
+
+
+class InplaceHandleBase
+{
+protected:
+ friend class InplaceStorage;
+ friend class InplaceArrayBase;
+
+ static const uint32_t NULL_VALUE = uint32_t(-1);
+ uint32_t _value;
+
+public:
+ APEX_CUDA_CALLABLE PX_INLINE InplaceHandleBase()
+ {
+ _value = NULL_VALUE;
+ }
+
+ PX_INLINE void setNull()
+ {
+ _value = NULL_VALUE;
+ }
+
+ APEX_CUDA_CALLABLE PX_INLINE bool isNull() const
+ {
+ return _value == NULL_VALUE;
+ }
+
+#ifdef __CUDACC__
+ template <bool B>
+ struct StorageSelector
+ {
+ static const bool value = B;
+ };
+
+ template <typename T>
+ APEX_CUDA_CALLABLE PX_INLINE void fetch(StorageSelector<false>, INPLACE_STORAGE_SUB_ARGS_DEF, T& out, uint32_t index = 0) const
+ {
+ //out = reinterpret_cast<const T*>(_arg_constMem_ + _value)[index];
+ InplaceTypeHelper::fetchType<T>(out, _arg_constMem_, _value + sizeof(T) * index);
+ }
+
+ template <typename T>
+ APEX_CUDA_CALLABLE PX_INLINE void fetch(StorageSelector<true>, INPLACE_STORAGE_SUB_ARGS_DEF, T& out, uint32_t index = 0) const
+ {
+ InplaceTypeHelper::fetchType<T>(out, _arg_texRef_, _value + sizeof(T) * index);
+ }
+#else
+ template <typename S, typename T>
+ PX_INLINE void fetch(const S& storage, T& out, uint32_t index = 0) const
+ {
+ storage.fetch(*this, out, index);
+ }
+
+ template <typename S, typename T>
+ PX_INLINE void update(S& storage, const T& in, uint32_t index = 0) const
+ {
+ storage.update(*this, in, index);
+ }
+
+ template <typename S, typename T>
+ PX_INLINE bool allocOrFetch(S& storage, T& out)
+ {
+ if (isNull())
+ {
+ storage.template alloc<T>(*this);
+ return true;
+ }
+ else
+ {
+ storage.fetch(*this, out);
+ return false;
+ }
+ }
+#endif
+
+ template <int _inplace_offset_, typename R, typename RA>
+ APEX_CUDA_CALLABLE PX_INLINE void reflectSelf(R& r, RA ra)
+ {
+ InplaceTypeHelper::reflectType<APEX_OFFSETOF(InplaceHandleBase, _value) + _inplace_offset_>(r, ra, _value, InplaceTypeMemberDefaultTraits());
+ }
+};
+
+template <typename T>
+class InplaceHandle : public InplaceHandleBase
+{
+public:
+ APEX_CUDA_CALLABLE PX_INLINE InplaceHandle() {}
+
+ template <typename S>
+ PX_INLINE bool alloc(S& storage)
+ {
+ return storage.alloc(*this);
+ }
+};
+
+
+class InplaceArrayBase
+{
+protected:
+ uint32_t _size;
+ InplaceHandleBase _elems;
+
+#ifndef __CUDACC__
+ PX_INLINE InplaceArrayBase()
+ {
+ _size = 0;
+ }
+#endif
+
+ template <int _inplace_offset_, typename R, typename RA, typename MT>
+ APEX_CUDA_CALLABLE PX_INLINE void reflectSelf(R& r, RA ra, MT mt)
+ {
+ InplaceTypeHelper::reflectType<APEX_OFFSETOF(InplaceArrayBase, _size) + _inplace_offset_>(r, ra, _size, InplaceTypeMemberDefaultTraits());
+ InplaceTypeHelper::reflectType<APEX_OFFSETOF(InplaceArrayBase, _elems) + _inplace_offset_>(r, ra, _elems, mt);
+ }
+};
+
+
+// if AutoFreeElems is true, then InplaceHandles in deleted elements are automaticly got free on array resize!
+template <typename T, bool AutoFreeElems = false>
+class InplaceArray : public InplaceArrayBase
+{
+public:
+ APEX_CUDA_CALLABLE PX_INLINE uint32_t getSize() const
+ {
+ return _size;
+ }
+
+#ifndef __CUDACC__
+ PX_INLINE InplaceArray()
+ {
+ }
+
+ template <typename S>
+ PX_INLINE void fetchElem(const S& storage, T& out, uint32_t index) const
+ {
+ storage.fetch(_elems, out, index);
+ }
+ template <typename S>
+ PX_INLINE void updateElem(S& storage, const T& in, uint32_t index) const
+ {
+ storage.update(_elems, in, index);
+ }
+ template <typename S>
+ PX_INLINE void updateRange(S& storage, const T* in, uint32_t count, uint32_t start = 0) const
+ {
+ storage.updateRange(_elems, in, count, start);
+ }
+
+ template <typename S>
+ PX_INLINE bool resize(S& storage, uint32_t size)
+ {
+ if (storage.template realloc<T>(_elems, _size, size))
+ {
+ _size = size;
+ return true;
+ }
+ return false;
+ }
+
+#else
+ INPLACE_TEMPL_ARGS_DEF
+ APEX_CUDA_CALLABLE PX_INLINE void fetchElem(INPLACE_STORAGE_ARGS_DEF, T& out, uint32_t index) const
+ {
+ _elems.fetch(INPLACE_STORAGE_ARGS_VAL, out, index);
+ }
+#endif
+
+ template <int _inplace_offset_, typename R, typename RA>
+ APEX_CUDA_CALLABLE PX_INLINE void reflectSelf(R& r, RA ra)
+ {
+ InplaceArrayBase::reflectSelf<_inplace_offset_>(r, ra, InplaceTypeMemberTraits<AutoFreeElems>());
+ }
+
+};
+
+
+}
+} // end namespace nvidia::apex
+
+#endif // __APEX_INPLACE_TYPES_H__
diff --git a/APEX_1.4/common/include/InplaceTypesBuilder.h b/APEX_1.4/common/include/InplaceTypesBuilder.h
new file mode 100644
index 00000000..a7277ff5
--- /dev/null
+++ b/APEX_1.4/common/include/InplaceTypesBuilder.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.
+ */
+
+
+#include <boost/preprocessor/seq.hpp>
+#include <boost/preprocessor/seq/for_each_i.hpp>
+#include <boost/preprocessor/seq/filter.hpp>
+#include <boost/preprocessor/iteration/local.hpp>
+#include <boost/preprocessor/tuple/elem.hpp>
+#include <boost/preprocessor/control/if.hpp>
+#include <boost/preprocessor/comparison/equal.hpp>
+#include <boost/preprocessor/facilities/empty.hpp>
+#include <boost/preprocessor/array/size.hpp>
+#include <boost/preprocessor/array/elem.hpp>
+#include <boost/preprocessor/punctuation/comma.hpp>
+
+#pragma warning(push)
+#pragma warning(disable: 4355)
+
+#define _PP_GET_FIELD_TYPE(n) BOOST_PP_ARRAY_ELEM(0, BOOST_PP_SEQ_ELEM(n, INPLACE_TYPE_STRUCT_FIELDS))
+#define _PP_GET_FIELD_NAME(n) BOOST_PP_ARRAY_ELEM(1, BOOST_PP_SEQ_ELEM(n, INPLACE_TYPE_STRUCT_FIELDS))
+
+#define _PP_HAS_FIELD_SIZE(n) BOOST_PP_EQUAL(BOOST_PP_ARRAY_SIZE(BOOST_PP_SEQ_ELEM(n, INPLACE_TYPE_STRUCT_FIELDS)), 3)
+#define _PP_GET_FIELD_SIZE(n) BOOST_PP_ARRAY_ELEM(2, BOOST_PP_SEQ_ELEM(n, INPLACE_TYPE_STRUCT_FIELDS))
+
+
+#ifdef INPLACE_TYPE_STRUCT_NAME
+
+struct INPLACE_TYPE_STRUCT_NAME
+#ifdef INPLACE_TYPE_STRUCT_BASE
+ : INPLACE_TYPE_STRUCT_BASE
+#endif
+{
+//fields
+#ifdef INPLACE_TYPE_STRUCT_FIELDS
+#define BOOST_PP_LOCAL_LIMITS (0, BOOST_PP_SEQ_SIZE(INPLACE_TYPE_STRUCT_FIELDS) - 1)
+#define BOOST_PP_LOCAL_MACRO(n) \
+ _PP_GET_FIELD_TYPE(n) _PP_GET_FIELD_NAME(n) BOOST_PP_IF(_PP_HAS_FIELD_SIZE(n), [##_PP_GET_FIELD_SIZE(n)##], BOOST_PP_EMPTY());
+#include BOOST_PP_LOCAL_ITERATE()
+#endif
+
+//reflectSelf
+ template <int _inplace_offset_, typename R, typename RA>
+#if defined(INPLACE_TYPE_STRUCT_BASE) | defined(INPLACE_TYPE_STRUCT_FIELDS)
+ APEX_CUDA_CALLABLE PX_INLINE void reflectSelf(R& r, RA ra)
+ {
+#ifdef INPLACE_TYPE_STRUCT_BASE
+ INPLACE_TYPE_STRUCT_BASE::reflectSelf<_inplace_offset_>(r, ra);
+#endif
+#ifdef INPLACE_TYPE_STRUCT_FIELDS
+#define BOOST_PP_LOCAL_LIMITS (0, BOOST_PP_SEQ_SIZE(INPLACE_TYPE_STRUCT_FIELDS) - 1)
+#define BOOST_PP_LOCAL_MACRO(n) \
+ InplaceTypeHelper::reflectType<APEX_OFFSETOF( INPLACE_TYPE_STRUCT_NAME, _PP_GET_FIELD_NAME(n) ) + _inplace_offset_>(r, ra, _PP_GET_FIELD_NAME(n), InplaceTypeMemberDefaultTraits());
+#include BOOST_PP_LOCAL_ITERATE()
+#endif
+ }
+#else
+ APEX_CUDA_CALLABLE PX_INLINE void reflectSelf(R& , RA )
+ {
+ }
+#endif
+
+#ifndef INPLACE_TYPE_STRUCT_LEAVE_OPEN
+};
+#endif
+
+#endif
+
+#undef _PP_GET_FIELD_TYPE
+#undef _PP_GET_FIELD_NAME
+#undef _PP_HAS_FIELD_SIZE
+#undef _PP_GET_FIELD_SIZE
+
+#undef INPLACE_TYPE_STRUCT_NAME
+#undef INPLACE_TYPE_STRUCT_BASE
+#undef INPLACE_TYPE_STRUCT_FIELDS
+#undef INPLACE_TYPE_STRUCT_LEAVE_OPEN
+
+#pragma warning(pop)
diff --git a/APEX_1.4/common/include/InstancedObjectSimulationIntl.h b/APEX_1.4/common/include/InstancedObjectSimulationIntl.h
new file mode 100644
index 00000000..d631589d
--- /dev/null
+++ b/APEX_1.4/common/include/InstancedObjectSimulationIntl.h
@@ -0,0 +1,160 @@
+/*
+ * 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 INSTANCED_OBJECT_SIMULATION_INTL_H
+#define INSTANCED_OBJECT_SIMULATION_INTL_H
+
+#include "ApexDefs.h"
+
+#include "PxTask.h"
+#include "ApexActor.h"
+#include "IofxManagerIntl.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+class RenderVolume;
+
+/* Input data structure from Emitter ==> (injector) IOS */
+struct IosNewObject
+{
+ PxVec3 initialPosition;
+ PxVec3 initialVelocity;
+ float lifetime; // in seconds
+ float lodBenefit; // filled in by injector
+ IofxActorIDIntl iofxActorID; // filled in by injector
+
+ uint32_t userData;
+};
+
+/**
+ * Note the difference between how lifetimes are provided by the emitter (in seconds), and how
+ * they are reported to the IOFX (as a percentage of time remaining). This implies a couple IOS
+ * requirements. 1) The IOS must remember the initial total lifetime and each frame do a remain/total
+ * division in order to report the percent remain. 2) In order for the liferemain to report 1.0 on
+ * the object's inital frame, new objects cannot have their remain decremented.
+ */
+
+/**
+ * An emitter will aquire an instance of this class from each IOS actor it instantiates. The IOS
+ * will hold an array of these instances to manage all of its emitters and object ID ranges.
+ */
+class IosInjectorIntl : public ApexActor
+{
+public:
+ /**
+ * An emitter calls createObjects() at the end of its tick/step function to register its newly
+ * spawned objects with the IOS. If the IOS has limits on the number of objects it can spawn each
+ * simulation step, it must provide buffering beneath this API. The IOS must copy this data if it
+ * cannot create the objects within this function call. Note that the IOFX is unaware of the
+ * object creation path, it discovers spawned objects when they show up with liferemain of 1.0
+ * An IOS may have built-in emitters that do not call this API (Turbulence).
+ */
+ virtual void createObjects(uint32_t count, const IosNewObject* createList) = 0;
+
+ /**
+ * An emitter calls setLODWeights() as often as it needs to adjust the LOD paramters for its
+ * particles.
+ */
+ // distanceWeight minimum squared distance from camera before distance is included in LOD weight
+ // speedWeight minimum velocity parameter. Particles slower than this are culled more aggressively.
+ // lifeWeight lifetime minimum limit. Particles with less lifetime than this remaining will be culled.
+ virtual void setLODWeights(float maxDistance, float distanceWeight, float speedWeight, float lifeWeight, float separationWeight, float bias) = 0;
+
+ /**
+ * When an emitter is being destroyed, it must call this release method on all of its injectors
+ * so those IOS instances can reclaim those ID ranges and destroy any active objects.
+ */
+ virtual void release() = 0;
+
+ virtual PxTaskID getCompletionTaskID() const = 0;
+
+ virtual void setPreferredRenderVolume(nvidia::apex::RenderVolume* volume) = 0;
+
+ /**
+ * Return the value of the least benefit particle to survive last frame's LOD culling.
+ * An emitter can query this value to voluntarily throttle itself. However, to prevent
+ * feedback loops it should always try to emit at least a few particles when it is
+ * throttled.
+ */
+ virtual float getLeastBenefitValue() const = 0;
+
+ virtual uint32_t getSimParticlesCount() const = 0;
+
+ /**
+ * This injector has particles in it that were unable to be inserted at the last simulation
+ * step because of an insertion limit in the IOS. The emitter may chose to throttle its
+ * emissions when this returns true.
+ */
+ virtual bool isBacklogged() const = 0;
+
+ /**
+ Returns the current number of particles/objects active in the simulation.
+ */
+ virtual uint32_t getActivePaticleCount() const = 0;
+
+ virtual void setObjectScale(float objectScale) = 0;
+
+protected:
+ virtual ~IosInjectorIntl() {}
+};
+
+
+/**
+ * Base class for all particle simulation systems and other systems that can efficiently simulate
+ * instanced geometry. This is the interface to the IOS Actor (instance).
+ */
+class InstancedObjectSimulationIntl : public ApexActor
+{
+public:
+ /**
+ * An emitter calls allocateInjector() to create an injector targeted at a particular
+ * IOFX Asset. The IOS will allocate an IOFX actor as necessary. The emitter has no
+ * knowledge of the size of the IOFX actor, or how many emitters are also using it.
+ */
+ virtual IosInjectorIntl* allocateInjector(IofxAsset* iofxAsset) = 0;
+
+ /**
+ * Query the authored radius of the instanced objects simulated by this IOS. Emitters need this
+ * value for volume fill effects and an IOFX may need it for rendering purposes.
+ */
+ virtual float getObjectRadius() const = 0;
+
+ /**
+ * Query the authored density of the instanced objects simulated by this IOS. Emitters need this
+ * value for constant density emitter effects.
+ */
+ virtual float getObjectDensity() const = 0;
+
+ /**
+ * An emitter may use this API functions to query particle positions from the most recent simulation step
+ * This IOS output buffer is updated each frame during fetchResults.
+ */
+ virtual const PxVec3* getRecentPositions(uint32_t& count, uint32_t& stride) const = 0;
+
+ /**
+ * Set's the origin of the density grid; this is implemented for BasicIOS and ParticleIOS
+ */
+ virtual void setDensityOrigin(const PxVec3& v)
+ {
+ PX_UNUSED(v);
+ }
+
+protected:
+ virtual ~InstancedObjectSimulationIntl() {}
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif // #ifndef INSTANCED_OBJECT_SIMULATION_INTL_H
diff --git a/APEX_1.4/common/include/IofxManagerIntl.h b/APEX_1.4/common/include/IofxManagerIntl.h
new file mode 100644
index 00000000..4ea3967d
--- /dev/null
+++ b/APEX_1.4/common/include/IofxManagerIntl.h
@@ -0,0 +1,208 @@
+/*
+ * 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 IOFX_MANAGER_INTL_H
+#define IOFX_MANAGER_INTL_H
+
+#include "PsArray.h"
+#include "PxVec3.h"
+#include "PxVec4.h"
+#include "PxTaskManager.h"
+
+namespace physx
+{
+ class PxGpuCopyDescQueue;
+}
+
+namespace nvidia
+{
+namespace apex
+{
+class IofxAsset;
+class RenderVolume;
+
+template <class T>
+class ApexMirroredArray;
+
+
+class IofxManagerDescIntl
+{
+public:
+ IofxManagerDescIntl() :
+ iosAssetName(NULL),
+ iosOutputsOnDevice(false),
+ iosSupportsDensity(false),
+ iosSupportsCollision(false),
+ iosSupportsUserData(false),
+ maxObjectCount(0),
+ maxInputCount(0),
+ maxInStateCount(0)
+ {
+ }
+
+ const char* iosAssetName;
+ bool iosOutputsOnDevice;
+ bool iosSupportsDensity;
+ bool iosSupportsCollision;
+ bool iosSupportsUserData;
+ uint32_t maxObjectCount;
+ uint32_t maxInputCount;
+ uint32_t maxInStateCount;
+};
+
+/// The IOFX will update the volumeID each simulation step, the IOS must
+/// persist this output. IOS provides initial volumeID, based on emitter's
+/// preferred volume.
+struct IofxActorIDIntl
+{
+ uint32_t value;
+
+ PX_CUDA_CALLABLE PX_INLINE IofxActorIDIntl() {}
+ PX_CUDA_CALLABLE PX_INLINE explicit IofxActorIDIntl(uint32_t arg)
+ {
+ value = arg;
+ }
+
+ PX_CUDA_CALLABLE PX_INLINE void set(uint16_t volumeID, uint16_t actorClassID)
+ {
+ value = (uint32_t(volumeID) << 16) | uint32_t(actorClassID);
+ }
+
+ PX_CUDA_CALLABLE PX_INLINE uint16_t getVolumeID() const
+ {
+ return uint16_t(value >> 16);
+ }
+ PX_CUDA_CALLABLE PX_INLINE void setVolumeID(uint16_t volumeID)
+ {
+ value &= 0x0000FFFFu;
+ value |= (uint32_t(volumeID) << 16);
+ }
+
+ PX_CUDA_CALLABLE PX_INLINE uint16_t getActorClassID() const
+ {
+ return uint16_t(value & 0xFFFFu);
+ }
+ PX_CUDA_CALLABLE PX_INLINE void setActorClassID(uint16_t actorClassID)
+ {
+ value &= 0xFFFF0000u;
+ value |= uint32_t(actorClassID);
+ }
+
+ static const uint16_t NO_VOLUME = 0xFFFFu;
+ static const uint16_t IPX_ACTOR = 0xFFFFu;
+};
+
+
+/* IOFX Manager returned pointers for simulation data */
+class IosBufferDescIntl
+{
+public:
+ /* All arrays are indexed by input ID */
+ ApexMirroredArray<PxVec4>* pmaPositionMass;
+ ApexMirroredArray<PxVec4>* pmaVelocityLife;
+ ApexMirroredArray<PxVec4>* pmaCollisionNormalFlags;
+ ApexMirroredArray<float>* pmaDensity;
+ ApexMirroredArray<IofxActorIDIntl>* pmaActorIdentifiers;
+ ApexMirroredArray<uint32_t>* pmaInStateToInput;
+ ApexMirroredArray<uint32_t>* pmaOutStateToInput;
+
+ ApexMirroredArray<uint32_t>* pmaUserData;
+
+ //< Value in inStateToInput field indicates a dead particle, input to IOFX
+ static const uint32_t NOT_A_PARTICLE = 0xFFFFFFFFu;
+
+ //< Flag in inStateToInput field indicates a new particle, input to IOFX
+ static const uint32_t NEW_PARTICLE_FLAG = 0x80000000u;
+};
+
+// This is a representative of uint4 on host
+struct IofxSlice
+{
+ uint32_t x, y, z, w;
+};
+
+typedef void (*EventCallback)(void*);
+
+class IofxManagerCallbackIntl
+{
+public:
+ virtual void operator()(void* stream = NULL) = 0;
+};
+
+class IofxManagerClientIntl
+{
+public:
+ struct Params
+ {
+ float objectScale;
+
+ Params()
+ {
+ setDefaults();
+ }
+
+ void setDefaults()
+ {
+ objectScale = 1.0f;
+ }
+ };
+ virtual void getParams(IofxManagerClientIntl::Params& params) const = 0;
+ virtual void setParams(const IofxManagerClientIntl::Params& params) = 0;
+};
+
+
+class IofxManagerIntl
+{
+public:
+ //! An IOS Actor will call this once, at creation
+ virtual void createSimulationBuffers(IosBufferDescIntl& outDesc) = 0;
+
+ //! An IOS actor will call this once, when it creates its fluid simulation
+ virtual void setSimulationParameters(float radius, const PxVec3& up, float gravity, float restDensity) = 0;
+
+ //! An IOS Actor will call this method after each simulation step
+ virtual void updateEffectsData(float deltaTime, uint32_t numObjects, uint32_t maxInputID, uint32_t maxStateID, void* extraData = 0) = 0;
+
+ //! An IOS Actor will call this method at the start of each step IOFX will run
+ virtual PxTaskID getUpdateEffectsTaskID(PxTaskID) = 0;
+
+ virtual uint16_t getActorClassID(IofxManagerClientIntl* client, uint16_t meshID) = 0;
+
+ virtual IofxManagerClientIntl* createClient(nvidia::apex::IofxAsset* asset, const IofxManagerClientIntl::Params& params) = 0;
+ virtual void releaseClient(IofxManagerClientIntl* client) = 0;
+
+ virtual uint16_t getVolumeID(nvidia::apex::RenderVolume* vol) = 0;
+
+ //! Triggers the IOFX Manager to copy host buffers to the device
+ //! This is intended for use in an IOS post-update task, if they
+ //! need the output buffers on the device.
+ virtual void outputHostToDevice(PxGpuCopyDescQueue& copyQueue) = 0;
+
+ //! IofxManagerCallbackIntl will be called before Iofx computations
+ virtual void setOnStartCallback(IofxManagerCallbackIntl*) = 0;
+ //! IofxManagerCallbackIntl will be called after Iofx computations
+ virtual void setOnFinishCallback(IofxManagerCallbackIntl*) = 0;
+
+ //! Called when IOS is being deleted
+ virtual void release() = 0;
+
+ //get bounding box
+ virtual PxBounds3 getBounds() const = 0;
+
+protected:
+ virtual ~IofxManagerIntl() {}
+};
+
+
+}
+} // end namespace nvidia::apex
+
+#endif // IOFX_MANAGER_INTL_H
diff --git a/APEX_1.4/common/include/ModuleBase.h b/APEX_1.4/common/include/ModuleBase.h
new file mode 100644
index 00000000..f58f6c1a
--- /dev/null
+++ b/APEX_1.4/common/include/ModuleBase.h
@@ -0,0 +1,46 @@
+/*
+ * 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_BASE_H
+#define MODULE_BASE_H
+
+#include "ApexResource.h"
+#include "ApexString.h"
+#include "ApexSDKIntl.h"
+#include "PsArray.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+class ModuleBase : public UserAllocated
+{
+public:
+ ModuleBase();
+ void release();
+
+ const char* getName() const;
+
+ /* Framework internal ModuleIntl class methods */
+ void destroy();
+
+ ApexSDKIntl* mSdk;
+
+protected:
+ ApexSimpleString mName;
+ Module* mApiProxy;
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif // MODULE_BASE_H
diff --git a/APEX_1.4/common/include/ModuleFieldSamplerIntl.h b/APEX_1.4/common/include/ModuleFieldSamplerIntl.h
new file mode 100644
index 00000000..4781fd06
--- /dev/null
+++ b/APEX_1.4/common/include/ModuleFieldSamplerIntl.h
@@ -0,0 +1,34 @@
+/*
+ * 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_FIELD_SAMPLER_INTL_H
+#define MODULE_FIELD_SAMPLER_INTL_H
+
+#include "ModuleIntl.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+class FieldSamplerManagerIntl;
+class Scene;
+
+class ModuleFieldSamplerIntl : public ModuleIntl
+{
+public:
+ virtual FieldSamplerManagerIntl* getInternalFieldSamplerManager(const Scene& apexScene) = 0;
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif // MODULE_FIELD_SAMPLER_INTL_H
diff --git a/APEX_1.4/common/include/ModuleIntl.h b/APEX_1.4/common/include/ModuleIntl.h
new file mode 100644
index 00000000..601564bb
--- /dev/null
+++ b/APEX_1.4/common/include/ModuleIntl.h
@@ -0,0 +1,264 @@
+/*
+ * 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_INTL_H
+#define MODULE_INTL_H
+
+#include "ApexSDK.h"
+
+typedef struct CUgraphicsResource_st* CUgraphicsResource;
+
+// REMOVE OLD REGISTERS/UNREGISTER FACTORY PREPROCESSOR APPROACHES
+// #define PARAM_CLASS_DECLARE_FACTORY(clas) clas ## Factory m ## clas ## Factory;
+// #define PARAM_CLASS_REGISTER_FACTORY(t, clas) t->registerFactory(m ## clas ## Factory);
+// #define PARAM_CLASS_REMOVE_FACTORY(t, clas) t->removeFactory(clas::staticClassName()); clas::freeParameterDefinitionTable(t);
+
+namespace physx
+{
+ namespace pvdsdk
+ {
+ class PvdDataStream;
+ }
+}
+
+namespace nvidia
+{
+namespace apex
+{
+
+class SceneIntl;
+class ModuleSceneIntl;
+class RenderDebugInterface;
+class ApexActor;
+class Actor;
+class ModuleCachedDataIntl;
+struct SceneStats;
+
+/**
+Framework interface to modules for use by ApexScenes and the ApexSDK
+*/
+class ModuleIntl
+{
+public:
+ ModuleIntl(void)
+ {
+ mParent = NULL;
+ mCreateOk = true;
+ }
+ virtual ~ModuleIntl(void)
+ {
+ if ( mParent )
+ {
+ mParent->notifyChildGone(this);
+ }
+ }
+ /**
+ Cause a module to free all of its resources. Only callable from ApexSDK::releaseModule()
+ */
+ virtual void destroy() = 0;
+
+ /**
+ Notification from ApexSDK when it is being destructed and will, therefore, be releasing all modules
+ */
+ virtual void notifyReleaseSDK(void)
+ {
+
+ }
+
+ /**
+ Inits Classes sent to Pvd from this module
+ */
+ virtual void initPvdClasses(pvdsdk::PvdDataStream& /*pvdDataStream*/)
+ {
+ }
+
+ /**
+ Inits Instances when Pvd connects
+ */
+ virtual void initPvdInstances(pvdsdk::PvdDataStream& /*pvdDataStream*/)
+ {
+ }
+
+ /**
+ Called by a newly created Scene to instantiate an ModuleSceneIntl. Can also be
+ called when modules are created after scenes. If your module does
+ not create ApexActors, this function can return NULL.
+
+ The debug render that the scene is to use is also passed.
+ */
+ virtual ModuleSceneIntl* createInternalModuleScene(SceneIntl& apexScene, RenderDebugInterface*) = 0;
+
+ /**
+ Release an ModuleSceneIntl. Only called when an ApexScene has been released.
+ All actors and other resources in the context should be released.
+ */
+ virtual void releaseModuleSceneIntl(ModuleSceneIntl& moduleScene) = 0;
+
+ /**
+ Module can provide a data cache for its objects. It is valid to return NULL.
+ */
+ virtual ModuleCachedDataIntl* getModuleDataCache()
+ {
+ return NULL;
+ }
+
+ /**
+ Returns the number of assets force loaded by all of the module's loaded assets
+ Default impl returns 0, maybe this should be something really bad
+ */
+ virtual uint32_t forceLoadAssets()
+ {
+ return 0;
+ }
+
+ virtual ApexActor* getApexActor(Actor*, AuthObjTypeID) const
+ {
+ return NULL;
+ }
+
+ virtual void setParent(ModuleIntl *parent)
+ {
+ mParent = parent;
+ }
+
+ virtual void notifyChildGone(ModuleIntl *child)
+ {
+ PX_UNUSED(child);
+ }
+
+ void setCreateOk(bool state)
+ {
+ mCreateOk = state;
+ }
+
+ bool isCreateOk(void) const
+ {
+ return mCreateOk;
+ }
+
+ bool mCreateOk;
+ ModuleIntl *mParent;
+};
+
+class ModuleSceneIntl
+{
+public:
+
+ /**
+ ModuleSceneIntl::simulate() is called by ApexScene::simulate() from the context of the
+ APEX API call (typically the main game thread). Context sensitive code should run here.
+ Note that the task manager will be executing tasks while simulate() is running, so it must
+ be thread safe.
+ \param elapsedTime The time passed to the Scene::simulate call
+ */
+ virtual void simulate(float elapsedTime)
+ {
+ PX_UNUSED(elapsedTime);
+ }
+
+ /**
+ \brief If the PhysX scene runs with multiple substeps, modules can request manual substepping
+ */
+ virtual bool needsManualSubstepping() const
+ {
+ return false;
+ }
+
+ virtual void interStep(uint32_t substepNumber, uint32_t maxSubSteps)
+ {
+ PX_UNUSED(substepNumber);
+ PX_UNUSED(maxSubSteps);
+ }
+
+ /**
+ ModuleSceneIntl::submitTasks() is called by ApexScene::simulate() at the start of every
+ simulation step. Each module should submit tasks within this function call, though
+ they are not restricted from submitting tasks later if they require.
+ \param elapsedTime The time passed to the Scene::simulate call
+ \param numSubSteps Will be >1 if manual sub stepping is turned on, 1 otherwise
+ */
+ virtual void submitTasks(float elapsedTime, float substepSize, uint32_t numSubSteps) = 0;
+
+ /**
+ ModuleSceneIntl::setTaskDependencies() is called by ApexScene::simulate() after every
+ module has had the opportunity to submit their tasks to the task manager. Therefore it
+ is safe to set dependencies in this function based on cross-module TaskID APIs.
+ */
+ virtual void setTaskDependencies() {}
+
+ /**
+ ModuleSceneIntl::fetchResults() is called by ApexScene::fetchResults() from the context of
+ the APEX API call (typically the main game thread). All renderable actors are locked by
+ the scene for the length of this function call.
+ */
+ virtual void fetchResults() = 0;
+
+ virtual void fetchResultsPreRenderLock() {}
+ virtual void fetchResultsPostRenderUnlock() {}
+
+#if PX_PHYSICS_VERSION_MAJOR == 3
+ /**
+ Called by ApexScene when its PxScene reference has changed. Provided pointer can be NULL.
+ */
+ virtual void setModulePhysXScene(PxScene* s) = 0;
+ virtual PxScene* getModulePhysXScene() const = 0;
+#endif // PX_PHYSICS_VERSION_MAJOR == 3
+
+ /**
+ Called by ApexScene when it has been released. The ModuleSceneIntl must call its
+ module's releaseModuleSceneIntl() method.
+ */
+ virtual void release() = 0;
+
+ /**
+ \brief Visualize the module's contents, using the new debug rendering facilities.
+
+ This gets called from Scene::updateRenderResources
+ */
+ virtual void visualize() = 0;
+
+ /**
+ \brief Returns the corresponding Module.
+
+ This allows to get to information like the module name.
+ */
+ virtual Module* getModule() = 0;
+
+ /**
+ \brief Lock render resources according to module scene-defined behavior.
+
+ Returns true iff successful.
+ */
+ virtual bool lockRenderResources() { return false; }
+
+ /**
+ \brief Unlock render resources according to module scene-defined behavior.
+
+ Returns true iff successful.
+ */
+ virtual bool unlockRenderResources() { return false; }
+
+ virtual SceneStats* getStats() = 0;
+
+ /**
+ \brief return ApexCudaObj from CudaModuleScene or NULL for non CUDA scenes
+ Should be implemented only for scenes that inherited from CudaModuleScene
+ */
+ virtual void* getHeadCudaObj()
+ {
+ return NULL;
+ }
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif // MODULE_INTL_H
diff --git a/APEX_1.4/common/include/ModuleIofxIntl.h b/APEX_1.4/common/include/ModuleIofxIntl.h
new file mode 100644
index 00000000..bb23cb04
--- /dev/null
+++ b/APEX_1.4/common/include/ModuleIofxIntl.h
@@ -0,0 +1,35 @@
+/*
+ * 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_IOFX_INTL_H
+#define MODULE_IOFX_INTL_H
+
+#include "ModuleIntl.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+class IofxManagerDescIntl;
+class IofxManagerIntl;
+class Scene;
+
+class ModuleIofxIntl : public ModuleIntl
+{
+public:
+ virtual IofxManagerIntl* createActorManager(const Scene& scene, const nvidia::apex::IofxAsset& asset, const IofxManagerDescIntl& desc) = 0;
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif // MODULE_IOFX_INTL_H
diff --git a/APEX_1.4/common/include/ModuleUpdateLoader.h b/APEX_1.4/common/include/ModuleUpdateLoader.h
new file mode 100644
index 00000000..d64d1eef
--- /dev/null
+++ b/APEX_1.4/common/include/ModuleUpdateLoader.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.
+ */
+
+
+#ifndef MODULEUPDATELOADER_H
+#define MODULEUPDATELOADER_H
+
+#ifdef WIN32
+
+#if PX_X64
+#define UPDATE_LOADER_DLL_NAME "PhysXUpdateLoader64.dll"
+#else
+#define UPDATE_LOADER_DLL_NAME "PhysXUpdateLoader.dll"
+#endif
+
+// This GUID should change any time we release APEX with a public interface change.
+#if PX_PHYSICS_VERSION_MAJOR == 0
+#define DEFAULT_APP_GUID "165F143C-15CB-47FA-ACE3-2002B3684026"
+#else
+#define DEFAULT_APP_GUID "1AE7180B-79E5-4234-91A7-E387331B5993"
+#endif
+
+//#include "PsWindowsInclude.h"
+#include <windows.h>
+
+class ModuleUpdateLoader
+{
+public:
+ ModuleUpdateLoader(const char* updateLoaderDllName);
+ ~ModuleUpdateLoader();
+
+ // Loads the given module through the update loader. Loads it from the path if
+ // the update loader doesn't find the requested module. Returns NULL if no
+ // module found.
+ HMODULE loadModule(const char* moduleName, const char* appGuid);
+
+protected:
+ HMODULE mUpdateLoaderDllHandle;
+ FARPROC mGetUpdatedModuleFunc;
+
+ // unit test fixture
+ friend class ModuleUpdateLoaderTest;
+};
+
+#endif // WIN32
+#endif // MODULEUPDATELOADER_H
diff --git a/APEX_1.4/common/include/P4Info.h b/APEX_1.4/common/include/P4Info.h
new file mode 100644
index 00000000..16ad7efb
--- /dev/null
+++ b/APEX_1.4/common/include/P4Info.h
@@ -0,0 +1,45 @@
+// 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.
+
+#ifndef P4_INFO_H
+#define P4_INFO_H
+
+#define P4_CHANGELIST 1111
+
+#define P4_TOOLS_CHANGELIST 1111
+
+#define P4_APEX_VERSION_STRING "1.4"
+
+#define P4_APEX_BRANCH "trunk"
+
+#define P4_BUILD_TIME "12:20:57, Fri Oct 21, 2016"
+
+#define AUTHOR_DISTRO "empty"
+
+#define REASON_DISTRO "empty"
+
+#endif // P4_INFO_H
diff --git a/APEX_1.4/common/include/PVDParameterizedHandler.h b/APEX_1.4/common/include/PVDParameterizedHandler.h
new file mode 100644
index 00000000..4ac59273
--- /dev/null
+++ b/APEX_1.4/common/include/PVDParameterizedHandler.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.
+ */
+
+
+#ifndef PVD_PARAMETERIZED_HANDLER
+#define PVD_PARAMETERIZED_HANDLER
+
+#include "ApexUsingNamespace.h"
+#ifndef WITHOUT_PVD
+
+#include "PsUserAllocated.h"
+#include "ApexPvdClient.h"
+
+#include "PsHashSet.h"
+#include "PsHashMap.h"
+
+namespace NvParameterized
+{
+class Definition;
+class Handle;
+}
+
+namespace physx
+{
+namespace pvdsdk
+{
+ struct NamespacedName;
+
+ class PvdDataStream;
+
+ class StructId
+ {
+ public:
+ StructId(void* address, const char* name) :
+ mAddress(address),
+ mName(name)
+ {}
+
+ bool operator<(const StructId& other) const
+ {
+ if (mAddress < other.mAddress)
+ return true;
+ else
+ return (mAddress == other.mAddress) && strcmp(mName, other.mName) < 0;
+ }
+
+ bool operator==(const StructId& other) const
+ {
+ return (mAddress == other.mAddress) && strcmp(mName, other.mName) == 0;
+ }
+
+ operator size_t() const
+ {
+ return (size_t)mAddress;
+ }
+
+ private:
+ void* mAddress;
+ const char* mName;
+ };
+
+ class PvdParameterizedHandler : public nvidia::UserAllocated
+ {
+ public:
+
+ PvdParameterizedHandler(pvdsdk::PvdDataStream& pvdStream) :
+ mPvdStream(&pvdStream)
+ ,mNextStructId(1)
+ {
+ }
+
+ /**
+ \brief Adds properties to the provided pvdClassName and creates classes for Structs that are inside the paramDefinition tree (not for references, though)
+ */
+ void initPvdClasses(const NvParameterized::Definition& paramDefinition, const char* pvdClassName);
+
+ /**
+ \brief Updates the provided pvd instance properties with the values in the provided handle, recursively.
+ pvdAction specifies if only properties are updated, if pvd instances for structs should be created (for initialization) or if they should be destroyed.
+ */
+ void updatePvd(const void* pvdInstance, NvParameterized::Handle& paramsHandle, PvdAction::Enum pvdAction = PvdAction::UPDATE);
+
+ protected:
+
+ bool createClass(const NamespacedName& className);
+ bool getPvdType(const NvParameterized::Definition& def, pvdsdk::NamespacedName& pvdTypeName);
+ size_t getStructId(void* structAddress, const char* structName, bool deleteId);
+ const void* getPvdId(const NvParameterized::Handle& handle, bool deleteId);
+ bool setProperty(const void* pvdInstance, NvParameterized::Handle& propertyHandle, bool isArrayElement, PvdAction::Enum pvdAction);
+
+
+ pvdsdk::PvdDataStream* mPvdStream;
+
+ physx::shdfnd::HashSet<const char*> mCreatedClasses;
+ physx::shdfnd::HashSet<const void*> mInstanceIds;
+
+ size_t mNextStructId;
+ nvidia::HashMap<StructId, size_t>mStructIdMap;
+ };
+
+} // namespacePvdNxParamSerializer
+}
+
+#endif //WITHOUT_PVD
+
+#endif // #ifndef PVD_PARAMETERIZED_HANDLER \ No newline at end of file
diff --git a/APEX_1.4/common/include/PhysXObjectDescIntl.h b/APEX_1.4/common/include/PhysXObjectDescIntl.h
new file mode 100644
index 00000000..1fd999d0
--- /dev/null
+++ b/APEX_1.4/common/include/PhysXObjectDescIntl.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 PHYSX_OBJECT_DESC_INTL_H
+#define PHYSX_OBJECT_DESC_INTL_H
+
+#include "PhysXObjectDesc.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+/**
+ * Module/Asset interface to actor info structure. This allows the asset to
+ * set the various flags without knowing their implementation.
+ */
+class PhysXObjectDescIntl : public PhysXObjectDesc
+{
+public:
+ void setIgnoreTransform(bool b)
+ {
+ if (b)
+ {
+ mFlags |= TRANSFORM;
+ }
+ else
+ {
+ mFlags &= ~(uint32_t)TRANSFORM;
+ }
+ };
+ void setIgnoreRaycasts(bool b)
+ {
+ if (b)
+ {
+ mFlags |= RAYCASTS;
+ }
+ else
+ {
+ mFlags &= ~(uint32_t)RAYCASTS;
+ }
+ };
+ void setIgnoreContacts(bool b)
+ {
+ if (b)
+ {
+ mFlags |= CONTACTS;
+ }
+ else
+ {
+ mFlags &= ~(uint32_t)CONTACTS;
+ }
+ };
+ void setUserDefinedFlag(uint32_t index, bool b)
+ {
+ if (b)
+ {
+ mFlags |= (1 << index);
+ }
+ else
+ {
+ mFlags &= ~(1 << index);
+ }
+ }
+
+ /**
+ \brief Implementation of pure virtual functions in PhysXObjectDesc, used for external (read-only)
+ access to the Actor list
+ */
+ uint32_t getApexActorCount() const
+ {
+ return mApexActors.size();
+ }
+ const Actor* getApexActor(uint32_t i) const
+ {
+ return mApexActors[i];
+ }
+
+
+ void swap(PhysXObjectDescIntl& rhs)
+ {
+ mApexActors.swap(rhs.mApexActors);
+ nvidia::swap(mPhysXObject, rhs.mPhysXObject);
+
+ nvidia::swap(userData, rhs.userData);
+ nvidia::swap(mFlags, rhs.mFlags);
+ }
+
+ /**
+ \brief Array of pointers to APEX actors assiciated with this PhysX object
+
+ Pointers may be NULL in cases where the APEX actor has been deleted
+ but PhysX actor cleanup has been deferred
+ */
+ physx::Array<const Actor*> mApexActors;
+
+ /**
+ \brief the PhysX object which uses this descriptor
+ */
+ const void* mPhysXObject;
+protected:
+ virtual ~PhysXObjectDescIntl(void) {}
+};
+
+}
+} // end namespace nvidia::apex
+
+#endif // PHYSX_OBJECT_DESC_INTL_H
diff --git a/APEX_1.4/common/include/ProfilerCallback.h b/APEX_1.4/common/include/ProfilerCallback.h
new file mode 100644
index 00000000..bf36aefe
--- /dev/null
+++ b/APEX_1.4/common/include/ProfilerCallback.h
@@ -0,0 +1,19 @@
+/*
+ * 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_PROFILER_CALLBACK_H
+#define PX_PROFILER_CALLBACK_H
+
+#include "PxProfiler.h"
+
+#endif
+
diff --git a/APEX_1.4/common/include/RandState.h b/APEX_1.4/common/include/RandState.h
new file mode 100644
index 00000000..315adde0
--- /dev/null
+++ b/APEX_1.4/common/include/RandState.h
@@ -0,0 +1,185 @@
+/*
+ * 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 RAND_STATE_H
+#define RAND_STATE_H
+
+// This is shared by legacy IOFX and shaders
+
+namespace nvidia
+{
+namespace apex
+{
+
+struct LCG_PRNG
+{
+ unsigned int a, c;
+
+ PX_CUDA_CALLABLE PX_INLINE LCG_PRNG()
+ {
+ }
+ PX_CUDA_CALLABLE PX_INLINE LCG_PRNG(unsigned int a, unsigned int c)
+ {
+ this->a = a;
+ this->c = c;
+ }
+
+ static PX_CUDA_CALLABLE PX_INLINE LCG_PRNG getIdentity()
+ {
+ return LCG_PRNG(1, 0);
+ }
+
+ static PX_CUDA_CALLABLE PX_INLINE LCG_PRNG getDefault()
+ {
+ return LCG_PRNG(1103515245u, 12345u);
+ }
+
+ PX_CUDA_CALLABLE PX_INLINE LCG_PRNG& operator *= (const LCG_PRNG& rhs)
+ {
+ a *= rhs.a;
+ c *= rhs.a; c += rhs.c;
+ return *this;
+ }
+
+ PX_CUDA_CALLABLE PX_INLINE LCG_PRNG leapFrog(unsigned int leap) const
+ {
+ LCG_PRNG ret = getIdentity();
+ for (unsigned int i = 0; i < leap; ++i)
+ {
+ ret *= (*this);
+ }
+ return ret;
+ }
+
+ PX_CUDA_CALLABLE PX_INLINE unsigned int operator()(unsigned int x) const
+ {
+ return x * a + c;
+ }
+};
+
+struct RandState
+{
+ explicit PX_CUDA_CALLABLE PX_INLINE RandState(unsigned int seed)
+ {
+ curr = seed;
+ }
+
+ PX_CUDA_CALLABLE PX_INLINE unsigned int next()
+ {
+ return (curr = LCG_PRNG::getDefault()(curr));
+ }
+
+ PX_CUDA_CALLABLE PX_INLINE float nextFloat()
+ {
+ return float(next()) * 0.00000000023283064365386962890625f;
+ }
+ PX_CUDA_CALLABLE PX_INLINE float nextFloat(float min, float max)
+ {
+ return min + nextFloat() * (max - min);
+ }
+
+private:
+ unsigned int curr;
+};
+
+// For CUDA PRNG
+struct PRNGInfo
+{
+ unsigned int* g_stateSpawnSeed;
+ nvidia::LCG_PRNG* g_randBlock;
+ unsigned int seed;
+ nvidia::LCG_PRNG randThread;
+ nvidia::LCG_PRNG randGrid;
+};
+
+// For CUDA PRNG: device part
+#ifdef __CUDACC__
+//*
+#define RAND_SCAN_OP(ofs) \
+ { \
+ unsigned int a = aData[scanIdx], c = cData[scanIdx]; \
+ unsigned int aOfs = aData[scanIdx - ofs], cOfs = cData[scanIdx - ofs]; \
+ aData[scanIdx] = a * aOfs; \
+ cData[scanIdx] = c * aOfs + cOfs; \
+ }
+/*/
+//THIS CODE CRASH ON CUDA 5.0.35
+#define RAND_SCAN_OP(ofs) \
+ { \
+ nvidia::LCG_PRNG val(aData[scanIdx], cData[scanIdx]); \
+ nvidia::LCG_PRNG valOfs(aData[scanIdx - ofs], cData[scanIdx - ofs]); \
+ val *= valOfs; \
+ aData[scanIdx] = val.a; cData[scanIdx] = val.c; \
+ }
+//*/
+PX_INLINE __device__ void randScanWarp(unsigned int scanIdx, volatile unsigned int* aData, volatile unsigned int* cData)
+{
+ RAND_SCAN_OP(1);
+ RAND_SCAN_OP(2);
+ RAND_SCAN_OP(4);
+ RAND_SCAN_OP(8);
+ RAND_SCAN_OP(16);
+}
+
+PX_INLINE __device__ nvidia::LCG_PRNG randScanBlock(nvidia::LCG_PRNG val, volatile unsigned int* aData, volatile unsigned int* cData)
+{
+ const unsigned int idx = threadIdx.x;
+ const unsigned int idxInWarp = idx & (WARP_SIZE-1);
+ const unsigned int warpIdx = (idx >> LOG2_WARP_SIZE);
+
+ //setup scan
+ unsigned int scanIdx = (warpIdx << (LOG2_WARP_SIZE + 1)) + idxInWarp;
+ //write identity
+ aData[scanIdx] = 1;
+ cData[scanIdx] = 0;
+
+ scanIdx += WARP_SIZE;
+ //write value
+ aData[scanIdx] = val.a;
+ cData[scanIdx] = val.c;
+
+ randScanWarp(scanIdx, aData, cData);
+
+ //read value
+ val.a = aData[scanIdx];
+ val.c = cData[scanIdx];
+
+ __syncthreads();
+
+ if (idxInWarp == WARP_SIZE-1)
+ {
+ const unsigned int idxWrite = warpIdx + WARP_SIZE;
+ aData[idxWrite] = val.a;
+ cData[idxWrite] = val.c;
+ }
+ __syncthreads();
+
+ if (warpIdx == 0)
+ {
+ randScanWarp(scanIdx, aData, cData);
+ }
+ __syncthreads();
+
+ if (warpIdx > 0)
+ {
+ const unsigned int idxRead = warpIdx + WARP_SIZE - 1;
+ const nvidia::LCG_PRNG valWarp(aData[idxRead], cData[idxRead]);
+ val *= valWarp;
+ }
+ return val;
+}
+
+#endif
+
+}
+} // nvidia::apex::
+
+#endif \ No newline at end of file
diff --git a/APEX_1.4/common/include/RandStateHelpers.h b/APEX_1.4/common/include/RandStateHelpers.h
new file mode 100644
index 00000000..afd79801
--- /dev/null
+++ b/APEX_1.4/common/include/RandStateHelpers.h
@@ -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.
+ */
+
+
+#ifndef RAND_STATE_HELPERS_H
+#define RAND_STATE_HELPERS_H
+
+#include "PxTask.h"
+#include "ApexMirroredArray.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+// For CUDA PRNG: host part
+PX_INLINE void InitDevicePRNGs(
+ SceneIntl& scene,
+ unsigned int blockSize,
+ LCG_PRNG& threadLeap,
+ LCG_PRNG& gridLeap,
+ ApexMirroredArray<LCG_PRNG>& blockPRNGs)
+{
+ threadLeap = LCG_PRNG::getDefault().leapFrog(16);
+
+ LCG_PRNG randBlock = LCG_PRNG::getIdentity();
+ LCG_PRNG randBlockLeap = threadLeap.leapFrog(blockSize);
+
+ const uint32_t numBlocks = 32; //Max Multiprocessor count
+ blockPRNGs.setSize(numBlocks, ApexMirroredPlace::CPU_GPU);
+ for (uint32_t i = 0; i < numBlocks; ++i)
+ {
+ blockPRNGs[i] = randBlock;
+ randBlock *= randBlockLeap;
+ }
+ gridLeap = randBlock;
+
+ {
+ PxTaskManager* tm = scene.getTaskManager();
+ PxCudaContextManager* ctx = tm->getGpuDispatcher()->getCudaContextManager();
+
+ PxScopedCudaLock s(*ctx);
+
+ PxGpuCopyDesc desc;
+ blockPRNGs.copyHostToDeviceDesc(desc, 0, 0);
+ tm->getGpuDispatcher()->launchCopyKernel(&desc, 1, 0);
+ }
+}
+
+}
+} // nvidia::apex::
+
+#endif
diff --git a/APEX_1.4/common/include/ReadCheck.h b/APEX_1.4/common/include/ReadCheck.h
new file mode 100644
index 00000000..21529ae5
--- /dev/null
+++ b/APEX_1.4/common/include/ReadCheck.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 READ_CHECK_H
+#define READ_CHECK_H
+
+#include "PxSimpleTypes.h"
+#include "ApexUsingNamespace.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+class ApexRWLockable;
+
+// RAII wrapper around the Scene::apexStartRead() method, note that this
+// object does not acquire any scene locks, it is an error checking only mechanism
+class ReadCheck
+{
+public:
+ ReadCheck(const ApexRWLockable* scene, const char* functionName);
+ ~ReadCheck();
+
+private:
+ const ApexRWLockable* mLockable;
+ const char* mName;
+ uint32_t mErrorCount;
+};
+
+#if (PX_DEBUG || PX_CHECKED)
+ // Creates a scoped read check object that detects whether appropriate scene locks
+ // have been acquired and checks if reads/writes overlap, this macro should typically
+ // be placed at the beginning of any const API methods that are not multi-thread safe,
+ // the error conditions checked can be summarized as:
+
+ // 1. Other threads were already writing, or began writing during the object lifetime
+ #define READ_ZONE() ReadCheck __readCheck(static_cast<const ApexRWLockable*>(this), __FUNCTION__);
+#else
+ #define READ_ZONE()
+#endif
+
+}
+}
+
+#endif // READ_CHECK_H
diff --git a/APEX_1.4/common/include/RenderAPIIntl.h b/APEX_1.4/common/include/RenderAPIIntl.h
new file mode 100644
index 00000000..481712be
--- /dev/null
+++ b/APEX_1.4/common/include/RenderAPIIntl.h
@@ -0,0 +1,515 @@
+/*
+ * 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 RENDER_API_INTL_H
+#define RENDER_API_INTL_H
+
+#include "PsArray.h"
+#include "PsMutex.h"
+#include "UserRenderCallback.h"
+#if APEX_CUDA_SUPPORT
+#include <cuda.h>
+#endif
+
+namespace nvidia
+{
+namespace apex
+{
+
+struct RenderEntityMapStateIntl
+{
+ enum Enum
+ {
+ UNMAPPED = 0,
+ PENDING_MAP,
+ MAPPED,
+ PENDING_UNMAP
+ };
+};
+
+class RenderStorageStateIntl
+{
+public:
+ PX_INLINE bool isMapped() const { return (mMapFlags & MAPPED) != 0; }
+
+ virtual bool map(UserRenderStorage* renderStorage, RenderMapType::Enum mapType) = 0;
+ virtual void unmap(UserRenderStorage* renderStorage) = 0;
+
+#if APEX_CUDA_SUPPORT
+ PX_INLINE bool isCudaMapped() const { return (mMapFlags & CUDA_MAPPED) != 0; }
+ PX_INLINE void setCudaMapped() { mMapFlags |= CUDA_MAPPED; }
+ PX_INLINE void resetCudaMapped() { mMapFlags &= ~CUDA_MAPPED; }
+
+ virtual CUgraphicsResource getCudaHandle(UserRenderStorage* renderStorage) = 0;
+ virtual bool getCudaMapppedResult(UserRenderStorage* renderStorage) = 0;
+
+ PX_INLINE bool checkCudaHandle() const { return mInteropHandle != NULL; }
+ PX_INLINE void resetCudaHandle() { mInteropHandle = NULL; }
+#endif
+
+protected:
+ RenderStorageStateIntl()
+ : mMapFlags(0)
+#if APEX_CUDA_SUPPORT
+ , mInteropHandle(NULL)
+#endif
+ {
+ }
+
+ enum MapFlag
+ {
+ MAPPED = 0x01,
+#if APEX_CUDA_SUPPORT
+ CUDA_MAPPED = 0x02,
+#endif
+ };
+ uint32_t mMapFlags;
+
+#if APEX_CUDA_SUPPORT
+ CUgraphicsResource mInteropHandle;
+#endif
+};
+
+class RenderBufferStateIntl : public RenderStorageStateIntl
+{
+public:
+ RenderBufferStateIntl()
+ : mMappedPtr(NULL)
+#if APEX_CUDA_SUPPORT
+ , mMappedCudaPtr(NULL)
+#endif
+ , mMapOffset(0)
+ , mMapSize(SIZE_MAX)
+ {
+ }
+
+ PX_INLINE void* getMappedPtr() const
+ {
+ return mMappedPtr;
+ }
+
+ PX_INLINE void setMapRange(size_t offset, size_t size)
+ {
+ mMapOffset = offset;
+ mMapSize = size;
+ }
+
+ virtual bool map(UserRenderStorage* renderStorage, RenderMapType::Enum mapType)
+ {
+ if ((mMapFlags & MAPPED) == 0)
+ {
+ PX_ASSERT(renderStorage->getType() == UserRenderStorage::BUFFER);
+ UserRenderBuffer* renderBuffer = static_cast<UserRenderBuffer*>(renderStorage);
+ mMappedPtr = renderBuffer->map(mapType, mMapOffset, mMapSize);
+ if (mMappedPtr != NULL)
+ {
+ mMapFlags += MAPPED;
+ }
+ }
+ return (mMapFlags & MAPPED) != 0;
+ }
+ virtual void unmap(UserRenderStorage* renderStorage)
+ {
+ if ((mMapFlags & MAPPED) != 0)
+ {
+ PX_ASSERT(renderStorage->getType() == UserRenderStorage::BUFFER);
+ UserRenderBuffer* renderBuffer = static_cast<UserRenderBuffer*>(renderStorage);
+ renderBuffer->unmap();
+ mMappedPtr = NULL;
+ mMapFlags -= MAPPED;
+ //reset map range
+ mMapOffset = 0;
+ mMapSize = SIZE_MAX;
+ }
+ }
+
+#if APEX_CUDA_SUPPORT
+ PX_INLINE CUdeviceptr getMappedCudaPtr() const
+ {
+ return mMappedCudaPtr;
+ }
+
+ virtual CUgraphicsResource getCudaHandle(UserRenderStorage* renderStorage)
+ {
+ if (mInteropHandle == NULL)
+ {
+ PX_ASSERT(renderStorage->getType() == UserRenderStorage::BUFFER);
+ UserRenderBuffer* renderBuffer = static_cast<UserRenderBuffer*>(renderStorage);
+ renderBuffer->getCUDAgraphicsResource(mInteropHandle);
+ }
+ return mInteropHandle;
+ }
+
+ virtual bool getCudaMapppedResult(UserRenderStorage* renderStorage)
+ {
+ PX_UNUSED(renderStorage);
+ if (mInteropHandle != NULL)
+ {
+ size_t size = 0;
+ if (cuGraphicsResourceGetMappedPointer(&mMappedCudaPtr, &size, mInteropHandle) == CUDA_SUCCESS)
+ {
+ return true;
+ }
+ mMappedCudaPtr = NULL;
+ }
+ return false;
+ }
+#endif
+
+private:
+ void* mMappedPtr;
+#if APEX_CUDA_SUPPORT
+ CUdeviceptr mMappedCudaPtr;
+#endif
+ size_t mMapOffset;
+ size_t mMapSize;
+};
+
+class RenderSurfaceStateIntl : public RenderStorageStateIntl
+{
+public:
+ RenderSurfaceStateIntl()
+#if APEX_CUDA_SUPPORT
+ : mMappedCudaArray(NULL)
+#endif
+ {
+ }
+
+ PX_INLINE const UserRenderSurface::MappedInfo& getMappedInfo() const
+ {
+ return mMappedInfo;
+ }
+
+ virtual bool map(UserRenderStorage* renderStorage, RenderMapType::Enum mapType)
+ {
+ if ((mMapFlags & MAPPED) == 0)
+ {
+ PX_ASSERT(renderStorage->getType() == UserRenderStorage::SURFACE);
+ UserRenderSurface* renderSurface = static_cast<UserRenderSurface*>(renderStorage);
+ if (renderSurface->map(mapType, mMappedInfo))
+ {
+ mMapFlags += MAPPED;
+ }
+ }
+ return (mMapFlags & MAPPED) != 0;
+ }
+ virtual void unmap(UserRenderStorage* renderStorage)
+ {
+ if ((mMapFlags & MAPPED) != 0)
+ {
+ PX_ASSERT(renderStorage->getType() == UserRenderStorage::SURFACE);
+ UserRenderSurface* renderSurface = static_cast<UserRenderSurface*>(renderStorage);
+ renderSurface->unmap();
+ mMapFlags -= MAPPED;
+ }
+ }
+#if APEX_CUDA_SUPPORT
+ PX_INLINE CUarray getMappedCudaArray() const
+ {
+ return mMappedCudaArray;
+ }
+
+ virtual CUgraphicsResource getCudaHandle(UserRenderStorage* renderStorage)
+ {
+ if (mInteropHandle == NULL)
+ {
+ PX_ASSERT(renderStorage->getType() == UserRenderStorage::SURFACE);
+ UserRenderSurface* renderSurface = static_cast<UserRenderSurface*>(renderStorage);
+ renderSurface->getCUDAgraphicsResource(mInteropHandle);
+ }
+ return mInteropHandle;
+ }
+
+ virtual bool getCudaMapppedResult(UserRenderStorage* renderStorage)
+ {
+ PX_UNUSED(renderStorage);
+ if (mInteropHandle != NULL)
+ {
+ //TODO: cuGraphicsSubResourceGetMappedArray arrayIndex & mipLevel???
+ if (cuGraphicsSubResourceGetMappedArray(&mMappedCudaArray, mInteropHandle, 0, 0) == CUDA_SUCCESS)
+ {
+ return true;
+ }
+ mMappedCudaArray = NULL;
+ }
+ return false;
+ }
+#endif
+
+private:
+ UserRenderSurface::MappedInfo mMappedInfo;
+#if APEX_CUDA_SUPPORT
+ CUarray mMappedCudaArray;
+#endif
+};
+
+class RenderEntityIntl : public UserAllocated
+{
+public:
+ virtual ~RenderEntityIntl() { PX_ASSERT(mRefCount == 0); }
+
+ virtual void free() = 0;
+
+
+ virtual void map() = 0;
+ virtual void unmap() = 0;
+
+#if APEX_CUDA_SUPPORT
+ virtual void fillMapUnmapArraysForInterop(nvidia::Array<CUgraphicsResource> &toMapArray, nvidia::Array<CUgraphicsResource> &toUnmapArray) = 0;
+ virtual void mapBufferResultsForInterop(bool mapSuccess, bool unmapSuccess) = 0;
+#endif
+
+ //
+ virtual void release()
+ {
+ bool triggerDelete = false;
+ mRefCountLock.lock();
+ if (mRefCount > 0)
+ {
+ triggerDelete = (--mRefCount) == 0;
+ }
+ mRefCountLock.unlock();
+ if (triggerDelete)
+ {
+ destroy();
+ }
+ }
+
+ // Returns this if successful, NULL otherwise
+ RenderEntityIntl* incrementReferenceCount()
+ {
+ RenderEntityIntl* returnValue = NULL;
+ mRefCountLock.lock();
+ if (mRefCount > 0)
+ {
+ ++mRefCount;
+ returnValue = this;
+ }
+ mRefCountLock.unlock();
+ return returnValue;
+ }
+
+ PX_INLINE int32_t getReferenceCount() const
+ {
+ return mRefCount;
+ }
+
+protected:
+ RenderEntityIntl()
+ : mRefCount(1) // Ref count initialized to 1, assuming that whoever calls this constructor will store a reference
+ {
+ }
+
+ virtual void destroy()
+ {
+ PX_DELETE(this);
+ }
+
+ volatile int32_t mRefCount;
+ physx::shdfnd::Mutex mRefCountLock;
+
+
+private:
+ RenderEntityIntl& operator=(const RenderEntityIntl&);
+};
+
+template <typename Impl, typename Base>
+class RenderEntityIntlImpl : public Base
+{
+protected:
+ PX_INLINE const Impl* getImpl() const { return static_cast<const Impl*>(this); }
+ PX_INLINE Impl* getImpl() { return static_cast<Impl*>(this); }
+
+public:
+ virtual ~RenderEntityIntlImpl()
+ {
+ getImpl()->freeAllRenderStorage();
+ }
+
+
+ virtual void free()
+ {
+ getImpl()->freeAllRenderStorage();
+ mMapState = RenderEntityMapStateIntl::UNMAPPED;
+ }
+
+ virtual void map()
+ {
+ if (mMapState == RenderEntityMapStateIntl::UNMAPPED)
+ {
+ if (mInteropFlags == RenderInteropFlags::CUDA_INTEROP)
+ {
+ mMapState = RenderEntityMapStateIntl::PENDING_MAP;
+ return;
+ }
+
+ bool result = false;
+ if (getImpl()->getRenderStorageCount() > 0)
+ {
+ //map render resources
+ result = true;
+ for (uint32_t i = 0; result && i < getImpl()->getRenderStorageCount(); ++i)
+ {
+ UserRenderStorage* renderStorage;
+ RenderInteropFlags::Enum interopFlags;
+ RenderStorageStateIntl& renderStorageState = getImpl()->getRenderStorage(i, renderStorage, interopFlags);
+ if (renderStorage)
+ {
+ getImpl()->onMapRenderStorage(i);
+ result &= renderStorageState.map(renderStorage, RenderMapType::MAP_WRITE_DISCARD);
+ }
+ }
+ if (!result)
+ {
+ //unmap in case of failure
+ unmapRenderResources();
+ }
+ }
+ if (result)
+ {
+ mMapState = RenderEntityMapStateIntl::MAPPED;
+ }
+ }
+ }
+
+ virtual void unmap()
+ {
+ if (mMapState == RenderEntityMapStateIntl::MAPPED)
+ {
+ if (mInteropFlags == RenderInteropFlags::CUDA_INTEROP)
+ {
+ mMapState = RenderEntityMapStateIntl::PENDING_UNMAP;
+ return;
+ }
+
+ unmapRenderResources();
+
+ mMapState = RenderEntityMapStateIntl::UNMAPPED;
+ }
+ }
+
+#if APEX_CUDA_SUPPORT
+ virtual void fillMapUnmapArraysForInterop(physx::Array<CUgraphicsResource> &toMapArray, physx::Array<CUgraphicsResource> &toUnmapArray)
+ {
+ if (mMapState == RenderEntityMapStateIntl::PENDING_MAP || mMapState == RenderEntityMapStateIntl::PENDING_UNMAP)
+ {
+ for (uint32_t i = 0; i < getImpl()->getRenderStorageCount(); ++i)
+ {
+ UserRenderStorage* renderStorage;
+ RenderInteropFlags::Enum interopFlags;
+ RenderStorageStateIntl& renderStorageState = getImpl()->getRenderStorage(i, renderStorage, interopFlags);
+ if (renderStorage && interopFlags == RenderInteropFlags::CUDA_INTEROP)
+ {
+ CUgraphicsResource interopHandle = renderStorageState.getCudaHandle(renderStorage);
+ if (interopHandle != NULL)
+ {
+ if (mMapState == RenderEntityMapStateIntl::PENDING_MAP && !renderStorageState.isCudaMapped())
+ {
+ toMapArray.pushBack(interopHandle);
+ }
+ if (mMapState == RenderEntityMapStateIntl::PENDING_UNMAP && renderStorageState.isCudaMapped())
+ {
+ toUnmapArray.pushBack(interopHandle);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ virtual void mapBufferResultsForInterop(bool mapSuccess, bool unmapSuccess)
+ {
+ PX_UNUSED(unmapSuccess);
+ if (mMapState == RenderEntityMapStateIntl::PENDING_MAP || mMapState == RenderEntityMapStateIntl::PENDING_UNMAP)
+ {
+ bool result = false;
+ if (getImpl()->getRenderStorageCount() > 0)
+ {
+ //map render resources
+ result = true;
+ for (uint32_t i = 0; i < getImpl()->getRenderStorageCount(); ++i)
+ {
+ UserRenderStorage* renderStorage;
+ RenderInteropFlags::Enum interopFlags;
+ RenderStorageStateIntl& renderStorageState = getImpl()->getRenderStorage(i, renderStorage, interopFlags);
+ if (renderStorage)
+ {
+ bool mappedResult = false;
+ if (renderStorageState.checkCudaHandle())
+ {
+ if (mMapState == RenderEntityMapStateIntl::PENDING_MAP && mapSuccess)
+ {
+ renderStorageState.setCudaMapped();
+ mappedResult = renderStorageState.getCudaMapppedResult(renderStorage);
+ }
+ if (mMapState == RenderEntityMapStateIntl::PENDING_UNMAP && unmapSuccess)
+ {
+ renderStorageState.resetCudaMapped();
+ }
+ renderStorageState.resetCudaHandle();
+ }
+ if (mMapState == RenderEntityMapStateIntl::PENDING_MAP && !mappedResult)
+ {
+ //fall back to CPU mapping
+ if (result)
+ {
+ getImpl()->onMapRenderStorage(i);
+ result &= renderStorageState.map(renderStorage, RenderMapType::MAP_WRITE_DISCARD);
+ }
+ }
+ }
+ }
+ }
+
+ if (result && mMapState == RenderEntityMapStateIntl::PENDING_MAP)
+ {
+ mMapState = RenderEntityMapStateIntl::MAPPED;
+ }
+ else
+ {
+ unmapRenderResources();
+
+ mMapState = RenderEntityMapStateIntl::UNMAPPED;
+ }
+ }
+ }
+#endif
+
+protected:
+ RenderEntityIntlImpl(RenderInteropFlags::Enum interopFlags)
+ : mInteropFlags(interopFlags)
+ , mMapState(RenderEntityMapStateIntl::UNMAPPED)
+ {
+ }
+
+ void unmapRenderResources()
+ {
+ for (uint32_t i = 0; i < getImpl()->getRenderStorageCount(); ++i)
+ {
+ UserRenderStorage* renderStorage;
+ RenderInteropFlags::Enum interopFlags;
+ RenderStorageStateIntl& renderStorageState = getImpl()->getRenderStorage(i, renderStorage, interopFlags);
+ if (renderStorage)
+ {
+ renderStorageState.unmap(renderStorage);
+ }
+ }
+ }
+
+ RenderInteropFlags::Enum mInteropFlags;
+ RenderEntityMapStateIntl::Enum mMapState;
+};
+
+
+}
+} // end namespace nvidia::apex
+
+#endif // #ifndef RENDER_API_INTL_H
diff --git a/APEX_1.4/common/include/RenderMeshAssetIntl.h b/APEX_1.4/common/include/RenderMeshAssetIntl.h
new file mode 100644
index 00000000..74c23923
--- /dev/null
+++ b/APEX_1.4/common/include/RenderMeshAssetIntl.h
@@ -0,0 +1,124 @@
+/*
+ * 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 RENDER_MESH_ASSET_INTL_H
+#define RENDER_MESH_ASSET_INTL_H
+
+#include "ApexUsingNamespace.h"
+#include "RenderMeshActor.h"
+#include "RenderMeshAsset.h"
+#include "PsArray.h"
+#include "PxMat44.h"
+
+
+/**
+\brief Describes how bones are to be assigned to render resources.
+*/
+struct RenderMeshActorSkinningMode
+{
+ enum Enum
+ {
+ Default, // Currently the same as OneBonePerPart
+ OneBonePerPart, // Used by destruction, default behavior
+ AllBonesPerPart, // All bones are written to each render resource, up to the maximum bones per material given by UserRenderResourceManager::getMaxBonesForMaterial
+
+ Count
+ };
+};
+
+
+namespace nvidia
+{
+namespace apex
+{
+
+// Forward declarations
+class DebugRenderParams;
+class RenderDebugInterface;
+
+class VertexBufferIntl : public VertexBuffer
+{
+public:
+ virtual ~VertexBufferIntl() {}
+ virtual VertexFormat& getFormatWritable() = 0;
+ virtual void build(const VertexFormat& format, uint32_t vertexCount) = 0;
+ virtual void applyTransformation(const PxMat44& transformation) = 0;
+ virtual void applyScale(float scale) = 0;
+ virtual bool mergeBinormalsIntoTangents() = 0;
+};
+
+class RenderSubmeshIntl : public RenderSubmesh
+{
+public:
+ virtual ~RenderSubmeshIntl() {}
+
+ virtual VertexBufferIntl& getVertexBufferWritable() = 0;
+ virtual uint32_t* getIndexBufferWritable(uint32_t partIndex) = 0;
+ virtual void applyPermutation(const Array<uint32_t>& old2new, const Array<uint32_t>& new2old) = 0;
+};
+
+
+/**
+* Framework interface to ApexRenderMesh for use by modules
+*/
+class RenderMeshAssetIntl : public RenderMeshAsset
+{
+public:
+ virtual RenderSubmeshIntl& getInternalSubmesh(uint32_t submeshIndex) = 0;
+ virtual void permuteBoneIndices(const physx::Array<int32_t>& old2new) = 0;
+ virtual void applyTransformation(const PxMat44& transformation, float scale) = 0;
+ virtual void reverseWinding() = 0;
+ virtual void applyScale(float scale) = 0;
+ virtual bool mergeBinormalsIntoTangents() = 0;
+ virtual void setOwnerModuleId(AuthObjTypeID id) = 0;
+ virtual TextureUVOrigin::Enum getTextureUVOrigin() const = 0;
+
+};
+
+class RenderMeshAssetAuthoringIntl : public RenderMeshAssetAuthoring
+{
+public:
+ virtual RenderSubmeshIntl& getInternalSubmesh(uint32_t submeshIndex) = 0;
+ virtual void permuteBoneIndices(const physx::Array<int32_t>& old2new) = 0;
+ virtual void applyTransformation(const PxMat44& transformation, float scale) = 0;
+ virtual void reverseWinding() = 0;
+ virtual void applyScale(float scale) = 0;
+};
+
+
+class RenderMeshActorIntl : public RenderMeshActor
+{
+public:
+ virtual void updateRenderResources(bool useBones, bool rewriteBuffers, void* userRenderData) = 0;
+
+ // add a buffer that will replace the dynamic buffer for the submesh
+ virtual void addVertexBuffer(uint32_t submeshIndex, bool alwaysDirty, PxVec3* position, PxVec3* normal, PxVec4* tangents) = 0;
+ virtual void removeVertexBuffer(uint32_t submeshIndex) = 0;
+
+ virtual void setStaticPositionReplacement(uint32_t submeshIndex, const PxVec3* staticPositions) = 0;
+ virtual void setStaticColorReplacement(uint32_t submeshIndex, const ColorRGBA* staticColors) = 0;
+
+ virtual void visualize(RenderDebugInterface& batcher, nvidia::apex::DebugRenderParams* debugParams, PxMat33* scaledRotations = NULL, PxVec3* translations = NULL, uint32_t stride = 0, uint32_t numberOfTransforms = 0) const = 0;
+
+ virtual void dispatchRenderResources(UserRenderer& renderer, const PxMat44& globalPose) = 0;
+
+ // Access to previous frame's transforms (if the buffer exists)
+ virtual void setLastFrameTM(const PxMat44& tm, uint32_t boneIndex = 0) = 0;
+ virtual void setLastFrameTM(const PxMat44& tm, const PxVec3& scale, uint32_t boneIndex = 0) = 0;
+
+ virtual void setSkinningMode(RenderMeshActorSkinningMode::Enum mode) = 0;
+ virtual RenderMeshActorSkinningMode::Enum getSkinningMode() const = 0;
+};
+
+} // end namespace apex
+} // end namespace nvidia
+
+#endif // RENDER_MESH_ASSET_INTL_H
diff --git a/APEX_1.4/common/include/ResourceProviderIntl.h b/APEX_1.4/common/include/ResourceProviderIntl.h
new file mode 100644
index 00000000..d4179f83
--- /dev/null
+++ b/APEX_1.4/common/include/ResourceProviderIntl.h
@@ -0,0 +1,165 @@
+/*
+ * 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 RESOURCE_PROVIDER_INTL_H
+#define RESOURCE_PROVIDER_INTL_H
+
+#include "ResourceProvider.h"
+#include "ApexString.h"
+#include "PsUserAllocated.h"
+
+/**
+Framework/Module interface to named resource provider
+*/
+
+namespace nvidia
+{
+namespace apex
+{
+
+typedef uint32_t ResID;
+
+const ResID INVALID_RESOURCE_ID = ResID(-1);
+
+/* Used for storing asset name/resID pairs */
+class AssetNameIDMapping : public UserAllocated
+{
+public:
+ AssetNameIDMapping()
+ {}
+
+ AssetNameIDMapping(const char* inAssetName, const char* inIosAssetTypeName, ResID inResID):
+ assetName(inAssetName),
+ iosAssetTypeName(inIosAssetTypeName),
+ resID(inResID),
+ isOpaqueMesh(false)
+ {}
+
+ AssetNameIDMapping(const char* inAssetName, const char* inIosAssetTypeName):
+ assetName(inAssetName),
+ iosAssetTypeName(inIosAssetTypeName),
+ resID(INVALID_RESOURCE_ID),
+ isOpaqueMesh(false)
+ {}
+
+ AssetNameIDMapping(const char* inAssetName, ResID inResID):
+ assetName(inAssetName),
+ iosAssetTypeName(""),
+ resID(inResID),
+ isOpaqueMesh(false)
+ {}
+
+ AssetNameIDMapping(const char* inAssetName, bool _isOpaqueMesh):
+ assetName(inAssetName),
+ iosAssetTypeName(""),
+ resID(INVALID_RESOURCE_ID),
+ isOpaqueMesh(_isOpaqueMesh)
+ {}
+
+ void setIsOpaqueMesh(bool state)
+ {
+ isOpaqueMesh = state;
+ }
+
+ ApexSimpleString assetName;
+ ApexSimpleString iosAssetTypeName;
+ ResID resID;
+ bool isOpaqueMesh;
+};
+
+
+class ResourceProviderIntl : public ResourceProvider
+{
+public:
+ /**
+ The Apex framework and modules can create name spaces in which unique names can be stored.
+ The user setResource() interface can also implicitly create new name spaces if they set a
+ resource in a new name space. This function will return the existing ID in this case.
+ The calling code must store this handle and call releaseResource() when appropriate.
+ releaseAtExit determines whether the NRP will call releaseResource() on items in this
+ namespace when the ApexSDK exits.
+ */
+ virtual ResID createNameSpace(const char* nameSpace, bool releaseAtExit = true) = 0;
+
+ /**
+ The Apex Authorable Object needs a way to tell the resource provider that the resource
+ value is no longer set and the app's callback should be used once again if the name
+ is queried
+ */
+ virtual void setResource(const char* nameSpace, const char* name, void* resource, bool valueIsSet, bool incRefCount = false) = 0;
+
+ /**
+ The Apex framework and modules should use this function to release their reference to a named
+ resource when they no longer use it. If the named resource's reference count reaches zero,
+ ResourceCallback::releaseResource() will be called.
+ */
+ virtual void releaseResource(ResID id) = 0;
+
+ /**
+ Create a named resource inside a specific name space. Returns a resource ID which must be
+ stored by the calling module or framework code.
+ */
+ virtual ResID createResource(ResID nameSpace, const char* name, bool refCount = true) = 0;
+
+ /**
+ Returns true if named resource has a specified pointer
+ */
+ virtual bool checkResource(ResID nameSpace, const char* name) = 0;
+
+ /**
+ Returns true if named resource has a specified pointer
+ */
+ virtual bool checkResource(ResID id) = 0;
+
+ /**
+ Modifies name parameter such that it is unique in its namespace
+ */
+ virtual void generateUniqueName(ResID nameSpace, ApexSimpleString& name) = 0;
+
+ /**
+ Retrieve the named resource pointer, which has been provided by the user interface. If the
+ named resource has never been set by the user API and the request callback has been specified,
+ the callback will be called to provide the void*. The user callback will be called only once
+ per named resource.
+ */
+ virtual void* getResource(ResID id) = 0;
+
+ /**
+ Retrieve the named resource name.
+ */
+ virtual const char* getResourceName(ResID id) = 0;
+
+ /**
+ Given a namespace name, this method will fill in all of the resource IDs registered
+ in the namespace. 'inCount' contains the total space allocated for the 'outResIDs' list.
+ 'outCount' will contain how many IDs are in the 'outResIDs' list. If 'inCount' is not
+ large enough, the method will return false
+ */
+ virtual bool getResourceIDs(const char* nameSpace, ResID* outResIDs, uint32_t& outCount, uint32_t inCount) = 0;
+
+ /**
+ \brief Returns if the resource provider is operating in a case sensitive mode.
+
+ \note By default the resource provider is NOT case sensitive
+ */
+ virtual bool isCaseSensitive() = 0;
+
+ /**
+ Retrieve the named resource name space.
+ */
+ virtual const char* getResourceNameSpace(ResID id) = 0;
+
+};
+
+} // namespace apex
+} // namespace nvidia
+
+#endif // RESOURCE_PROVIDER_INTL_H
diff --git a/APEX_1.4/common/include/SceneIntl.h b/APEX_1.4/common/include/SceneIntl.h
new file mode 100644
index 00000000..7f5a5077
--- /dev/null
+++ b/APEX_1.4/common/include/SceneIntl.h
@@ -0,0 +1,133 @@
+/*
+ * 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 SCENE_INTL_H
+#define SCENE_INTL_H
+
+#define APEX_CHECK_STAT_TIMER(name)// { PX_PROFILE_ZONE(name, GetInternalApexSDK()->getContextId()); }
+
+#include "Scene.h"
+#include "ApexUsingNamespace.h"
+
+#if PX_PHYSICS_VERSION_MAJOR == 3
+// PH prevent PxScene.h from including PxPhysX.h, it will include sooo many files that it will break the clothing embedded branch
+#define PX_PHYSICS_NX_PHYSICS
+#include "PxScene.h"
+#undef PX_PHYSICS_NX_PHYSICS
+#endif
+
+namespace nvidia
+{
+namespace apex
+{
+
+class ModuleSceneIntl;
+class ApexContext;
+class RenderDebugInterface;
+class PhysX3Interface;
+class ApexCudaTestManager;
+
+/**
+ * Framework interface to ApexScenes for use by modules
+ */
+class SceneIntl : public Scene
+{
+public:
+ /**
+ When a module has been released by the end-user, the module must release
+ its ModuleScenesIntl and notify those Scenes that their module
+ scenes no longer exist
+ */
+ virtual void moduleReleased(ModuleSceneIntl& moduleScene) = 0;
+
+#if PX_PHYSICS_VERSION_MAJOR == 3
+ virtual void lockRead(const char *fileName,uint32_t lineo) = 0;
+ virtual void lockWrite(const char *fileName,uint32_t lineno) = 0;
+ virtual void unlockRead() = 0;
+ virtual void unlockWrite() = 0;
+
+ virtual void addModuleUserNotifier(physx::PxSimulationEventCallback& notify) = 0;
+ virtual void removeModuleUserNotifier(physx::PxSimulationEventCallback& notify) = 0;
+ virtual void addModuleUserContactModify(physx::PxContactModifyCallback& notify) = 0;
+ virtual void removeModuleUserContactModify(physx::PxContactModifyCallback& notify) = 0;
+ virtual PhysX3Interface* getApexPhysX3Interface() const = 0;
+#endif
+
+ virtual ApexContext* getApexContext() = 0;
+ virtual float getElapsedTime() const = 0;
+
+ /* Get total elapsed simulation time, in integer milliseconds */
+ virtual uint32_t getTotalElapsedMS() const = 0;
+
+ virtual bool isSimulating() const = 0;
+ virtual bool physXElapsedTime(float& dt) const = 0;
+
+ virtual float getPhysXSimulateTime() const = 0;
+
+ virtual bool isFinalStep() const = 0;
+
+ virtual uint32_t getSeed() = 0; // Not necessarily const
+
+ enum ApexStatsDataEnum
+ {
+ NumberOfActors,
+ NumberOfShapes,
+ NumberOfAwakeShapes,
+ NumberOfCpuShapePairs,
+ ApexBeforeTickTime,
+ ApexDuringTickTime,
+ ApexPostTickTime,
+ PhysXSimulationTime,
+ ClothingSimulationTime,
+ ParticleSimulationTime,
+ TurbulenceSimulationTime,
+ PhysXFetchResultTime,
+ UserDelayedFetchTime,
+ RbThroughput,
+ SimulatedSpriteParticlesCount,
+ SimulatedMeshParticlesCount,
+ VisibleDestructibleChunkCount,
+ DynamicDestructibleChunkIslandCount,
+
+ // insert new items before this line
+ NumberOfApexStats // The number of stats
+ };
+
+ virtual void setApexStatValue(int32_t index, StatValue dataVal) = 0;
+
+#if APEX_CUDA_SUPPORT
+ virtual ApexCudaTestManager& getApexCudaTestManager() = 0;
+ virtual bool isUsingCuda() const = 0;
+#endif
+ virtual ModuleSceneIntl* getInternalModuleScene(const char* moduleName) = 0;
+};
+
+/* ApexScene task names */
+#define APEX_DURING_TICK_TIMING_FIX 1
+
+#define AST_PHYSX_SIMULATE "ApexScene::PhysXSimulate"
+#define AST_PHYSX_BETWEEN_STEPS "ApexScene::PhysXBetweenSteps"
+
+#if APEX_DURING_TICK_TIMING_FIX
+# define AST_DURING_TICK_COMPLETE "ApexScene::DuringTickComplete"
+#endif
+
+#define AST_PHYSX_CHECK_RESULTS "ApexScene::CheckResults"
+#define AST_PHYSX_FETCH_RESULTS "ApexScene::FetchResults"
+
+
+
+
+}
+} // end namespace nvidia::apex
+
+
+#endif // SCENE_INTL_H
diff --git a/APEX_1.4/common/include/SimplexNoise.h b/APEX_1.4/common/include/SimplexNoise.h
new file mode 100644
index 00000000..352c542b
--- /dev/null
+++ b/APEX_1.4/common/include/SimplexNoise.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.
+ */
+
+
+#ifndef SIMPLEX_NOISE_H
+#define SIMPLEX_NOISE_H
+
+#include "PxVec4.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+class SimplexNoise
+{
+ static const int X_NOISE_GEN = 1619;
+ static const int Y_NOISE_GEN = 31337;
+ static const int Z_NOISE_GEN = 6971;
+ static const int W_NOISE_GEN = 1999;
+ static const int SEED_NOISE_GEN = 1013;
+ static const int SHIFT_NOISE_GEN = 8;
+
+ PX_CUDA_CALLABLE static PX_INLINE int fastfloor(float x)
+ {
+ return (x >= 0) ? (int)x : (int)(x - 1);
+ }
+
+public:
+
+ // 4D simplex noise
+ // returns: (x,y,z) = noise grad, w = noise value
+ PX_CUDA_CALLABLE static physx::PxVec4 eval4D(float x, float y, float z, float w, int seed)
+ {
+ // The skewing and unskewing factors are hairy again for the 4D case
+ const float F4 = (physx::PxSqrt(5.0f) - 1.0f) / 4.0f;
+ const float G4 = (5.0f - physx::PxSqrt(5.0f)) / 20.0f;
+ // Skew the (x,y,z,w) space to determine which cell of 24 simplices we're in
+ float s = (x + y + z + w) * F4; // Factor for 4D skewing
+ int ix = fastfloor(x + s);
+ int iy = fastfloor(y + s);
+ int iz = fastfloor(z + s);
+ int iw = fastfloor(w + s);
+ float t = (ix + iy + iz + iw) * G4; // Factor for 4D unskewing
+ // Unskew the cell origin back to (x,y,z,w) space
+ float x0 = x - (ix - t); // The x,y,z,w distances from the cell origin
+ float y0 = y - (iy - t);
+ float z0 = z - (iz - t);
+ float w0 = w - (iw - t);
+
+ int c = (x0 > y0) ? (1 << 0) : (1 << 2);
+ c += (x0 > z0) ? (1 << 0) : (1 << 4);
+ c += (x0 > w0) ? (1 << 0) : (1 << 6);
+ c += (y0 > z0) ? (1 << 2) : (1 << 4);
+ c += (y0 > w0) ? (1 << 2) : (1 << 6);
+ c += (z0 > w0) ? (1 << 4) : (1 << 6);
+
+ physx::PxVec4 res;
+ res.setZero();
+
+ // Calculate the contribution from the five corners
+#ifdef __CUDACC__
+#pragma unroll
+#endif
+ for (int p = 4; p >= 0; --p)
+ {
+ int ixp = ((c >> 0) & 3) >= p ? 1 : 0;
+ int iyp = ((c >> 2) & 3) >= p ? 1 : 0;
+ int izp = ((c >> 4) & 3) >= p ? 1 : 0;
+ int iwp = ((c >> 6) & 3) >= p ? 1 : 0;
+
+ float xp = x0 - ixp + (4 - p) * G4;
+ float yp = y0 - iyp + (4 - p) * G4;
+ float zp = z0 - izp + (4 - p) * G4;
+ float wp = w0 - iwp + (4 - p) * G4;
+
+ float t = 0.6f - xp * xp - yp * yp - zp * zp - wp * wp;
+ if (t > 0)
+ {
+ //get index
+ int gradIndex = int((
+ X_NOISE_GEN * (ix + ixp)
+ + Y_NOISE_GEN * (iy + iyp)
+ + Z_NOISE_GEN * (iz + izp)
+ + W_NOISE_GEN * (iw + iwp)
+ + SEED_NOISE_GEN * seed)
+ & 0xffffffff);
+ gradIndex ^= (gradIndex >> SHIFT_NOISE_GEN);
+ gradIndex &= 31;
+
+ physx::PxVec4 g;
+ {
+ const int h = gradIndex;
+ const int hs = 2 - (h >> 4);
+ const int h1 = (h >> 3);
+ g.x = (h1 == 0) ? 0.0f : ((h & 4) ? -1.0f : 1.0f);
+ g.y = (h1 == 1) ? 0.0f : ((h & (hs << 1)) ? -1.0f : 1.0f);
+ g.z = (h1 == 2) ? 0.0f : ((h & hs) ? -1.0f : 1.0f);
+ g.w = (h1 == 3) ? 0.0f : ((h & 1) ? -1.0f : 1.0f);
+ }
+ float gdot = (g.x * xp + g.y * yp + g.z * zp + g.w * wp);
+
+ float t2 = t * t;
+ float t3 = t2 * t;
+ float t4 = t3 * t;
+
+ float dt4gdot = 8 * t3 * gdot;
+
+ res.x += t4 * g.x - dt4gdot * xp;
+ res.y += t4 * g.y - dt4gdot * yp;
+ res.z += t4 * g.z - dt4gdot * zp;
+ res.w += t4 * gdot;
+ }
+ }
+ // scale the result to cover the range [-1,1]
+ res *= 27;
+ return res;
+ }
+};
+
+
+}
+} // namespace nvidia::apex
+
+#endif
diff --git a/APEX_1.4/common/include/Spline.h b/APEX_1.4/common/include/Spline.h
new file mode 100644
index 00000000..39e3bf60
--- /dev/null
+++ b/APEX_1.4/common/include/Spline.h
@@ -0,0 +1,168 @@
+/*
+ * 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 SPLINE_H
+
+#define SPLINE_H
+
+
+/** @file spline.h
+ * @brief A utility class to manage 3d spline curves.
+ *
+ * This is used heavily by the terrain terraforming tools for roads, lakes, and flatten operations.
+ *
+ * @author John W. Ratcliff
+*/
+
+/** @file spline.cpp
+ * @brief A utility class to manage 3d spline curves.
+ *
+ * This is used heavily by the terrain terraforming tools for roads, lakes, and flatten operations.
+ *
+ * @author John W. Ratcliff
+*/
+
+
+#include "PsArray.h"
+#include "PsUserAllocated.h"
+#include "PxVec3.h"
+#include "ApexUsingNamespace.h"
+
+class SplineNode
+{
+public:
+ float GetY(void) const
+ {
+ return y;
+ };
+ float x; // time/distance x-axis component.
+ float y; // y component.
+ float u;
+ float p;
+};
+
+typedef nvidia::Array< SplineNode > SplineNodeVector;
+typedef nvidia::Array< physx::PxVec3 > PxVec3Vector;
+typedef nvidia::Array< uint32_t > uint32_tVector;
+
+class Spline : public nvidia::UserAllocated
+{
+public:
+ void Reserve(int32_t size)
+ {
+ mNodes.reserve((uint32_t)size);
+ };
+ void AddNode(float x,float y);
+ void ComputeSpline(void);
+ float Evaluate(float x,uint32_t &index,float &fraction) const; // evaluate Y component based on X
+ int32_t GetSize(void) const
+ {
+ return (int32_t)mNodes.size();
+ }
+ float GetEntry(int32_t i) const
+ {
+ return mNodes[(uint32_t)i].GetY();
+ };
+ void Clear(void)
+ {
+ mNodes.clear();
+ };
+private:
+ SplineNodeVector mNodes; // nodes.
+};
+
+class SplineCurve : public nvidia::UserAllocated
+{
+public:
+ void Reserve(int32_t size)
+ {
+ mXaxis.Reserve(size);
+ mYaxis.Reserve(size);
+ mZaxis.Reserve(size);
+ };
+
+ void setControlPoints(const PxVec3Vector &points)
+ {
+ Clear();
+ Reserve( (int32_t)points.size() );
+ for (uint32_t i=0; i<points.size(); i++)
+ {
+ AddControlPoint(points[i]);
+ }
+ ComputeSpline();
+ }
+
+ float AddControlPoint(const physx::PxVec3& p); // add control point, time is computed based on distance along the curve.
+ void AddControlPoint(const physx::PxVec3& p,float t); // add control point.
+
+ void GetPointOnSpline(float t,physx::PxVec3 &pos)
+ {
+ float d = t*mTime;
+ uint32_t index;
+ float fraction;
+ pos = Evaluate(d,index,fraction);
+ }
+
+ physx::PxVec3 Evaluate(float dist,uint32_t &index,float &fraction);
+
+ float GetLength(void) { return mTime; }; //total length of spline
+
+ int32_t GetSize(void) { return mXaxis.GetSize(); };
+
+ physx::PxVec3 GetEntry(int32_t i);
+
+ void ComputeSpline(void); // compute spline.
+
+ void Clear(void)
+ {
+ mXaxis.Clear();
+ mYaxis.Clear();
+ mZaxis.Clear();
+ mTime = 0;
+ };
+
+ float Set(const PxVec3Vector &vlist)
+ {
+ Clear();
+ int32_t count = (int32_t)vlist.size();
+ Reserve(count);
+ for (uint32_t i=0; i<vlist.size(); i++)
+ {
+ AddControlPoint( vlist[i] );
+ }
+ ComputeSpline();
+ return mTime;
+ };
+
+ void ResampleControlPoints(const PxVec3Vector &inputpoints,
+ PxVec3Vector &outputpoints,
+ uint32_tVector &outputIndex,
+ float dtime)
+ {
+ float length = Set(inputpoints);
+ for (float l=0; l<=length; l+=dtime)
+ {
+ uint32_t index;
+ float fraction;
+ physx::PxVec3 pos = Evaluate(l,index,fraction);
+ outputpoints.pushBack(pos);
+ outputIndex.pushBack(index);
+ }
+ };
+
+private:
+ float mTime; // time/distance traveled.
+ Spline mXaxis;
+ Spline mYaxis;
+ Spline mZaxis;
+};
+
+#endif
diff --git a/APEX_1.4/common/include/TableLookup.h b/APEX_1.4/common/include/TableLookup.h
new file mode 100644
index 00000000..9b32d68e
--- /dev/null
+++ b/APEX_1.4/common/include/TableLookup.h
@@ -0,0 +1,154 @@
+/*
+ * 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 TABLE_LOOKUP_H
+#define TABLE_LOOKUP_H
+
+namespace nvidia
+{
+namespace apex
+{
+
+// Stored Tables
+const float custom[] = { 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f };
+const float linear[] = { 1.00f, 0.90f, 0.80f, 0.70f, 0.60f, 0.50f, 0.40f, 0.30f, 0.20f, 0.10f, 0.00f };
+const float steep[] = { 1.00f, 0.99f, 0.96f, 0.91f, 0.84f, 0.75f, 0.64f, 0.51f, 0.36f, 0.19f, 0.00f };
+const float scurve[] = { 1.00f, 0.99f, 0.96f, 0.91f, 0.80f, 0.50f, 0.20f, 0.09f, 0.04f, 0.01f, 0.00f };
+
+// Table sizes must be same for all stored tables
+#define NUM_ELEMENTS(X) (sizeof(X)/sizeof(*(X)))
+#define TABLE_SIZE NUM_ELEMENTS(custom)
+
+// Stored Table enums
+struct TableName
+{
+ enum Enum
+ {
+ CUSTOM = 0,
+ LINEAR,
+ STEEP,
+ SCURVE,
+ };
+};
+
+struct TableLookup
+{
+ float xVals[TABLE_SIZE];
+ float yVals[TABLE_SIZE];
+ float x1;
+ float x2;
+ float multiplier;
+
+#ifdef __CUDACC__
+ __device__ TableLookup() {}
+#else
+ TableLookup():
+ x1(0),
+ x2(0),
+ multiplier(0)
+ {
+ zeroTable();
+ }
+#endif
+
+ PX_CUDA_CALLABLE void zeroTable()
+ {
+ for (size_t i = 0; i < TABLE_SIZE; ++i)
+ {
+ xVals[i] = 0.0f;
+ yVals[i] = 0.0f;
+ }
+ }
+
+ PX_CUDA_CALLABLE void applyStoredTable(TableName::Enum tableName)
+ {
+ // build y values
+ for (size_t i = 0; i < TABLE_SIZE; ++i)
+ {
+ if (tableName == TableName::LINEAR)
+ {
+ yVals[i] = linear[i];
+ }
+ else if (tableName == TableName::STEEP)
+ {
+ yVals[i] = steep[i];
+ }
+ else if (tableName == TableName::SCURVE)
+ {
+ yVals[i] = scurve[i];
+ }
+ else if (tableName == TableName::CUSTOM)
+ {
+ yVals[i] = custom[i];
+ }
+ }
+ }
+
+ PX_CUDA_CALLABLE void buildTable()
+ {
+ // build x values
+ float interval = (x2 - x1) / (TABLE_SIZE - 1);
+ for (size_t i = 0; i < TABLE_SIZE; ++i)
+ {
+ xVals[i] = x1 + i * interval;
+ }
+
+ // apply multipler to y values
+ if (multiplier >= -1.0f && multiplier <= 1.0f)
+ {
+ for (size_t i = 0; i < TABLE_SIZE; ++i)
+ {
+ yVals[i] = yVals[i] * multiplier;
+ }
+
+ // offset = max y value in array
+ float max = yVals[0];
+ for (size_t i = 1; i < TABLE_SIZE; ++i)
+ {
+ if (yVals[i] > max)
+ {
+ max = yVals[i];
+ }
+ }
+
+ // apply offset
+ for (size_t i = 0; i < TABLE_SIZE; ++i)
+ {
+ yVals[i] = yVals[i] + (1.0f - max);
+ }
+ }
+ }
+
+ PX_CUDA_CALLABLE float lookupTableValue(float x) const
+ {
+ if (x <= xVals[0])
+ {
+ return yVals[0];
+ }
+ else if (x >= xVals[TABLE_SIZE-1])
+ {
+ return yVals[TABLE_SIZE-1];
+ }
+ else
+ {
+ // linear interpolation between x values
+ float interval = (xVals[TABLE_SIZE-1] - xVals[0]) / (TABLE_SIZE - 1);
+ uint32_t lerpPos = (uint32_t)((x - xVals[0]) / interval);
+ float yDiff = yVals[lerpPos+1] - yVals[lerpPos];
+ return yVals[lerpPos] + (x - xVals[lerpPos]) / interval * yDiff;
+ }
+ }
+};
+
+}
+} // namespace nvidia::apex
+
+#endif
diff --git a/APEX_1.4/common/include/WriteCheck.h b/APEX_1.4/common/include/WriteCheck.h
new file mode 100644
index 00000000..23710813
--- /dev/null
+++ b/APEX_1.4/common/include/WriteCheck.h
@@ -0,0 +1,65 @@
+/*
+ * 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 WRITE_CHECK_H
+#define WRITE_CHECK_H
+
+#include "PxSimpleTypes.h"
+#include "ApexUsingNamespace.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+class ApexRWLockable;
+
+// RAII wrapper around the Scene::startWrite() method, note that this
+// object does not acquire any scene locks, it is an error checking only mechanism
+class WriteCheck
+{
+public:
+ WriteCheck(ApexRWLockable* scene, const char* functionName, bool allowReentry=true);
+ ~WriteCheck();
+
+private:
+ ApexRWLockable* mLockable;
+ const char* mName;
+ bool mAllowReentry;
+ uint32_t mErrorCount;
+};
+
+#if PX_DEBUG || PX_CHECKED
+ // Creates a scoped write check object that detects whether appropriate scene locks
+ // have been acquired and checks if reads/writes overlap, this macro should typically
+ // be placed at the beginning of any non-const API methods that are not multi-thread safe.
+ // By default re-entrant write calls by the same thread are allowed, the error conditions
+ // checked can be summarized as:
+
+ // 1. Other threads were already reading, or began reading during the object lifetime
+ // 2. Other threads were already writing, or began writing during the object lifetime
+ #define WRITE_ZONE() WriteCheck __writeCheck(static_cast<ApexRWLockable*>(this), __FUNCTION__);
+
+ // Creates a scoped write check object that disallows re-entrant writes, this is used by
+ // the Scene::simulate method to detect when callbacks make write calls to the API
+ #define WRITE_ZONE_NOREENTRY() WriteCheck __writeCheck(static_cast<ApexRWLockable*>(this), __FUNCTION__, false);
+#else
+ #define WRITE_ZONE()
+ #define WRITE_ZONE_NOREENTRY()
+#endif
+
+}
+}
+
+#endif // WRITE_CHECK_H
diff --git a/APEX_1.4/common/include/autogen/ConvexHullParameters.h b/APEX_1.4/common/include/autogen/ConvexHullParameters.h
new file mode 100644
index 00000000..ba369ddd
--- /dev/null
+++ b/APEX_1.4/common/include/autogen/ConvexHullParameters.h
@@ -0,0 +1,276 @@
+// 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_ConvexHullParameters_h
+#define HEADER_ConvexHullParameters_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 apex
+{
+
+#if PX_VC
+#pragma warning(push)
+#pragma warning(disable: 4324) // structure was padded due to __declspec(align())
+#endif
+
+namespace ConvexHullParametersNS
+{
+
+struct Plane_Type;
+
+struct VEC3_DynamicArray1D_Type
+{
+ physx::PxVec3* buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+struct Plane_DynamicArray1D_Type
+{
+ Plane_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 Plane_Type
+{
+ physx::PxVec3 normal;
+ float d;
+};
+
+struct ParametersStruct
+{
+
+ VEC3_DynamicArray1D_Type vertices;
+ Plane_DynamicArray1D_Type uniquePlanes;
+ F32_DynamicArray1D_Type widths;
+ U32_DynamicArray1D_Type edges;
+ U32_DynamicArray1D_Type adjacentFaces;
+ physx::PxBounds3 bounds;
+ float volume;
+ uint32_t uniqueEdgeDirectionCount;
+ uint32_t planeCount;
+
+};
+
+static const uint32_t checksum[] = { 0x8a50b89e, 0xda2f896b, 0x82da2553, 0x3b609a3d, };
+
+} // namespace ConvexHullParametersNS
+
+#ifndef NV_PARAMETERIZED_ONLY_LAYOUTS
+class ConvexHullParameters : public NvParameterized::NvParameters, public ConvexHullParametersNS::ParametersStruct
+{
+public:
+ ConvexHullParameters(NvParameterized::Traits* traits, void* buf = 0, int32_t* refCount = 0);
+
+ virtual ~ConvexHullParameters();
+
+ virtual void destroy();
+
+ static const char* staticClassName(void)
+ {
+ return("ConvexHullParameters");
+ }
+
+ 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(ConvexHullParametersNS::checksum);
+ return ConvexHullParametersNS::checksum;
+ }
+
+ static void freeParameterDefinitionTable(NvParameterized::Traits* traits);
+
+ const uint32_t* checksum(uint32_t& bits) const
+ {
+ return staticChecksum(bits);
+ }
+
+ const ConvexHullParametersNS::ParametersStruct& parameters(void) const
+ {
+ ConvexHullParameters* tmpThis = const_cast<ConvexHullParameters*>(this);
+ return *(static_cast<ConvexHullParametersNS::ParametersStruct*>(tmpThis));
+ }
+
+ ConvexHullParametersNS::ParametersStruct& parameters(void)
+ {
+ return *(static_cast<ConvexHullParametersNS::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 ConvexHullParametersFactory : public NvParameterized::Factory
+{
+ static const char* const vptr;
+
+public:
+
+ virtual void freeParameterDefinitionTable(NvParameterized::Traits* traits)
+ {
+ ConvexHullParameters::freeParameterDefinitionTable(traits);
+ }
+
+ virtual NvParameterized::Interface* create(NvParameterized::Traits* paramTraits)
+ {
+ // placement new on this class using mParameterizedTraits
+
+ void* newPtr = paramTraits->alloc(sizeof(ConvexHullParameters), ConvexHullParameters::ClassAlignment);
+ if (!NvParameterized::IsAligned(newPtr, ConvexHullParameters::ClassAlignment))
+ {
+ NV_PARAM_TRAITS_WARNING(paramTraits, "Unaligned memory allocation for class ConvexHullParameters");
+ paramTraits->free(newPtr);
+ return 0;
+ }
+
+ memset(newPtr, 0, sizeof(ConvexHullParameters)); // always initialize memory allocated to zero for default values
+ return NV_PARAM_PLACEMENT_NEW(newPtr, ConvexHullParameters)(paramTraits);
+ }
+
+ virtual NvParameterized::Interface* finish(NvParameterized::Traits* paramTraits, void* bufObj, void* bufStart, int32_t* refCount)
+ {
+ if (!NvParameterized::IsAligned(bufObj, ConvexHullParameters::ClassAlignment)
+ || !NvParameterized::IsAligned(bufStart, ConvexHullParameters::ClassAlignment))
+ {
+ NV_PARAM_TRAITS_WARNING(paramTraits, "Unaligned memory allocation for class ConvexHullParameters");
+ return 0;
+ }
+
+ // Init NvParameters-part
+ // We used to call empty constructor of ConvexHullParameters 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 (ConvexHullParameters*)bufObj;
+ }
+
+ virtual const char* getClassName()
+ {
+ return (ConvexHullParameters::staticClassName());
+ }
+
+ virtual uint32_t getVersion()
+ {
+ return (ConvexHullParameters::staticVersion());
+ }
+
+ virtual uint32_t getAlignment()
+ {
+ return (ConvexHullParameters::ClassAlignment);
+ }
+
+ virtual const uint32_t* getChecksum(uint32_t& bits)
+ {
+ return (ConvexHullParameters::staticChecksum(bits));
+ }
+};
+#endif // NV_PARAMETERIZED_ONLY_LAYOUTS
+
+} // namespace apex
+} // namespace nvidia
+
+#if PX_VC
+#pragma warning(pop)
+#endif
+
+#endif
diff --git a/APEX_1.4/common/include/autogen/DebugColorParams.h b/APEX_1.4/common/include/autogen/DebugColorParams.h
new file mode 100644
index 00000000..bc650c9f
--- /dev/null
+++ b/APEX_1.4/common/include/autogen/DebugColorParams.h
@@ -0,0 +1,265 @@
+// 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_DebugColorParams_h
+#define HEADER_DebugColorParams_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 apex
+{
+
+#if PX_VC
+#pragma warning(push)
+#pragma warning(disable: 4324) // structure was padded due to __declspec(align())
+#endif
+
+namespace DebugColorParamsNS
+{
+
+
+
+struct ParametersStruct
+{
+
+ uint32_t Default;
+ uint32_t PoseArrows;
+ uint32_t MeshStatic;
+ uint32_t MeshDynamic;
+ uint32_t Shape;
+ uint32_t Text0;
+ uint32_t Text1;
+ uint32_t ForceArrowsLow;
+ uint32_t ForceArrowsNorm;
+ uint32_t ForceArrowsHigh;
+ uint32_t Color0;
+ uint32_t Color1;
+ uint32_t Color2;
+ uint32_t Color3;
+ uint32_t Color4;
+ uint32_t Color5;
+ uint32_t Red;
+ uint32_t Green;
+ uint32_t Blue;
+ uint32_t DarkRed;
+ uint32_t DarkGreen;
+ uint32_t DarkBlue;
+ uint32_t LightRed;
+ uint32_t LightGreen;
+ uint32_t LightBlue;
+ uint32_t Purple;
+ uint32_t DarkPurple;
+ uint32_t Yellow;
+ uint32_t Orange;
+ uint32_t Gold;
+ uint32_t Emerald;
+ uint32_t White;
+ uint32_t Black;
+ uint32_t Gray;
+ uint32_t LightGray;
+ uint32_t DarkGray;
+
+};
+
+static const uint32_t checksum[] = { 0x21b30efd, 0xaea10022, 0x72a4df62, 0x8fab217f, };
+
+} // namespace DebugColorParamsNS
+
+#ifndef NV_PARAMETERIZED_ONLY_LAYOUTS
+class DebugColorParams : public NvParameterized::NvParameters, public DebugColorParamsNS::ParametersStruct
+{
+public:
+ DebugColorParams(NvParameterized::Traits* traits, void* buf = 0, int32_t* refCount = 0);
+
+ virtual ~DebugColorParams();
+
+ virtual void destroy();
+
+ static const char* staticClassName(void)
+ {
+ return("DebugColorParams");
+ }
+
+ 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(DebugColorParamsNS::checksum);
+ return DebugColorParamsNS::checksum;
+ }
+
+ static void freeParameterDefinitionTable(NvParameterized::Traits* traits);
+
+ const uint32_t* checksum(uint32_t& bits) const
+ {
+ return staticChecksum(bits);
+ }
+
+ const DebugColorParamsNS::ParametersStruct& parameters(void) const
+ {
+ DebugColorParams* tmpThis = const_cast<DebugColorParams*>(this);
+ return *(static_cast<DebugColorParamsNS::ParametersStruct*>(tmpThis));
+ }
+
+ DebugColorParamsNS::ParametersStruct& parameters(void)
+ {
+ return *(static_cast<DebugColorParamsNS::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 DebugColorParamsFactory : public NvParameterized::Factory
+{
+ static const char* const vptr;
+
+public:
+
+ virtual void freeParameterDefinitionTable(NvParameterized::Traits* traits)
+ {
+ DebugColorParams::freeParameterDefinitionTable(traits);
+ }
+
+ virtual NvParameterized::Interface* create(NvParameterized::Traits* paramTraits)
+ {
+ // placement new on this class using mParameterizedTraits
+
+ void* newPtr = paramTraits->alloc(sizeof(DebugColorParams), DebugColorParams::ClassAlignment);
+ if (!NvParameterized::IsAligned(newPtr, DebugColorParams::ClassAlignment))
+ {
+ NV_PARAM_TRAITS_WARNING(paramTraits, "Unaligned memory allocation for class DebugColorParams");
+ paramTraits->free(newPtr);
+ return 0;
+ }
+
+ memset(newPtr, 0, sizeof(DebugColorParams)); // always initialize memory allocated to zero for default values
+ return NV_PARAM_PLACEMENT_NEW(newPtr, DebugColorParams)(paramTraits);
+ }
+
+ virtual NvParameterized::Interface* finish(NvParameterized::Traits* paramTraits, void* bufObj, void* bufStart, int32_t* refCount)
+ {
+ if (!NvParameterized::IsAligned(bufObj, DebugColorParams::ClassAlignment)
+ || !NvParameterized::IsAligned(bufStart, DebugColorParams::ClassAlignment))
+ {
+ NV_PARAM_TRAITS_WARNING(paramTraits, "Unaligned memory allocation for class DebugColorParams");
+ return 0;
+ }
+
+ // Init NvParameters-part
+ // We used to call empty constructor of DebugColorParams 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 (DebugColorParams*)bufObj;
+ }
+
+ virtual const char* getClassName()
+ {
+ return (DebugColorParams::staticClassName());
+ }
+
+ virtual uint32_t getVersion()
+ {
+ return (DebugColorParams::staticVersion());
+ }
+
+ virtual uint32_t getAlignment()
+ {
+ return (DebugColorParams::ClassAlignment);
+ }
+
+ virtual const uint32_t* getChecksum(uint32_t& bits)
+ {
+ return (DebugColorParams::staticChecksum(bits));
+ }
+};
+#endif // NV_PARAMETERIZED_ONLY_LAYOUTS
+
+} // namespace apex
+} // namespace nvidia
+
+#if PX_VC
+#pragma warning(pop)
+#endif
+
+#endif
diff --git a/APEX_1.4/common/include/autogen/DebugRenderParams.h b/APEX_1.4/common/include/autogen/DebugRenderParams.h
new file mode 100644
index 00000000..0c992de6
--- /dev/null
+++ b/APEX_1.4/common/include/autogen/DebugRenderParams.h
@@ -0,0 +1,248 @@
+// 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_DebugRenderParams_h
+#define HEADER_DebugRenderParams_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 apex
+{
+
+#if PX_VC
+#pragma warning(push)
+#pragma warning(disable: 4324) // structure was padded due to __declspec(align())
+#endif
+
+namespace DebugRenderParamsNS
+{
+
+
+struct REF_DynamicArray1D_Type
+{
+ NvParameterized::Interface** buf;
+ bool isAllocated;
+ int32_t elementSize;
+ int32_t arraySizes[1];
+};
+
+
+struct ParametersStruct
+{
+
+ bool Enable;
+ float Scale;
+ float LodBenefits;
+ float RelativeLodBenefitsScreenPos;
+ float RelativeLodBenefitsThickness;
+ float LodDistanceScale;
+ float RenderNormals;
+ float RenderTangents;
+ float RenderBitangents;
+ bool Bounds;
+ REF_DynamicArray1D_Type moduleName;
+
+};
+
+static const uint32_t checksum[] = { 0x0679a129, 0x4119501f, 0xde4ce2b2, 0xecb0049b, };
+
+} // namespace DebugRenderParamsNS
+
+#ifndef NV_PARAMETERIZED_ONLY_LAYOUTS
+class DebugRenderParams : public NvParameterized::NvParameters, public DebugRenderParamsNS::ParametersStruct
+{
+public:
+ DebugRenderParams(NvParameterized::Traits* traits, void* buf = 0, int32_t* refCount = 0);
+
+ virtual ~DebugRenderParams();
+
+ virtual void destroy();
+
+ static const char* staticClassName(void)
+ {
+ return("DebugRenderParams");
+ }
+
+ 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(DebugRenderParamsNS::checksum);
+ return DebugRenderParamsNS::checksum;
+ }
+
+ static void freeParameterDefinitionTable(NvParameterized::Traits* traits);
+
+ const uint32_t* checksum(uint32_t& bits) const
+ {
+ return staticChecksum(bits);
+ }
+
+ const DebugRenderParamsNS::ParametersStruct& parameters(void) const
+ {
+ DebugRenderParams* tmpThis = const_cast<DebugRenderParams*>(this);
+ return *(static_cast<DebugRenderParamsNS::ParametersStruct*>(tmpThis));
+ }
+
+ DebugRenderParamsNS::ParametersStruct& parameters(void)
+ {
+ return *(static_cast<DebugRenderParamsNS::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 DebugRenderParamsFactory : public NvParameterized::Factory
+{
+ static const char* const vptr;
+
+public:
+
+ virtual void freeParameterDefinitionTable(NvParameterized::Traits* traits)
+ {
+ DebugRenderParams::freeParameterDefinitionTable(traits);
+ }
+
+ virtual NvParameterized::Interface* create(NvParameterized::Traits* paramTraits)
+ {
+ // placement new on this class using mParameterizedTraits
+
+ void* newPtr = paramTraits->alloc(sizeof(DebugRenderParams), DebugRenderParams::ClassAlignment);
+ if (!NvParameterized::IsAligned(newPtr, DebugRenderParams::ClassAlignment))
+ {
+ NV_PARAM_TRAITS_WARNING(paramTraits, "Unaligned memory allocation for class DebugRenderParams");
+ paramTraits->free(newPtr);
+ return 0;
+ }
+
+ memset(newPtr, 0, sizeof(DebugRenderParams)); // always initialize memory allocated to zero for default values
+ return NV_PARAM_PLACEMENT_NEW(newPtr, DebugRenderParams)(paramTraits);
+ }
+
+ virtual NvParameterized::Interface* finish(NvParameterized::Traits* paramTraits, void* bufObj, void* bufStart, int32_t* refCount)
+ {
+ if (!NvParameterized::IsAligned(bufObj, DebugRenderParams::ClassAlignment)
+ || !NvParameterized::IsAligned(bufStart, DebugRenderParams::ClassAlignment))
+ {
+ NV_PARAM_TRAITS_WARNING(paramTraits, "Unaligned memory allocation for class DebugRenderParams");
+ return 0;
+ }
+
+ // Init NvParameters-part
+ // We used to call empty constructor of DebugRenderParams 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 (DebugRenderParams*)bufObj;
+ }
+
+ virtual const char* getClassName()
+ {
+ return (DebugRenderParams::staticClassName());
+ }
+
+ virtual uint32_t getVersion()
+ {
+ return (DebugRenderParams::staticVersion());
+ }
+
+ virtual uint32_t getAlignment()
+ {
+ return (DebugRenderParams::ClassAlignment);
+ }
+
+ virtual const uint32_t* getChecksum(uint32_t& bits)
+ {
+ return (DebugRenderParams::staticChecksum(bits));
+ }
+};
+#endif // NV_PARAMETERIZED_ONLY_LAYOUTS
+
+} // namespace apex
+} // namespace nvidia
+
+#if PX_VC
+#pragma warning(pop)
+#endif
+
+#endif
diff --git a/APEX_1.4/common/include/autogen/ModuleCommonRegistration.h b/APEX_1.4/common/include/autogen/ModuleCommonRegistration.h
new file mode 100644
index 00000000..febd3743
--- /dev/null
+++ b/APEX_1.4/common/include/autogen/ModuleCommonRegistration.h
@@ -0,0 +1,120 @@
+/*
+ * 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_MODULECOMMONREGISTRATIONH_H
+#define MODULE_MODULECOMMONREGISTRATIONH_H
+
+#include "PsAllocator.h"
+#include "NvRegistrationsForTraitsBase.h"
+#include "nvparameterized/NvParameterizedTraits.h"
+#include "PxAssert.h"
+#include <stdint.h>
+
+// INCLUDE GENERATED FACTORIES
+#include "ConvexHullParameters.h"
+#include "DebugColorParams.h"
+#include "DebugRenderParams.h"
+
+
+// INCLUDE GENERATED CONVERSION
+
+
+namespace nvidia {
+namespace apex {
+
+
+class ModuleCommonRegistration : public NvParameterized::RegistrationsForTraitsBase
+{
+public:
+ static void invokeRegistration(NvParameterized::Traits* parameterizedTraits)
+ {
+ if (parameterizedTraits)
+ {
+ ModuleCommonRegistration().registerAll(*parameterizedTraits);
+ }
+ }
+
+ static void invokeUnregistration(NvParameterized::Traits* parameterizedTraits)
+ {
+ if (parameterizedTraits)
+ {
+ ModuleCommonRegistration().unregisterAll(*parameterizedTraits);
+ }
+ }
+
+ void registerAvailableFactories(NvParameterized::Traits& parameterizedTraits)
+ {
+ ::NvParameterized::Factory* factoriesToRegister[] = {
+// REGISTER GENERATED FACTORIES
+ new nvidia::apex::ConvexHullParametersFactory(),
+ new nvidia::apex::DebugColorParamsFactory(),
+ new nvidia::apex::DebugRenderParamsFactory(),
+
+ };
+
+ 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::apex::ConvexHullParametersFactory(),
+ new nvidia::apex::DebugColorParamsFactory(),
+ new nvidia::apex::DebugRenderParamsFactory(),
+
+ };
+
+ 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::apex
+
+#endif
diff --git a/APEX_1.4/common/include/variable_oscillator.h b/APEX_1.4/common/include/variable_oscillator.h
new file mode 100644
index 00000000..02d4aeea
--- /dev/null
+++ b/APEX_1.4/common/include/variable_oscillator.h
@@ -0,0 +1,48 @@
+/*
+ * 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 VARIABLE_OSCILLATOR_H
+#define VARIABLE_OSCILLATOR_H
+
+#include "ApexUsingNamespace.h"
+#include "PsUserAllocated.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+class variableOscillator : public UserAllocated
+{
+public:
+ variableOscillator(float min, float max, float initial, float period);
+ ~variableOscillator();
+ float updateVariableOscillator(float deltaTime);
+
+private:
+ float computeEndVal(float current, float max_or_min);
+
+private:
+ float mMin;
+ float mMax;
+ float mPeriod;
+
+ float mCumTime;
+ float mStartVal;
+ float mEndVal;
+ float mLastVal;
+ bool mGoingUp;
+};
+
+}
+} // namespace nvidia::apex
+
+#endif
diff --git a/APEX_1.4/common/src/ApexActor.cpp b/APEX_1.4/common/src/ApexActor.cpp
new file mode 100644
index 00000000..55a5c0eb
--- /dev/null
+++ b/APEX_1.4/common/src/ApexActor.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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 "Apex.h"
+#include "ApexActor.h"
+#include "ApexContext.h"
+
+#include "RenderDebugInterface.h"
+#include "SceneIntl.h"
+
+#include "PsAtomic.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+#if UNIQUE_ACTOR_ID
+int32_t ApexActor::mUniqueActorIdCounter = 0;
+#endif
+
+ApexActor::ApexActor() : mInRelease(false), mEnableDebugVisualization(true)
+{
+#if UNIQUE_ACTOR_ID
+ mUniqueActorId = shdfnd::atomicIncrement(&mUniqueActorIdCounter);
+#endif
+}
+
+
+ApexActor::~ApexActor()
+{
+ destroy();
+}
+
+void ApexActor::addSelfToContext(ApexContext& ctx, ApexActor* actorPtr)
+{
+ ContextTrack t;
+
+ t.ctx = &ctx;
+ t.index = ctx.addActor(*this, actorPtr);
+ mContexts.pushBack(t);
+}
+
+void ApexActor::updateIndex(ApexContext& ctx, uint32_t index)
+{
+ for (uint32_t i = 0 ; i < mContexts.size() ; i++)
+ {
+ ContextTrack& t = mContexts[i];
+ if (t.ctx == &ctx)
+ {
+ t.index = index;
+ break;
+ }
+ }
+}
+
+bool ApexActor::findSelfInContext(ApexContext& ctx)
+{
+ for (uint32_t i = 0 ; i < mContexts.size() ; i++)
+ {
+ ContextTrack& t = mContexts[i];
+ if (t.ctx == &ctx)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void ApexActor::destroy()
+{
+ mInRelease = true;
+
+ renderDataLock();
+
+ for (uint32_t i = 0 ; i < mContexts.size() ; i++)
+ {
+ ContextTrack& t = mContexts[i];
+ t.ctx->removeActorAtIndex(t.index);
+ }
+ mContexts.clear();
+}
+
+}
+} // end namespace nvidia::apex
diff --git a/APEX_1.4/common/src/ApexAssetAuthoring.cpp b/APEX_1.4/common/src/ApexAssetAuthoring.cpp
new file mode 100644
index 00000000..14845ff1
--- /dev/null
+++ b/APEX_1.4/common/src/ApexAssetAuthoring.cpp
@@ -0,0 +1,121 @@
+/*
+ * 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 "ApexAssetAuthoring.h"
+
+#include "P4Info.h"
+#include "PsString.h"
+
+#include "PhysXSDKVersion.h"
+#include "ApexSDKIntl.h"
+
+
+
+namespace nvidia
+{
+namespace apex
+{
+
+
+void ApexAssetAuthoring::setToolString(const char* toolName, const char* toolVersion, uint32_t toolChangelist)
+{
+#ifdef WITHOUT_APEX_AUTHORING
+ PX_UNUSED(toolName);
+ PX_UNUSED(toolVersion);
+ PX_UNUSED(toolChangelist);
+#else
+ const uint32_t buflen = 256;
+ char buf[buflen];
+ nvidia::strlcpy(buf, buflen, toolName);
+ nvidia::strlcat(buf, buflen, " ");
+
+ if (toolVersion != NULL)
+ {
+ nvidia::strlcat(buf, buflen, toolVersion);
+ nvidia::strlcat(buf, buflen, ":");
+ }
+
+ if (toolChangelist == 0)
+ {
+ toolChangelist = P4_TOOLS_CHANGELIST;
+ }
+
+ {
+ char buf2[14];
+ shdfnd::snprintf(buf2, 14, "CL %d", toolChangelist);
+ nvidia::strlcat(buf, buflen, buf2);
+ nvidia::strlcat(buf, buflen, " ");
+ }
+
+ {
+#ifdef WIN64
+ nvidia::strlcat(buf, buflen, "Win64 ");
+#elif defined(WIN32)
+ nvidia::strlcat(buf, buflen, "Win32 ");
+#endif
+ }
+
+ {
+ nvidia::strlcat(buf, buflen, "(Apex ");
+ nvidia::strlcat(buf, buflen, P4_APEX_VERSION_STRING);
+ char buf2[20];
+ shdfnd::snprintf(buf2, 20, ", CL %d, ", P4_CHANGELIST);
+ nvidia::strlcat(buf, buflen, buf2);
+#ifdef _DEBUG
+ nvidia::strlcat(buf, buflen, "DEBUG ");
+#elif defined(PHYSX_PROFILE_SDK)
+ nvidia::strlcat(buf, buflen, "PROFILE ");
+#endif
+ nvidia::strlcat(buf, buflen, P4_APEX_BRANCH);
+ nvidia::strlcat(buf, buflen, ") ");
+ }
+
+ {
+ nvidia::strlcat(buf, buflen, "(PhysX ");
+
+ char buf2[10] = { 0 };
+#if PX_PHYSICS_VERSION_MAJOR == 0
+ shdfnd::snprintf(buf2, 10, "No) ");
+#elif PX_PHYSICS_VERSION_MAJOR == 3
+ shdfnd::snprintf(buf2, 10, "%d.%d) ", PX_PHYSICS_VERSION_MAJOR, PX_PHYSICS_VERSION_MINOR);
+#endif
+ nvidia::strlcat(buf, buflen, buf2);
+ }
+
+
+ nvidia::strlcat(buf, buflen, "Apex Build Time: ");
+ nvidia::strlcat(buf, buflen, P4_BUILD_TIME);
+
+ nvidia::strlcat(buf, buflen, "Distribution author: ");
+ nvidia::strlcat(buf, buflen, AUTHOR_DISTRO);
+
+ nvidia::strlcat(buf, buflen, "The reason for the creation of the distribution: ");
+ nvidia::strlcat(buf, buflen, REASON_DISTRO);
+
+ //uint32_t len = strlen(buf);
+ //len = len;
+
+ //"<toolName> <toolVersion>:<toolCL> <platform> (Apex <apexVersion>, CL <apexCL> <apexConfiguration> <apexBranch>) (PhysX <physxVersion>) <toolBuildDate>"
+
+ setToolString(buf);
+#endif
+}
+
+
+
+void ApexAssetAuthoring::setToolString(const char* /*toolString*/)
+{
+ PX_ALWAYS_ASSERT();
+ APEX_INVALID_OPERATION("Not Implemented.");
+}
+
+} // namespace apex
+} // namespace nvidia \ No newline at end of file
diff --git a/APEX_1.4/common/src/ApexAssetTracker.cpp b/APEX_1.4/common/src/ApexAssetTracker.cpp
new file mode 100644
index 00000000..2e442bbc
--- /dev/null
+++ b/APEX_1.4/common/src/ApexAssetTracker.cpp
@@ -0,0 +1,303 @@
+/*
+ * 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 "ApexAssetTracker.h"
+#include "Apex.h"
+#include "ApexSDKIntl.h"
+#include "ApexResource.h"
+#include "ApexSDKHelpers.h"
+#include "AuthorableObjectIntl.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+/******************************************************************************
+ * ApexAssetTracker class
+ * Intended to be a base class for asset classes that have named sub-assets.
+ * - Allows their actors to easily get asset pointers
+ * - Uses the NRP in an appropriate fashion
+ * - calls to checkResource(), createResource(), and getResource()
+ * - handles that tricky IOS asset double call mechanism
+ * - Sub class must implement initializeAssetNameTable()
+ *
+ */
+ApexAssetTracker::~ApexAssetTracker()
+{
+ /* Get the NRP */
+ if (mSdk)
+ {
+ ResourceProviderIntl* nrp = mSdk->getInternalResourceProvider();
+
+ /* release references to rendermesh assets */
+ for (uint32_t j = 0 ; j < mNameIdList.size() ; j++)
+ {
+ AssetNameIDMapping *nameId = mNameIdList[j];
+ if (nameId->resID != INVALID_RESOURCE_ID)
+ {
+ if ( nameId->isOpaqueMesh )
+ {
+ ResID opaqueMeshId = nrp->createResource(mSdk->getOpaqueMeshNameSpace(),nameId->assetName.c_str(),false);
+ PX_ASSERT( opaqueMeshId != INVALID_RESOURCE_ID );
+ if (nrp->checkResource(opaqueMeshId))
+ {
+ nrp->releaseResource(opaqueMeshId);
+ }
+ uint32_t refCount;
+ bool found =nrp->findRefCount(RENDER_MESH_AUTHORING_TYPE_NAME,nameId->assetName.c_str(),refCount);
+ PX_ASSERT(found);
+ PX_UNUSED(found);
+ if (nrp->checkResource(nameId->resID))
+ {
+ if ( refCount == 1 )
+ {
+ void *asset = nrp->getResource(nameId->resID);
+ PX_ASSERT(asset);
+ if ( asset )
+ {
+ Asset *apexAsset = (Asset *)asset;
+ apexAsset->release();
+ }
+ }
+ nrp->releaseResource(nameId->resID);
+ }
+ }
+ else
+ {
+ if (nrp->checkResource(nameId->resID))
+ {
+ nrp->releaseResource(nameId->resID);
+ }
+ }
+ }
+ delete nameId;
+ }
+ }
+}
+
+bool ApexAssetTracker::addAssetName(const char* assetName, bool isOpaqueMesh)
+{
+ /* first see if the name is already here */
+ for (uint32_t i = 0; i < mNameIdList.size(); i++)
+ {
+ if (mNameIdList[i]->assetName == assetName && mNameIdList[i]->isOpaqueMesh == isOpaqueMesh)
+ {
+ return false;
+ }
+ }
+
+ /* now add it to the list */
+ mNameIdList.pushBack(PX_NEW(AssetNameIDMapping)(assetName, isOpaqueMesh));
+
+ return true;
+}
+
+bool ApexAssetTracker::addAssetName(const char* iosTypeName, const char* assetName)
+{
+ /* first see if the name is already here */
+ for (uint32_t i = 0; i < mNameIdList.size(); i++)
+ {
+ if (mNameIdList[i]->assetName == assetName &&
+ mNameIdList[i]->iosAssetTypeName == iosTypeName)
+ {
+ return false;
+ }
+ }
+
+ /* now add it to the list */
+ mNameIdList.pushBack(PX_NEW(AssetNameIDMapping)(assetName, iosTypeName));
+
+ return true;
+}
+
+void ApexAssetTracker::removeAllAssetNames()
+{
+ /* Get the NRP */
+ ResourceProviderIntl* nrp = mSdk->getInternalResourceProvider();
+
+ /* release references to rendermesh assets */
+ for (uint32_t j = 0 ; j < mNameIdList.size() ; j++)
+ {
+ nrp->releaseResource(mNameIdList[j]->resID);
+ delete mNameIdList[j];
+ }
+ mNameIdList.reset();
+}
+
+IosAsset* ApexAssetTracker::getIosAssetFromName(const char* iosTypeName, const char* assetName)
+{
+ /* This will actually call the NRP to force the asset to be loaded (if it isn't already loaded)
+ * loading the APS will cause the particle module to call setResource on the iosans
+ */
+ void* asset = ApexAssetHelper::getAssetFromNameList(mSdk,
+ iosTypeName,
+ mNameIdList,
+ assetName);
+
+ Asset* aa = static_cast<Asset*>(asset);
+ return DYNAMIC_CAST(IosAsset*)(aa);
+}
+
+Asset* ApexAssetTracker::getAssetFromName(const char* assetName)
+{
+ /* handle the material namespace, which is different (not authorable) */
+ ResID resID = INVALID_RESOURCE_ID;
+ if (mAuthoringTypeName == "")
+ {
+ resID = mSdk->getMaterialNameSpace();
+ }
+
+ void* tmp = ApexAssetHelper::getAssetFromNameList(mSdk,
+ mAuthoringTypeName.c_str(),
+ mNameIdList,
+ assetName,
+ resID);
+
+ return static_cast<Asset*>(tmp);
+}
+
+Asset* ApexAssetTracker::getMeshAssetFromName(const char* assetName, bool isOpaqueMesh)
+{
+ PX_UNUSED(isOpaqueMesh);
+ /* handle the material namespace, which is different (not authorable) */
+ ResID resID = INVALID_RESOURCE_ID;
+ if (isOpaqueMesh)
+ {
+ resID = mSdk->getOpaqueMeshNameSpace();
+ }
+ else if (mAuthoringTypeName == "")
+ {
+ resID = mSdk->getMaterialNameSpace();
+ }
+
+ void* tmp = ApexAssetHelper::getAssetFromNameList(mSdk,
+ mAuthoringTypeName.c_str(),
+ mNameIdList,
+ assetName,
+ resID);
+
+ return static_cast<Asset*>(tmp);
+}
+
+ResID ApexAssetTracker::getResourceIdFromName(const char* assetName, bool isOpaqueMesh)
+{
+ /* handle the material namespace, which is different (not authorable) */
+ ResID assetPsId = INVALID_RESOURCE_ID;
+ if (isOpaqueMesh)
+ {
+ assetPsId = mSdk->getOpaqueMeshNameSpace();
+ }
+ else if (mAuthoringTypeName == "")
+ {
+ assetPsId = mSdk->getMaterialNameSpace();
+ }
+
+ // find the index of the asset name in our list of name->resID maps
+ uint32_t assetIdx = 0;
+ for (assetIdx = 0; assetIdx < mNameIdList.size(); assetIdx++)
+ {
+ if (mNameIdList[assetIdx]->assetName == assetName)
+ {
+ break;
+ }
+ }
+ // This can't ever happen
+ PX_ASSERT(assetIdx < mNameIdList.size());
+ if (assetIdx < mNameIdList.size())
+ {
+ ApexAssetHelper::getAssetFromName(mSdk,
+ mAuthoringTypeName.c_str(),
+ assetName,
+ mNameIdList[assetIdx]->resID,
+ assetPsId);
+
+ return mNameIdList[assetIdx]->resID;
+ }
+ else
+ {
+ APEX_DEBUG_WARNING("Request for asset %s of type %s not registered in asset tracker's list", assetName, mAuthoringTypeName.c_str());
+ return INVALID_RESOURCE_ID;
+ }
+}
+
+uint32_t ApexAssetTracker::forceLoadAssets()
+{
+ if (mNameIdList.size() == 0)
+ {
+ return 0;
+ }
+
+ uint32_t assetLoadedCount = 0;
+
+ /* handle the material namespace, which is different (not authorable) */
+ ResID assetPsID = INVALID_RESOURCE_ID;
+ if (mAuthoringTypeName == "")
+ {
+ assetPsID = mSdk->getMaterialNameSpace();
+ }
+ else
+ {
+ AuthorableObjectIntl* ao = mSdk->getAuthorableObject(mAuthoringTypeName.c_str());
+ if (ao)
+ {
+ assetPsID = ao->getResID();
+ }
+ else
+ {
+ APEX_INTERNAL_ERROR("Unknown authorable type: %s, please load all required modules.", mAuthoringTypeName.c_str());
+ }
+ }
+
+ for (uint32_t i = 0 ; i < mNameIdList.size() ; i++)
+ {
+ bool useIosNamespace = false;
+ /* Check if we are using the special IOS namespace ID */
+ if (!(mNameIdList[i]->iosAssetTypeName == ""))
+ {
+ AuthorableObjectIntl* ao = mSdk->getAuthorableObject(mNameIdList[i]->iosAssetTypeName.c_str());
+ if (!ao)
+ {
+ APEX_INTERNAL_ERROR("Particles Module is not loaded, cannot create particle system asset.");
+ return 0;
+ }
+
+ assetPsID = ao->getResID();
+
+ useIosNamespace = true;
+ }
+
+ // check if the asset has loaded yet
+ if (mNameIdList[i]->resID == INVALID_RESOURCE_ID)
+ {
+ // if not, go ahead and ask the NRP for them
+ if (useIosNamespace)
+ {
+ getIosAssetFromName(mNameIdList[i]->iosAssetTypeName.c_str(), mNameIdList[i]->assetName.c_str());
+ }
+ else if (mNameIdList[i]->isOpaqueMesh)
+ {
+ getMeshAssetFromName(mNameIdList[i]->assetName.c_str(), true);
+ }
+ else
+ {
+ getAssetFromName(mNameIdList[i]->assetName.c_str());
+ }
+ assetLoadedCount++;
+ }
+ }
+
+ return assetLoadedCount;
+}
+
+}
+} // end namespace nvidia::apex
+
diff --git a/APEX_1.4/common/src/ApexCollision.cpp b/APEX_1.4/common/src/ApexCollision.cpp
new file mode 100644
index 00000000..2e16a714
--- /dev/null
+++ b/APEX_1.4/common/src/ApexCollision.cpp
@@ -0,0 +1,750 @@
+/*
+ * 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 "ApexCollision.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+bool capsuleCapsuleIntersection(const Capsule& worldCaps0, const Capsule& worldCaps1, float tolerance)
+{
+ float s, t;
+ float squareDist = APEX_segmentSegmentSqrDist(worldCaps0, worldCaps1, &s, &t);
+
+ float totRad = (worldCaps0.radius * tolerance) + (worldCaps1.radius * tolerance); //incl a bit of tolerance.
+ return squareDist < totRad * totRad;
+}
+
+//----------------------------------------------------------------------------//
+
+/// \todo replace this hack
+bool boxBoxIntersection(const Box& worldBox0, const Box& worldBox1)
+{
+ Capsule worldCaps0, worldCaps1;
+ worldCaps0.p0 = worldBox0.center - worldBox0.rot * PxVec3(0, worldBox0.extents.y, 0);
+ worldCaps0.p1 = worldBox0.center + worldBox0.rot * PxVec3(0, worldBox0.extents.y, 0);
+ worldCaps0.radius = worldBox0.extents.x / 0.7f;
+ worldCaps1.p0 = worldBox1.center - worldBox1.rot * PxVec3(0, worldBox1.extents.y, 0);
+ worldCaps1.p1 = worldBox1.center + worldBox1.rot * PxVec3(0, worldBox1.extents.y, 0);
+ worldCaps1.radius = worldBox1.extents.x / 0.7f;
+
+ float s, t;
+ float squareDist = APEX_segmentSegmentSqrDist(worldCaps0, worldCaps1, &s, &t);
+
+ float totRad = (worldCaps0.radius * 1.2f) + (worldCaps1.radius * 1.2f); //incl a bit of tolerance.
+ return squareDist < totRad * totRad;
+}
+
+//----------------------------------------------------------------------------//
+
+float APEX_pointTriangleSqrDst(const Triangle& triangle, const PxVec3& position)
+{
+ PxVec3 d1 = triangle.v1 - triangle.v0;
+ PxVec3 d2 = triangle.v2 - triangle.v0;
+ PxVec3 pp1 = position - triangle.v0;
+ float a = d1.dot(d1);
+ float b = d2.dot(d1);
+ float c = pp1.dot(d1);
+ float d = b;
+ float e = d2.dot(d2);
+ float f = pp1.dot(d2);
+ float det = a * e - b * d;
+ if (det != 0.0f)
+ {
+ float s = (c * e - b * f) / det;
+ float t = (a * f - c * d) / det;
+ if (s > 0.0f && t > 0.0f && (s + t) < 1.0f)
+ {
+ PxVec3 q = triangle.v0 + d1 * s + d2 * t;
+ return (q - position).magnitudeSquared();
+ }
+ }
+ Segment segment;
+ segment.p0 = triangle.v0;
+ segment.p1 = triangle.v1;
+ float dist = APEX_pointSegmentSqrDist(segment , position, NULL);
+ segment.p0 = triangle.v1;
+ segment.p1 = triangle.v2;
+ dist = PxMin(dist, APEX_pointSegmentSqrDist(segment, position, NULL));
+ segment.p0 = triangle.v2;
+ segment.p1 = triangle.v0;
+ dist = PxMin(dist, APEX_pointSegmentSqrDist(segment, position, NULL));
+ return dist;
+
+}
+
+//----------------------------------------------------------------------------//
+
+#define PARALLEL_TOLERANCE 1e-02f
+
+float APEX_segmentSegmentSqrDist(const Segment& seg0, const Segment& seg1, float* s, float* t)
+{
+ PxVec3 rkSeg0Direction = seg0.p1 - seg0.p0;
+ PxVec3 rkSeg1Direction = seg1.p1 - seg1.p0;
+
+ PxVec3 kDiff = seg0.p0 - seg1.p0;
+ float fA00 = rkSeg0Direction.magnitudeSquared();
+ float fA01 = -rkSeg0Direction.dot(rkSeg1Direction);
+ float fA11 = rkSeg1Direction.magnitudeSquared();
+ float fB0 = kDiff.dot(rkSeg0Direction);
+ float fC = kDiff.magnitudeSquared();
+ float fDet = PxAbs(fA00 * fA11 - fA01 * fA01);
+
+ float fB1, fS, fT, fSqrDist, fTmp;
+
+ if (fDet >= PARALLEL_TOLERANCE)
+ {
+ // line segments are not parallel
+ fB1 = -kDiff.dot(rkSeg1Direction);
+ fS = fA01 * fB1 - fA11 * fB0;
+ fT = fA01 * fB0 - fA00 * fB1;
+
+ if (fS >= 0.0f)
+ {
+ if (fS <= fDet)
+ {
+ if (fT >= 0.0f)
+ {
+ if (fT <= fDet) // region 0 (interior)
+ {
+ // minimum at two interior points of 3D lines
+ float fInvDet = 1.0f / fDet;
+ fS *= fInvDet;
+ fT *= fInvDet;
+ fSqrDist = fS * (fA00 * fS + fA01 * fT + 2.0f * fB0) +
+ fT * (fA01 * fS + fA11 * fT + 2.0f * fB1) + fC;
+ }
+ else // region 3 (side)
+ {
+ fT = 1.0f;
+ fTmp = fA01 + fB0;
+ if (fTmp >= 0.0f)
+ {
+ fS = 0.0f;
+ fSqrDist = fA11 + 2.0f * fB1 + fC;
+ }
+ else if (-fTmp >= fA00)
+ {
+ fS = 1.0f;
+ fSqrDist = fA00 + fA11 + fC + 2.0f * (fB1 + fTmp);
+ }
+ else
+ {
+ fS = -fTmp / fA00;
+ fSqrDist = fTmp * fS + fA11 + 2.0f * fB1 + fC;
+ }
+ }
+ }
+ else // region 7 (side)
+ {
+ fT = 0.0f;
+ if (fB0 >= 0.0f)
+ {
+ fS = 0.0f;
+ fSqrDist = fC;
+ }
+ else if (-fB0 >= fA00)
+ {
+ fS = 1.0f;
+ fSqrDist = fA00 + 2.0f * fB0 + fC;
+ }
+ else
+ {
+ fS = -fB0 / fA00;
+ fSqrDist = fB0 * fS + fC;
+ }
+ }
+ }
+ else
+ {
+ if (fT >= 0.0)
+ {
+ if (fT <= fDet) // region 1 (side)
+ {
+ fS = 1.0f;
+ fTmp = fA01 + fB1;
+ if (fTmp >= 0.0f)
+ {
+ fT = 0.0f;
+ fSqrDist = fA00 + 2.0f * fB0 + fC;
+ }
+ else if (-fTmp >= fA11)
+ {
+ fT = 1.0f;
+ fSqrDist = fA00 + fA11 + fC + 2.0f * (fB0 + fTmp);
+ }
+ else
+ {
+ fT = -fTmp / fA11;
+ fSqrDist = fTmp * fT + fA00 + 2.0f * fB0 + fC;
+ }
+ }
+ else // region 2 (corner)
+ {
+ fTmp = fA01 + fB0;
+ if (-fTmp <= fA00)
+ {
+ fT = 1.0f;
+ if (fTmp >= 0.0f)
+ {
+ fS = 0.0f;
+ fSqrDist = fA11 + 2.0f * fB1 + fC;
+ }
+ else
+ {
+ fS = -fTmp / fA00;
+ fSqrDist = fTmp * fS + fA11 + 2.0f * fB1 + fC;
+ }
+ }
+ else
+ {
+ fS = 1.0f;
+ fTmp = fA01 + fB1;
+ if (fTmp >= 0.0f)
+ {
+ fT = 0.0f;
+ fSqrDist = fA00 + 2.0f * fB0 + fC;
+ }
+ else if (-fTmp >= fA11)
+ {
+ fT = 1.0f;
+ fSqrDist = fA00 + fA11 + fC + 2.0f * (fB0 + fTmp);
+ }
+ else
+ {
+ fT = -fTmp / fA11;
+ fSqrDist = fTmp * fT + fA00 + 2.0f * fB0 + fC;
+ }
+ }
+ }
+ }
+ else // region 8 (corner)
+ {
+ if (-fB0 < fA00)
+ {
+ fT = 0.0f;
+ if (fB0 >= 0.0f)
+ {
+ fS = 0.0f;
+ fSqrDist = fC;
+ }
+ else
+ {
+ fS = -fB0 / fA00;
+ fSqrDist = fB0 * fS + fC;
+ }
+ }
+ else
+ {
+ fS = 1.0f;
+ fTmp = fA01 + fB1;
+ if (fTmp >= 0.0f)
+ {
+ fT = 0.0f;
+ fSqrDist = fA00 + 2.0f * fB0 + fC;
+ }
+ else if (-fTmp >= fA11)
+ {
+ fT = 1.0f;
+ fSqrDist = fA00 + fA11 + fC + 2.0f * (fB0 + fTmp);
+ }
+ else
+ {
+ fT = -fTmp / fA11;
+ fSqrDist = fTmp * fT + fA00 + 2.0f * fB0 + fC;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (fT >= 0.0f)
+ {
+ if (fT <= fDet) // region 5 (side)
+ {
+ fS = 0.0f;
+ if (fB1 >= 0.0f)
+ {
+ fT = 0.0f;
+ fSqrDist = fC;
+ }
+ else if (-fB1 >= fA11)
+ {
+ fT = 1.0f;
+ fSqrDist = fA11 + 2.0f * fB1 + fC;
+ }
+ else
+ {
+ fT = -fB1 / fA11;
+ fSqrDist = fB1 * fT + fC;
+ }
+ }
+ else // region 4 (corner)
+ {
+ fTmp = fA01 + fB0;
+ if (fTmp < 0.0f)
+ {
+ fT = 1.0f;
+ if (-fTmp >= fA00)
+ {
+ fS = 1.0f;
+ fSqrDist = fA00 + fA11 + fC + 2.0f * (fB1 + fTmp);
+ }
+ else
+ {
+ fS = -fTmp / fA00;
+ fSqrDist = fTmp * fS + fA11 + 2.0f * fB1 + fC;
+ }
+ }
+ else
+ {
+ fS = 0.0f;
+ if (fB1 >= 0.0f)
+ {
+ fT = 0.0f;
+ fSqrDist = fC;
+ }
+ else if (-fB1 >= fA11)
+ {
+ fT = 1.0f;
+ fSqrDist = fA11 + 2.0f * fB1 + fC;
+ }
+ else
+ {
+ fT = -fB1 / fA11;
+ fSqrDist = fB1 * fT + fC;
+ }
+ }
+ }
+ }
+ else // region 6 (corner)
+ {
+ if (fB0 < 0.0f)
+ {
+ fT = 0.0f;
+ if (-fB0 >= fA00)
+ {
+ fS = 1.0f;
+ fSqrDist = fA00 + 2.0f * fB0 + fC;
+ }
+ else
+ {
+ fS = -fB0 / fA00;
+ fSqrDist = fB0 * fS + fC;
+ }
+ }
+ else
+ {
+ fS = 0.0f;
+ if (fB1 >= 0.0f)
+ {
+ fT = 0.0f;
+ fSqrDist = fC;
+ }
+ else if (-fB1 >= fA11)
+ {
+ fT = 1.0f;
+ fSqrDist = fA11 + 2.0f * fB1 + fC;
+ }
+ else
+ {
+ fT = -fB1 / fA11;
+ fSqrDist = fB1 * fT + fC;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // line segments are parallel
+ if (fA01 > 0.0f)
+ {
+ // direction vectors form an obtuse angle
+ if (fB0 >= 0.0f)
+ {
+ fS = 0.0f;
+ fT = 0.0f;
+ fSqrDist = fC;
+ }
+ else if (-fB0 <= fA00)
+ {
+ fS = -fB0 / fA00;
+ fT = 0.0f;
+ fSqrDist = fB0 * fS + fC;
+ }
+ else
+ {
+ fB1 = -kDiff.dot(rkSeg1Direction);
+ fS = 1.0f;
+ fTmp = fA00 + fB0;
+ if (-fTmp >= fA01)
+ {
+ fT = 1.0f;
+ fSqrDist = fA00 + fA11 + fC + 2.0f * (fA01 + fB0 + fB1);
+ }
+ else
+ {
+ fT = -fTmp / fA01;
+ fSqrDist = fA00 + 2.0f * fB0 + fC + fT * (fA11 * fT + 2.0f * (fA01 + fB1));
+ }
+ }
+ }
+ else
+ {
+ // direction vectors form an acute angle
+ if (-fB0 >= fA00)
+ {
+ fS = 1.0f;
+ fT = 0.0f;
+ fSqrDist = fA00 + 2.0f * fB0 + fC;
+ }
+ else if (fB0 <= 0.0f)
+ {
+ fS = -fB0 / fA00;
+ fT = 0.0f;
+ fSqrDist = fB0 * fS + fC;
+ }
+ else
+ {
+ fB1 = -kDiff.dot(rkSeg1Direction);
+ fS = 0.0f;
+ if (fB0 >= -fA01)
+ {
+ fT = 1.0f;
+ fSqrDist = fA11 + 2.0f * fB1 + fC;
+ }
+ else
+ {
+ fT = -fB0 / fA01;
+ fSqrDist = fC + fT * (2.0f * fB1 + fA11 * fT);
+ }
+ }
+ }
+ }
+
+ if (s)
+ {
+ *s = fS;
+ }
+ if (t)
+ {
+ *t = fT;
+ }
+
+ return PxAbs(fSqrDist);
+
+}
+
+//----------------------------------------------------------------------------//
+
+float APEX_pointSegmentSqrDist(const Segment& seg, const PxVec3& point, float* param)
+{
+ PxVec3 Diff = point - seg.p0;
+ PxVec3 segExtent = seg.p1 - seg.p0;
+ float fT = Diff.dot(segExtent);
+
+ if (fT <= 0.0f)
+ {
+ fT = 0.0f;
+ }
+ else
+ {
+ float SqrLen = (seg.p1 - seg.p0).magnitudeSquared();
+ if (fT >= SqrLen)
+ {
+ fT = 1.0f;
+ Diff -= segExtent;
+ }
+ else
+ {
+ fT /= SqrLen;
+ Diff -= fT * segExtent;
+ }
+ }
+
+ if (param)
+ {
+ *param = fT;
+ }
+
+ return Diff.magnitudeSquared();
+}
+
+//----------------------------------------------------------------------------//
+
+uint32_t APEX_RayCapsuleIntersect(const PxVec3& origin, const PxVec3& dir, const Capsule& capsule, float s[2])
+{
+ // set up quadratic Q(t) = a*t^2 + 2*b*t + c
+
+ PxVec3 kU, kV, kW;
+ const PxVec3 capsDir = capsule.p1 - capsule.p0;
+ kW = capsDir;
+
+ float fWLength = kW.normalize();
+
+ // generate orthonormal basis
+
+ float fInvLength;
+ if (PxAbs(kW.x) >= PxAbs(kW.y))
+ {
+ // W.x or W.z is the largest magnitude component, swap them
+ fInvLength = 1.0f / PxSqrt(kW.x * kW.x + kW.z * kW.z);
+ kU.x = -kW.z * fInvLength;
+ kU.y = 0.0f;
+ kU.z = +kW.x * fInvLength;
+ }
+ else
+ {
+ // W.y or W.z is the largest magnitude component, swap them
+ fInvLength = 1.0f / PxSqrt(kW.y * kW.y + kW.z * kW.z);
+ kU.x = 0.0f;
+ kU.y = +kW.z * fInvLength;
+ kU.z = -kW.y * fInvLength;
+ }
+ kV = kW.cross(kU);
+ kV.normalize(); // PT: fixed november, 24, 2004. This is a bug in Magic.
+
+ // compute intersection
+
+ PxVec3 kD(kU.dot(dir), kV.dot(dir), kW.dot(dir));
+ float fDLength = kD.normalize();
+
+ float fInvDLength = 1.0f / fDLength;
+ PxVec3 kDiff = origin - capsule.p0;
+ PxVec3 kP(kU.dot(kDiff), kV.dot(kDiff), kW.dot(kDiff));
+ float fRadiusSqr = capsule.radius * capsule.radius;
+
+ float fInv, fA, fB, fC, fDiscr, fRoot, fT, fTmp;
+
+ // Is the velocity parallel to the capsule direction? (or zero)
+ if (PxAbs(kD.z) >= 1.0f - PX_EPS_F32 || fDLength < PX_EPS_F32)
+ {
+
+ float fAxisDir = dir.dot(capsDir);
+
+ fDiscr = fRadiusSqr - kP.x * kP.x - kP.y * kP.y;
+ if (fAxisDir < 0 && fDiscr >= 0.0f)
+ {
+ // Velocity anti-parallel to the capsule direction
+ fRoot = PxSqrt(fDiscr);
+ s[0] = (kP.z + fRoot) * fInvDLength;
+ s[1] = -(fWLength - kP.z + fRoot) * fInvDLength;
+ return 2;
+ }
+ else if (fAxisDir > 0 && fDiscr >= 0.0f)
+ {
+ // Velocity parallel to the capsule direction
+ fRoot = PxSqrt(fDiscr);
+ s[0] = -(kP.z + fRoot) * fInvDLength;
+ s[1] = (fWLength - kP.z + fRoot) * fInvDLength;
+ return 2;
+ }
+ else
+ {
+ // sphere heading wrong direction, or no velocity at all
+ return 0;
+ }
+ }
+
+ // test intersection with infinite cylinder
+ fA = kD.x * kD.x + kD.y * kD.y;
+ fB = kP.x * kD.x + kP.y * kD.y;
+ fC = kP.x * kP.x + kP.y * kP.y - fRadiusSqr;
+ fDiscr = fB * fB - fA * fC;
+ if (fDiscr < 0.0f)
+ {
+ // line does not intersect infinite cylinder
+ return 0;
+ }
+
+ int iQuantity = 0;
+
+ if (fDiscr > 0.0f)
+ {
+ // line intersects infinite cylinder in two places
+ fRoot = PxSqrt(fDiscr);
+ fInv = 1.0f / fA;
+ fT = (-fB - fRoot) * fInv;
+ fTmp = kP.z + fT * kD.z;
+ if (0.0f <= fTmp && fTmp <= fWLength)
+ {
+ s[iQuantity++] = fT * fInvDLength;
+ }
+
+ fT = (-fB + fRoot) * fInv;
+ fTmp = kP.z + fT * kD.z;
+ if (0.0f <= fTmp && fTmp <= fWLength)
+ {
+ s[iQuantity++] = fT * fInvDLength;
+ }
+
+ if (iQuantity == 2)
+ {
+ // line intersects capsule wall in two places
+ return 2;
+ }
+ }
+ else
+ {
+ // line is tangent to infinite cylinder
+ fT = -fB / fA;
+ fTmp = kP.z + fT * kD.z;
+ if (0.0f <= fTmp && fTmp <= fWLength)
+ {
+ s[0] = fT * fInvDLength;
+ return 1;
+ }
+ }
+
+ // test intersection with bottom hemisphere
+ // fA = 1
+ fB += kP.z * kD.z;
+ fC += kP.z * kP.z;
+ fDiscr = fB * fB - fC;
+ if (fDiscr > 0.0f)
+ {
+ fRoot = PxSqrt(fDiscr);
+ fT = -fB - fRoot;
+ fTmp = kP.z + fT * kD.z;
+ if (fTmp <= 0.0f)
+ {
+ s[iQuantity++] = fT * fInvDLength;
+ if (iQuantity == 2)
+ {
+ return 2;
+ }
+ }
+
+ fT = -fB + fRoot;
+ fTmp = kP.z + fT * kD.z;
+ if (fTmp <= 0.0f)
+ {
+ s[iQuantity++] = fT * fInvDLength;
+ if (iQuantity == 2)
+ {
+ return 2;
+ }
+ }
+ }
+ else if (fDiscr == 0.0f)
+ {
+ fT = -fB;
+ fTmp = kP.z + fT * kD.z;
+ if (fTmp <= 0.0f)
+ {
+ s[iQuantity++] = fT * fInvDLength;
+ if (iQuantity == 2)
+ {
+ return 2;
+ }
+ }
+ }
+
+ // test intersection with top hemisphere
+ // fA = 1
+ fB -= kD.z * fWLength;
+ fC += fWLength * (fWLength - 2.0f * kP.z);
+
+ fDiscr = fB * fB - fC;
+ if (fDiscr > 0.0f)
+ {
+ fRoot = PxSqrt(fDiscr);
+ fT = -fB - fRoot;
+ fTmp = kP.z + fT * kD.z;
+ if (fTmp >= fWLength)
+ {
+ s[iQuantity++] = fT * fInvDLength;
+ if (iQuantity == 2)
+ {
+ return 2;
+ }
+ }
+
+ fT = -fB + fRoot;
+ fTmp = kP.z + fT * kD.z;
+ if (fTmp >= fWLength)
+ {
+ s[iQuantity++] = fT * fInvDLength;
+ if (iQuantity == 2)
+ {
+ return 2;
+ }
+ }
+ }
+ else if (fDiscr == 0.0f)
+ {
+ fT = -fB;
+ fTmp = kP.z + fT * kD.z;
+ if (fTmp >= fWLength)
+ {
+ s[iQuantity++] = fT * fInvDLength;
+ if (iQuantity == 2)
+ {
+ return 2;
+ }
+ }
+ }
+
+ return (uint32_t)iQuantity;
+}
+
+
+//----------------------------------------------------------------------------//
+
+bool APEX_RayTriangleIntersect(const PxVec3& orig, const PxVec3& dir, const PxVec3& a, const PxVec3& b, const PxVec3& c, float& t, float& u, float& v)
+{
+ PxVec3 edge1 = b - a;
+ PxVec3 edge2 = c - a;
+ PxVec3 pvec = dir.cross(edge2);
+
+ // if determinant is near zero, ray lies in plane of triangle
+ float det = edge1.dot(pvec);
+
+ if (det == 0.0f)
+ {
+ return false;
+ }
+
+ float iPX_det = 1.0f / det;
+
+ // calculate distance from vert0 to ray origin
+ PxVec3 tvec = orig - a;
+
+ // calculate U parameter and test bounds
+ u = tvec.dot(pvec) * iPX_det;
+ if (u < 0.0f || u > 1.0f)
+ {
+ return false;
+ }
+
+ // prepare to test V parameter
+ PxVec3 qvec = tvec.cross(edge1);
+
+ // calculate V parameter and test bounds
+ v = dir.dot(qvec) * iPX_det;
+ if (v < 0.0f || u + v > 1.0f)
+ {
+ return false;
+ }
+
+ // calculate t, ray intersects triangle
+ t = edge2.dot(qvec) * iPX_det;
+
+ return true;
+}
+
+} // namespace apex
+} // namespace nvidia
diff --git a/APEX_1.4/common/src/ApexContext.cpp b/APEX_1.4/common/src/ApexContext.cpp
new file mode 100644
index 00000000..0b6cf03c
--- /dev/null
+++ b/APEX_1.4/common/src/ApexContext.cpp
@@ -0,0 +1,330 @@
+/*
+ * 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 "Apex.h"
+#include "ApexContext.h"
+#include "ApexActor.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+//*** Apex Context ***
+ApexContext::~ApexContext()
+{
+ if (mIterator)
+ {
+ mIterator->release();
+ }
+ removeAllActors();
+ mActorArray.clear();
+ mActorArrayCallBacks.clear();
+}
+
+uint32_t ApexContext::addActor(ApexActor& actor, ApexActor* actorPtr)
+{
+ mActorListLock.lockWriter();
+ uint32_t index = mActorArray.size();
+ mActorArray.pushBack(&actor);
+ if (actorPtr != NULL)
+ {
+ mActorArrayCallBacks.pushBack(actorPtr);
+ }
+ callContextCreationCallbacks(&actor);
+ mActorListLock.unlockWriter();
+ return index;
+}
+
+void ApexContext::callContextCreationCallbacks(ApexActor* actorPtr)
+{
+ Asset* assetPtr;
+ AuthObjTypeID ObjectTypeID;
+ uint32_t numCallBackActors;
+
+ numCallBackActors = mActorArrayCallBacks.size();
+ for (uint32_t i = 0; i < numCallBackActors; i++)
+ {
+ assetPtr = actorPtr->getAsset();
+ if (assetPtr != NULL)
+ {
+ // get the resIds
+ ObjectTypeID = assetPtr->getObjTypeID();
+ // call the call back function
+ mActorArrayCallBacks[i]->ContextActorCreationNotification(ObjectTypeID,
+ actorPtr);
+ }
+ }
+}
+
+void ApexContext::callContextDeletionCallbacks(ApexActor* actorPtr)
+{
+ Asset* assetPtr;
+ AuthObjTypeID ObjectTypeID;
+ uint32_t numCallBackActors;
+
+ numCallBackActors = mActorArrayCallBacks.size();
+ for (uint32_t i = 0; i < numCallBackActors; i++)
+ {
+ assetPtr = actorPtr->getAsset();
+ if (assetPtr != NULL)
+ {
+ // get the resIds
+ ObjectTypeID = assetPtr->getObjTypeID();
+ // call the call back function
+ mActorArrayCallBacks[i]->ContextActorDeletionNotification(ObjectTypeID,
+ actorPtr);
+ }
+ }
+
+}
+
+void ApexContext::removeActorAtIndex(uint32_t index)
+{
+ ApexActor* actorPtr;
+
+ // call the callbacks so they know this actor is going to be deleted!
+ callContextDeletionCallbacks(mActorArray[index]);
+
+ mActorListLock.lockWriter();
+
+ // remove the actor from the call back array if it is in it
+ actorPtr = mActorArray[index];
+
+ for (uint32_t i = 0; i < mActorArrayCallBacks.size(); i++)
+ {
+ if (actorPtr == mActorArrayCallBacks[i]) // is this the actor to be removed?
+ {
+ mActorArrayCallBacks.replaceWithLast(i); // yes, remove it
+ }
+ }
+
+ if (mIterator)
+ {
+ Renderable* renderable = mActorArray[ index ]->getRenderable();
+ if (renderable)
+ {
+ mIterator->removeCachedActor(*(mActorArray[ index ]));
+ }
+ }
+ mActorArray.replaceWithLast(index);
+ if (index < mActorArray.size())
+ {
+ mActorArray[index]->updateIndex(*this, index);
+ }
+ mActorListLock.unlockWriter();
+}
+
+void ApexContext::renderLockAllActors()
+{
+ // Hold the render lock of all actors in the scene. Used to protect PxScene::fetchResults()
+ mActorListLock.lockReader();
+ for (uint32_t i = 0 ; i < mActorArray.size() ; i++)
+ {
+ mActorArray[i]->renderDataLock();
+ }
+
+ // NOTE: We are unlocking here now, and locking at the beginning of renderUnLockAllActors, below.
+ // This is under the assumption that this lock is ONLY to protect a loop over mActorArray, not
+ // anything between renderLockAllActors() and renderUnLockAllActors() in fetchResults().
+ mActorListLock.unlockReader();
+}
+
+void ApexContext::renderUnLockAllActors()
+{
+ // NOTE: We are unlocking at the end of renderLockAllActors(), above, and unlocking here now.
+ // This is under the assumption that this lock is ONLY to protect a loop over mActorArray, not
+ // anything between renderLockAllActors() and renderUnLockAllActors() in fetchResults().
+ mActorListLock.lockReader();
+
+ for (uint32_t i = 0 ; i < mActorArray.size() ; i++)
+ {
+ mActorArray[i]->renderDataUnLock();
+ }
+ mActorListLock.unlockReader();
+}
+
+void ApexContext::removeAllActors()
+{
+ while (mActorArray.size())
+ {
+ mActorArray.back()->release();
+ }
+ mActorArrayCallBacks.clear();
+}
+
+RenderableIterator* ApexContext::createRenderableIterator()
+{
+ if (mIterator)
+ {
+ PX_ALWAYS_ASSERT(); // Only one per context at a time, please
+ return NULL;
+ }
+ else
+ {
+ mIterator = PX_NEW(ApexRenderableIterator)(*this);
+ return mIterator;
+ }
+}
+void ApexContext::releaseRenderableIterator(RenderableIterator& iter)
+{
+ if (mIterator == DYNAMIC_CAST(ApexRenderableIterator*)(&iter))
+ {
+ mIterator->destroy();
+ mIterator = NULL;
+ }
+ else
+ {
+ PX_ASSERT(mIterator == DYNAMIC_CAST(ApexRenderableIterator*)(&iter));
+ }
+}
+
+ApexRenderableIterator::ApexRenderableIterator(ApexContext& _ctx) :
+ ctx(&_ctx),
+ curActor(0),
+ mLockedActor(NULL)
+{
+ // Make copy of list of renderable actors currently in the context.
+ // If an actor is later removed, we mark it as NULL in our cached
+ // array. If an actor is added, we do _NOT_ add it to our list since
+ // it would be quite dangerous to call dispatchRenderResources() on an
+ // actor that has never had updateRenderResources() called to it.
+
+ mCachedActors.reserve(ctx->mActorArray.size());
+ ctx->mActorListLock.lockWriter();
+ for (uint32_t i = 0 ; i < ctx->mActorArray.size() ; i++)
+ {
+ Renderable* renderable = ctx->mActorArray[ i ]->getRenderable();
+ if (renderable)
+ {
+ mCachedActors.pushBack(ctx->mActorArray[ i ]);
+ }
+ }
+ ctx->mActorListLock.unlockWriter();
+}
+
+void ApexRenderableIterator::removeCachedActor(ApexActor& actor)
+{
+ // This function is called with a locked context, so we can modify our
+ // internal lists at will.
+
+ for (uint32_t i = 0 ; i < mCachedActors.size() ; i++)
+ {
+ if (&actor == mCachedActors[ i ])
+ {
+ mCachedActors[ i ] = NULL;
+ break;
+ }
+ }
+ for (uint32_t i = 0 ; i < mSkippedActors.size() ; i++)
+ {
+ if (&actor == mSkippedActors[ i ])
+ {
+ mSkippedActors.replaceWithLast(i);
+ break;
+ }
+ }
+ if (&actor == mLockedActor)
+ {
+ mLockedActor->renderDataUnLock();
+ mLockedActor = NULL;
+ }
+}
+
+Renderable* ApexRenderableIterator::getFirst()
+{
+ curActor = 0;
+ mSkippedActors.reserve(mCachedActors.size());
+ return getNext();
+}
+
+Renderable* ApexRenderableIterator::getNext()
+{
+ if (mLockedActor)
+ {
+ mLockedActor->renderDataUnLock();
+ mLockedActor = NULL;
+ }
+
+ //physx::ScopedReadLock scopedContextLock( ctx->mActorListLock );
+ ctx->mActorListLock.lockReader();
+ while (curActor < mCachedActors.size())
+ {
+ ApexActor* actor = mCachedActors[ curActor++ ];
+ if (actor)
+ {
+ if (actor->renderDataTryLock())
+ {
+ mLockedActor = actor;
+ ctx->mActorListLock.unlockReader();
+ return actor->getRenderable();
+ }
+ else
+ {
+ mSkippedActors.pushBack(actor);
+ }
+ }
+ }
+ if (mSkippedActors.size())
+ {
+ ApexActor* actor = mSkippedActors.back();
+ mSkippedActors.popBack();
+ ctx->mActorListLock.unlockReader();
+ actor->renderDataLock();
+ mLockedActor = actor;
+ return actor->getRenderable();
+ }
+ ctx->mActorListLock.unlockReader();
+ return NULL;
+}
+
+void ApexRenderableIterator::release()
+{
+ ctx->releaseRenderableIterator(*this);
+}
+
+void ApexRenderableIterator::reset()
+{
+ if (mLockedActor)
+ {
+ mLockedActor->renderDataUnLock();
+ mLockedActor = NULL;
+ }
+
+ curActor = 0;
+
+ mCachedActors.reserve(ctx->mActorArray.size());
+ mCachedActors.reset();
+ ctx->mActorListLock.lockWriter();
+ for (uint32_t i = 0 ; i < ctx->mActorArray.size() ; i++)
+ {
+ Renderable* renderable = ctx->mActorArray[ i ]->getRenderable();
+ if (renderable)
+ {
+ mCachedActors.pushBack(ctx->mActorArray[ i ]);
+ }
+ }
+ ctx->mActorListLock.unlockWriter();
+}
+
+void ApexRenderableIterator::destroy()
+{
+ if (mLockedActor)
+ {
+ mLockedActor->renderDataUnLock();
+ mLockedActor = NULL;
+ }
+ delete this;
+}
+
+}
+} // end namespace nvidia::apex
+
diff --git a/APEX_1.4/common/src/ApexCudaProfile.cpp b/APEX_1.4/common/src/ApexCudaProfile.cpp
new file mode 100644
index 00000000..cee4cfc2
--- /dev/null
+++ b/APEX_1.4/common/src/ApexCudaProfile.cpp
@@ -0,0 +1,332 @@
+/*
+ * 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"
+#if APEX_CUDA_SUPPORT && !defined(INSTALLER)
+
+#include "ApexCudaProfile.h"
+#include "ApexCudaWrapper.h"
+#include <cuda.h>
+#include "ModuleIntl.h"
+#include "ApexSDKHelpers.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+ ApexCudaProfileSession::ApexCudaProfileSession()
+ : mTimer(NULL)
+ , mFrameStart(PX_MAX_F32)
+ , mFrameFinish(0.f)
+ {
+ mMemBuf.setEndianMode(nvidia::PsMemoryBuffer::ENDIAN_LITTLE);
+ }
+ ApexCudaProfileSession::~ApexCudaProfileSession()
+ {
+ if (mTimer)
+ {
+ CUT_SAFE_CALL(cuEventDestroy((CUevent)mTimer));
+ }
+ }
+
+ void ApexCudaProfileSession::nextFrame()
+ {
+ mFrameStart = PX_MAX_F32;
+ mFrameFinish = 0.f;
+ float sumElapsed = 0.f;
+ for (uint32_t i = 0; i < mProfileDataList.size(); i++)
+ {
+ sumElapsed += flushProfileInfo(mProfileDataList[i]);
+ }
+
+ // Write frame as fictive event
+ uint32_t op = 1, id = 0;
+ uint64_t start = static_cast<uint64_t>(mFrameStart * mManager->mTimeFormat);
+ mMemBuf.write(&op, sizeof(op));
+ mMemBuf.write(&start, sizeof(start));
+ mMemBuf.write(&id, sizeof(id));
+
+ op = 2;
+ uint64_t stop = static_cast<uint64_t>(mFrameFinish * mManager->mTimeFormat);
+ mMemBuf.write(&op, sizeof(op));
+ mMemBuf.write(&stop, sizeof(stop));
+ mMemBuf.write(&id, sizeof(id));
+
+ // Write summary of elapsed gpu kernel time as event
+ op = 1, id = 1;
+ start = static_cast<uint64_t>(mFrameStart * mManager->mTimeFormat);
+ mMemBuf.write(&op, sizeof(op));
+ mMemBuf.write(&start, sizeof(start));
+ mMemBuf.write(&id, sizeof(id));
+
+ op = 2;
+ stop = static_cast<uint64_t>((mFrameStart + sumElapsed) * mManager->mTimeFormat);
+ mMemBuf.write(&op, sizeof(op));
+ mMemBuf.write(&stop, sizeof(stop));
+ mMemBuf.write(&id, sizeof(id));
+
+ mProfileDataList.clear();
+ }
+
+ void ApexCudaProfileSession::start()
+ {
+ if (!mManager || !mManager->mApexScene) return;
+
+ mLock.lock();
+
+ mMemBuf.seekWrite(0);
+ uint32_t op = 0, sz, id = 0;
+ const char* frameEvent = "Frame"; sz = sizeof(frameEvent);
+ mMemBuf.write(&op, sizeof(op));
+ mMemBuf.write(&sz, sizeof(sz));
+ mMemBuf.write(frameEvent, sz);
+ mMemBuf.write(&id, sizeof(id));
+
+ const char* summaryElapsed = "Summary of elapsed time"; sz = sizeof(summaryElapsed);
+ id = 1;
+ mMemBuf.write(&op, sizeof(op));
+ mMemBuf.write(&sz, sizeof(sz));
+ mMemBuf.write(summaryElapsed, sz);
+ mMemBuf.write(&id, sizeof(id));
+
+ //Register kernels
+ for (uint32_t i = 0; i < mManager->mKernels.size(); i++)
+ {
+ ApexCudaProfileManager::KernelInfo& ki = mManager->mKernels[i];
+ sz = ki.functionName.size();
+ mMemBuf.write(&op, sizeof(op));
+ mMemBuf.write(&sz, sizeof(sz));
+ mMemBuf.write(ki.functionName.c_str(), sz);
+ mMemBuf.write(&ki.id, sizeof(ki.id));
+
+ ModuleSceneIntl* moduleScene = mManager->mApexScene->getInternalModuleScene(ki.moduleName.c_str());
+ ApexCudaObj* obj = NULL;
+ if (moduleScene)
+ {
+ obj = static_cast<ApexCudaObj*>(moduleScene->getHeadCudaObj());
+ }
+ while(obj)
+ {
+ if (obj->getType() == ApexCudaObj::FUNCTION)
+ {
+ if (ApexSimpleString(DYNAMIC_CAST(ApexCudaFunc*)(obj)->getName()) == ki.functionName)
+ {
+ DYNAMIC_CAST(ApexCudaFunc*)(obj)->setProfileSession(this);
+ break;
+ }
+ }
+ obj = obj->next();
+ }
+ }
+
+ {
+ PxCudaContextManager* ctx = mManager->mApexScene->getTaskManager()->getGpuDispatcher()->getCudaContextManager();
+ PxScopedCudaLock s(*ctx);
+
+ //Run timer
+ if (mTimer == NULL)
+ {
+ CUT_SAFE_CALL(cuEventCreate((CUevent*)&mTimer, CU_EVENT_DEFAULT));
+ }
+ CUT_SAFE_CALL(cuEventRecord((CUevent)mTimer, 0));
+ }
+ mLock.unlock();
+ }
+
+ uint32_t ApexCudaProfileSession::getProfileId(const char* name, const char* moduleName)
+ {
+ Array <ApexCudaProfileManager::KernelInfo>::Iterator it
+ = mManager->mKernels.find(ApexCudaProfileManager::KernelInfo(name, moduleName));
+ if (it != mManager->mKernels.end())
+ {
+ return it->id;
+ }
+ return 0;
+ }
+
+ void ApexCudaProfileSession::onFuncStart(uint32_t id, void* stream)
+ {
+ mLock.lock();
+ CUevent start;
+ CUevent stop;
+
+ CUT_SAFE_CALL(cuEventCreate(&start, CU_EVENT_DEFAULT));
+ CUT_SAFE_CALL(cuEventCreate(&stop, CU_EVENT_DEFAULT));
+
+ CUT_SAFE_CALL(cuEventRecord(start, (CUstream)stream));
+
+ ProfileData data;
+ data.id = id;
+ data.start = start;
+ data.stop = stop;
+ mProfileDataList.pushBack(data);
+
+ }
+ void ApexCudaProfileSession::onFuncFinish(uint32_t id, void* stream)
+ {
+ PX_UNUSED(id);
+ ProfileData& data = mProfileDataList.back();
+ PX_ASSERT(data.id == id);
+
+ CUT_SAFE_CALL(cuEventRecord((CUevent)data.stop, (CUstream)stream));
+
+ mLock.unlock();
+ }
+
+ float ApexCudaProfileSession::flushProfileInfo(ProfileData& pd)
+ {
+ CUevent start = (CUevent)pd.start;
+ CUevent stop = (CUevent)pd.stop;
+
+ uint32_t op = 1;
+ float startTf = 0.f, stopTf = 0.f;
+ uint64_t startT = 0, stopT = 0;
+ CUT_SAFE_CALL(cuEventSynchronize(start));
+ CUT_SAFE_CALL(cuEventElapsedTime(&startTf, (CUevent)mTimer, start));
+ startT = static_cast<uint64_t>(startTf * mManager->mTimeFormat) ;
+ mMemBuf.write(&op, sizeof(op));
+ mMemBuf.write(&startT, sizeof(startT));
+ mMemBuf.write(&pd.id, sizeof(pd.id));
+
+ op = 2;
+ CUT_SAFE_CALL(cuEventSynchronize((CUevent)stop));
+ CUT_SAFE_CALL(cuEventElapsedTime(&stopTf, (CUevent)mTimer, (CUevent)stop));
+ stopT = static_cast<uint64_t>(stopTf * mManager->mTimeFormat);
+ mMemBuf.write(&op, sizeof(op));
+ mMemBuf.write(&stopT, sizeof(stopT));
+ mMemBuf.write(&pd.id, sizeof(pd.id));
+
+ CUT_SAFE_CALL(cuEventDestroy((CUevent)start));
+ CUT_SAFE_CALL(cuEventDestroy((CUevent)stop));
+
+ mFrameStart = PxMin(mFrameStart, startTf);
+ mFrameFinish = PxMax(mFrameFinish, stopTf);
+ return stopTf - startTf;
+ }
+
+ bool ApexCudaProfileSession::stopAndSave()
+ {
+ if (!mManager || !mManager->mApexScene) return false;
+
+ //unregister functions
+ for (uint32_t i = 0; i < mManager->mKernels.size(); i++)
+ {
+ ApexCudaProfileManager::KernelInfo& ki = mManager->mKernels[i];
+
+ ModuleSceneIntl* moduleScene = mManager->mApexScene->getInternalModuleScene(ki.moduleName.c_str());
+ ApexCudaObj* obj = NULL;
+ if (moduleScene)
+ {
+ obj = static_cast<ApexCudaObj*>(moduleScene->getHeadCudaObj());
+ }
+ while(obj)
+ {
+ if (obj->getType() == ApexCudaObj::FUNCTION)
+ {
+ if (ApexSimpleString(DYNAMIC_CAST(ApexCudaFunc*)(obj)->getName()) == ki.functionName)
+ {
+ DYNAMIC_CAST(ApexCudaFunc*)(obj)->setProfileSession(NULL);
+ break;
+ }
+ }
+ obj = obj->next();
+ }
+ }
+
+ //save to file
+ ApexSimpleString path(mManager->mPath);
+ path += ApexSimpleString("profileSesion_");
+ path += ApexSimpleString(mManager->mSessionCount, 3);
+ FILE* saveFile = fopen(path.c_str(), "wb");
+ if (saveFile)
+ {
+ fwrite(mMemBuf.getWriteBuffer(), mMemBuf.getWriteBufferSize(), 1, saveFile);
+ return !fclose(saveFile);
+ }
+ return false;
+ }
+
+ ApexCudaProfileManager::ApexCudaProfileManager()
+ : mState(false)
+ , mTimeFormat(NANOSECOND)
+ , mSessionCount(0)
+ , mReservedId(2)
+ {
+ mSession.init(this);
+ }
+
+ ApexCudaProfileManager::~ApexCudaProfileManager()
+ {
+ }
+
+ void ApexCudaProfileManager::setKernel(const char* functionName, const char* moduleName)
+ {
+ if (mKernels.find(KernelInfo(functionName, moduleName)) == mKernels.end())
+ {
+ if (ApexSimpleString(functionName) == "*")
+ {
+ //Add all function registered in module
+ ModuleSceneIntl* moduleScene = mApexScene->getInternalModuleScene(moduleName);
+ ApexCudaObj* obj = NULL;
+ if (moduleScene)
+ {
+ obj = static_cast<ApexCudaObj*>(moduleScene->getHeadCudaObj());
+ }
+ while(obj)
+ {
+ if (obj->getType() == ApexCudaObj::FUNCTION)
+ {
+ const char* name = DYNAMIC_CAST(ApexCudaFunc*)(obj)->getName();
+ if (mKernels.find(KernelInfo(name, moduleName)) == mKernels.end())
+ {
+ mKernels.pushBack(KernelInfo(name, moduleName, mKernels.size() + mReservedId));
+ }
+ }
+ obj = obj->next();
+ }
+ }
+ else
+ {
+ mKernels.pushBack(KernelInfo(functionName, moduleName, mKernels.size() + mReservedId));
+ }
+ enable(false);
+ }
+ }
+
+ void ApexCudaProfileManager::enable(bool state)
+ {
+ if (state != mState)
+ {
+ if (state)
+ {
+ mSession.start();
+ mSessionCount++;
+ }
+ else
+ {
+ mSession.stopAndSave();
+ }
+ }
+ mState = state;
+ }
+
+ void ApexCudaProfileManager::nextFrame()
+ {
+ if (mApexScene && mState)
+ {
+ mSession.nextFrame();
+ }
+ }
+}
+} // namespace nvidia::apex
+
+#endif
diff --git a/APEX_1.4/common/src/ApexCudaTest.cpp b/APEX_1.4/common/src/ApexCudaTest.cpp
new file mode 100644
index 00000000..35ad85e3
--- /dev/null
+++ b/APEX_1.4/common/src/ApexCudaTest.cpp
@@ -0,0 +1,1209 @@
+/*
+ * 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"
+#if APEX_CUDA_SUPPORT && !defined(INSTALLER)
+
+#include "ApexCudaTest.h"
+#include "ApexCudaWrapper.h"
+#include <cuda.h>
+#include "ModuleIntl.h"
+#include "ApexSDKHelpers.h"
+
+# define CUT_SAFE_CALL(call) { CUresult ret = call; \
+ if( CUDA_SUCCESS != ret ) { \
+ APEX_INTERNAL_ERROR("Cuda Error %d", ret); \
+ PX_ASSERT(!ret); } }
+
+#define ALIGN_OFFSET(offset, alignment) (offset) = ((offset) + (alignment) - 1) & ~((alignment) - 1)
+
+#define WRITE_SCALAR(val) mMemBuf.alignWrite(4); mMemBuf.write(&val, sizeof(val));
+
+#define WRITE_ALIGN_ARRAY(ptr, size, align) { uint32_t nsz = size; \
+ mMemBuf.alignWrite(4); mMemBuf.write(&nsz, sizeof(nsz)); mMemBuf.alignWrite(align); mMemBuf.write(ptr, nsz); }
+
+#define WRITE_ARRAY(ptr, size) WRITE_ALIGN_ARRAY(ptr, size, 4)
+
+#define WRITE_STRING(str) { mMemBuf.alignWrite(4); str.serialize(mMemBuf); }
+
+#define READ_SCALAR(val) mMemBuf->alignRead(4); mMemBuf->read(&val, sizeof(val));
+
+#define READ_STRING(str) { mMemBuf->alignRead(4); str.deserialize(*mMemBuf); }
+
+namespace nvidia
+{
+namespace apex
+{
+
+ ApexCudaTestKernelContextReader::ApexCudaTestKernelContextReader(const char* path, SceneIntl* scene)
+ : mMemBuf(NULL)
+ , mHeadCudaObj(NULL)
+ , mFunc(NULL)
+ , mApexScene(scene)
+ , mCuStream(NULL)
+ , mTmpArray(*scene, __FILE__, __LINE__)
+ , mCopyQueue(*(scene->getTaskManager()->getGpuDispatcher()))
+ , mCudaArrayCount(0)
+ , mCudaArrayList(NULL)
+ {
+ FILE* loadFile;
+ loadFile = fopen(path, "rb");
+ if (loadFile)
+ {
+ uint32_t serviceInfo[5];
+
+ fread(serviceInfo, sizeof(uint32_t), 5, loadFile);
+ if (serviceInfo[0] != ApexCudaTestFileVersion)
+ {
+ PX_ASSERT(!"Unknown version of cuda context file");
+ }
+ fseek(loadFile, 0, 0);
+
+ mMemBuf = PX_NEW(nvidia::PsMemoryBuffer)(serviceInfo[1]);
+ mMemBuf->initWriteBuffer(serviceInfo[1]);
+ mCudaObjOffset = serviceInfo[3];
+ mParamOffset = serviceInfo[4];
+ fread((void*)mMemBuf->getWriteBuffer(), 1, serviceInfo[1], loadFile);
+
+ // Header
+ mMemBuf->seekRead(serviceInfo[2]);
+ READ_STRING(mName);
+ READ_STRING(mModuleName);
+ READ_SCALAR(mFrame);
+ READ_SCALAR(mCallPerFrame);
+
+ READ_SCALAR(mFuncInstId);
+ READ_SCALAR(mSharedSize);
+ READ_SCALAR(mBlockDim.x);
+ READ_SCALAR(mBlockDim.y);
+ READ_SCALAR(mBlockDim.z);
+ READ_SCALAR(mGridDim.x);
+ READ_SCALAR(mGridDim.y);
+ mGridDim.z = 0;
+ READ_SCALAR(mKernelType);
+ READ_SCALAR(mThreadCount[0]);
+ READ_SCALAR(mThreadCount[1]);
+ READ_SCALAR(mThreadCount[2]);
+ READ_SCALAR(mBlockCountY);
+
+ ModuleSceneIntl* moduleScene = scene->getInternalModuleScene(mModuleName.c_str());
+ if (moduleScene)
+ {
+ mHeadCudaObj = static_cast<ApexCudaObj*>(moduleScene->getHeadCudaObj());
+ }
+
+ ApexCudaObj* obj = mHeadCudaObj;
+ while(obj)
+ {
+ if (obj->getType() == ApexCudaObj::FUNCTION)
+ {
+ if (ApexSimpleString(DYNAMIC_CAST(ApexCudaFunc*)(obj)->getName()) == mName)
+ {
+ mFunc = DYNAMIC_CAST(ApexCudaFunc*)(obj);
+ break;
+ }
+ }
+ obj = obj->next();
+ }
+ }
+ }
+
+ ApexCudaTestKernelContextReader::~ApexCudaTestKernelContextReader()
+ {
+ if (mMemBuf)
+ {
+ PX_DELETE(mMemBuf);
+ }
+ if (mCudaArrayList)
+ {
+ PX_DELETE_ARRAY(mCudaArrayList);
+ }
+ }
+
+ bool ApexCudaTestKernelContextReader::runKernel()
+ {
+ if (mFunc)
+ {
+ //launch1
+ ApexCudaFuncParams params;
+ int* tmp = NULL;
+ int itmp = 0;
+
+ PxScopedCudaLock _lock_(*mApexScene->getTaskManager()->getGpuDispatcher()->getCudaContextManager());
+
+ mFunc->setParam(params, tmp); // profile buffer (NULL)
+ mFunc->setParam(params, itmp); // kernelID (0)
+
+ switch(mKernelType)
+ {
+ case apexCudaTest::KT_SYNC :
+ PX_ASSERT(!"Not implemented!");
+ break;
+ case apexCudaTest::KT_FREE2D :
+ mFunc->setParam(params, mThreadCount[0]);
+ mFunc->setParam(params, mThreadCount[1]);
+ break;
+ case apexCudaTest::KT_FREE3D :
+ mFunc->setParam(params, mThreadCount[0]);
+ mFunc->setParam(params, mThreadCount[1]);
+ mFunc->setParam(params, mThreadCount[2]);
+ mFunc->setParam(params, mBlockCountY);
+ break;
+ case apexCudaTest::KT_BOUND :
+ case apexCudaTest::KT_FREE :
+ mFunc->setParam(params, mThreadCount[0]);
+ break;
+ default :
+ PX_ASSERT(!"Wrong kernel type");
+ }
+
+ loadContext(params);
+
+ void *config[5] = {
+ CU_LAUNCH_PARAM_BUFFER_POINTER, params.mParams,
+ CU_LAUNCH_PARAM_BUFFER_SIZE, &params.mOffset,
+ CU_LAUNCH_PARAM_END
+ };
+ PX_ASSERT(mFuncInstId < mFunc->mFuncInstCount);
+ CUT_SAFE_CALL(cuLaunchKernel(mFunc->mFuncInstData[mFuncInstId].mCuFunc, (uint32_t)mGridDim.x, (uint32_t)mGridDim.y, 1, (uint32_t)mBlockDim.x, (uint32_t)mBlockDim.y, (uint32_t)mBlockDim.z, mSharedSize, (CUstream)mCuStream, 0, (void **)config));
+
+ mTmpArray.copyDeviceToHostQ(mCopyQueue);
+ mCopyQueue.flushEnqueued();
+
+ //copy mOutArrayRefs to host
+ uint32_t outArrayRefsOffset = 0;
+ for (uint32_t i = 0; i < mOutArrayRefs.size(); i++)
+ {
+ if (mOutArrayRefs[i].cudaArray != NULL)
+ {
+ outArrayRefsOffset += mOutArrayRefs[i].size;
+ }
+ }
+ Array <uint8_t> outArrayRefsBuffer(outArrayRefsOffset);
+ outArrayRefsOffset = 0;
+ for (uint32_t i = 0; i < mOutArrayRefs.size(); i++)
+ {
+ if (mOutArrayRefs[i].cudaArray != NULL)
+ {
+ mOutArrayRefs[i].cudaArray->copyToHost((CUstream)mCuStream, outArrayRefsBuffer.begin() + outArrayRefsOffset);
+ outArrayRefsOffset += mOutArrayRefs[i].size;
+ }
+ }
+
+ CUT_SAFE_CALL(cuStreamSynchronize((CUstream)mCuStream));
+
+ for (uint32_t i = 0; i < mTexRefs.size(); i++)
+ {
+ if (mTexRefs[i].cudaTexRef)
+ {
+ mTexRefs[i].cudaTexRef->unbind();
+ }
+ }
+ for (uint32_t i = 0; i < mSurfRefs.size(); i++)
+ {
+ if (mSurfRefs[i].cudaSurfRef)
+ {
+ mSurfRefs[i].cudaSurfRef->unbind();
+ }
+ }
+
+ bool isOk = true;
+ for (uint32_t i = 0; i < mOutMemRefs.size() && isOk; i++)
+ {
+ isOk = compare(
+ (const uint8_t*)mTmpArray.getPtr() + mOutMemRefs[i].bufferOffset,
+ (const uint8_t*)mOutMemRefs[i].gpuPtr,
+ mOutMemRefs[i].size,
+ mOutMemRefs[i].fpType,
+ mOutMemRefs[i].name.c_str());
+ }
+ outArrayRefsOffset = 0;
+ for (uint32_t i = 0; i < mOutArrayRefs.size() && isOk; i++)
+ {
+ if (mOutArrayRefs[i].cudaArray != NULL)
+ {
+ uint32_t fpType;
+ switch (mOutArrayRefs[i].cudaArray->getFormat())
+ {
+ case CU_AD_FORMAT_HALF:
+ fpType = 2;
+ break;
+ case CU_AD_FORMAT_FLOAT:
+ fpType = 4;
+ break;
+ default:
+ fpType = 0;
+ break;
+ };
+ isOk = compare(
+ outArrayRefsBuffer.begin() + outArrayRefsOffset,
+ mOutArrayRefs[i].bufferPtr,
+ mOutArrayRefs[i].size,
+ fpType,
+ mOutArrayRefs[i].name.c_str());
+ outArrayRefsOffset += mOutArrayRefs[i].size;
+ }
+ }
+ return isOk;
+ }
+
+ APEX_DEBUG_WARNING("can't find kernel '%s'", mName.c_str());
+ return false;
+ }
+
+ class Float16Compressor
+ {
+ union Bits
+ {
+ float f;
+ int32_t si;
+ uint32_t ui;
+ };
+
+ static int32_t const shift = 13;
+ static int32_t const shiftSign = 16;
+
+ static int32_t const infN = 0x7F800000; // flt32 infinity
+ static int32_t const maxN = 0x477FE000; // max flt16 normal as a flt32
+ static int32_t const minN = 0x38800000; // min flt16 normal as a flt32
+ static int32_t const signN = 0x80000000; // flt32 sign bit
+
+ static int32_t const infC = infN >> shift;
+ static int32_t const nanN = (infC + 1) << shift; // minimum flt16 nan as a flt32
+ static int32_t const maxC = maxN >> shift;
+ static int32_t const minC = minN >> shift;
+ static int32_t const signC = signN >> shiftSign; // flt16 sign bit
+
+ static int32_t const mulN = 0x52000000; // (1 << 23) / minN
+ static int32_t const mulC = 0x33800000; // minN / (1 << (23 - shift))
+
+ static int32_t const subC = 0x003FF; // max flt32 subnormal down shifted
+ static int32_t const norC = 0x00400; // min flt32 normal down shifted
+
+ static int32_t const maxD = infC - maxC - 1;
+ static int32_t const minD = minC - subC - 1;
+
+ public:
+ static float decompress(uint16_t value)
+ {
+ Bits v;
+ v.ui = value;
+ int32_t sign = v.si & signC;
+ v.si ^= sign;
+ sign <<= shiftSign;
+ v.si ^= ((v.si + minD) ^ v.si) & -(v.si > subC);
+ v.si ^= ((v.si + maxD) ^ v.si) & -(v.si > maxC);
+ Bits s;
+ s.si = mulC;
+ s.f *= v.si;
+ int32_t mask = -(norC > v.si);
+ v.si <<= shift;
+ v.si ^= (s.si ^ v.si) & mask;
+ v.si |= sign;
+ return v.f;
+ }
+ };
+
+ bool ApexCudaTestKernelContextReader::compare(const uint8_t* resData, const uint8_t* refData, size_t size, uint32_t fpType, const char* name)
+ {
+ char str[4096];
+ bool isOk = true;
+ switch (fpType)
+ {
+ case 2:
+ for (uint32_t j = 0; j < size && isOk; j += 2)
+ {
+ float ref = Float16Compressor::decompress(*reinterpret_cast<const uint16_t*>(refData + j));
+ float res = Float16Compressor::decompress(*reinterpret_cast<const uint16_t*>(resData + j));
+ isOk = PxAbs(res - ref) <= 2.5e-3 * PxMax(2.f, PxAbs(res + ref));
+ if (!isOk)
+ {
+ sprintf(str, "data mismatch at %d (%f != %f) in kernel '%s' param '%s'", (j / 2), res, ref, mName.c_str(), name);
+ dumpParams(str);
+ APEX_DEBUG_WARNING(str);
+ }
+ }
+ break;
+ case 4:
+ for (uint32_t j = 0; j < size && isOk; j += 4)
+ {
+ float ref = *reinterpret_cast<const float*>(refData + j);
+ float res = *reinterpret_cast<const float*>(resData + j);
+ isOk = PxAbs(res - ref) <= 2.5e-7 * PxMax(2.f, PxAbs(res + ref));
+ if (!isOk)
+ {
+ sprintf(str, "data mismatch at %d (%f != %f) in kernel '%s' param '%s'", (j / 4), res, ref, mName.c_str(), name);
+ dumpParams(str);
+ APEX_DEBUG_WARNING(str);
+ }
+ }
+ break;
+ case 8:
+ for (uint32_t j = 0; j < size && isOk; j += 8)
+ {
+ double ref = *reinterpret_cast<const double*>(refData + j);
+ double res = *reinterpret_cast<const double*>(resData + j);
+ isOk = PxAbs(res - ref) <= 2.5e-14 * PxMax(2., PxAbs(res + ref));
+ if (!isOk)
+ {
+ sprintf(str, "data mismatch at %d (%lf != %lf) in kernel '%s' param '%s'", (j / 8), res, ref, mName.c_str(), name);
+ dumpParams(str);
+ APEX_DEBUG_WARNING(str);
+ }
+ }
+ break;
+ default:
+ for (uint32_t j = 0; j < size && isOk; j += 4)
+ {
+ int ref = *reinterpret_cast<const int*>(refData + j);
+ int res = *reinterpret_cast<const int*>(resData + j);
+ isOk = (res == ref);
+ if (!isOk)
+ {
+ sprintf(str, "data mismatch at %d (%d != %d) in kernel '%s' param '%s'", (j / 4), res, ref, mName.c_str(), name);
+ dumpParams(str);
+ APEX_DEBUG_WARNING(str);
+ }
+ }
+ break;
+ };
+ return isOk;
+ }
+
+ void ApexCudaTestKernelContextReader::dumpParams(char* str)
+ {
+ size_t len = strlen(str);
+ str += len;
+ *str++ = '\n';
+ sprintf(str, "blockDim = (%d, %d, %d) GridDim = (%d, %d, %d) threadCount = (%d, %d, %d)", mBlockDim.x, mBlockDim.y, mBlockDim.z, mGridDim.x, mGridDim.y, mGridDim.z, mThreadCount[0], mThreadCount[1], mThreadCount[2]);
+ for (uint32_t i = 0; i < mParamRefs.size(); ++i)
+ {
+ size_t len = strlen(str);
+ str += len;
+ *str++ = '\n';
+ sprintf(str, "arg '%s' = 0x%x", mParamRefs[i].name.c_str(), mParamRefs[i].value);
+ }
+ }
+
+ void ApexCudaTestKernelContextReader::loadContext(ApexCudaFuncParams& params)
+ {
+ uint32_t n;
+ uint32_t cudaMemOffset = 0;
+
+ //Read cuda objs
+ mMemBuf->seekRead(mCudaObjOffset);
+ READ_SCALAR(n)
+ mCudaArrayList = PX_NEW(ApexCudaArray)[n];
+ mCudaArrayCount = 0;
+ for (uint32_t i = 0; i < n; i++)
+ {
+ uint32_t t;
+ READ_SCALAR(t);
+ switch(t)
+ {
+ case apexCudaTest::OBJ_TYPE_TEX_REF_MEM:
+ loadTexRef(cudaMemOffset, false);
+ break;
+ case apexCudaTest::OBJ_TYPE_CONST_MEM:
+ loadConstMem();
+ break;
+ case apexCudaTest::OBJ_TYPE_SURF_REF:
+ loadSurfRef();
+ break;
+ case apexCudaTest::OBJ_TYPE_TEX_REF_ARR:
+ loadTexRef(cudaMemOffset, true);
+ break;
+ default:
+ PX_ASSERT(!"Wrong type");
+ return;
+ }
+ }
+
+
+ //Read call params
+ mMemBuf->seekRead(mParamOffset);
+ READ_SCALAR(n);
+ uint32_t cudaMemOffsetPS = 0;
+ for (uint32_t i = 0; i < n; i++)
+ {
+ cudaMemOffsetPS += getParamSize();
+ ALIGN_OFFSET(cudaMemOffsetPS, APEX_CUDA_TEX_MEM_ALIGNMENT);
+ }
+
+ uint32_t arrSz = PxMax(cudaMemOffset + cudaMemOffsetPS, 4U);
+ mTmpArray.reserve(arrSz, ApexMirroredPlace::CPU_GPU);
+ mTmpArray.setSize(arrSz);
+
+ mMemBuf->seekRead(this->mParamOffset + sizeof(n));
+ for (uint32_t i = 0; i < n; i++)
+ {
+ loadParam(cudaMemOffset, params);
+ }
+
+ for (uint32_t i = 0; i < mInMemRefs.size(); i++)
+ {
+ memcpy(mTmpArray.getPtr() + mInMemRefs[i].bufferOffset, mInMemRefs[i].gpuPtr, mInMemRefs[i].size);
+ }
+
+ if (cudaMemOffset > 0)
+ {
+ mCopyQueue.reset((CUstream)mCuStream, 1);
+ mTmpArray.copyHostToDeviceQ(mCopyQueue, cudaMemOffset);
+ mCopyQueue.flushEnqueued();
+ }
+ for (uint32_t i = 0; i < mInArrayRefs.size(); i++)
+ {
+ if (mInArrayRefs[i].cudaArray != NULL)
+ {
+ mInArrayRefs[i].cudaArray->copyFromHost((CUstream)mCuStream, mInArrayRefs[i].bufferPtr);
+ }
+ }
+
+ for (uint32_t i = 0; i < mTexRefs.size(); i++)
+ {
+ if (mTexRefs[i].cudaTexRef)
+ {
+ if (mTexRefs[i].memRefIdx != uint32_t(-1))
+ {
+ const apexCudaTest::MemRef& memRef = mInMemRefs[ mTexRefs[i].memRefIdx ];
+ mTexRefs[i].cudaTexRef->bindTo(mTmpArray.getGpuPtr() + memRef.bufferOffset, memRef.size);
+ }
+ else if (mTexRefs[i].cudaArray != NULL)
+ {
+ mTexRefs[i].cudaTexRef->bindTo(*mTexRefs[i].cudaArray);
+ }
+ }
+ }
+ for (uint32_t i = 0; i < mSurfRefs.size(); i++)
+ {
+ if (mSurfRefs[i].cudaArray != NULL)
+ {
+ mSurfRefs[i].cudaSurfRef->bindTo(*mSurfRefs[i].cudaArray, mSurfRefs[i].flags);
+ }
+ }
+ }
+
+ ApexCudaArray* ApexCudaTestKernelContextReader::loadCudaArray()
+ {
+ uint32_t format, numChannels, width, height, depth, flags;
+ READ_SCALAR(format);
+ READ_SCALAR(numChannels);
+ READ_SCALAR(width);
+ READ_SCALAR(height);
+ READ_SCALAR(depth);
+ READ_SCALAR(flags);
+
+ CUDA_ARRAY3D_DESCRIPTOR desc;
+ desc.Format = CUarray_format(format);
+ desc.NumChannels = numChannels;
+ desc.Width = width;
+ desc.Height = height;
+ desc.Depth = depth;
+ desc.Flags = flags;
+
+ ApexCudaArray* cudaArray = &mCudaArrayList[mCudaArrayCount++];
+ cudaArray->create(desc);
+
+ return cudaArray;
+ }
+
+ void ApexCudaTestKernelContextReader::loadTexRef(uint32_t& memOffset, bool bBindToArray)
+ {
+ ApexSimpleString name;
+ READ_STRING(name);
+
+ TexRef texRef;
+ texRef.memRefIdx = uint32_t(-1);
+ texRef.cudaArray = NULL;
+ if (bBindToArray)
+ {
+ texRef.cudaArray = loadCudaArray();
+ const uint32_t size = uint32_t(texRef.cudaArray->getByteSize());
+
+ mMemBuf->alignRead(4);
+ mInArrayRefs.pushBack( ArrayRef(name.c_str(), texRef.cudaArray, mMemBuf->getReadLoc(), size) );
+ mMemBuf->advanceReadLoc(size);
+ }
+ else
+ {
+ uint32_t size;
+ READ_SCALAR(size);
+ if (size > 0)
+ {
+ texRef.memRefIdx = mInMemRefs.size();
+
+ mMemBuf->alignRead(4);
+ mInMemRefs.pushBack( apexCudaTest::MemRef(mMemBuf->getReadLoc(), size, 0, memOffset) );
+ mMemBuf->advanceReadLoc(size);
+
+ memOffset += size; ALIGN_OFFSET(memOffset, APEX_CUDA_TEX_MEM_ALIGNMENT);
+ }
+ }
+
+ //Find texture
+ for (ApexCudaObj* obj = mHeadCudaObj; obj; obj = obj->next())
+ {
+ if (obj->getType() == ApexCudaObj::TEXTURE && ::strcmp(obj->getName(), name.c_str()) == 0)
+ {
+ texRef.cudaTexRef = DYNAMIC_CAST(ApexCudaTexRef*)(obj);
+ mTexRefs.pushBack(texRef);
+ break;
+ }
+ }
+ }
+
+ void ApexCudaTestKernelContextReader::loadSurfRef()
+ {
+ ApexSimpleString name;
+ uint32_t flags;
+ READ_STRING(name);
+ READ_SCALAR(flags);
+
+ SurfRef surfRef;
+ surfRef.flags = ApexCudaMemFlags::Enum(flags);
+ surfRef.cudaArray = loadCudaArray();
+ const uint32_t size = uint32_t(surfRef.cudaArray->getByteSize());
+
+ if (surfRef.flags & ApexCudaMemFlags::IN)
+ {
+ mMemBuf->alignRead(4);
+ mInArrayRefs.pushBack( ArrayRef(name.c_str(), surfRef.cudaArray, mMemBuf->getReadLoc(), size) );
+ mMemBuf->advanceReadLoc(size);
+ }
+ if (surfRef.flags & ApexCudaMemFlags::OUT)
+ {
+ mMemBuf->alignRead(4);
+ mOutArrayRefs.pushBack( ArrayRef(name.c_str(), surfRef.cudaArray, mMemBuf->getReadLoc(), size) );
+ mMemBuf->advanceReadLoc(size);
+ }
+
+ //Find surface
+ for (ApexCudaObj* obj = mHeadCudaObj; obj; obj = obj->next())
+ {
+ if (obj->getType() == ApexCudaObj::SURFACE && ::strcmp(obj->getName(), name.c_str()) == 0)
+ {
+ surfRef.cudaSurfRef = DYNAMIC_CAST(ApexCudaSurfRef*)(obj);
+ mSurfRefs.pushBack(surfRef);
+ break;
+ }
+ }
+ }
+
+ void ApexCudaTestKernelContextReader::loadConstMem()
+ {
+ uint32_t size;
+ ApexSimpleString name;
+ READ_STRING(name);
+ READ_SCALAR(size);
+
+ //Load const mem
+ ApexCudaObj* obj = mHeadCudaObj;
+ while(obj)
+ {
+ if (obj->getType() == ApexCudaObj::CONST_STORAGE)
+ {
+ ApexCudaConstStorage* constMem = DYNAMIC_CAST(ApexCudaConstStorage*)(obj);
+ if (ApexSimpleString(constMem->getName()) == name)
+ {
+ PX_ASSERT(constMem->mHostBuffer != 0);
+ PX_ASSERT(constMem->mHostBuffer->getSize() >= size);
+ void* hostPtr = reinterpret_cast<void*>(constMem->mHostBuffer->getPtr());
+
+ mMemBuf->read(hostPtr, size);
+ CUT_SAFE_CALL(cuMemcpyHtoDAsync(constMem->mDevPtr, hostPtr, size, NULL));
+ break;
+ }
+ }
+ obj = obj->next();
+ }
+ }
+
+ uint32_t ApexCudaTestKernelContextReader::getParamSize()
+ {
+ ApexSimpleString name;
+ uint32_t size, align, intent;
+ int32_t dataOffset;
+ READ_STRING(name);
+ READ_SCALAR(align);
+ READ_SCALAR(intent);
+ READ_SCALAR(dataOffset);
+ READ_SCALAR(size);
+ if (size > 0)
+ {
+ mMemBuf->alignRead(align);
+ mMemBuf->advanceReadLoc(size);
+
+ if ((intent & 3) == 3)
+ {
+ mMemBuf->alignRead(align);
+ mMemBuf->advanceReadLoc(size);
+ }
+ if (intent & 3)
+ {
+ return size;
+ }
+ }
+ return 0;
+ }
+
+ void ApexCudaTestKernelContextReader::loadParam(uint32_t& memOffset, ApexCudaFuncParams& params)
+ {
+ ParamRef paramRef;
+ uint32_t size, align, intent;
+ int32_t dataOffset;
+ READ_STRING(paramRef.name);
+ READ_SCALAR(align);
+ READ_SCALAR(intent);
+ READ_SCALAR(dataOffset);
+ READ_SCALAR(size);
+ if (size > 0)
+ {
+ if (!intent) // scalar param
+ {
+ paramRef.value = *(uint32_t*)(mMemBuf->getReadLoc());
+ mParamRefs.pushBack(paramRef);
+
+ mFunc->setParam(params, align, size, (void*)(mMemBuf->getReadLoc()));
+ mMemBuf->advanceReadLoc(size);
+ }
+ else
+ {
+ mMemBuf->alignRead(align);
+ mInMemRefs.pushBack(apexCudaTest::MemRef(mMemBuf->getReadLoc(), size, dataOffset, memOffset));
+ if (intent & 0x01) // input intent
+ {
+ mMemBuf->advanceReadLoc(size);
+ }
+ if (intent & 0x02) // output intent
+ {
+ mMemBuf->alignRead(align);
+ mOutMemRefs.pushBack(apexCudaTest::MemRef(mMemBuf->getReadLoc(), size, dataOffset, memOffset, intent >> 2));
+ mOutMemRefs.back().name = paramRef.name;
+ mMemBuf->advanceReadLoc(size);
+ }
+ void* ptr = mTmpArray.getGpuPtr() + memOffset - dataOffset;
+ mFunc->setParam(params, align, sizeof(void*), &ptr);
+ memOffset += size; ALIGN_OFFSET(memOffset, APEX_CUDA_TEX_MEM_ALIGNMENT);
+ }
+ }
+ else
+ {
+ void* ptr = NULL;//mTmpArray.getGpuPtr() + memOffset - dataOffset;
+ mFunc->setParam(params, align, sizeof(void*), &ptr);
+ }
+ }
+
+ ApexCudaTestKernelContext::ApexCudaTestKernelContext(const char* path, const char* functionName, const char* moduleName, uint32_t frame, uint32_t callPerFrame,
+ bool isWriteForNonSuccessfulKernel, bool isContextForSave)
+ : mVersion(ApexCudaTestFileVersion)
+ , mFrame(frame)
+ , mCallPerFrame(callPerFrame)
+ , mPath(path)
+ , mName(functionName)
+ , mModuleName(moduleName)
+ , mCudaObjsCounter(0)
+ , mCallParamsCounter(0)
+ , mIsCompleteContext(false)
+ , mIsWriteForNonSuccessfulKernel(isWriteForNonSuccessfulKernel)
+ , mIsContextForSave(isContextForSave)
+ {
+ uint32_t writeLoc;
+ // service info
+ mMemBuf.setEndianMode(nvidia::PsMemoryBuffer::ENDIAN_LITTLE);
+ mMemBuf.write(&mVersion, sizeof(uint32_t)); // Version of format
+ mMemBuf.seekWrite(2 * sizeof(uint32_t)); // Space for file size
+ writeLoc = 32; // Offset for header block
+ mMemBuf.write(&writeLoc, sizeof(uint32_t));
+
+ // header info
+ mMemBuf.seekWrite(writeLoc);
+ WRITE_STRING(mName) // Name of function
+ WRITE_STRING(mModuleName) // Name of module
+ WRITE_SCALAR(frame) // Current frame
+ WRITE_SCALAR(callPerFrame) // Call of kernel per current frame
+
+ writeLoc = mMemBuf.tellWrite();
+ writeLoc += 12 * sizeof(uint32_t); // Space for cuda kernel parameters
+
+ mCudaObjsOffset = writeLoc; // Offset for cuda objects block
+ mMemBuf.seekWrite(3 * sizeof(uint32_t));
+ mMemBuf.write(&mCudaObjsOffset, sizeof(uint32_t));
+
+ writeLoc = mCudaObjsOffset + sizeof(uint32_t); // Space for N of cuda objs
+ mMemBuf.seekWrite(writeLoc);
+ }
+
+ ApexCudaTestKernelContext::~ApexCudaTestKernelContext()
+ {
+ }
+
+ PX_INLINE uint32_t ApexCudaTestKernelContext::advanceMemBuf(uint32_t size, uint32_t align)
+ {
+ uint32_t writeLoc = mMemBuf.tellWrite();
+ ALIGN_OFFSET(writeLoc, align);
+ const uint32_t ret = writeLoc;
+ writeLoc += size;
+ mMemBuf.seekWrite(writeLoc);
+ return ret;
+ }
+ PX_INLINE void ApexCudaTestKernelContext::copyToMemBuf(const apexCudaTest::MemRef& memRef)
+ {
+ CUT_SAFE_CALL(cuMemcpyDtoHAsync(
+ (void*)(mMemBuf.getWriteBuffer() + memRef.bufferOffset), CUdeviceptr((const uint8_t*)memRef.gpuPtr + memRef.dataOffset), memRef.size, CUstream(mCuStream))
+ );
+ }
+ PX_INLINE void ApexCudaTestKernelContext::copyToMemBuf(const ArrayRef& arrayRef)
+ {
+ ApexCudaArray cudaArray;
+ cudaArray.assign(arrayRef.cuArray, false);
+ cudaArray.copyToHost((CUstream)mCuStream, (void*)(mMemBuf.getWriteBuffer() + arrayRef.bufferOffset));
+ }
+
+ void ApexCudaTestKernelContext::completeCudaObjsBlock()
+ {
+ uint32_t writeLoc = mMemBuf.tellWrite();
+ mMemBuf.seekWrite(4 * sizeof(uint32_t)); // Offset for call param block
+ mMemBuf.write(&writeLoc, sizeof(uint32_t));
+ mCallParamsOffset = writeLoc;
+
+ mMemBuf.seekWrite(mCudaObjsOffset); // Write N of cuda objs
+ mMemBuf.write(&mCudaObjsCounter, sizeof(uint32_t));
+
+ writeLoc += sizeof(uint32_t); // Space for N of call params
+ mMemBuf.seekWrite(writeLoc);
+ }
+
+ void ApexCudaTestKernelContext::completeCallParamsBlock()
+ {
+ uint32_t writeLoc = mMemBuf.tellWrite();
+ mMemBuf.seekWrite(mCallParamsOffset); // Write N of call params
+ mMemBuf.write(&mCallParamsCounter, sizeof(uint32_t));
+ mMemBuf.seekWrite(writeLoc);
+ }
+
+ void ApexCudaTestKernelContext::setFreeKernel(uint32_t threadCount)
+ {
+ uint32_t writeLoc = mMemBuf.tellWrite();
+ mMemBuf.seekWrite(mCudaObjsOffset - 5 * sizeof(uint32_t));
+ uint32_t tmp = apexCudaTest::KT_FREE;
+ mMemBuf.write(&tmp, sizeof(tmp));
+ mMemBuf.write(&threadCount, sizeof(threadCount));
+ tmp = 0;
+ mMemBuf.write(&tmp, sizeof(tmp));
+ mMemBuf.write(&tmp, sizeof(tmp));
+ mMemBuf.write(&tmp, sizeof(tmp));
+ mMemBuf.seekWrite(writeLoc);
+ }
+ void ApexCudaTestKernelContext::setFreeKernel(uint32_t threadCountX, uint32_t threadCountY)
+ {
+ uint32_t writeLoc = mMemBuf.tellWrite();
+ mMemBuf.seekWrite(mCudaObjsOffset - 5 * sizeof(uint32_t));
+ uint32_t tmp = apexCudaTest::KT_FREE2D;
+ mMemBuf.write(&tmp, sizeof(tmp));
+ mMemBuf.write(&threadCountX, sizeof(threadCountX));
+ mMemBuf.write(&threadCountY, sizeof(threadCountY));
+ tmp = 0;
+ mMemBuf.write(&tmp, sizeof(tmp));
+ mMemBuf.write(&tmp, sizeof(tmp));
+ mMemBuf.seekWrite(writeLoc);
+ }
+ void ApexCudaTestKernelContext::setFreeKernel(uint32_t threadCountX, uint32_t threadCountY, uint32_t threadCountZ, uint32_t blockCountY)
+ {
+ uint32_t writeLoc = mMemBuf.tellWrite();
+ mMemBuf.seekWrite(mCudaObjsOffset - 5 * sizeof(uint32_t));
+ uint32_t tmp = apexCudaTest::KT_FREE3D;
+ mMemBuf.write(&tmp, sizeof(tmp));
+ mMemBuf.write(&threadCountX, sizeof(threadCountX));
+ mMemBuf.write(&threadCountY, sizeof(threadCountY));
+ mMemBuf.write(&threadCountZ, sizeof(threadCountZ));
+ mMemBuf.write(&blockCountY, sizeof(blockCountY));
+ mMemBuf.seekWrite(writeLoc);
+ }
+ void ApexCudaTestKernelContext::setBoundKernel(uint32_t threadCount)
+ {
+ uint32_t writeLoc = mMemBuf.tellWrite();
+ mMemBuf.seekWrite(mCudaObjsOffset - 5 * sizeof(uint32_t));
+ uint32_t tmp = apexCudaTest::KT_BOUND;
+ mMemBuf.write(&tmp, sizeof(tmp));
+ mMemBuf.write(&threadCount, sizeof(threadCount));
+ tmp = 0;
+ mMemBuf.write(&tmp, sizeof(tmp));
+ mMemBuf.write(&tmp, sizeof(tmp));
+ mMemBuf.write(&tmp, sizeof(tmp));
+ mMemBuf.seekWrite(writeLoc);
+ }
+ void ApexCudaTestKernelContext::setSyncKernel()
+ {
+ uint32_t writeLoc = mMemBuf.tellWrite();
+ mMemBuf.seekWrite(mCudaObjsOffset - 5 * sizeof(uint32_t));
+ uint32_t tmp = apexCudaTest::KT_SYNC;
+ mMemBuf.write(&tmp, sizeof(tmp));
+ mMemBuf.seekWrite(writeLoc);
+ }
+
+ void ApexCudaTestKernelContext::setSharedSize(uint32_t size)
+ {
+ uint32_t writeLoc = mMemBuf.tellWrite();
+ mMemBuf.seekWrite(mCudaObjsOffset - 11 * sizeof(uint32_t));
+ mMemBuf.write(&size, sizeof(int));
+ mMemBuf.seekWrite(writeLoc);
+ }
+ void ApexCudaTestKernelContext::setFuncInstId(int id)
+ {
+ uint32_t writeLoc = mMemBuf.tellWrite();
+ mMemBuf.seekWrite(mCudaObjsOffset - 12 * sizeof(uint32_t));
+ mMemBuf.write(&id, sizeof(int));
+ mMemBuf.seekWrite(writeLoc);
+ }
+
+ void ApexCudaTestKernelContext::setBlockDim(uint32_t x, uint32_t y, uint32_t z)
+ {
+ uint32_t writeLoc = mMemBuf.tellWrite();
+ mMemBuf.seekWrite(mCudaObjsOffset - 10 * sizeof(uint32_t));
+ mMemBuf.write(&x, sizeof(int));
+ mMemBuf.write(&y, sizeof(int));
+ mMemBuf.write(&z, sizeof(int));
+ mMemBuf.seekWrite(writeLoc);
+ }
+
+ void ApexCudaTestKernelContext::setGridDim(uint32_t x, uint32_t y)
+ {
+ uint32_t writeLoc = mMemBuf.tellWrite();
+ mMemBuf.seekWrite(mCudaObjsOffset - 7 * sizeof(uint32_t));
+ mMemBuf.write(&x, sizeof(int));
+ mMemBuf.write(&y, sizeof(int));
+ mMemBuf.seekWrite(writeLoc);
+ }
+
+ void ApexCudaTestKernelContext::addParam(const char* name, uint32_t align, const void *val, size_t size, int memRefIntent, int dataOffset, uint32_t fpType)
+ {
+ if (val == 0)
+ {
+ //handle NULL-ptr case
+ size = 0;
+ dataOffset = 0;
+ }
+ uint32_t sz = (uint32_t)size;
+ mCallParamsCounter++;
+ ApexSimpleString tName(name);
+ WRITE_STRING(tName);
+ WRITE_SCALAR(align);
+ uint32_t intent = (uint32_t)memRefIntent;
+ intent += fpType << 2;
+ WRITE_SCALAR(intent);
+ WRITE_SCALAR(dataOffset);
+ if (memRefIntent == 0)
+ {
+ WRITE_ALIGN_ARRAY(val, sz, align);
+ }
+ else
+ {
+ WRITE_SCALAR(sz);
+ if (sz > 0)
+ {
+ if (memRefIntent & ApexCudaMemFlags::IN)
+ {
+ const uint32_t offset = advanceMemBuf(sz, align);
+ apexCudaTest::MemRef memRef(val, size, dataOffset, offset);
+ copyToMemBuf(memRef);
+ }
+ if (memRefIntent & ApexCudaMemFlags::OUT)
+ {
+ const uint32_t offset = advanceMemBuf(sz, align);
+ apexCudaTest::MemRef memRef(val, size, dataOffset, offset);
+ mMemRefs.pushBack(memRef);
+ }
+ }
+ }
+ }
+
+ void ApexCudaTestKernelContext::startObjList()
+ {
+ }
+ void ApexCudaTestKernelContext::finishObjList()
+ {
+ completeCudaObjsBlock();
+ }
+
+ uint32_t ApexCudaTestKernelContext::addCuArray(CUarray cuArray)
+ {
+ ApexCudaArray cudaArray;
+ cudaArray.assign(cuArray, false);
+
+ const CUDA_ARRAY3D_DESCRIPTOR& desc = cudaArray.getDesc();
+ uint32_t format = uint32_t(desc.Format);
+ uint32_t numChannels = uint32_t(desc.NumChannels);
+ uint32_t width = uint32_t(desc.Width);
+ uint32_t height = uint32_t(desc.Height);
+ uint32_t depth = uint32_t(desc.Depth);
+ uint32_t flags = uint32_t(desc.Flags);
+
+ WRITE_SCALAR(format);
+ WRITE_SCALAR(numChannels);
+ WRITE_SCALAR(width);
+ WRITE_SCALAR(height);
+ WRITE_SCALAR(depth);
+ WRITE_SCALAR(flags);
+
+ return uint32_t(cudaArray.getByteSize());
+ }
+
+ void ApexCudaTestKernelContext::addTexRef(const char* name, const void* mem, size_t size, CUarray arr)
+ {
+ PX_ASSERT(!mIsCompleteContext);
+ const uint32_t objType = (arr != NULL) ? apexCudaTest::OBJ_TYPE_TEX_REF_ARR : apexCudaTest::OBJ_TYPE_TEX_REF_MEM;
+ mCudaObjsCounter++;
+ WRITE_SCALAR(objType);
+ ApexSimpleString tName(name);
+ WRITE_STRING(tName);
+ if (arr != NULL)
+ {
+ const uint32_t sz = addCuArray(arr);
+ const uint32_t offset = advanceMemBuf(sz);
+ ArrayRef arrayRef(arr, offset);
+ copyToMemBuf(arrayRef);
+ }
+ else
+ {
+ const uint32_t sz = uint32_t(size);
+ WRITE_SCALAR(sz);
+ if (sz > 0)
+ {
+ const uint32_t offset = advanceMemBuf(sz);
+ apexCudaTest::MemRef memRef(mem, size, 0, offset);
+ copyToMemBuf(memRef);
+ }
+ }
+ }
+
+ void ApexCudaTestKernelContext::addSurfRef(const char* name, CUarray arr, ApexCudaMemFlags::Enum flags)
+ {
+ PX_ASSERT(!mIsCompleteContext);
+ const uint32_t objType = apexCudaTest::OBJ_TYPE_SURF_REF;
+ mCudaObjsCounter++;
+ WRITE_SCALAR(objType);
+ ApexSimpleString tName(name);
+ WRITE_STRING(tName);
+ const uint32_t intent = flags;
+ WRITE_SCALAR(intent);
+
+ const uint32_t sz = addCuArray(arr);
+ if (intent & ApexCudaMemFlags::IN)
+ {
+ const uint32_t offset = advanceMemBuf(sz);
+ ArrayRef arrayRef(arr, offset);
+ copyToMemBuf(arrayRef);
+ }
+ if (intent & ApexCudaMemFlags::OUT)
+ {
+ const uint32_t offset = advanceMemBuf(sz);
+ ArrayRef arrayRef(arr, offset);
+ mArrayRefs.pushBack(arrayRef);
+ }
+ }
+
+ void ApexCudaTestKernelContext::addConstMem(const char* name, const void* mem, size_t size)
+ {
+ PX_ASSERT(!mIsCompleteContext);
+ const uint32_t objType = apexCudaTest::OBJ_TYPE_CONST_MEM;
+ mCudaObjsCounter++;
+ WRITE_SCALAR(objType);
+ ApexSimpleString cmName(name);
+ WRITE_STRING(cmName);
+ WRITE_ARRAY(mem, (uint32_t)size);
+ }
+
+ void ApexCudaTestKernelContext::copyMemRefs()
+ {
+ for (uint32_t i = 0; i < mMemRefs.size(); i++)
+ {
+ copyToMemBuf(mMemRefs[i]);
+ }
+ mMemRefs.clear();
+ }
+
+ void ApexCudaTestKernelContext::copyArrayRefs()
+ {
+ for (uint32_t i = 0; i < mArrayRefs.size(); i++)
+ {
+ copyToMemBuf(mArrayRefs[i]);
+ }
+ mArrayRefs.clear();
+ }
+
+ void ApexCudaTestKernelContext::setKernelStatus()
+ {
+ if (mIsWriteForNonSuccessfulKernel)
+ {
+ int cuResult = cuCtxSynchronize();//= cudaPeekAtLastError();
+ //cudaDeviceSynchronize();
+
+ if (cuResult)
+ {
+ mErrorCode += 'E';
+ mErrorCode += ApexSimpleString((uint32_t)cuResult, 3);
+ saveToFile();
+ APEX_INTERNAL_ERROR("Cuda Error %d", cuResult);
+ }
+ else if (mIsContextForSave)
+ {
+ copyMemRefs();
+ copyArrayRefs();
+ }
+ }
+ else
+ {
+ copyMemRefs();
+ copyArrayRefs();
+ }
+ }
+
+ bool ApexCudaTestKernelContext::saveToFile()
+ {
+ if (!mIsContextForSave && mErrorCode.size() == 0)
+ {
+ return false;
+ }
+ if (!mIsCompleteContext)
+ {
+ completeCallParamsBlock();
+
+ uint32_t writeLoc = mMemBuf.tellWrite();
+ mMemBuf.seekWrite(sizeof(uint32_t)); // Write size of file
+ mMemBuf.write(&writeLoc, sizeof(uint32_t));
+ mIsCompleteContext = true;
+
+ mMemBuf.seekWrite(writeLoc);
+ }
+
+ ApexSimpleString path(mPath);
+ path += mName;
+ path += '_';
+ path += ApexSimpleString(mCallPerFrame, 3);
+ path += ApexSimpleString(mFrame, 5);
+ path += mErrorCode;
+ FILE* saveFile = fopen(path.c_str(), "wb");
+
+ if (saveFile)
+ {
+ fwrite(mMemBuf.getWriteBuffer(), mMemBuf.getWriteBufferSize(), 1, saveFile);
+ return !fclose(saveFile);
+ }
+
+ return false;
+ }
+
+
+ ApexCudaTestManager::ApexCudaTestManager()
+ : mCurrentFrame(0)
+ , mMaxSamples(0)
+ , mFramePeriod(0)
+ , mCallPerFrameMaxCount(1)
+ , mIsWriteForNonSuccessfulKernel(false)
+ {
+ }
+
+ ApexCudaTestManager::~ApexCudaTestManager()
+ {
+ for (uint32_t i = 0; i < mContexts.size(); i++)
+ {
+ PX_DELETE(mContexts[i]);
+ }
+ }
+
+ void ApexCudaTestManager::setWriteForFunction(const char* functionName, const char* moduleName)
+ {
+ if (::strcmp(functionName, "*") == 0)
+ {
+ //Add all function registered in module
+ ModuleSceneIntl* moduleScene = mApexScene->getInternalModuleScene(moduleName);
+ ApexCudaObj* obj = NULL;
+ if (moduleScene)
+ {
+ obj = static_cast<ApexCudaObj*>(moduleScene->getHeadCudaObj());
+ }
+ while(obj)
+ {
+ if (obj->getType() == ApexCudaObj::FUNCTION)
+ {
+ const char* name = DYNAMIC_CAST(ApexCudaFunc*)(obj)->getName();
+ if (mKernels.find(KernelInfo(name, moduleName)) == mKernels.end())
+ {
+ mKernels.pushBack(KernelInfo(name, moduleName));
+ }
+ }
+ obj = obj->next();
+ }
+ }
+ else
+ {
+ ApexSimpleString fName(moduleName);
+ fName += '_';
+ fName += ApexSimpleString(functionName);
+ mKernels.pushBack(KernelInfo(fName.c_str(), moduleName));
+ }
+ }
+
+ bool ApexCudaTestManager::runKernel(const char* path)
+ {
+ if (mApexScene)
+ {
+ ApexCudaTestKernelContextReader contextReader(path, mApexScene);
+ return contextReader.runKernel();
+ }
+ return false;
+ }
+
+ void ApexCudaTestManager::nextFrame()
+ {
+ mCurrentFrame++;
+
+ if (mContexts.size() > 0)
+ {
+ for (uint32_t i = 0; i < mContexts.size(); i++)
+ {
+ mContexts[i]->saveToFile();
+ PX_DELETE(mContexts[i]);
+ }
+ mContexts.clear();
+
+ for (uint32_t i = 0; i < mKernels.size(); i++)
+ {
+ mKernels[i].callCount = 0;
+ }
+ }
+ }
+
+ ApexCudaTestKernelContext* ApexCudaTestManager::isTestKernel(const char* functionName, const char* moduleName)
+ {
+ KernelInfo* kernel = NULL;
+ if ( mContexts.size() < mMaxSamples
+ && ( mSampledFrames.find(mCurrentFrame) != mSampledFrames.end()
+ || mFramePeriod && (mCurrentFrame % mFramePeriod) == 0
+ )
+ && (kernel = mKernels.find(KernelInfo(functionName, moduleName))) != mKernels.end()
+ && (kernel->callCount < mCallPerFrameMaxCount)
+ )
+ {
+ mContexts.pushBack(PX_NEW(ApexCudaTestKernelContext)(mPath.c_str(), functionName, moduleName, mCurrentFrame, ++(kernel->callCount), mIsWriteForNonSuccessfulKernel, true));
+ return mContexts.back();
+ }
+ else if (mIsWriteForNonSuccessfulKernel && (mKernels.size() == 0 || (mKernels.find(KernelInfo(functionName, moduleName)) != mKernels.end())))
+ {
+ mContexts.pushBack(PX_NEW(ApexCudaTestKernelContext)(mPath.c_str(), functionName, moduleName, mCurrentFrame, 0, true, false));
+ return mContexts.back();
+ }
+ return NULL;
+ }
+}
+} // namespace nvidia::apex
+
+#endif
diff --git a/APEX_1.4/common/src/ApexGeneralizedCubeTemplates.cpp b/APEX_1.4/common/src/ApexGeneralizedCubeTemplates.cpp
new file mode 100644
index 00000000..87a9d6ea
--- /dev/null
+++ b/APEX_1.4/common/src/ApexGeneralizedCubeTemplates.cpp
@@ -0,0 +1,677 @@
+/*
+ * 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 "ApexGeneralizedCubeTemplates.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+ApexGeneralizedCubeTemplates::ApexGeneralizedCubeTemplates()
+{
+ // init basis
+ uint32_t p = 0;
+ const float d = 1.0f / (SUB_GRID_LEN - 1);
+ for (uint32_t xi = 0; xi < SUB_GRID_LEN; xi++)
+ {
+ const float wx = d * xi;
+ const float mx = 1.0f - wx;
+ for (uint32_t yi = 0; yi < SUB_GRID_LEN; yi++)
+ {
+ const float wy = d * yi;
+ const float my = 1.0f - wy;
+ for (uint32_t zi = 0; zi < SUB_GRID_LEN; zi++)
+ {
+ const float wz = d * zi;
+ const float mz = 1.0f - wz;
+ mBasis[p][0] = mx * my * mz;
+ mBasis[p][1] = wx * my * mz;
+ mBasis[p][2] = wx * wy * mz;
+ mBasis[p][3] = mx * wy * mz;
+ mBasis[p][4] = mx * my * wz;
+ mBasis[p][5] = wx * my * wz;
+ mBasis[p][6] = wx * wy * wz;
+ mBasis[p][7] = mx * wy * wz;
+ p++;
+ }
+ }
+ }
+
+ // default vertex positions
+ mVertPos[ 0] = PxVec3(0.5f, 0.0f, 0.0f); // on edges
+ mVertPos[ 1] = PxVec3(1.0f, 0.5f, 0.0f);
+ mVertPos[ 2] = PxVec3(0.5f, 1.0f, 0.0f);
+ mVertPos[ 3] = PxVec3(0.0f, 0.5f, 0.0f);
+ mVertPos[ 4] = PxVec3(0.5f, 0.0f, 1.0f);
+ mVertPos[ 5] = PxVec3(1.0f, 0.5f, 1.0f);
+ mVertPos[ 6] = PxVec3(0.5f, 1.0f, 1.0f);
+ mVertPos[ 7] = PxVec3(0.0f, 0.5f, 1.0f);
+ mVertPos[ 8] = PxVec3(0.0f, 0.0f, 0.5f);
+ mVertPos[ 9] = PxVec3(1.0f, 0.0f, 0.5f);
+ mVertPos[10] = PxVec3(1.0f, 1.0f, 0.5f);
+ mVertPos[11] = PxVec3(0.0f, 1.0f, 0.5f);
+ mVertPos[12] = PxVec3(0.0f, 0.5f, 0.5f); // on faces
+ mVertPos[13] = PxVec3(1.0f, 0.5f, 0.5f);
+ mVertPos[14] = PxVec3(0.5f, 0.0f, 0.5f);
+ mVertPos[15] = PxVec3(0.5f, 1.0f, 0.5f);
+ mVertPos[16] = PxVec3(0.5f, 0.5f, 0.0f);
+ mVertPos[17] = PxVec3(0.5f, 0.5f, 1.0f);
+ mVertPos[18] = PxVec3(0.5f, 0.5f, 0.5f); // in center
+
+ // init other data structures
+ for (int i = 0; i < NUM_SUB_CELLS; i++)
+ {
+ mSubGrid[i].init();
+ }
+
+ for (int i = 0; i < NUM_CASES_3; i++)
+ {
+ mFirst3[i] = -1;
+ }
+
+ mLookupIndices3.clear();
+
+ createLookupTable3();
+}
+
+
+
+
+void ApexGeneralizedCubeTemplates::getTriangles(const int groups[8], physx::Array<int32_t> &indices)
+{
+ int32_t maxGroup = 0;
+ for (uint32_t i = 0; i < 8; i++)
+ {
+ if (groups[i] > maxGroup)
+ {
+ maxGroup = groups[i];
+ }
+ }
+
+ //physx::Array<int32_t> currentIndices;
+
+ indices.clear();
+ PX_ASSERT(maxGroup < 8);
+ if (maxGroup <= 2 && !mLookupIndices3.empty())
+ {
+ uint32_t code = 0;
+ for (int32_t i = 7; i >= 0; i--)
+ {
+ code = code * 3 + groups[i];
+ }
+
+ int32_t first = mFirst3[code];
+ if (first >= 0)
+ {
+ for (uint32_t i = (uint32_t)first; mLookupIndices3[i] >= 0; i++)
+ {
+ indices.pushBack(mLookupIndices3[i]);
+ //currentIndices.pushBack(mLookupIndices3[i]);
+ }
+ return;
+ }
+ }
+
+ setCellGroups(groups);
+ splitDisconnectedGroups();
+ findVertices();
+ createTriangles(indices);
+}
+
+
+
+
+void ApexGeneralizedCubeTemplates::createLookupTable3()
+{
+ if (!mLookupIndices3.empty())
+ {
+ return;
+ }
+
+ int32_t groups[8];
+ physx::Array<int32_t> indices;
+ indices.reserve(32);
+
+ mLookupIndices3.clear();
+ mLookupIndices3.reserve(169200); // otherwise it crashes in release mode!
+
+ for (uint32_t i = 0; i < NUM_CASES_3; i++)
+ {
+ int32_t c = (int32_t)i;
+ for (uint32_t j = 0; j < 8; j++)
+ {
+ groups[j] = c % 3;
+ c /= 3;
+ }
+
+ getTriangles(groups, indices);
+
+ mFirst3[i] = (int32_t)mLookupIndices3.size();
+ for (uint32_t j = 0; j < indices.size(); j++)
+ {
+ mLookupIndices3.pushBack(indices[j]);
+ }
+
+ mLookupIndices3.pushBack(-1); // marks end
+ }
+}
+
+
+
+void ApexGeneralizedCubeTemplates::setCellGroups(const int32_t groups[8])
+{
+ float groupWeights[8];
+ uint32_t p = 0;
+
+ for (uint32_t xi = 0; xi < SUB_GRID_LEN; xi++)
+ {
+ for (uint32_t yi = 0; yi < SUB_GRID_LEN; yi++)
+ {
+ for (uint32_t zi = 0; zi < SUB_GRID_LEN; zi++)
+ {
+ GenSubCell& c = mSubGrid[p];
+
+ float* basis = mBasis[p];
+ p++;
+ c.init();
+
+ memset(groupWeights, 0, sizeof(float) * 8);
+
+ for (uint32_t corner = 0; corner < 8; corner++)
+ {
+ groupWeights[groups[corner]] += basis[corner];
+ }
+
+ c.group = 0;
+ float maxWeight = groupWeights[0];
+ for (int32_t group = 1; group < 8; group++)
+ {
+ if (groupWeights[group] > maxWeight)
+ {
+ maxWeight = groupWeights[group];
+ c.group = group;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+void ApexGeneralizedCubeTemplates::splitDisconnectedGroups()
+{
+ // in certain cases groups are not connected sub spaces
+ // in that case we want to create (more) new connected groups
+
+ physx::Array<GenCoord> queue;
+ //GenCoord c;
+
+ const int n[6][3] =
+ {
+ { -1, 0, 0},
+ { 1, 0, 0},
+ { 0, -1, 0},
+ { 0, 1, 0},
+ { 0, 0, -1},
+ { 0, 0, 1}
+ };
+
+ int newGroup = -1;
+ for (int32_t xi = 0; xi < SUB_GRID_LEN; xi++)
+ {
+ for (int32_t yi = 0; yi < SUB_GRID_LEN; yi++)
+ {
+ for (int32_t zi = 0; zi < SUB_GRID_LEN; zi++)
+ {
+ GenSubCell& start = mSubGrid[cellNr((uint32_t)xi, (uint32_t)yi, (uint32_t)zi)];
+
+ if (start.group < 0 || start.marked)
+ {
+ continue;
+ }
+
+ newGroup++;
+ int32_t oldGroup = start.group;
+
+ GenCoord c;
+ c.xi = xi;
+ c.yi = yi;
+ c.zi = zi;
+
+ queue.pushBack(c);
+ while (!queue.empty())
+ {
+ c = queue[queue.size() - 1];
+ queue.popBack();
+
+ GenSubCell& cell = mSubGrid[cellNr((uint32_t)c.xi, (uint32_t)c.yi, (uint32_t)c.zi)];
+
+ if (cell.marked)
+ {
+ continue;
+ }
+
+ cell.marked = true;
+ cell.group = newGroup;
+
+ for (uint32_t i = 0; i < 6; i++)
+ {
+ GenCoord ci = c;
+ ci.xi = c.xi + n[i][0];
+ ci.yi = c.yi + n[i][1];
+ ci.zi = c.zi + n[i][2];
+ if (ci.xi < 0 || ci.xi >= SUB_GRID_LEN ||
+ ci.yi < 0 || ci.yi >= SUB_GRID_LEN ||
+ ci.zi < 0 || ci.zi >= SUB_GRID_LEN)
+ {
+ continue;
+ }
+
+ GenSubCell& celli = mSubGrid[cellNr((uint32_t)ci.xi, (uint32_t)ci.yi, (uint32_t)ci.zi)];
+
+ if (celli.marked || celli.group != oldGroup)
+ {
+ continue;
+ }
+
+ queue.pushBack(ci);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+void ApexGeneralizedCubeTemplates::findVertices()
+{
+ //int i,j,xi,yi,zi;
+
+ for (uint32_t i = 0; i < 8; i++)
+ for (uint32_t j = 0; j < 8; j++)
+ {
+ mFirstPairVertex[i][j] = -1;
+ }
+
+ const int faces[6][4] =
+ {
+ {0, 4, 7, 3},
+ {1, 2, 6, 5},
+ {0, 1, 5, 4},
+ {2, 3, 7, 6},
+ {0, 3, 2, 1},
+ {4, 5, 6, 7},
+ };
+ const int edges[12][6] =
+ {
+ {0, 1, 2, 3, 4, 5},
+ {0, 1, 2, 3, 5, 6},
+ {0, 1, 2, 3, 6, 7},
+ {0, 1, 2, 3, 7, 4},
+ {4, 5, 6, 7, 0, 1},
+ {4, 5, 6, 7, 1, 2},
+ {4, 5, 6, 7, 2, 3},
+ {4, 5, 6, 7, 3, 0},
+ {0, 1, 4, 5, 3, 7},
+ {0, 1, 4, 5, 2, 6},
+ {3, 2, 7, 6, 1, 5},
+ {3, 2, 7, 6, 0, 4},
+ };
+
+ for (int32_t xi = 0; xi <= SUB_GRID_LEN; xi++)
+ {
+ for (int32_t yi = 0; yi <= SUB_GRID_LEN; yi++)
+ {
+ for (int32_t zi = 0; zi <= SUB_GRID_LEN; zi++)
+ {
+ int32_t groups[8];
+ groups[0] = groupAt(xi - 1, yi - 1, zi - 1);
+ groups[1] = groupAt(xi , yi - 1, zi - 1);
+ groups[2] = groupAt(xi , yi , zi - 1);
+ groups[3] = groupAt(xi - 1, yi, zi - 1);
+ groups[4] = groupAt(xi - 1, yi - 1, zi);
+ groups[5] = groupAt(xi , yi - 1, zi);
+ groups[6] = groupAt(xi , yi, zi);
+ groups[7] = groupAt(xi - 1, yi, zi);
+
+ // edges test
+ uint32_t numEdges = 0;
+ for (uint32_t i = 0; i < 6; i++)
+ {
+ int32_t g0 = groups[faces[i][0]];
+ int32_t g1 = groups[faces[i][1]];
+ int32_t g2 = groups[faces[i][2]];
+ int32_t g3 = groups[faces[i][3]];
+ uint32_t flips = 0;
+ if (g0 != g1)
+ {
+ flips++;
+ }
+ if (g1 != g2)
+ {
+ flips++;
+ }
+ if (g2 != g3)
+ {
+ flips++;
+ }
+ if (g3 != g0)
+ {
+ flips++;
+ }
+ if (flips > 2)
+ {
+ numEdges++;
+ }
+ }
+
+ int32_t vertexNr = -1;
+
+ // edge vertex?
+ if (numEdges > 1)
+ {
+ for (uint32_t i = 0; i < 12; i++)
+ {
+ if (groups[edges[i][0]] < 0 &&
+ groups[edges[i][1]] < 0 &&
+ groups[edges[i][2]] < 0 &&
+ groups[edges[i][3]] < 0 &&
+ groups[edges[i][4]] < 0 &&
+ groups[edges[i][5]] < 0)
+ {
+ vertexNr = (int32_t)i;
+ }
+ }
+ }
+
+ // face vertex?
+ if (vertexNr < 0 && numEdges > 2)
+ {
+ for (uint32_t i = 0; i < 6; i++)
+ {
+ if (groups[faces[i][0]] < 0 &&
+ groups[faces[i][1]] < 0 &&
+ groups[faces[i][2]] < 0 &&
+ groups[faces[i][3]] < 0)
+ {
+ vertexNr = (int32_t)i + 12;
+ }
+ }
+ }
+
+ // inner vertex
+ if (vertexNr < 0 && numEdges > 2)
+ {
+ vertexNr = 18;
+ }
+
+ mVertexAt[xi][yi][zi] = vertexNr;
+
+ if (vertexNr < 0)
+ {
+ continue;
+ }
+
+ for (uint32_t i = 0; i < 8; i++)
+ {
+ if (groups[i] < 0)
+ {
+ continue;
+ }
+
+ for (uint32_t j = 0; j < 8; j++)
+ {
+ if (groups[j] < 0)
+ {
+ continue;
+ }
+
+ if (vertexNr > mFirstPairVertex[groups[i]][groups[j]])
+ {
+ mFirstPairVertex[groups[i]][groups[j]] = vertexNr;
+ mFirstPairCoord[groups[i]][groups[j]].init(xi, yi, zi);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+void ApexGeneralizedCubeTemplates::createTriangles(physx::Array<int32_t>& currentIndices)
+{
+ physx::Array<int32_t> verts;
+ physx::Array<GenCoord> queue;
+
+ currentIndices.clear();
+
+ for (int32_t group0 = 0; group0 < 8; group0++)
+ {
+ for (int32_t group1 = group0 + 1; group1 < 8; group1++)
+ {
+ int32_t first = mFirstPairVertex[group0][group1];
+
+ if (first < 0)
+ {
+ continue;
+ }
+
+ // walk around the edge of the surface between group 0 and group 1
+ verts.clear();
+
+ GenCoord c;
+ for (c.xi = 0; c.xi <= SUB_GRID_LEN; c.xi++)
+ for (c.yi = 0; c.yi <= SUB_GRID_LEN; c.yi++)
+ for (c.zi = 0; c.zi <= SUB_GRID_LEN; c.zi++)
+ {
+ mVertexMarked[c.xi][c.yi][c.zi] = false;
+ }
+
+ c = mFirstPairCoord[group0][group1];
+ queue.pushBack(c);
+ while (!queue.empty())
+ {
+ c = queue[queue.size() - 1];
+ queue.popBack();
+
+ if (vertexMarked(c))
+ {
+ continue;
+ }
+
+ markVertex(c);
+
+ int vert = mVertexAt[c.xi][c.yi][c.zi];
+ if (vert >= 0)
+ {
+ if (verts.size() == 1)
+ {
+ queue.clear(); // otherwise the search goes both ways around the border
+ }
+ if (verts.empty() || verts[verts.size() - 1] != vert)
+ {
+ verts.pushBack(vert);
+ }
+ }
+
+ GenCoord next;
+ next = c;
+ next.xi--;
+ if (!vertexMarked(next) && isEdge(next, 0, group0, group1))
+ {
+ queue.pushBack(next);
+ }
+ next = c;
+ next.yi--;
+ if (!vertexMarked(next) && isEdge(next, 1, group0, group1))
+ {
+ queue.pushBack(next);
+ }
+ next = c;
+ next.zi--;
+ if (!vertexMarked(next) && isEdge(next, 2, group0, group1))
+ {
+ queue.pushBack(next);
+ }
+ next = c;
+ next.xi++;
+ if (!vertexMarked(next) && isEdge(c, 0, group0, group1))
+ {
+ queue.pushBack(next);
+ }
+ next = c;
+ next.yi++;
+ if (!vertexMarked(next) && isEdge(c, 1, group0, group1))
+ {
+ queue.pushBack(next);
+ }
+ next = c;
+ next.zi++;
+ if (!vertexMarked(next) && isEdge(c, 2, group0, group1))
+ {
+ queue.pushBack(next);
+ }
+ }
+
+ if (verts.size() < 3)
+ {
+ continue;
+ }
+
+ // create triangle fan
+ if (verts[0] == verts[verts.size() - 1])
+ {
+ verts.popBack();
+ }
+
+ for (uint32_t i = 1; i + 1 < verts.size(); i++)
+ {
+ // PH: Attemt to fix: This is a double fan where the initial value also appears somewhere in the middle
+ if (verts[0] == verts[i] || verts[0] == verts[i + 1])
+ {
+ continue;
+ }
+
+ PX_ASSERT(verts[0] != verts[i]);
+ PX_ASSERT(verts[0] != verts[i + 1]);
+ PX_ASSERT(verts[i] != verts[i + 1]);
+ currentIndices.pushBack(verts[0]);
+ currentIndices.pushBack(verts[i]);
+ currentIndices.pushBack(verts[i + 1]);
+ }
+ }
+ }
+}
+
+
+
+bool ApexGeneralizedCubeTemplates::isEdge(const GenCoord& c, int32_t dim, int32_t group0, int32_t group1)
+{
+ if (dim < 0 || dim >= 3)
+ {
+ return false;
+ }
+
+ int g0, g1, g2, g3;
+ if (dim == 0)
+ {
+ g0 = groupAt(c.xi, c.yi, c.zi);
+ g1 = groupAt(c.xi, c.yi - 1, c.zi);
+ g2 = groupAt(c.xi, c.yi - 1, c.zi - 1);
+ g3 = groupAt(c.xi, c.yi, c.zi - 1);
+ }
+ else if (dim == 1)
+ {
+ g0 = groupAt(c.xi, c.yi, c.zi);
+ g1 = groupAt(c.xi, c.yi, c.zi - 1);
+ g2 = groupAt(c.xi - 1, c.yi, c.zi - 1);
+ g3 = groupAt(c.xi - 1, c.yi, c.zi);
+ }
+ else
+ {
+ g0 = groupAt(c.xi, c.yi, c.zi);
+ g1 = groupAt(c.xi - 1, c.yi, c.zi);
+ g2 = groupAt(c.xi - 1, c.yi - 1, c.zi);
+ g3 = groupAt(c.xi, c.yi - 1, c.zi);
+ }
+
+ uint32_t flips = 0;
+ if (g0 != g1)
+ {
+ flips++;
+ }
+ if (g1 != g2)
+ {
+ flips++;
+ }
+ if (g2 != g3)
+ {
+ flips++;
+ }
+ if (g3 != g0)
+ {
+ flips++;
+ }
+
+ if (flips <= 2)
+ {
+ return false;
+ }
+
+ if (group0 < 0 || group1 < 0)
+ {
+ return true;
+ }
+
+ if (g0 == group0 && g1 == group1)
+ {
+ return true;
+ }
+ if (g1 == group0 && g2 == group1)
+ {
+ return true;
+ }
+ if (g2 == group0 && g3 == group1)
+ {
+ return true;
+ }
+ if (g3 == group0 && g0 == group1)
+ {
+ return true;
+ }
+
+ if (g0 == group1 && g1 == group0)
+ {
+ return true;
+ }
+ if (g1 == group1 && g2 == group0)
+ {
+ return true;
+ }
+ if (g2 == group1 && g3 == group0)
+ {
+ return true;
+ }
+ if (g3 == group1 && g0 == group0)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+}
+} // end namespace nvidia::apex
+
diff --git a/APEX_1.4/common/src/ApexGeneralizedMarchingCubes.cpp b/APEX_1.4/common/src/ApexGeneralizedMarchingCubes.cpp
new file mode 100644
index 00000000..b2f8b1e3
--- /dev/null
+++ b/APEX_1.4/common/src/ApexGeneralizedMarchingCubes.cpp
@@ -0,0 +1,1222 @@
+/*
+ * 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 "ApexGeneralizedMarchingCubes.h"
+
+#include "ApexGeneralizedCubeTemplates.h"
+
+#include "PxMath.h"
+
+#include "ApexSharedUtils.h"
+
+#include "PsSort.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+struct TriangleEdge
+{
+ void init(int32_t v0, int32_t v1, int32_t edgeNr, int32_t triNr)
+ {
+ this->v0 = PxMin(v0, v1);
+ this->v1 = PxMax(v0, v1);
+ this->edgeNr = edgeNr;
+ this->triNr = triNr;
+ }
+ bool operator == (const TriangleEdge& e) const
+ {
+ if (v0 == e.v0 && v1 == e.v1)
+ {
+ return true;
+ }
+ if (v0 == e.v1 && v1 == e.v0)
+ {
+ return true;
+ }
+ return false;
+ }
+ bool operator()(const TriangleEdge& a, const TriangleEdge& 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.triNr < b.triNr;
+ }
+ int32_t v0, v1;
+ int32_t edgeNr;
+ int32_t triNr;
+};
+
+
+
+struct BorderEdge
+{
+ void set(int vertNr, int prev = -1, int depth = 0)
+ {
+ this->vertNr = vertNr;
+ this->prev = prev;
+ this->depth = depth;
+ }
+ int32_t vertNr;
+ int32_t prev;
+ int32_t depth;
+};
+
+
+
+
+ApexGeneralizedMarchingCubes::ApexGeneralizedMarchingCubes(const PxBounds3& bound, uint32_t subdivision) :
+ mTemplates(NULL)
+{
+ mCubes.clear();
+ mBound = bound;
+ PX_ASSERT(subdivision > 0);
+ mSpacing = (bound.maximum - bound.minimum).magnitude() / (float)subdivision;
+ mInvSpacing = 1.0f / mSpacing;
+
+ memset(mFirstCube, -1, sizeof(int32_t) * HASH_INDEX_SIZE);
+
+ mVertices.clear();
+ mIndices.clear();
+}
+
+
+ApexGeneralizedMarchingCubes::~ApexGeneralizedMarchingCubes()
+{
+ if (mTemplates != NULL)
+ {
+ delete mTemplates;
+ mTemplates = NULL;
+ }
+}
+
+
+
+
+
+void ApexGeneralizedMarchingCubes::registerTriangle(const PxVec3& p0, const PxVec3& p1, const PxVec3& p2)
+{
+ PxBounds3 bounds;
+ bounds.setEmpty();
+ bounds.include(p0);
+ bounds.include(p1);
+ bounds.include(p2);
+ PX_ASSERT(!bounds.isEmpty());
+ bounds.fattenFast(0.001f * mSpacing);
+ PxVec3 n, vertPos, q0, q1, qt;
+ n = (p1 - p0).cross(p2 - p0);
+ float d = n.dot(p0);
+
+ int32_t min[3] = { (int32_t)PxFloor(bounds.minimum.x* mInvSpacing), (int32_t)PxFloor(bounds.minimum.y* mInvSpacing), (int32_t)PxFloor(bounds.minimum.z* mInvSpacing) };
+ int32_t max[3] = { (int32_t)PxFloor(bounds.maximum.x* mInvSpacing) + 1, (int32_t)PxFloor(bounds.maximum.y* mInvSpacing) + 1, (int32_t)PxFloor(bounds.maximum.z* mInvSpacing) + 1 };
+
+ int32_t coord[3];
+
+ for (uint32_t dim0 = 0; dim0 < 3; dim0++)
+ {
+ if (n[dim0] == 0.0f)
+ {
+ continue; // singular case
+ }
+
+ const uint32_t dim1 = (dim0 + 1) % 3;
+ const uint32_t dim2 = (dim1 + 1) % 3;
+
+ for (coord[dim1] = min[dim1]; coord[dim1] <= max[dim1]; coord[dim1]++)
+ {
+ for (coord[dim2] = min[dim2]; coord[dim2] <= max[dim2]; coord[dim2]++)
+ {
+ //const float axis0 = coord[dim0] * mSpacing;
+ const float axis1 = coord[dim1] * mSpacing;
+ const float axis2 = coord[dim2] * mSpacing;
+
+ // does the ray go through the triangle?
+ bool intersection = true;
+ if (n[dim0] > 0.0f)
+ {
+ if ((p1[dim1] - p0[dim1]) * (axis2 - p0[dim2]) - (axis1 - p0[dim1]) * (p1[dim2] - p0[dim2]) < 0.0f)
+ {
+ intersection = false;
+ }
+ if ((p2[dim1] - p1[dim1]) * (axis2 - p1[dim2]) - (axis1 - p1[dim1]) * (p2[dim2] - p1[dim2]) < 0.0f)
+ {
+ intersection = false;
+ }
+ if ((p0[dim1] - p2[dim1]) * (axis2 - p2[dim2]) - (axis1 - p2[dim1]) * (p0[dim2] - p2[dim2]) < 0.0f)
+ {
+ intersection = false;
+ }
+ }
+ else
+ {
+ if ((p1[dim1] - p0[dim1]) * (axis2 - p0[dim2]) - (axis1 - p0[dim1]) * (p1[dim2] - p0[dim2]) > 0.0f)
+ {
+ intersection = false;
+ }
+ if ((p2[dim1] - p1[dim1]) * (axis2 - p1[dim2]) - (axis1 - p1[dim1]) * (p2[dim2] - p1[dim2]) > 0.0f)
+ {
+ intersection = false;
+ }
+ if ((p0[dim1] - p2[dim1]) * (axis2 - p2[dim2]) - (axis1 - p2[dim1]) * (p0[dim2] - p2[dim2]) > 0.0f)
+ {
+ intersection = false;
+ }
+ }
+
+ if (intersection)
+ {
+ const float pos = (d - axis1 * n[dim1] - axis2 * n[dim2]) / n[dim0];
+ coord[dim0] = (int32_t)PxFloor(pos * mInvSpacing);
+
+ uint32_t nr = (uint32_t)createCube(coord[0], coord[1], coord[2]);
+ GeneralizedCube& cube = mCubes[nr];
+
+ if (cube.vertRefs[dim0].vertNr < 0)
+ {
+ vertPos = PxVec3(coord[0] * mSpacing, coord[1] * mSpacing, coord[2] * mSpacing);
+ vertPos[dim0] = pos;
+ cube.vertRefs[dim0].vertNr = (int32_t)mVertices.size();
+ mVertices.pushBack(vertPos);
+ }
+ }
+ }
+ }
+ }
+
+ // does a triangle edge cut a cube face?
+ PxBounds3 cellBounds;
+ for (int32_t xi = min[0]; xi <= max[0]; xi++)
+ {
+ for (int32_t yi = min[1]; yi <= max[1]; yi++)
+ {
+ for (int32_t zi = min[2]; zi <= max[2]; zi++)
+ {
+ cellBounds.minimum = PxVec3(xi * mSpacing, yi * mSpacing, zi * mSpacing);
+ cellBounds.maximum = PxVec3((xi + 1) * mSpacing, (yi + 1) * mSpacing, (zi + 1) * mSpacing);
+
+ for (uint32_t i = 0; i < 3; i++)
+ {
+ switch (i)
+ {
+ case 0 :
+ q0 = p0;
+ q1 = p1;
+ break;
+ case 1 :
+ q0 = p1;
+ q1 = p2;
+ break;
+ case 2 :
+ q0 = p2;
+ q1 = p0;
+ break;
+ default: // Make compiler happy
+ q0 = q1 = PxVec3(0.0f);
+ break;
+ }
+
+ if (q0.x != q1.x)
+ {
+ const float t = (cellBounds.minimum.x - q0.x) / (q1.x - q0.x);
+ if (0.0f <= t && t <= 1.0f)
+ {
+ qt = q0 + (q1 - q0) * t;
+ if (cellBounds.minimum.y <= qt.y && qt.y <= cellBounds.maximum.y && cellBounds.minimum.z <= qt.z && qt.z <= cellBounds.maximum.z)
+ {
+ GeneralizedCube& cube = mCubes[(uint32_t)createCube(xi, yi, zi)];
+ cube.sideBounds[0].include(qt);
+ }
+ }
+ }
+ if (q0.y != q1.y)
+ {
+ const float t = (cellBounds.minimum.y - q0.y) / (q1.y - q0.y);
+ if (0.0f <= t && t <= 1.0f)
+ {
+ qt = q0 + (q1 - q0) * t;
+ if (cellBounds.minimum.z <= qt.z && qt.z <= cellBounds.maximum.z && cellBounds.minimum.x <= qt.x && qt.x <= cellBounds.maximum.x)
+ {
+ GeneralizedCube& cube = mCubes[(uint32_t)createCube(xi, yi, zi)];
+ cube.sideBounds[1].include(qt);
+ }
+ }
+ }
+ if (q0.z != q1.z)
+ {
+ const float t = (cellBounds.minimum.z - q0.z) / (q1.z - q0.z);
+ if (0.0f <= t && t <= 1.0f)
+ {
+ qt = q0 + (q1 - q0) * t;
+ if (cellBounds.minimum.x <= qt.x && qt.x <= cellBounds.maximum.x && cellBounds.minimum.y <= qt.y && qt.y <= cellBounds.maximum.y)
+ {
+ GeneralizedCube& cube = mCubes[(uint32_t)createCube(xi, yi, zi)];
+ cube.sideBounds[2].include(qt);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+bool ApexGeneralizedMarchingCubes::endRegistration(uint32_t bubleSizeToRemove, IProgressListener* progressListener)
+{
+ HierarchicalProgressListener progress(100, progressListener);
+
+ progress.setSubtaskWork(20, "Complete Cells");
+ completeCells();
+ progress.completeSubtask();
+
+ progress.setSubtaskWork(20, "Create Triangles");
+ for (int i = 0; i < (int)mCubes.size(); i++)
+ {
+ createTrianglesForCube(i);
+ }
+ progress.completeSubtask();
+
+ progress.setSubtaskWork(20, "Create Neighbor Info");
+ createNeighbourInfo();
+ progress.completeSubtask();
+
+ uint32_t numTris = mIndices.size() / 3;
+
+ mTriangleDeleted.resize(numTris);
+ for (uint32_t i = 0; i < numTris; i++)
+ {
+ mTriangleDeleted[i] = 0;
+ }
+
+ if (bubleSizeToRemove > 0)
+ {
+ progress.setSubtaskWork(10, "Remove Bubbles");
+ determineGroups();
+ removeBubbles((int32_t)bubleSizeToRemove);
+ progress.completeSubtask();
+ }
+ progress.setSubtaskWork(20, "Fix Orientation");
+ determineGroups();
+ fixOrientations();
+ progress.completeSubtask();
+
+ progress.setSubtaskWork(-1, "Compress");
+ compress();
+ progress.completeSubtask();
+
+ return true;
+}
+
+
+int32_t ApexGeneralizedMarchingCubes::createCube(int32_t xi, int32_t yi, int32_t zi)
+{
+ int32_t nr = findCube(xi, yi, zi);
+ if (nr >= 0)
+ {
+ return nr;
+ }
+
+ GeneralizedCube newCube;
+ newCube.init(xi, yi, zi);
+ int32_t h = hashFunction(xi, yi, zi);
+ newCube.next = mFirstCube[h];
+ mFirstCube[h] = (int32_t)mCubes.size();
+ nr = (int32_t)mCubes.size();
+ mCubes.pushBack(newCube);
+ return nr;
+}
+
+
+
+int32_t ApexGeneralizedMarchingCubes::findCube(int32_t xi, int32_t yi, int32_t zi)
+{
+ int32_t h = hashFunction(xi, yi, zi);
+ int32_t i = mFirstCube[h];
+
+ while (i >= 0)
+ {
+ GeneralizedCube& c = mCubes[(uint32_t)i];
+ if (!c.deleted && c.xi == xi && c.yi == yi && c.zi == zi)
+ {
+ return i;
+ }
+ i = mCubes[(uint32_t)i].next;
+ }
+ return -1;
+}
+
+
+
+void ApexGeneralizedMarchingCubes::completeCells()
+{
+ // make sure we have the boarder cells as well
+ uint32_t numCubes = mCubes.size();
+ for (uint32_t i = 0; i < numCubes; i++)
+ {
+ int32_t xi = mCubes[i].xi;
+ int32_t yi = mCubes[i].yi;
+ int32_t zi = mCubes[i].zi;
+ //createCube(xi-1,yi, zi);
+ //createCube(xi, yi-1,zi);
+ //createCube(xi, yi, zi-1);
+
+ createCube(xi - 1, yi, zi);
+ createCube(xi - 1, yi - 1, zi);
+ createCube(xi, yi - 1, zi);
+ createCube(xi, yi, zi - 1);
+ createCube(xi - 1, yi, zi - 1);
+ createCube(xi - 1, yi - 1, zi - 1);
+ createCube(xi, yi - 1, zi - 1);
+ }
+}
+
+
+
+void ApexGeneralizedMarchingCubes::createTrianglesForCube(int32_t cellNr)
+{
+ const int sideEdges[6][4] =
+ {
+ {3, 7, 8, 11}, {1, 5, 9, 10}, {0, 4, 8, 9}, {2, 6, 10, 11}, {0, 1, 2, 3}, {4, 5, 6, 7}
+ };
+ const int adjVerts[12][8] =
+ {
+ {16, 1, 2, 3, 14, 4, 8, 9}, {16, 0, 2, 3, 13, 5, 9, 10}, {16, 0, 1, 3, 15, 6, 10, 11}, {16, 0, 1, 2, 12, 7, 8, 11},
+ {17, 5, 6, 7, 14, 0, 8, 9}, {17, 4, 6, 7, 13, 1, 9, 10}, {17, 4, 5, 7, 15, 2, 10, 11}, {17, 4, 5, 6, 12, 3, 8, 11},
+ {12, 3, 7, 11, 14, 0, 4, 9}, {14, 0, 4, 8, 13, 1, 5, 10}, {13, 1, 5, 9, 15, 2, 6, 11}, {15, 2, 6, 10, 12, 3, 7, 8}
+ };
+
+ int32_t groups[8];
+ int32_t vertNrs[19];
+
+ memset(vertNrs, -1, sizeof(int32_t) * 19);
+
+ // get edge vertices
+ GeneralizedVertRef* vertRefs[12];
+ getCubeEdgesAndGroups(cellNr, vertRefs, groups);
+
+ uint32_t numCuts = 0;
+ for (uint32_t i = 0; i < 12; i++)
+ {
+ if (vertRefs[i] != NULL)
+ {
+ vertNrs[i] = vertRefs[i]->vertNr;
+ if (vertNrs[i] >= 0)
+ {
+ numCuts++;
+ }
+ }
+ }
+
+ if (numCuts == 0)
+ {
+ return;
+ }
+
+ GeneralizedCube& c = mCubes[(uint32_t)cellNr];
+
+ int startFace = -1, endFace = -1;
+
+ PX_UNUSED(endFace); // Make compiler happy
+
+ // create side vertices if necessary
+ for (uint32_t i = 0; i < 6; i++)
+ {
+ uint32_t faceNr = 12 + i;
+ int32_t* faceVertNr = NULL;
+ PxBounds3* b = NULL;
+ switch (faceNr)
+ {
+ case 12:
+ faceVertNr = &c.sideVertexNr[0];
+ b = &c.sideBounds[0];
+ break;
+ case 13:
+ {
+ int32_t nr = findCube(c.xi + 1, c.yi, c.zi);
+ if (nr >= 0)
+ {
+ faceVertNr = &mCubes[(uint32_t)nr].sideVertexNr[0];
+ b = &mCubes[(uint32_t)nr].sideBounds[0];
+ }
+ }
+ break;
+ case 14:
+ faceVertNr = &c.sideVertexNr[1];
+ b = &c.sideBounds[1];
+ break;
+ case 15:
+ {
+ int32_t nr = findCube(c.xi, c.yi + 1, c.zi);
+ if (nr >= 0)
+ {
+ faceVertNr = &mCubes[(uint32_t)nr].sideVertexNr[1];
+ b = &mCubes[(uint32_t)nr].sideBounds[1];
+ }
+ }
+ break;
+ case 16:
+ faceVertNr = &c.sideVertexNr[2];
+ b = &c.sideBounds[2];
+ break;
+ case 17:
+ {
+ int32_t nr = findCube(c.xi, c.yi, c.zi + 1);
+ if (nr >= 0)
+ {
+ faceVertNr = &mCubes[(uint32_t)nr].sideVertexNr[2];
+ b = &mCubes[(uint32_t)nr].sideBounds[2];
+ }
+ }
+ break;
+ }
+
+ PxVec3 pos(0.0f, 0.0f, 0.0f);
+ uint32_t num = 0;
+
+ for (uint32_t j = 0; j < 4; j++)
+ {
+ int32_t edgeVertNr = vertNrs[sideEdges[i][j]];
+ if (edgeVertNr < 0)
+ {
+ continue;
+ }
+
+ pos += mVertices[(uint32_t)edgeVertNr];
+ num++;
+ }
+
+ if (num == 0 || num == 2)
+ {
+ continue;
+ }
+
+ pos = pos / (float)num;
+
+ if (num == 1)
+ {
+ if (startFace < 0)
+ {
+ startFace = (int32_t)faceNr;
+ }
+ else
+ {
+ endFace = (int32_t)faceNr;
+ }
+
+ if (!(b->isEmpty()))
+ {
+ if (PxAbs(pos.x - b->minimum.x) > PxAbs(pos.x - b->maximum.x))
+ {
+ pos.x = b->minimum.x;
+ }
+ else
+ {
+ pos.x = b->maximum.x;
+ }
+ if (PxAbs(pos.y - b->minimum.y) > PxAbs(pos.y - b->maximum.y))
+ {
+ pos.y = b->minimum.y;
+ }
+ else
+ {
+ pos.y = b->maximum.y;
+ }
+ if (PxAbs(pos.z - b->minimum.z) > PxAbs(pos.z - b->maximum.z))
+ {
+ pos.z = b->minimum.z;
+ }
+ else
+ {
+ pos.z = b->maximum.z;
+ }
+ }
+ else
+ {
+ continue;
+ }
+ }
+
+ if (*faceVertNr < 0)
+ {
+ *faceVertNr = (int32_t)mVertices.size();
+ mVertices.pushBack(pos);
+ }
+ vertNrs[faceNr] = *faceVertNr;
+ }
+
+ int32_t maxGroup = groups[0];
+ for (uint32_t i = 1; i < 8; i++)
+ {
+ if (groups[i] > maxGroup)
+ {
+ maxGroup = groups[i];
+ }
+ }
+
+ // boundary cell
+ physx::Array<BorderEdge> queue;
+ if (startFace >= 0)
+ {
+ BorderEdge edge;
+ queue.clear();
+ if (queue.capacity() < 20)
+ {
+ queue.reserve(20);
+ }
+
+ int32_t prev[19];
+ bool visited[19];
+ for (uint32_t i = 0; i < 19; i++)
+ {
+ prev[i] = -1;
+ visited[i] = false;
+ }
+
+ edge.set(startFace);
+ queue.pushBack(edge);
+
+ int32_t maxVert = -1;
+ int32_t maxDepth = -1;
+
+ while (!queue.empty())
+ {
+ edge = queue[queue.size() - 1];
+ queue.popBack();
+
+ int32_t v = edge.vertNr;
+ if (visited[v])
+ {
+ continue;
+ }
+
+ visited[v] = true;
+ prev[v] = edge.prev;
+ edge.prev = v;
+ edge.depth++;
+
+ if (edge.depth > maxDepth)
+ {
+ maxDepth = edge.depth;
+ maxVert = v;
+ }
+ // if (v == endFace) break;
+
+ if (v < 12)
+ {
+ for (uint32_t i = 0; i < 8; i += 4)
+ {
+ edge.vertNr = adjVerts[v][i];
+ if (vertNrs[edge.vertNr] >= 0)
+ {
+ if (!visited[edge.vertNr])
+ {
+ queue.pushBack(edge);
+ }
+ }
+ else
+ {
+ for (uint32_t j = i + 1; j < i + 4; j++)
+ {
+ edge.vertNr = adjVerts[v][j];
+ if (vertNrs[edge.vertNr] >= 0 && !visited[edge.vertNr])
+ {
+ queue.pushBack(edge);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ for (uint32_t i = 0; i < 4; i++)
+ {
+ edge.vertNr = sideEdges[v - 12][i];
+ if (!visited[edge.vertNr] && vertNrs[edge.vertNr] >= 0)
+ {
+ queue.pushBack(edge);
+ }
+ }
+ }
+ }
+
+ int32_t chain[14];
+ uint32_t chainLen = 0;
+ int32_t v = maxVert;
+
+ if (vertNrs[v] >= 0)
+ {
+ chain[chainLen++] = v;
+ }
+
+ v = prev[v];
+ while (v >= 0)
+ {
+ if (vertNrs[v] >= 0)
+ {
+ chain[chainLen++] = v;
+ }
+ v = prev[v];
+ }
+
+ int32_t numTris = (int32_t)chainLen - 2;
+
+ c.firstTriangle = (int32_t)mIndices.size() / 3;
+ for (int i = 0; i < numTris; i++)
+ {
+ mIndices.pushBack((uint32_t)vertNrs[(uint32_t)chain[0]]);
+ mIndices.pushBack((uint32_t)vertNrs[(uint32_t)chain[i + 1]]);
+ mIndices.pushBack((uint32_t)vertNrs[(uint32_t)chain[i + 2]]);
+ c.numTriangles++;
+ }
+ return;
+ }
+
+ // inner cell
+ if (mTemplates == NULL)
+ {
+ mTemplates = PX_NEW(ApexGeneralizedCubeTemplates)();
+ }
+ mTemplates->getTriangles(groups, mGeneralizedTriangles);
+
+ // create face and inner vertices if necessary
+ for (uint32_t i = 0; i < mGeneralizedTriangles.size(); i++)
+ {
+ int32_t localNr = mGeneralizedTriangles[i];
+
+ if (vertNrs[localNr] < 0)
+ {
+ if (localNr < 12)
+ {
+ return; // impossible to create triangles, border cube
+ }
+
+ if (localNr == 18 && vertNrs[18] < 0)
+ {
+ // center vertex, not shared with other cells
+ vertNrs[18] = (int32_t)mVertices.size();
+ PxVec3 pos(0.0f);
+ float num = 0.0f;
+ for (int j = 0; j < 12; j++)
+ {
+ if (vertNrs[j] >= 0)
+ {
+ pos += mVertices[(uint32_t)vertNrs[j]];
+ num = num + 1.0f;
+ }
+ }
+ mVertices.pushBack(pos / num);
+ }
+ }
+ }
+
+ c.firstTriangle = (int32_t)mIndices.size() / 3;
+ const uint32_t numTris = mGeneralizedTriangles.size() / 3;
+ for (uint32_t i = 0; i < numTris; i++)
+ {
+ PX_ASSERT(vertNrs[mGeneralizedTriangles[3 * i + 0]] != vertNrs[mGeneralizedTriangles[3 * i + 1]]);
+ PX_ASSERT(vertNrs[mGeneralizedTriangles[3 * i + 0]] != vertNrs[mGeneralizedTriangles[3 * i + 2]]);
+ PX_ASSERT(vertNrs[mGeneralizedTriangles[3 * i + 1]] != vertNrs[mGeneralizedTriangles[3 * i + 2]]);
+ mIndices.pushBack((uint32_t)vertNrs[mGeneralizedTriangles[3 * i + 0]]);
+ mIndices.pushBack((uint32_t)vertNrs[mGeneralizedTriangles[3 * i + 1]]);
+ mIndices.pushBack((uint32_t)vertNrs[mGeneralizedTriangles[3 * i + 2]]);
+ c.numTriangles++;
+ }
+}
+
+
+
+void ApexGeneralizedMarchingCubes::createNeighbourInfo()
+{
+ physx::Array<TriangleEdge> edges;
+ edges.reserve(mIndices.size());
+
+ mFirstNeighbour.resize(mIndices.size());
+ for (uint32_t i = 0; i < mFirstNeighbour.size(); i++)
+ {
+ mFirstNeighbour[i] = -1;
+ }
+
+ mNeighbours.clear();
+
+ const uint32_t numTriangles = mIndices.size() / 3;
+ for (uint32_t i = 0; i < numTriangles; i++)
+ {
+ TriangleEdge edge;
+ int32_t i0 = (int32_t)mIndices[3 * i];
+ int32_t i1 = (int32_t)mIndices[3 * i + 1];
+ int32_t i2 = (int32_t)mIndices[3 * i + 2];
+ PX_ASSERT(i0 != i1);
+ PX_ASSERT(i0 != i2);
+ PX_ASSERT(i1 != i2);
+ edge.init(i0, i1, 0, (int32_t)i);
+ edges.pushBack(edge);
+ edge.init(i1, i2, 1, (int32_t)i);
+ edges.pushBack(edge);
+ edge.init(i2, i0, 2, (int32_t)i);
+ edges.pushBack(edge);
+ }
+ shdfnd::sort(edges.begin(), edges.size(), TriangleEdge());
+
+ uint32_t i = 0;
+ const uint32_t numEdges = edges.size();
+ while (i < numEdges)
+ {
+ const TriangleEdge& e0 = edges[i];
+ const int32_t first = (int32_t)mNeighbours.size();
+ PX_ASSERT(mFirstNeighbour[(uint32_t)(e0.triNr * 3 + e0.edgeNr)] == -1);
+ mFirstNeighbour[(uint32_t)(e0.triNr * 3 + e0.edgeNr)] = first;
+ mNeighbours.pushBack(e0.triNr);
+ i++;
+
+ while (i < numEdges && edges[i] == e0)
+ {
+ const TriangleEdge& e1 = edges[i];
+ PX_ASSERT(mFirstNeighbour[(uint32_t)(e1.triNr * 3 + e1.edgeNr)] == -1);
+ mFirstNeighbour[(uint32_t)(e1.triNr * 3 + e1.edgeNr)] = first;
+ mNeighbours.pushBack(e1.triNr);
+ i++;
+ }
+ mNeighbours.pushBack(-1); // end marker
+ }
+}
+
+
+
+void ApexGeneralizedMarchingCubes::getCubeEdgesAndGroups(int32_t cellNr, GeneralizedVertRef* vertRefs[12], int32_t groups[8])
+{
+ const int32_t adjCorners[8][3] =
+ {
+ {1, 3, 4}, {0, 2, 5}, {1, 3, 6}, {0, 2, 7}, {0, 5, 7}, {1, 4, 6}, {2, 5, 7}, {3, 4, 6}
+ };
+
+ const int32_t adjEdges[8][3] =
+ {
+ {0, 3, 8}, {0, 1, 9}, {1, 2, 10}, {3, 2, 11}, {8, 4, 7}, {9, 4, 5}, {10, 5, 6}, {11, 7, 6}
+ };
+
+ // collect edge vertices
+ GeneralizedCube& c = mCubes[(uint32_t)cellNr];
+ for (uint32_t i = 0; i < 12; i++)
+ {
+ vertRefs[i] = NULL;
+ }
+
+ vertRefs[0] = &c.vertRefs[0];
+ vertRefs[3] = &c.vertRefs[1];
+ vertRefs[8] = &c.vertRefs[2];
+
+ int32_t nr = findCube(c.xi + 1, c.yi, c.zi);
+ if (nr >= 0)
+ {
+ vertRefs[1] = &mCubes[(uint32_t)nr].vertRefs[1];
+ vertRefs[9] = &mCubes[(uint32_t)nr].vertRefs[2];
+ }
+ nr = findCube(c.xi, c.yi + 1, c.zi);
+ if (nr >= 0)
+ {
+ vertRefs[2] = &mCubes[(uint32_t)nr].vertRefs[0];
+ vertRefs[11] = &mCubes[(uint32_t)nr].vertRefs[2];
+ }
+ nr = findCube(c.xi, c.yi, c.zi + 1);
+ if (nr >= 0)
+ {
+ vertRefs[4] = &mCubes[(uint32_t)nr].vertRefs[0];
+ vertRefs[7] = &mCubes[(uint32_t)nr].vertRefs[1];
+ }
+ nr = findCube(c.xi + 1, c.yi + 1, c.zi);
+ if (nr >= 0)
+ {
+ vertRefs[10] = &mCubes[(uint32_t)nr].vertRefs[2];
+ }
+ nr = findCube(c.xi, c.yi + 1, c.zi + 1);
+ if (nr >= 0)
+ {
+ vertRefs[6] = &mCubes[(uint32_t)nr].vertRefs[0];
+ }
+ nr = findCube(c.xi + 1, c.yi, c.zi + 1);
+ if (nr >= 0)
+ {
+ vertRefs[5] = &mCubes[(uint32_t)nr].vertRefs[1];
+ }
+
+ // assign groups using flood fill on the cube edges
+ for (uint32_t i = 0; i < 8; i++)
+ {
+ groups[i] = -1;
+ }
+
+ int groupNr = -1;
+ for (uint32_t i = 0; i < 8; i++)
+ {
+ if (groups[i] >= 0)
+ {
+ continue;
+ }
+
+ groupNr++;
+ mCubeQueue.clear();
+ mCubeQueue.pushBack((int32_t)i);
+ while (!mCubeQueue.empty())
+ {
+ int32_t cornerNr = mCubeQueue[mCubeQueue.size() - 1];
+ mCubeQueue.popBack();
+
+ if (groups[cornerNr] >= 0)
+ {
+ continue;
+ }
+
+ groups[cornerNr] = groupNr;
+
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ int32_t adjCorner = adjCorners[cornerNr][j];
+ int32_t adjEdge = adjEdges[cornerNr][j];
+ if (vertRefs[adjEdge] != NULL && vertRefs[adjEdge]->vertNr >= 0) // edge blocked by vertex
+ {
+ continue;
+ }
+
+ if (groups[adjCorner] < 0)
+ {
+ mCubeQueue.pushBack(adjCorner);
+ }
+ }
+ }
+ }
+}
+
+
+
+void ApexGeneralizedMarchingCubes::determineGroups()
+{
+ const uint32_t numTris = mIndices.size() / 3;
+
+ mTriangleGroup.resize(numTris);
+ for (uint32_t i = 0; i < numTris; i++)
+ {
+ mTriangleGroup[i] = -1;
+ }
+
+ mGroupFirstTriangle.clear();
+ mGroupTriangles.clear();
+
+ for (uint32_t i = 0; i < numTris; i++)
+ {
+ if (mTriangleDeleted[i])
+ {
+ continue;
+ }
+ if (mTriangleGroup[i] >= 0)
+ {
+ continue;
+ }
+
+ int32_t group = (int32_t)mGroupFirstTriangle.size();
+ mGroupFirstTriangle.pushBack((int32_t)mGroupTriangles.size());
+
+ mCubeQueue.clear();
+ mCubeQueue.pushBack((int32_t)i);
+ while (!mCubeQueue.empty())
+ {
+ const uint32_t t = (uint32_t)mCubeQueue[mCubeQueue.size() - 1];
+ mCubeQueue.popBack();
+
+ if (mTriangleGroup[t] >= 0)
+ {
+ continue;
+ }
+
+ mTriangleGroup[t] = group;
+ mGroupTriangles.pushBack((int32_t)t);
+
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ uint32_t first = (uint32_t)mFirstNeighbour[3 * t + j];
+ uint32_t num = 0;
+ int32_t n = -1;
+ while (mNeighbours[first] >= 0)
+ {
+ if (mNeighbours[first] != (int32_t)t)
+ {
+ n = mNeighbours[first];
+ }
+
+ first++;
+ num++;
+ }
+ if (num == 2 && n >= 0 && mTriangleGroup[(uint32_t)n] < 0)
+ {
+ if (!mTriangleDeleted[(uint32_t)n])
+ {
+ mCubeQueue.pushBack(n);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+void ApexGeneralizedMarchingCubes::removeBubbles(int32_t minGroupSize)
+{
+ const uint32_t numGroups = mGroupFirstTriangle.size();
+ for (uint32_t i = 0; i < numGroups; i++)
+ {
+ int32_t firstTri = mGroupFirstTriangle[i];
+ int32_t lastTri = i < numGroups - 1 ? mGroupFirstTriangle[i + 1] : (int32_t)mGroupTriangles.size();
+
+ if (lastTri - firstTri > minGroupSize)
+ {
+ continue;
+ }
+
+ bool OK = true;
+
+ for (int32_t j = firstTri; j < lastTri; j++)
+ {
+ int32_t t = mGroupTriangles[(uint32_t)j];
+ for (uint32_t k = 0; k < 3; k++)
+ {
+ uint32_t first = (uint32_t)mFirstNeighbour[3 * t + k];
+ uint32_t num = 0;
+ int32_t n = -1;
+ while (mNeighbours[first] >= 0)
+ {
+ if (mNeighbours[first] != t)
+ {
+ n = mNeighbours[first];
+ }
+
+ num++;
+ first++;
+ }
+ if (num == 2 && mTriangleGroup[(uint32_t)n] != (int32_t)i)
+ {
+ OK = false;
+ break;
+ }
+ }
+ if (!OK)
+ {
+ break;
+ }
+ }
+
+
+ if (!OK)
+ {
+ continue;
+ }
+
+ for (int32_t j = firstTri; j < lastTri; j++)
+ {
+ uint32_t t = (uint32_t)mGroupTriangles[(uint32_t)j];
+ // remove neighbor info
+ for (int k = 0; k < 3; k++)
+ {
+ uint32_t first = (uint32_t)mFirstNeighbour[3 * t + k];
+ int32_t pos = -1;
+ while (mNeighbours[first] >= 0)
+ {
+ if (mNeighbours[first] == (int32_t)t)
+ {
+ PX_ASSERT(pos == -1);
+ pos = (int32_t)first;
+ }
+
+ first++;
+ }
+ if (pos >= 0)
+ {
+ mNeighbours[(uint32_t)pos] = mNeighbours[first - 1];
+ mNeighbours[first - 1] = -1;
+ }
+ }
+ // remove triangle
+ mTriangleDeleted[t] = true;
+
+ /*
+ // debugging only
+ mDebugLines.pushBack(mVertices[mIndices[t * 3 + 0]]);
+ mDebugLines.pushBack(mVertices[mIndices[t * 3 + 1]]);
+ mDebugLines.pushBack(mVertices[mIndices[t * 3 + 1]]);
+ mDebugLines.pushBack(mVertices[mIndices[t * 3 + 2]]);
+ mDebugLines.pushBack(mVertices[mIndices[t * 3 + 2]]);
+ mDebugLines.pushBack(mVertices[mIndices[t * 3 + 0]]);
+ */
+ }
+ }
+}
+
+
+
+void ApexGeneralizedMarchingCubes::fixOrientations()
+{
+ if (mIndices.size() == 0)
+ {
+ return;
+ }
+
+ const uint32_t numTris = mIndices.size() / 3;
+
+ physx::Array<uint8_t> marks;
+ marks.resize(numTris);
+
+ // 0 = non visited, 1 = visited, 2 = visited, to be flipped
+ for (uint32_t i = 0; i < numTris; i++)
+ {
+ marks[i] = 0;
+ }
+
+ physx::Array<int32_t> queue;
+ for (uint32_t i = 0; i < numTris; i++)
+ {
+ if (mTriangleDeleted[i])
+ {
+ continue;
+ }
+
+ if (marks[i] != 0)
+ {
+ continue;
+ }
+
+ queue.clear();
+
+ marks[i] = 1;
+ queue.pushBack((int32_t)i);
+ while (!queue.empty())
+ {
+ uint32_t triNr = (uint32_t)queue[queue.size() - 1];
+ queue.popBack();
+
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ uint32_t first = (uint32_t)mFirstNeighbour[3 * triNr + j];
+ uint32_t num = 0;
+ int32_t adjNr = -1;
+
+ while (mNeighbours[first] >= 0)
+ {
+ if (mNeighbours[first] != (int32_t)triNr)
+ {
+ adjNr = mNeighbours[first];
+ }
+
+ first++;
+ num++;
+ }
+
+ if (num != 2)
+ {
+ continue;
+ }
+ if (marks[(uint32_t)adjNr] != 0)
+ {
+ continue;
+ }
+
+ queue.pushBack(adjNr);
+
+ uint32_t i0, i1;
+ if (marks[(uint32_t)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 < numTris; i++)
+ {
+ if (marks[i] == 2)
+ {
+ uint32_t i0 = mIndices[3 * i];
+ mIndices[3 * i] = mIndices[3 * i + 1];
+ mIndices[3 * i + 1] = i0;
+ }
+ }
+}
+
+
+
+void ApexGeneralizedMarchingCubes::compress()
+{
+ PX_ASSERT(mTriangleDeleted.size() * 3 == mIndices.size());
+
+ uint32_t writePos = 0;
+
+ for (uint32_t i = 0; i < mTriangleDeleted.size(); i++)
+ {
+ if (mTriangleDeleted[i] == 1)
+ {
+ continue;
+ }
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ mIndices[3 * writePos + j] = mIndices[3 * i + j];
+ }
+ writePos++;
+ }
+
+ mIndices.resize(3 * writePos);
+
+ mTriangleDeleted.clear();
+ mTriangleDeleted.reset();
+
+ mNeighbours.clear();
+ mNeighbours.reset();
+
+ mFirstNeighbour.clear();
+ mFirstNeighbour.reset();
+}
+
+}
+} // end namespace nvidia::apex
diff --git a/APEX_1.4/common/src/ApexIsoMesh.cpp b/APEX_1.4/common/src/ApexIsoMesh.cpp
new file mode 100644
index 00000000..7700c9e2
--- /dev/null
+++ b/APEX_1.4/common/src/ApexIsoMesh.cpp
@@ -0,0 +1,658 @@
+/*
+ * 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 "ApexIsoMesh.h"
+#include "ApexCollision.h"
+#include "ApexMarchingCubes.h"
+#include "ApexSharedUtils.h"
+
+#include "ApexSDKIntl.h"
+
+#include "PsSort.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+ApexIsoMesh::ApexIsoMesh(uint32_t isoGridSubdivision, uint32_t keepNBiggestMeshes, bool discardInnerMeshes) :
+ mIsoGridSubdivision(isoGridSubdivision),
+ mKeepNBiggestMeshes(keepNBiggestMeshes),
+ mDiscardInnerMeshes(discardInnerMeshes),
+ mCellSize(0.0f),
+ mThickness(0.0f),
+ mOrigin(0.0f, 0.0f, 0.0f),
+ mNumX(0), mNumY(0), mNumZ(0),
+ mIsoValue(0.5f)
+{
+ if (mIsoGridSubdivision == 0)
+ {
+ APEX_INVALID_PARAMETER("isoGridSubdivision must be bigger than 0, setting it to 10");
+ mIsoGridSubdivision = 10;
+ }
+ mBound.setEmpty();
+}
+
+
+
+ApexIsoMesh::~ApexIsoMesh()
+{
+}
+
+
+
+void ApexIsoMesh::setBound(const PxBounds3& bound)
+{
+ mBound = bound;
+ mCellSize = (mBound.maximum - mBound.minimum).magnitude() / mIsoGridSubdivision;
+ if (mCellSize == 0.0f)
+ {
+ mCellSize = 1.0f;
+ }
+ mThickness = mCellSize * 1.5f;
+ PX_ASSERT(!mBound.isEmpty());
+ mBound.fattenFast(2.0f * mThickness);
+
+ mOrigin = mBound.minimum;
+ float invH = 1.0f / mCellSize;
+ mNumX = (int32_t)((mBound.maximum.x - mBound.minimum.x) * invH) + 1;
+ mNumY = (int32_t)((mBound.maximum.y - mBound.minimum.y) * invH) + 1;
+ mNumZ = (int32_t)((mBound.maximum.z - mBound.minimum.z) * invH) + 1;
+}
+
+
+
+void ApexIsoMesh::clear()
+{
+ mCellSize = 0.0f;
+ mThickness = 0.0f;
+ mOrigin = PxVec3(0.0f);
+ mNumX = mNumY = mNumZ = 0;
+ mBound.setEmpty();
+
+ clearTemp();
+
+ mIsoVertices.clear();
+ mIsoTriangles.clear();
+ mIsoEdges.clear();
+}
+
+
+
+void ApexIsoMesh::clearTemp()
+{
+ mGrid.clear();
+ mGrid.reset();
+}
+
+
+
+void ApexIsoMesh::addTriangle(const PxVec3& v0, const PxVec3& v1, const PxVec3& v2)
+{
+ int32_t num = mNumX * mNumY * mNumZ;
+ if (mGrid.size() != (uint32_t) num)
+ {
+ IsoCell cell;
+ cell.init();
+ mGrid.resize((uint32_t)num, cell);
+ }
+
+ PX_ASSERT(mThickness != 0.0f);
+
+ PxBounds3 bounds;
+ bounds.minimum = bounds.maximum = v0;
+ bounds.include(v1);
+ bounds.include(v2);
+ PX_ASSERT(!bounds.isEmpty());
+ bounds.fattenFast(mThickness);
+
+ float h = mCellSize;
+ float invH = 1.0f / h;
+ float invT = 1.0f / mThickness;
+
+ int32_t x0 = PxMax(0, (int32_t)((bounds.minimum.x - mOrigin.x) * invH));
+ int32_t x1 = PxMin(mNumX - 1, (int32_t)((bounds.maximum.x - mOrigin.x) * invH));
+ int32_t y0 = PxMax(0, (int32_t)((bounds.minimum.y - mOrigin.y) * invH));
+ int32_t y1 = PxMin(mNumY - 1, (int32_t)((bounds.maximum.y - mOrigin.y) * invH));
+ int32_t z0 = PxMax(0, (int32_t)((bounds.minimum.z - mOrigin.z) * invH));
+ int32_t z1 = PxMin(mNumZ - 1, (int32_t)((bounds.maximum.z - mOrigin.z) * invH));
+
+ for (int32_t xi = x0; xi <= x1; xi++)
+ {
+ PxVec3 pos;
+ pos.x = mOrigin.x + h * xi;
+ for (int32_t yi = y0; yi <= y1; yi++)
+ {
+ pos.y = mOrigin.y + h * yi;
+ for (int32_t zi = z0; zi <= z1; zi++)
+ {
+ pos.z = mOrigin.z + h * zi;
+ Triangle triangle(v0, v1, v2);
+ float dist = PxSqrt(APEX_pointTriangleSqrDst(triangle, pos));
+ if (dist > mThickness)
+ {
+ continue;
+ }
+
+ IsoCell& cell = cellAt(xi, yi, zi);
+ float density = 1.0f - dist * invT;
+ PX_ASSERT(density >= 0);
+ cell.density = PxMax(cell.density, density); ///< \todo, is this right?
+ }
+ }
+ }
+}
+
+
+
+bool ApexIsoMesh::update(IProgressListener* progressListener)
+{
+ HierarchicalProgressListener progress(100, progressListener);
+ progress.setSubtaskWork(90, "Generating first mesh");
+
+ if (generateMesh(&progress))
+ {
+
+ progress.completeSubtask();
+ progress.setSubtaskWork(5, "Finding Neighbors");
+
+ if (findNeighbors(&progress))
+ {
+
+ if (mKeepNBiggestMeshes > 0 || mDiscardInnerMeshes)
+ {
+ progress.completeSubtask();
+ progress.setSubtaskWork(3, "Removing layers");
+ removeLayers();
+ // removeSide(2);
+ }
+ progress.completeSubtask();
+ progress.setSubtaskWork(2, "Removing Triangles and Vertices");
+
+ removeTrisAndVerts();
+ }
+ }
+ progress.completeSubtask();
+
+ return true;
+}
+
+
+
+void ApexIsoMesh::getTriangle(uint32_t index, uint32_t& v0, uint32_t& v1, uint32_t& v2) const
+{
+ PX_ASSERT(index < mIsoTriangles.size());
+ const IsoTriangle& t = mIsoTriangles[index];
+ v0 = (uint32_t)t.vertexNr[0];
+ v1 = (uint32_t)t.vertexNr[1];
+ v2 = (uint32_t)t.vertexNr[2];
+}
+
+
+
+bool ApexIsoMesh::generateMesh(IProgressListener* progressListener)
+{
+ mIsoVertices.clear();
+
+ int xi, yi, zi;
+ float h = mCellSize;
+ PxVec3 pos, vPos;
+
+ uint32_t maximum = (uint32_t)(mNumX * mNumY * mNumZ);
+ uint32_t progressCounter = 0;
+
+ HierarchicalProgressListener progress(100, progressListener);
+ progress.setSubtaskWork(80, "Generating Vertices");
+
+ // generate vertices
+ for (xi = 0; xi < mNumX; xi++)
+ {
+ pos.x = mOrigin.x + h * xi;
+ for (yi = 0; yi < mNumY; yi++)
+ {
+ pos.y = mOrigin.y + h * yi;
+ for (zi = 0; zi < mNumZ; zi++)
+ {
+
+ if ((progressCounter++ & 0xff) == 0)
+ {
+ const int32_t curr = ((xi * mNumY) + yi) * mNumZ + zi;
+ const int32_t percent = 100 * curr / (int32_t)maximum;
+ progress.setProgress(percent);
+ }
+
+ pos.z = mOrigin.z + h * zi;
+ IsoCell& cell = cellAt(xi, yi, zi);
+ float d = cell.density;
+ if (xi < mNumX - 1)
+ {
+ float dx = cellAt(xi + 1, yi, zi).density;
+ if (interpolate(d, dx, pos, pos + PxVec3(h, 0.0f, 0.0f), vPos))
+ {
+ cell.vertNrX = (int32_t)mIsoVertices.size();
+ mIsoVertices.pushBack(vPos);
+ }
+ }
+ if (yi < mNumY - 1)
+ {
+ float dy = cellAt(xi, yi + 1, zi).density;
+ if (interpolate(d, dy, pos, pos + PxVec3(0.0f, h, 0.0f), vPos))
+ {
+ cell.vertNrY = (int32_t)mIsoVertices.size();
+ mIsoVertices.pushBack(vPos);
+ }
+ }
+ if (zi < mNumZ - 1)
+ {
+ float dz = cellAt(xi, yi, zi + 1).density;
+ if (interpolate(d, dz, pos, pos + PxVec3(0.0f, 0.0f, h), vPos))
+ {
+ cell.vertNrZ = (int32_t)mIsoVertices.size();
+ mIsoVertices.pushBack(vPos);
+ }
+ }
+ }
+ }
+ }
+
+ progress.completeSubtask();
+ progress.setSubtaskWork(20, "Generating Faces");
+ progressCounter = 0;
+
+ mIsoTriangles.clear();
+ // generate triangles
+ int edges[12];
+ IsoTriangle triangle;
+
+ for (xi = 0; xi < mNumX - 1; xi++)
+ {
+ pos.x = mOrigin.x + h * xi;
+ for (yi = 0; yi < mNumY - 1; yi++)
+ {
+ pos.y = mOrigin.y + h * yi;
+ for (zi = 0; zi < mNumZ - 1; zi++)
+ {
+
+ if ((progressCounter++ & 0xff) == 0)
+ {
+ const int32_t curr = ((xi * mNumY) + yi) * mNumZ + zi;
+ const int32_t percent = 100 * curr / (int32_t)maximum;
+ progress.setProgress(percent);
+ }
+ pos.z = mOrigin.z + h * zi;
+ int code = 0;
+ if (cellAt(xi, yi, zi).density > mIsoValue)
+ {
+ code |= 1;
+ }
+ if (cellAt(xi + 1, yi, zi).density > mIsoValue)
+ {
+ code |= 2;
+ }
+ if (cellAt(xi + 1, yi + 1, zi).density > mIsoValue)
+ {
+ code |= 4;
+ }
+ if (cellAt(xi, yi + 1, zi).density > mIsoValue)
+ {
+ code |= 8;
+ }
+ if (cellAt(xi, yi, zi + 1).density > mIsoValue)
+ {
+ code |= 16;
+ }
+ if (cellAt(xi + 1, yi, zi + 1).density > mIsoValue)
+ {
+ code |= 32;
+ }
+ if (cellAt(xi + 1, yi + 1, zi + 1).density > mIsoValue)
+ {
+ code |= 64;
+ }
+ if (cellAt(xi, yi + 1, zi + 1).density > mIsoValue)
+ {
+ code |= 128;
+ }
+ if (code == 0 || code == 255)
+ {
+ continue;
+ }
+
+ edges[ 0] = cellAt(xi, yi, zi).vertNrX;
+ edges[ 1] = cellAt(xi + 1, yi, zi).vertNrY;
+ edges[ 2] = cellAt(xi, yi + 1, zi).vertNrX;
+ edges[ 3] = cellAt(xi, yi, zi).vertNrY;
+
+ edges[ 4] = cellAt(xi, yi, zi + 1).vertNrX;
+ edges[ 5] = cellAt(xi + 1, yi, zi + 1).vertNrY;
+ edges[ 6] = cellAt(xi, yi + 1, zi + 1).vertNrX;
+ edges[ 7] = cellAt(xi, yi, zi + 1).vertNrY;
+
+ edges[ 8] = cellAt(xi, yi, zi).vertNrZ;
+ edges[ 9] = cellAt(xi + 1, yi, zi).vertNrZ;
+ edges[10] = cellAt(xi + 1, yi + 1, zi).vertNrZ;
+ edges[11] = cellAt(xi, yi + 1, zi).vertNrZ;
+
+ IsoCell& c = cellAt(xi, yi, zi);
+ c.firstTriangle = (int32_t)mIsoTriangles.size();
+
+ const int* v = MarchingCubes::triTable[code];
+ while (*v >= 0)
+ {
+ int v0 = edges[*v++];
+ PX_ASSERT(v0 >= 0);
+ int v1 = edges[*v++];
+ PX_ASSERT(v1 >= 0);
+ int v2 = edges[*v++];
+ PX_ASSERT(v2 >= 0);
+ triangle.set(v0, v1, v2, xi, yi, zi);
+ mIsoTriangles.pushBack(triangle);
+ c.numTriangles++;
+ }
+ }
+ }
+ }
+ progress.completeSubtask();
+
+ return true;
+}
+
+
+
+bool ApexIsoMesh::interpolate(float d0, float d1, const PxVec3& pos0, const PxVec3& pos1, PxVec3& pos)
+{
+ if ((d0 < mIsoValue && d1 < mIsoValue) || (d0 > mIsoValue && d1 > mIsoValue))
+ {
+ return false;
+ }
+
+ float s = (mIsoValue - d0) / (d1 - d0);
+ s = PxClamp(s, 0.01f, 0.99f); // safety not to produce vertices at the same location
+ pos = pos0 * (1.0f - s) + pos1 * s;
+ return true;
+}
+
+
+
+bool ApexIsoMesh::findNeighbors(IProgressListener* progress)
+{
+ mIsoEdges.clear();
+ IsoEdge edge;
+
+ for (int32_t i = 0; i < (int32_t)mIsoTriangles.size(); i++)
+ {
+ IsoTriangle& t = mIsoTriangles[(uint32_t)i];
+ edge.set(t.vertexNr[0], t.vertexNr[1], i);
+ mIsoEdges.pushBack(edge);
+ edge.set(t.vertexNr[1], t.vertexNr[2], i);
+ mIsoEdges.pushBack(edge);
+ edge.set(t.vertexNr[2], t.vertexNr[0], i);
+ mIsoEdges.pushBack(edge);
+ }
+
+ progress->setProgress(30);
+
+ shdfnd::sort(mIsoEdges.begin(), mIsoEdges.size(), IsoEdge());
+
+ progress->setProgress(60);
+
+ uint32_t i = 0;
+ while (i < mIsoEdges.size())
+ {
+ uint32_t j = i + 1;
+ while (j < mIsoEdges.size() && mIsoEdges[j] == mIsoEdges[i])
+ {
+ j++;
+ }
+ if (j > i + 1)
+ {
+ mIsoTriangles[(uint32_t)mIsoEdges[i ].triangleNr].addNeighbor(mIsoEdges[j - 1].triangleNr);
+ mIsoTriangles[(uint32_t)mIsoEdges[j - 1].triangleNr].addNeighbor(mIsoEdges[i ].triangleNr);
+ }
+ i = j;
+ }
+
+ progress->setProgress(100);
+ return true;
+}
+
+struct GroupAndSize
+{
+ int32_t group;
+ uint32_t size;
+ bool deleteMesh;
+
+ bool operator()(const GroupAndSize& a, const GroupAndSize& b) const
+ {
+ return a.size > b.size;
+ }
+};
+
+struct TimeAndDot
+{
+ float time;
+ float dot;
+
+ bool operator()(const TimeAndDot& a, const TimeAndDot& b) const
+ {
+ return a.time > b.time;
+ }
+};
+
+void ApexIsoMesh::removeLayers()
+{
+ // mark regions
+ nvidia::Array<GroupAndSize> triangleGroups;
+
+ for (uint32_t i = 0; i < mIsoTriangles.size(); i++)
+ {
+ if (mIsoTriangles[i].groupNr >= 0)
+ {
+ continue;
+ }
+
+ GroupAndSize gas;
+ gas.size = 0;
+ gas.group = (int32_t)triangleGroups.size();
+ gas.deleteMesh = false;
+
+ gas.size = floodFill(i, (uint32_t)gas.group);
+
+ triangleGroups.pushBack(gas);
+ }
+
+ if (triangleGroups.size() == 0)
+ {
+ return;
+ }
+
+ // clear regions
+ if (mDiscardInnerMeshes)
+ {
+ nvidia::Array<TimeAndDot> raycastHits;
+ for (uint32_t group = 0; group < triangleGroups.size(); group++)
+ {
+ // see if this group is an inner mesh
+ raycastHits.clear();
+
+ const int32_t groupNumber = triangleGroups[group].group;
+
+ uint32_t start = 0;
+ const uint32_t numTriangles = mIsoTriangles.size();
+ for (uint32_t i = 0; i < numTriangles; i++)
+ {
+ if (mIsoTriangles[i].groupNr == groupNumber)
+ {
+ start = i;
+ break;
+ }
+ }
+
+ // raycast from the start triangle
+ const PxVec3 rayOrig = (mIsoVertices[(uint32_t)mIsoTriangles[start].vertexNr[0]]
+ + mIsoVertices[(uint32_t)mIsoTriangles[start].vertexNr[1]]
+ + mIsoVertices[(uint32_t)mIsoTriangles[start].vertexNr[2]]) / 3.0f;
+ PxVec3 rayDir(1.0f, 1.0f, 1.0f);
+ rayDir.normalize(); // can really be anything.
+
+ // Find all ray hits
+ for (uint32_t i = start; i < numTriangles; i++)
+ {
+ if (mIsoTriangles[i].groupNr != groupNumber)
+ {
+ continue;
+ }
+
+ float t, u, v;
+ PxVec3 verts[3] =
+ {
+ mIsoVertices[(uint32_t)mIsoTriangles[i].vertexNr[0]],
+ mIsoVertices[(uint32_t)mIsoTriangles[i].vertexNr[1]],
+ mIsoVertices[(uint32_t)mIsoTriangles[i].vertexNr[2]],
+ };
+
+ if (APEX_RayTriangleIntersect(rayOrig, rayDir, verts[0], verts[1], verts[2], t, u, v))
+ {
+ TimeAndDot hit;
+ hit.time = t;
+
+ PxVec3 faceNormal = (verts[1] - verts[0]).cross(verts[2] - verts[0]);
+ faceNormal.normalize();
+
+ hit.dot = faceNormal.dot(rayDir);
+
+ raycastHits.pushBack(hit);
+ }
+ }
+
+ if (raycastHits.size() > 0)
+ {
+ shdfnd::sort(raycastHits.begin(), raycastHits.size(), TimeAndDot());
+
+ triangleGroups[group].deleteMesh = raycastHits[0].dot > 0.0f;
+ }
+ }
+ }
+
+ if (mKeepNBiggestMeshes > 0)
+ {
+ shdfnd::sort(triangleGroups.begin(), triangleGroups.size(), GroupAndSize());
+
+ for (uint32_t i = mKeepNBiggestMeshes; i < triangleGroups.size(); i++)
+ {
+ triangleGroups[i].deleteMesh = true;
+ }
+ }
+
+
+ for (uint32_t i = 0; i < triangleGroups.size(); i++)
+ {
+ if (!triangleGroups[i].deleteMesh)
+ {
+ continue;
+ }
+
+ const int32_t group = triangleGroups[i].group;
+
+ const uint32_t size = mIsoTriangles.size();
+ for (uint32_t j = 0; j < size; j++)
+ {
+ if (mIsoTriangles[j].groupNr == group)
+ {
+ mIsoTriangles[j].deleted = true;
+ }
+ }
+ }
+}
+
+
+
+uint32_t ApexIsoMesh::floodFill(uint32_t triangleNr, uint32_t groupNr)
+{
+ uint32_t numTriangles = 0;
+ nvidia::Array<uint32_t> queue;
+ queue.pushBack(triangleNr);
+
+ while (!queue.empty())
+ {
+ IsoTriangle& t = mIsoTriangles[queue.back()];
+ queue.popBack();
+ if (t.groupNr == int32_t(groupNr))
+ {
+ continue;
+ }
+
+ t.groupNr = (int32_t)groupNr;
+ numTriangles++;
+
+ int32_t adj = t.adjTriangles[0];
+ if (adj >= 0 && mIsoTriangles[(uint32_t)adj].groupNr < 0)
+ {
+ queue.pushBack((uint32_t)adj);
+ }
+ adj = t.adjTriangles[1];
+ if (adj >= 0 && mIsoTriangles[(uint32_t)adj].groupNr < 0)
+ {
+ queue.pushBack((uint32_t)adj);
+ }
+ adj = t.adjTriangles[2];
+ if (adj >= 0 && mIsoTriangles[(uint32_t)adj].groupNr < 0)
+ {
+ queue.pushBack((uint32_t)adj);
+ }
+ }
+
+ return numTriangles;
+}
+
+
+
+void ApexIsoMesh::removeTrisAndVerts()
+{
+ for (int32_t i = (int32_t)mIsoTriangles.size() - 1; i >= 0; i--)
+ {
+ if (mIsoTriangles[(uint32_t)i].deleted)
+ {
+ mIsoTriangles.replaceWithLast((uint32_t)i);
+ }
+ }
+
+ Array<int32_t> oldToNew;
+ Array<PxVec3> newVertices;
+
+ oldToNew.resize(mIsoVertices.size(), -1);
+
+ for (uint32_t i = 0; i < mIsoTriangles.size(); i++)
+ {
+ IsoTriangle& t = mIsoTriangles[i];
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ uint32_t vNr = (uint32_t)t.vertexNr[j];
+ if (oldToNew[vNr] < 0)
+ {
+ oldToNew[vNr] = (int32_t)newVertices.size();
+ newVertices.pushBack(mIsoVertices[vNr]);
+ }
+ t.vertexNr[j] = oldToNew[vNr];
+ }
+ }
+
+ mIsoVertices.clear();
+ mIsoVertices.reserve(newVertices.size());
+
+ for (uint32_t i = 0; i < newVertices.size(); i++)
+ {
+ mIsoVertices.pushBack(newVertices[i]);
+ }
+}
+
+} // end namespace apex
+} // end namespace nvidia
diff --git a/APEX_1.4/common/src/ApexMath.cpp b/APEX_1.4/common/src/ApexMath.cpp
new file mode 100644
index 00000000..0aaf9e9d
--- /dev/null
+++ b/APEX_1.4/common/src/ApexMath.cpp
@@ -0,0 +1,49 @@
+#include "NvSimd4f.h"
+
+#include "PxMat44.h"
+#include "PxMat33.h"
+#include "PxVec3.h"
+#include "PxVec4.h"
+#include "PxQuat.h"
+
+using physx::PxMat44;
+using physx::PxMat33;
+using physx::PxVec3;
+using physx::PxVec4;
+using physx::PxQuat;
+
+#include "PxPreprocessor.h"
+#include "PxAssert.h"
+#include "ApexMath.h"
+
+namespace nvidia
+{
+
+ bool operator != (const PxMat44& a, const PxMat44& b)
+ {
+ PX_ASSERT((((size_t)&a) & 0xf) == 0); // verify 16 byte alignment
+ PX_ASSERT((((size_t)&b) & 0xf) == 0); // verify 16 byte alignment
+
+ int allEq = true;
+
+ typedef Simd4fLoadFactory loadFactory;
+
+ const Simd4f ca1 = loadFactory(&a.column0.x);
+ const Simd4f cb1 = loadFactory(&b.column0.x);
+ allEq &= allEqual(ca1, cb1);
+
+ const Simd4f ca2 = loadFactory(&a.column1.x);
+ const Simd4f cb2 = loadFactory(&b.column1.x);
+ allEq &= allEqual(ca2, cb2);
+
+ const Simd4f ca3 = loadFactory(&a.column2.x);
+ const Simd4f cb3 = loadFactory(&b.column2.x);
+ allEq &= allEqual(ca3, cb3);
+
+ const Simd4f ca4 = loadFactory(&a.column3.x);
+ const Simd4f cb4 = loadFactory(&b.column3.x);
+ allEq &= allEqual(ca4, cb4);
+
+ return allEq == 0;
+ }
+}
diff --git a/APEX_1.4/common/src/ApexMeshContractor.cpp b/APEX_1.4/common/src/ApexMeshContractor.cpp
new file mode 100644
index 00000000..a9e4b1fe
--- /dev/null
+++ b/APEX_1.4/common/src/ApexMeshContractor.cpp
@@ -0,0 +1,1708 @@
+/*
+ * 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 "ApexMeshContractor.h"
+#include "ApexSDKIntl.h"
+#include "PxBounds3.h"
+#include "ApexBinaryHeap.h"
+#include "ApexSharedUtils.h"
+
+#include "PsSort.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+#define EDGE_PRESERVATION 1
+
+struct TriangleEdge
+{
+ void init(uint32_t v0, uint32_t v1, uint32_t edgeNr, uint32_t triNr)
+ {
+ PX_ASSERT(v0 != v1);
+ this->v0 = PxMin(v0, v1);
+ this->v1 = PxMax(v0, v1);
+ this->edgeNr = edgeNr;
+ this->triNr = triNr;
+ }
+ bool operator < (const TriangleEdge& e) const
+ {
+ if (v0 < e.v0)
+ {
+ return true;
+ }
+ if (v0 > e.v0)
+ {
+ return false;
+ }
+ return v1 < e.v1;
+ }
+ bool operator()(const TriangleEdge& a, const TriangleEdge& b) const
+ {
+ if (a.v0 < b.v0)
+ {
+ return true;
+ }
+ if (a.v0 > b.v0)
+ {
+ return false;
+ }
+ return a.v1 < b.v1;
+ }
+ bool operator == (const TriangleEdge& e) const
+ {
+ if (v0 == e.v0 && v1 == e.v1)
+ {
+ return true;
+ }
+ PX_ASSERT(!(v0 == e.v1 && v1 == e.v0));
+ //if (v0 == e.v1 && v1 == e.v0) return true;
+ return false;
+ }
+ uint32_t v0, v1;
+ uint32_t edgeNr;
+ uint32_t triNr;
+};
+
+
+
+struct CellCoord
+{
+ uint32_t xi, yi, zi;
+ float value;
+ bool operator < (CellCoord& c) const
+ {
+ return value < c.value;
+ }
+};
+
+
+
+ApexMeshContractor::ApexMeshContractor() :
+ mCellSize(1.0f),
+ mOrigin(0.0f, 0.0f, 0.0f),
+ mNumX(0), mNumY(0), mNumZ(0),
+ mInitialVolume(0.0f),
+ mCurrentVolume(0.0f)
+{
+ PX_COMPILE_TIME_ASSERT(sizeof(ContractorCell) == 12);
+}
+
+
+
+void ApexMeshContractor::registerVertex(const PxVec3& pos)
+{
+ mVertices.pushBack(pos);
+}
+
+
+
+void ApexMeshContractor::registerTriangle(uint32_t v0, uint32_t v1, uint32_t v2)
+{
+ mIndices.pushBack(v0);
+ mIndices.pushBack(v1);
+ mIndices.pushBack(v2);
+}
+
+
+
+bool ApexMeshContractor::endRegistration(uint32_t subdivision, IProgressListener* progressListener)
+{
+ HierarchicalProgressListener progress(100, progressListener);
+ progress.setSubtaskWork(30, "Compute Neighbors");
+ computeNeighbours();
+
+ PxBounds3 bounds;
+ bounds.setEmpty();
+ for (unsigned i = 0; i < mVertices.size(); i++)
+ {
+ bounds.include(mVertices[i]);
+ }
+
+ mCellSize = (bounds.maximum - bounds.minimum).magnitude() / subdivision;
+ if (mCellSize == 0.0f)
+ {
+ mCellSize = 1.0f;
+ }
+ PX_ASSERT(!bounds.isEmpty());
+ bounds.fattenFast(2.0f * mCellSize);
+
+ mOrigin = bounds.minimum;
+ float invH = 1.0f / mCellSize;
+ mNumX = (uint32_t)((bounds.maximum.x - bounds.minimum.x) * invH) + 1;
+ mNumY = (uint32_t)((bounds.maximum.y - bounds.minimum.y) * invH) + 1;
+ mNumZ = (uint32_t)((bounds.maximum.z - bounds.minimum.z) * invH) + 1;
+ unsigned num = mNumX * mNumY * mNumZ;
+ mGrid.resize(num, ContractorCell());
+
+ progress.completeSubtask();
+
+ progress.setSubtaskWork(60, "Compute Signed Distance Field");
+ computeSignedDistanceField();
+ progress.completeSubtask();
+
+ progress.setSubtaskWork(10, "Computing Volume");
+ float area = 0;
+ computeAreaAndVolume(area, mInitialVolume);
+ progress.completeSubtask();
+
+ return true;
+}
+
+
+
+uint32_t ApexMeshContractor::contract(int32_t steps, float abortionRatio, float& volumeRatio, IProgressListener* progressListener)
+{
+ if (steps == -1 && (abortionRatio <= 0 || abortionRatio > 1))
+ {
+ APEX_INTERNAL_ERROR("Invalid abortionRatio when doing infinite steps (%f)", abortionRatio);
+ return 0;
+ }
+
+ HierarchicalProgressListener progress(100, progressListener);
+ progress.setSubtaskWork(100, "Contract");
+
+ bool abort = false;
+ int32_t currStep = 0;
+ for (; (steps < 0 || currStep < steps) && !abort; currStep++)
+ {
+ {
+ int32_t percent = 100 * currStep / steps;
+ progress.setProgress(percent);
+ }
+ if (!abort)
+ {
+ contractionStep();
+ subdivide(1.5f * mCellSize);
+ collapse(0.3f * mCellSize);
+
+ float area;
+ computeAreaAndVolume(area, mCurrentVolume);
+
+ volumeRatio = mCurrentVolume / mInitialVolume;
+ abort = volumeRatio < abortionRatio;
+ }
+ }
+
+ progress.completeSubtask();
+ return (uint32_t)currStep;
+}
+
+
+
+void ApexMeshContractor::expandBorder()
+{
+ const float localRadius = 2.0f * mCellSize;
+ //const float minDist = 1.0f * mCellSize;
+ float maxDot = 0.0f;
+
+ if (mNeighbours.size() != mIndices.size())
+ {
+ return;
+ }
+
+ const uint32_t numTris = mIndices.size() / 3;
+ const uint32_t numVerts = mVertices.size();
+
+ void* memory = PX_ALLOC(sizeof(uint32_t) * numTris + sizeof(PxVec3) * numTris, PX_DEBUG_EXP("ApexMeshContractor"));
+ uint32_t* triMarks = (uint32_t*)memory;
+ PxVec3* triComs = (PxVec3*)(triMarks + numTris);
+ memset(triMarks, -1, sizeof(uint32_t) * numTris);
+
+ physx::Array<PxVec3> dispField;
+ dispField.resize(numVerts);
+
+ physx::Array<float> dispWeights;
+ dispWeights.resize(numVerts);
+
+ for (uint32_t i = 0; i < numVerts; i++)
+ {
+ dispField[i] = PxVec3(0.0f);
+ dispWeights[i] = 0.0f;
+ }
+
+ physx::Array<int32_t> localTris;
+ physx::Array<float> localDists;
+
+ for (uint32_t i = 0; i < numTris; i++)
+ {
+ triComs[i] = PxVec3(0.0f);
+
+ // is there a border edge?
+ uint32_t i0 = mIndices[3 * i];
+ uint32_t i1 = mIndices[3 * i + 1];
+ uint32_t i2 = mIndices[3 * i + 2];
+
+ const PxVec3& p0 = mVertices[i0];
+ const PxVec3& p1 = mVertices[i1];
+ const PxVec3& p2 = mVertices[i2];
+
+ const PxVec3 ci = (p0 + p1 + p2) / 3.0f;
+
+ PxVec3 ni = (p1 - p0).cross(p2 - p0);
+ ni.normalize();
+
+ bool edgeFound = false;
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ int32_t adj = mNeighbours[3 * i + j];
+ if (adj < 0)
+ {
+ continue;
+ }
+
+ PxVec3& q0 = mVertices[mIndices[3 * adj + j]];
+ PxVec3& q1 = mVertices[mIndices[3 * adj + (j + 1) % 3]];
+ PxVec3& q2 = mVertices[mIndices[3 * adj + (j + 2) % 3]];
+
+ PxVec3 nadj = (q1 - q0).cross(q2 - q0);
+ nadj.normalize();
+
+ if (ni.dot(nadj) < maxDot)
+ {
+ edgeFound = true;
+ break;
+ }
+ }
+
+ if (!edgeFound)
+ {
+ continue;
+ }
+
+ collectNeighborhood((int32_t)i, localRadius, i, localTris, localDists, triMarks);
+ uint32_t numLocals = localTris.size();
+
+ // is the neighborhood double sided?
+ float doubleArea = 0.0f;
+ PxVec3 com(0.0f, 0.0f, 0.0f);
+ float totalW = 0.0f;
+
+ for (uint32_t j = 0; j < numLocals; j++)
+ {
+ uint32_t triJ = (uint32_t)localTris[j];
+ const PxVec3& p0 = mVertices[mIndices[3 * triJ + 0]];
+ const PxVec3& p1 = mVertices[mIndices[3 * triJ + 1]];
+ const PxVec3& p2 = mVertices[mIndices[3 * triJ + 2]];
+
+ PxVec3 nj = (p1 - p0).cross(p2 - p0);
+ const float area = nj.normalize();
+ const float w = area;
+ totalW += w;
+ com += (p0 + p1 + p2) / 3.0f * w;
+
+ for (uint32_t k = 0; k < numLocals; k++)
+ {
+ uint32_t triK = (uint32_t)localTris[k];
+
+ const PxVec3& q0 = mVertices[mIndices[3 * triK + 0]];
+ const PxVec3& q1 = mVertices[mIndices[3 * triK + 1]];
+ const PxVec3& q2 = mVertices[mIndices[3 * triK + 2]];
+
+ PxVec3 nk = (q1 - p0).cross(q2 - q0);
+ nk.normalize();
+
+ if (nj.dot(nk) < -0.999f)
+ {
+ doubleArea += area;
+ break;
+ }
+ }
+ }
+
+ float totalArea = PxPi * localRadius * localRadius;
+ if (doubleArea < 0.5f * totalArea)
+ {
+ continue;
+ }
+
+ if (totalW > 0.0f)
+ {
+ com /= totalW;
+ }
+
+ triComs[i] = com;
+
+ // update displacement field
+ PxVec3 disp = ci - com;
+ disp.normalize();
+ disp *= 2.0f * mCellSize;
+
+ float minT = findMin(ci, disp);
+ disp *= minT;
+
+ float maxDist = 0.0f;
+ for (uint32_t j = 0; j < numLocals; j++)
+ {
+ maxDist = PxMax(maxDist, localDists[j]);
+ }
+
+ for (uint32_t j = 0; j < numLocals; j++)
+ {
+ int32_t triJ = localTris[j];
+
+ float w = 1.0f;
+ if (maxDist != 0.0f)
+ {
+ w = 1.0f - localDists[j] / maxDist;
+ }
+
+ for (uint32_t k = 0; k < 3; k++)
+ {
+ uint32_t v = mIndices[3 * triJ + k];
+ dispField[v] += disp * w * w;
+ dispWeights[v] += w;
+ }
+ }
+ }
+
+ for (uint32_t i = 0; i < mVertices.size(); i++)
+ {
+ const float w = dispWeights[i];
+ if (w == 0.0f)
+ {
+ continue;
+ }
+
+ mVertices[i] += dispField[i] / w;
+ }
+
+ PX_FREE(memory);
+}
+
+
+
+
+void ApexMeshContractor::computeNeighbours()
+{
+ physx::Array<TriangleEdge> edges;
+ edges.reserve(mIndices.size());
+
+ mNeighbours.resize(mIndices.size());
+ for (uint32_t i = 0; i < mNeighbours.size(); i++)
+ {
+ mNeighbours[i] = -1;
+ }
+
+ PX_ASSERT(mIndices.size() % 3 == 0);
+ const 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];
+ TriangleEdge edge;
+ edge.init(i0, i1, 0, i);
+ edges.pushBack(edge);
+ edge.init(i1, i2, 1, i);
+ edges.pushBack(edge);
+ edge.init(i2, i0, 2, i);
+ edges.pushBack(edge);
+ }
+
+ shdfnd::sort(edges.begin(), edges.size(), TriangleEdge());
+
+ uint32_t i = 0;
+ const uint32_t numEdges = edges.size();
+ while (i < numEdges)
+ {
+ const TriangleEdge& e0 = edges[i];
+ i++;
+ while (i < numEdges && edges[i] == e0)
+ {
+ const TriangleEdge& e1 = edges[i];
+ PX_ASSERT(mNeighbours[e0.triNr * 3 + e0.edgeNr] == -1);///?
+ mNeighbours[e0.triNr * 3 + e0.edgeNr] = (int32_t)e1.triNr;
+ PX_ASSERT(mNeighbours[e1.triNr * 3 + e1.edgeNr] == -1);///?
+ mNeighbours[e1.triNr * 3 + e1.edgeNr] = (int32_t)e0.triNr;
+ i++;
+ }
+ }
+}
+
+
+
+void ApexMeshContractor::computeSignedDistanceField()
+{
+ // init
+ for (uint32_t i = 0; i < mGrid.size(); i++)
+ {
+ PX_ASSERT(mGrid[i].distance == PX_MAX_F32);
+ PX_ASSERT(mGrid[i].inside == 0);
+ }
+
+ PX_ASSERT(mIndices.size() % 3 == 0);
+ uint32_t numTris = mIndices.size() / 3;
+
+ for (uint32_t i = 0; i < numTris; i++)
+ {
+ PxVec3 p0 = mVertices[mIndices[3 * i ]] - mOrigin;
+ PxVec3 p1 = mVertices[mIndices[3 * i + 1]] - mOrigin;
+ PxVec3 p2 = mVertices[mIndices[3 * i + 2]] - mOrigin;
+ addTriangle(p0, p1, p2);
+ }
+
+
+ // fast marching, see J.A. Sethian "Level Set Methods and Fast Marching Methods"
+ // create front
+ ApexBinaryHeap<CellCoord> heap;
+ //CellCoord cc;
+
+ //int xi,yi,zi;
+
+ for (uint32_t xi = 0; xi < mNumX - 1; xi++)
+ {
+ CellCoord cc;
+ cc.xi = xi;
+ for (uint32_t yi = 0; yi < mNumY - 1; yi++)
+ {
+ cc.yi = yi;
+ for (uint32_t zi = 0; zi < mNumZ - 1; zi++)
+ {
+ cc.zi = zi;
+ const ContractorCell& c = cellAt((int32_t)xi, (int32_t)yi, (int32_t)zi);
+ if (!c.marked)
+ {
+ continue;
+ }
+ cc.value = c.distance;
+ heap.push(cc);
+ }
+ }
+ }
+
+ while (!heap.isEmpty())
+ {
+ CellCoord cc;
+
+ // Make compiler happy
+ cc.xi = cc.yi = cc.zi = 0;
+ cc.value = 0.0f;
+
+ heap.pop(cc);
+
+ ContractorCell& c = cellAt((int32_t)cc.xi, (int32_t)cc.yi, (int32_t)cc.zi);
+ c.marked = true;
+ for (int i = 0; i < 6; i++)
+ {
+ CellCoord ncc = cc;
+ switch (i)
+ {
+ case 0:
+ if (ncc.xi < 1)
+ {
+ continue;
+ }
+ else
+ {
+ ncc.xi--;
+ }
+ break;
+ case 1:
+ if (ncc.xi >= mNumX - 1)
+ {
+ continue;
+ }
+ else
+ {
+ ncc.xi++;
+ }
+ break;
+ case 2:
+ if (ncc.yi < 1)
+ {
+ continue;
+ }
+ else
+ {
+ ncc.yi--;
+ }
+ break;
+ case 3:
+ if (ncc.yi >= mNumY - 1)
+ {
+ continue;
+ }
+ else
+ {
+ ncc.yi++;
+ }
+ break;
+ case 4:
+ if (ncc.zi < 1)
+ {
+ continue;
+ }
+ else
+ {
+ ncc.zi--;
+ }
+ break;
+ case 5:
+ if (ncc.zi >= mNumZ - 1)
+ {
+ continue;
+ }
+ else
+ {
+ ncc.zi++;
+ }
+ break;
+ }
+
+ ContractorCell& cn = cellAt((int32_t)ncc.xi, (int32_t)ncc.yi, (int32_t)ncc.zi);
+ if (cn.marked)
+ {
+ continue;
+ }
+ if (!updateDistance(ncc.xi, ncc.yi, ncc.zi))
+ {
+ continue;
+ }
+ ncc.value = cn.distance;
+ heap.push(ncc);
+ }
+ }
+
+ setInsideOutside();
+ for (unsigned i = 0; i < mGrid.size(); i++)
+ {
+ if (mGrid[i].inside < 3) // majority vote
+ {
+ mGrid[i].distance = -mGrid[i].distance;
+ }
+ }
+}
+
+
+
+void ApexMeshContractor::contractionStep()
+{
+#if EDGE_PRESERVATION
+ unsigned numTris = mIndices.size() / 3;
+ mVertexCurvatures.resize(mVertices.size());
+ for (unsigned i = 0; i < mVertexCurvatures.size(); i++)
+ {
+ mVertexCurvatures[i] = 0.0f;
+ }
+
+ for (unsigned i = 0; i < numTris; i++)
+ {
+ for (unsigned j = 0; j < 3; j++)
+ {
+ unsigned vertNr = mIndices[3 * i + j];
+ if (mVertexCurvatures[vertNr] == 0.0f)
+ {
+ float curv = curvatureAt((int32_t)i, (int32_t)vertNr);
+ mVertexCurvatures[vertNr] = curv;
+ }
+ }
+ }
+#endif
+
+ float s = 0.1f * mCellSize;
+ for (unsigned i = 0; i < mVertices.size(); i++)
+ {
+ PxVec3& p = mVertices[i];
+ PxVec3 grad;
+ interpolateGradientAt(p, grad);
+
+#if EDGE_PRESERVATION
+ p += grad * s * (1.0f - mVertexCurvatures[i]);
+#else
+ p += grad * s;
+#endif
+ }
+}
+
+
+
+void ApexMeshContractor::computeAreaAndVolume(float& area, float& volume)
+{
+ area = volume = 0.0f;
+
+ for (uint32_t i = 0; i < mIndices.size(); i += 3)
+ {
+ PxVec3& d0 = mVertices[mIndices[i]];
+ PxVec3 d1 = mVertices[mIndices[i + 1]] - mVertices[mIndices[i]];
+ PxVec3 d2 = mVertices[mIndices[i + 2]] - mVertices[mIndices[i]];
+ PxVec3 n = d1.cross(d2);
+ area += n.magnitude();
+ volume += n.dot(d0);
+ }
+
+ area /= 2.0f;
+ volume /= 6.0f;
+}
+
+
+
+void ApexMeshContractor::addTriangle(const PxVec3& p0, const PxVec3& p1, const PxVec3& p2)
+{
+ PxBounds3 bounds;
+ bounds.setEmpty();
+ bounds.include(p0);
+ bounds.include(p1);
+ bounds.include(p2);
+ PX_ASSERT(!bounds.isEmpty());
+ bounds.fattenFast(0.01f * mCellSize);
+
+ PxVec3 n = (p1 - p0).cross(p2 - p0);
+
+ float d_big = n.dot(p0);
+ float invH = 1.0f / mCellSize;
+
+ int32_t min[3];
+ min[0] = (int32_t)PxFloor(bounds.minimum.x * invH) + 1;
+ min[1] = (int32_t)PxFloor(bounds.minimum.y * invH) + 1;
+ min[2] = (int32_t)PxFloor(bounds.minimum.z * invH) + 1;
+ int32_t max[3];
+ max[0] = (int32_t)PxFloor(bounds.maximum.x * invH);
+ max[1] = (int32_t)PxFloor(bounds.maximum.y * invH);
+ max[2] = (int32_t)PxFloor(bounds.maximum.z * invH);
+
+ if (min[0] < 0)
+ {
+ min[0] = 0;
+ }
+ if (min[1] < 0)
+ {
+ min[1] = 0;
+ }
+ if (min[2] < 0)
+ {
+ min[2] = 0;
+ }
+ if (max[0] >= (int32_t)mNumX)
+ {
+ max[0] = (int32_t)mNumX - 1;
+ }
+ if (max[1] >= (int32_t)mNumY)
+ {
+ max[1] = (int32_t)mNumY - 1;
+ }
+ if (max[2] >= (int32_t)mNumZ)
+ {
+ max[2] = (int32_t)mNumZ - 1;
+ }
+
+ int32_t num[3] = { (int32_t)mNumX, (int32_t)mNumY, (int32_t)mNumZ };
+
+ int32_t coord[3];
+
+ for (uint32_t dim0 = 0; dim0 < 3; dim0++)
+ {
+ if (n[dim0] == 0.0f)
+ {
+ continue; // singular case
+ }
+
+ const uint32_t dim1 = (dim0 + 1) % 3;
+ const uint32_t dim2 = (dim1 + 1) % 3;
+ for (coord[dim1] = min[dim1]; coord[dim1] <= max[dim1]; coord[dim1]++)
+ {
+ for (coord[dim2] = min[dim2]; coord[dim2] <= max[dim2]; coord[dim2]++)
+ {
+ float axis1 = coord[dim1] * mCellSize;
+ float axis2 = coord[dim2] * mCellSize;
+ /// \todo prevent singular cases when the same spacing was used in previous steps ????
+ axis1 += 0.00017f * mCellSize;
+ axis2 += 0.00017f * mCellSize;
+
+ // does the ray go through the triangle?
+ if (n[dim0] > 0.0f)
+ {
+ if ((p1[dim1] - p0[dim1]) * (axis2 - p0[dim2]) - (axis1 - p0[dim1]) * (p1[dim2] - p0[dim2]) < 0.0f)
+ {
+ continue;
+ }
+ if ((p2[dim1] - p1[dim1]) * (axis2 - p1[dim2]) - (axis1 - p1[dim1]) * (p2[dim2] - p1[dim2]) < 0.0f)
+ {
+ continue;
+ }
+ if ((p0[dim1] - p2[dim1]) * (axis2 - p2[dim2]) - (axis1 - p2[dim1]) * (p0[dim2] - p2[dim2]) < 0.0f)
+ {
+ continue;
+ }
+ }
+ else
+ {
+ if ((p1[dim1] - p0[dim1]) * (axis2 - p0[dim2]) - (axis1 - p0[dim1]) * (p1[dim2] - p0[dim2]) > 0.0f)
+ {
+ continue;
+ }
+ if ((p2[dim1] - p1[dim1]) * (axis2 - p1[dim2]) - (axis1 - p1[dim1]) * (p2[dim2] - p1[dim2]) > 0.0f)
+ {
+ continue;
+ }
+ if ((p0[dim1] - p2[dim1]) * (axis2 - p2[dim2]) - (axis1 - p2[dim1]) * (p0[dim2] - p2[dim2]) > 0.0f)
+ {
+ continue;
+ }
+ }
+
+ float pos = (d_big - axis1 * n[dim1] - axis2 * n[dim2]) / n[dim0];
+ coord[dim0] = (int)PxFloor(pos * invH);
+ if (coord[dim0] < 0 || coord[dim0] >= num[dim0])
+ {
+ continue;
+ }
+
+ ContractorCell& cell = cellAt(coord[0], coord[1], coord[2]);
+ cell.numCuts[dim0]++;
+
+ float d = PxAbs(pos - coord[dim0] * mCellSize) * invH;
+ if (d < cell.distance)
+ {
+ cell.distance = d;
+ cell.marked = true;
+ }
+
+ if (coord[dim0] < num[dim0] - 1)
+ {
+ int adj[3] = { coord[0], coord[1], coord[2] };
+ adj[dim0]++;
+ ContractorCell& ca = cellAt(adj[0], adj[1], adj[2]);
+ d = 1.0f - d;
+ if (d < ca.distance)
+ {
+ ca.distance = d;
+ ca.marked = true;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+bool ApexMeshContractor::updateDistance(uint32_t xi, uint32_t yi, uint32_t zi)
+{
+ ContractorCell& ci = cellAt((int32_t)xi, (int32_t)yi, (int32_t)zi);
+ if (ci.marked)
+ {
+ return false;
+ }
+
+ // create quadratic equation from the stencil
+ float a = 0.0f;
+ float b = 0.0f;
+ float c = -1.0f;
+ for (uint32_t i = 0; i < 3; i++)
+ {
+ float min = PX_MAX_F32;
+ int32_t x = (int32_t)xi, y = (int32_t)yi, z = (int32_t)zi;
+ switch (i)
+ {
+ case 0:
+ x--;
+ break;
+ case 1:
+ y--;
+ break;
+ case 2:
+ z--;
+ break;
+ }
+
+ if (x >= 0 && y >= 0 && z >= 0)
+ {
+ ContractorCell& c = cellAt(x, y, z);
+ if (c.marked)
+ {
+ min = c.distance;
+ }
+ }
+
+ switch (i)
+ {
+ case 0:
+ x += 2;
+ break;
+ case 1:
+ y += 2;
+ break;
+ case 2:
+ z += 2;
+ break;
+ }
+
+ if (x < (int32_t)mNumX && y < (int32_t)mNumY && z < (int32_t)mNumZ)
+ {
+ ContractorCell& c = cellAt(x, y, z);
+ if (c.marked && c.distance < min)
+ {
+ min = c.distance;
+ }
+ }
+
+ if (min != PX_MAX_F32)
+ {
+ a += 1.0f;
+ b -= 2.0f * min;
+ c += min * min;
+ }
+ }
+
+ // solve the equation, the larger solution is the right one (distances grow as we proceed)
+ if (a == 0.0f)
+ {
+ return false;
+ }
+
+ float d = b * b - 4.0f * a * c;
+
+ if (d < 0.0f)
+ {
+ d = 0.0f; // debug
+ }
+
+ float distance = (-b + PxSqrt(d)) / (2.0f * a);
+
+ if (distance < ci.distance)
+ {
+ ci.distance = distance;
+ return true;
+ }
+
+ return false;
+}
+void ApexMeshContractor::setInsideOutside()
+{
+ int32_t num[3] = { (int32_t)mNumX, (int32_t)mNumY, (int32_t)mNumZ };
+
+ int32_t coord[3];
+ for (uint32_t dim0 = 0; dim0 < 3; dim0++)
+ {
+ const uint32_t dim1 = (dim0 + 1) % 3;
+ const uint32_t dim2 = (dim0 + 2) % 3;
+ for (coord[dim1] = 0; coord[dim1] < num[dim1]; coord[dim1]++)
+ {
+ for (coord[dim2] = 0; coord[dim2] < num[dim2]; coord[dim2]++)
+ {
+ bool inside = false;
+ for (coord[dim0] = 0; coord[dim0] < num[dim0]; coord[dim0]++)
+ {
+ ContractorCell& cell = cellAt(coord[0], coord[1], coord[2]);
+ if (inside)
+ {
+ cell.inside++;
+ }
+ if ((cell.numCuts[dim0] % 2) == 1)
+ {
+ inside = !inside;
+ }
+ }
+
+ inside = false;
+ for (coord[dim0] = num[dim0] - 1; coord[dim0] >= 0; coord[dim0]--)
+ {
+ ContractorCell& cell = cellAt(coord[0], coord[1], coord[2]);
+ if ((cell.numCuts[dim0] % 2) == 1)
+ {
+ inside = !inside;
+ }
+ if (inside)
+ {
+ cell.inside++;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+void ApexMeshContractor::interpolateGradientAt(const PxVec3& pos, PxVec3& grad)
+{
+ // the derivatives of the distances are defined on the center of the edges
+ // from there they are interpolated trilinearly
+ const PxVec3 p = pos - mOrigin;
+ const float h = mCellSize;
+ const float h1 = 1.0f / h;
+ const float h2 = 0.5f * h;
+ int32_t x0 = (int32_t)PxFloor(p.x * h1);
+ const float dx0 = (p.x - h * x0) * h1;
+ const float ex0 = 1.0f - dx0;
+ int32_t y0 = (int32_t)PxFloor(p.y * h1);
+ const float dy0 = (p.y - h * y0) * h1;
+ const float ey0 = 1.0f - dy0;
+ int32_t z0 = (int32_t)PxFloor(p.z * h1);
+ const float dz0 = (p.z - h * z0) * h1;
+ const float ez0 = 1.0f - dz0;
+
+ if (x0 < 0)
+ {
+ x0 = 0;
+ }
+ if (x0 + 1 >= (int32_t)mNumX)
+ {
+ x0 = (int32_t)mNumX - 2; // todo: handle boundary correctly
+ }
+ if (y0 < 0)
+ {
+ y0 = 0;
+ }
+ if (y0 + 1 >= (int32_t)mNumY)
+ {
+ y0 = (int32_t)mNumY - 2;
+ }
+ if (z0 < 0)
+ {
+ z0 = 0;
+ }
+ if (z0 + 1 >= (int32_t)mNumZ)
+ {
+ z0 = (int32_t)mNumZ - 2;
+ }
+
+ // the following coefficients are used on the axis of the component that is computed
+ // everything is shifted there because the derivatives are defined at the center of edges
+ //float dx2,dy2,dz2,ex2,ey2,ez2;
+ int32_t x2 = (int32_t)PxFloor((p.x - h2) * h1);
+ const float dx2 = (p.x - h2 - h * x2) * h1;
+ const float ex2 = 1.0f - dx2;
+ int32_t y2 = (int32_t)PxFloor((p.y - h2) * h1);
+ const float dy2 = (p.y - h2 - h * y2) * h1;
+ const float ey2 = 1.0f - dy2;
+ int32_t z2 = (int32_t)PxFloor((p.z - h2) * h1);
+ const float dz2 = (p.z - h2 - h * z2) * h1;
+ const float ez2 = 1.0f - dz2;
+
+ if (x2 < 0)
+ {
+ x2 = 0;
+ }
+ if (x2 + 2 >= (int32_t)mNumX)
+ {
+ x2 = (int32_t)mNumX - 3; // todo: handle boundary correctly
+ }
+ if (y2 < 0)
+ {
+ y2 = 0;
+ }
+ if (y2 + 2 >= (int32_t)mNumY)
+ {
+ y2 = (int32_t)mNumY - 3;
+ }
+ if (z2 < 0)
+ {
+ z2 = 0;
+ }
+ if (z2 + 2 >= (int32_t)mNumZ)
+ {
+ z2 = (int32_t)mNumZ - 3;
+ }
+
+ float d, d0, d1, d2, d3, d4, d5, d6, d7;
+ d = cellAt(x2 + 1, y0 , z0).distance;
+ d0 = d - cellAt(x2, y0, z0).distance;
+ d4 = cellAt(x2 + 2, y0, z0).distance - d;
+ d = cellAt(x2 + 1, y0 + 1, z0).distance;
+ d1 = d - cellAt(x2, y0 + 1, z0).distance;
+ d5 = cellAt(x2 + 2, y0 + 1, z0).distance - d;
+ d = cellAt(x2 + 1, y0 + 1, z0 + 1).distance;
+ d2 = d - cellAt(x2, y0 + 1, z0 + 1).distance;
+ d6 = cellAt(x2 + 2, y0 + 1, z0 + 1).distance - d;
+ d = cellAt(x2 + 1, y0, z0 + 1).distance;
+ d3 = d - cellAt(x2, y0, z0 + 1).distance;
+ d7 = cellAt(x2 + 2, y0, z0 + 1).distance - d;
+
+ grad.x = ex2 * (d0 * ey0 * ez0 + d1 * dy0 * ez0 + d2 * dy0 * dz0 + d3 * ey0 * dz0)
+ + dx2 * (d4 * ey0 * ez0 + d5 * dy0 * ez0 + d6 * dy0 * dz0 + d7 * ey0 * dz0);
+
+ d = cellAt(x0, y2 + 1, z0).distance;
+ d0 = d - cellAt(x0, y2, z0).distance;
+ d4 = cellAt(x0, y2 + 2, z0).distance - d;
+ d = cellAt(x0, y2 + 1, z0 + 1).distance;
+ d1 = d - cellAt(x0, y2, z0 + 1).distance;
+ d5 = cellAt(x0, y2 + 2, z0 + 1).distance - d;
+ d = cellAt(x0 + 1, y2 + 1, z0 + 1).distance;
+ d2 = d - cellAt(x0 + 1, y2, z0 + 1).distance;
+ d6 = cellAt(x0 + 1, y2 + 2, z0 + 1).distance - d;
+ d = cellAt(x0 + 1, y2 + 1, z0).distance;
+ d3 = d - cellAt(x0 + 1, y2, z0).distance;
+ d7 = cellAt(x0 + 1, y2 + 2, z0).distance - d;
+
+ grad.y = ey2 * (d0 * ez0 * ex0 + d1 * dz0 * ex0 + d2 * dz0 * dx0 + d3 * ez0 * dx0)
+ + dy2 * (d4 * ez0 * ex0 + d5 * dz0 * ex0 + d6 * dz0 * dx0 + d7 * ez0 * dx0);
+
+ d = cellAt(x0, y0 , z2 + 1).distance;
+ d0 = d - cellAt(x0, y0 , z2).distance;
+ d4 = cellAt(x0, y0 , z2 + 2).distance - d;
+ d = cellAt(x0 + 1, y0, z2 + 1).distance;
+ d1 = d - cellAt(x0 + 1, y0, z2).distance;
+ d5 = cellAt(x0 + 1, y0, z2 + 2).distance - d;
+ d = cellAt(x0 + 1, y0 + 1, z2 + 1).distance;
+ d2 = d - cellAt(x0 + 1, y0 + 1, z2).distance;
+ d6 = cellAt(x0 + 1, y0 + 1, z2 + 2).distance - d;
+ d = cellAt(x0, y0 + 1, z2 + 1).distance;
+ d3 = d - cellAt(x0, y0 + 1, z2).distance;
+ d7 = cellAt(x0, y0 + 1, z2 + 2).distance - d;
+
+ grad.z = ez2 * (d0 * ex0 * ey0 + d1 * dx0 * ey0 + d2 * dx0 * dy0 + d3 * ex0 * dy0)
+ + dz2 * (d4 * ex0 * ey0 + d5 * dx0 * ey0 + d6 * dx0 * dy0 + d7 * ex0 * dy0);
+}
+
+
+
+void ApexMeshContractor::subdivide(float spacing)
+{
+ const float min2 = spacing * spacing;
+ const uint32_t numTris = mIndices.size() / 3;
+ //const uint32_t numVerts = mVertices.size();
+
+ for (uint32_t i = 0; i < numTris; i++)
+ {
+ const uint32_t triNr = i;
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ uint32_t k = (j + 1) % 3;
+ uint32_t v0 = mIndices[3 * triNr + j];
+ uint32_t v1 = mIndices[3 * triNr + k];
+
+ PxVec3& p0 = mVertices[v0];
+ PxVec3& p1 = mVertices[v1];
+ if ((p1 - p0).magnitudeSquared() < min2)
+ {
+ continue;
+ }
+
+ uint32_t newVert = mVertices.size();
+ mVertices.pushBack((p1 + p0) * 0.5f);
+
+ int32_t adj;
+ int32_t t0, t1, t2, t3;
+ getButterfly(triNr, v0, v1, adj, t0, t1, t2, t3);
+
+ uint32_t newTri = mIndices.size() / 3;
+ int newAdj = -1;
+
+ int v = getOppositeVertex((int32_t)triNr, v0, v1);
+ PX_ASSERT(v >= 0);
+ mIndices.pushBack(newVert);
+ mIndices.pushBack(v1);
+ mIndices.pushBack((uint32_t)v);
+ if (adj >= 0)
+ {
+ v = getOppositeVertex(adj, v0, v1);
+ PX_ASSERT(v >= 0);
+ newAdj = (int32_t)mIndices.size() / 3;
+ mIndices.pushBack(newVert);
+ mIndices.pushBack((uint32_t)v);
+ mIndices.pushBack(v1);
+ }
+
+ replaceVertex((int32_t)triNr, v1, newVert);
+ replaceVertex(adj, v1, newVert);
+
+ replaceNeighbor((int32_t)triNr, t1, newTri);
+ replaceNeighbor(adj, t3, (uint32_t)newAdj);
+ replaceNeighbor(t1, (int32_t)triNr, newTri);
+ replaceNeighbor(t3, adj, (uint32_t)newAdj);
+
+ mNeighbours.pushBack(newAdj);
+ mNeighbours.pushBack(t1);
+ mNeighbours.pushBack((int32_t)triNr);
+ if (adj >= 0)
+ {
+ mNeighbours.pushBack(adj);
+ mNeighbours.pushBack(t3);
+ mNeighbours.pushBack((int32_t)newTri);
+ }
+ }
+ }
+}
+
+
+
+void ApexMeshContractor::collapse(float spacing)
+{
+ const float min2 = spacing * spacing;
+ const uint32_t numTris = mIndices.size() / 3;
+ const uint32_t numVerts = mVertices.size();
+
+ const uint32_t size = sizeof(int32_t) * numVerts + sizeof(int32_t) * numTris;
+ void* memory = PX_ALLOC(size, PX_DEBUG_EXP("ApexMeshContractor"));
+ memset(memory, 0, size);
+
+ int32_t* old2newVerts = (int32_t*)memory;
+ int32_t* old2newTris = old2newVerts + numVerts;
+
+ // collapse edges
+ for (uint32_t i = 0; i < numTris; i++)
+ {
+ const uint32_t triNr = i;
+
+ if (old2newTris[triNr] < 0)
+ {
+ continue;
+ }
+
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ const uint32_t k = (j + 1) % 3;
+ const uint32_t v0 = mIndices[3 * triNr + j];
+ const uint32_t v1 = mIndices[3 * triNr + k];
+
+ PxVec3& p0 = mVertices[v0];
+ PxVec3& p1 = mVertices[v1];
+ if ((p1 - p0).magnitudeSquared() > min2)
+ {
+ continue;
+ }
+
+ //if (iterNr == 14 && triNr == 388 && j == 0) {
+ // int foo = 0;
+ // checkConsistency();
+ //}
+
+ if (!legalCollapse((int32_t)triNr, v0, v1))
+ {
+ continue;
+ }
+
+ int32_t adj, t0, t1, t2, t3;
+ getButterfly(triNr, v0, v1, adj, t0, t1, t2, t3);
+
+ mVertices[v0] = (p1 + p0) * 0.5f;
+
+ int32_t prev = (int32_t)triNr;
+ int32_t t = t1;
+ while (t >= 0)
+ {
+ replaceVertex(t, v1, v0);
+ advanceAdjTriangle(v1, t, prev);
+ if (t == (int32_t)triNr)
+ {
+ break;
+ }
+ }
+
+ for (uint32_t k = 0; k < 3; k++)
+ {
+ if (t0 >= 0 && mNeighbours[3 * (uint32_t)t0 + k] == (int32_t)triNr)
+ {
+ mNeighbours[3 * (uint32_t)t0 + k] = t1;
+ }
+ if (t1 >= 0 && mNeighbours[3 * (uint32_t)t1 + k] == (int32_t)triNr)
+ {
+ mNeighbours[3 * (uint32_t)t1 + k] = t0;
+ }
+ if (t2 >= 0 && mNeighbours[3 * (uint32_t)t2 + k] == adj)
+ {
+ mNeighbours[3 * t2 + k] = t3;
+ }
+ if (t3 >= 0 && mNeighbours[3 * (uint32_t)t3 + k] == adj)
+ {
+ mNeighbours[3 * (uint32_t)t3 + k] = t2;
+ }
+ }
+
+ old2newVerts[v1] = -1;
+ old2newTris[triNr] = -1;
+ if (adj >= 0)
+ {
+ old2newTris[adj] = -1;
+ }
+
+ //checkConsistency();
+
+ break;
+ }
+ }
+
+ // compress mesh
+ uint32_t vertNr = 0;
+ for (uint32_t i = 0; i < numVerts; i++)
+ {
+ if (old2newVerts[i] != -1)
+ {
+ old2newVerts[i] = (int32_t)vertNr;
+ mVertices[vertNr] = mVertices[i];
+ vertNr++;
+ }
+ }
+ mVertices.resize(vertNr);
+
+ uint32_t triNr = 0;
+ for (uint32_t i = 0; i < numTris; i++)
+ {
+ if (old2newTris[i] != -1)
+ {
+ old2newTris[i] = (int32_t)triNr;
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ mIndices[3 * triNr + j] = (uint32_t)old2newVerts[mIndices[3 * i + j]];
+ mNeighbours[3 * triNr + j] = mNeighbours[3 * i + j];
+ }
+ triNr++;
+ }
+ }
+ mIndices.resize(triNr * 3);
+ mNeighbours.resize(triNr * 3);
+ for (uint32_t i = 0; i < mNeighbours.size(); i++)
+ {
+ PX_ASSERT(mNeighbours[i] != -1);
+ PX_ASSERT(old2newTris[mNeighbours[i]] != -1);
+ mNeighbours[i] = old2newTris[mNeighbours[i]];
+ }
+
+ PX_FREE(memory);
+}
+
+
+
+void ApexMeshContractor::getButterfly(uint32_t triNr, uint32_t v0, uint32_t v1, int32_t& adj, int32_t& t0, int32_t& t1, int32_t& t2, int32_t& t3) const
+{
+ t0 = -1;
+ t1 = -1;
+ t2 = -1;
+ t3 = -1;
+ adj = -1;
+ for (uint32_t i = 0; i < 3; i++)
+ {
+ int32_t n = mNeighbours[triNr * 3 + i];
+
+ if (n < 0)
+ {
+ continue;
+ }
+
+ if (triangleContains(n, v0) && triangleContains(n, v1))
+ {
+ adj = n;
+ }
+ else if (triangleContains(n, v0))
+ {
+ t0 = n;
+ }
+ else if (triangleContains(n, v1))
+ {
+ t1 = n;
+ }
+ }
+ if (adj >= 0)
+ {
+ for (uint32_t i = 0; i < 3; i++)
+ {
+ int32_t n = mNeighbours[adj * 3 + i];
+
+ if (n < 0 || (uint32_t)n == triNr)
+ {
+ continue;
+ }
+
+ if (triangleContains(n, v0))
+ {
+ t2 = n;
+ }
+ else if (triangleContains(n, v1))
+ {
+ t3 = n;
+ }
+ }
+ }
+}
+
+
+
+int32_t ApexMeshContractor::getOppositeVertex(int32_t t, uint32_t v0, uint32_t v1) const
+{
+ if (t < 0 || 3 * t + 2 >= (int32_t)mIndices.size())
+ {
+ return -1;
+ }
+ const uint32_t i = 3 * (uint32_t)t;
+ if (mIndices[i + 0] != v0 && mIndices[i + 0] != v1)
+ {
+ return (int32_t)mIndices[i + 0];
+ }
+ if (mIndices[i + 1] != v0 && mIndices[i + 1] != v1)
+ {
+ return (int32_t)mIndices[i + 1];
+ }
+ if (mIndices[i + 2] != v0 && mIndices[i + 2] != v1)
+ {
+ return (int32_t)mIndices[i + 2];
+ }
+ return -1;
+}
+
+
+
+void ApexMeshContractor::replaceVertex(int32_t t, uint32_t vOld, uint32_t vNew)
+{
+ if (t < 0 || 3 * t + 2 >= (int32_t)mIndices.size())
+ {
+ return;
+ }
+ const uint32_t i = 3 * (uint32_t)t;
+ if (mIndices[i + 0] == vOld)
+ {
+ mIndices[i + 0] = vNew;
+ }
+ if (mIndices[i + 1] == vOld)
+ {
+ mIndices[i + 1] = vNew;
+ }
+ if (mIndices[i + 2] == vOld)
+ {
+ mIndices[i + 2] = vNew;
+ }
+}
+
+
+
+void ApexMeshContractor::replaceNeighbor(int32_t t, int32_t nOld, uint32_t nNew)
+{
+ if (t < 0 || 3 * t + 2 >= (int32_t)mNeighbours.size())
+ {
+ return;
+ }
+ const uint32_t i = 3 * (uint32_t)t;
+ if (mNeighbours[i + 0] == nOld)
+ {
+ mNeighbours[i + 0] = (int32_t)nNew;
+ }
+ if (mNeighbours[i + 1] == nOld)
+ {
+ mNeighbours[i + 1] = (int32_t)nNew;
+ }
+ if (mNeighbours[i + 2] == nOld)
+ {
+ mNeighbours[i + 2] = (int32_t)nNew;
+ }
+}
+
+
+bool ApexMeshContractor::triangleContains(int32_t t, uint32_t v) const
+{
+ if (t < 0 || 3 * t + 2 >= (int32_t)mIndices.size())
+ {
+ return false;
+ }
+ const uint32_t i = 3 * (uint32_t)t;
+ return mIndices[i] == v || mIndices[i + 1] == v || mIndices[i + 2] == v;
+}
+
+
+
+bool ApexMeshContractor::legalCollapse(int32_t triNr, uint32_t v0, uint32_t v1) const
+{
+ int32_t adj, t0, t1, t2, t3;
+ getButterfly((uint32_t)triNr, v0, v1, adj, t0, t1, t2, t3);
+
+ // both of the end vertices must be completely surrounded by triangles
+ int32_t prev = triNr;
+ int32_t t = t0;
+ while (t >= 0)
+ {
+ advanceAdjTriangle(v0, t, prev);
+ if (t == triNr)
+ {
+ break;
+ }
+ }
+
+ if (t != triNr)
+ {
+ return false;
+ }
+
+ prev = triNr;
+ t = t1;
+ while (t >= 0)
+ {
+ advanceAdjTriangle(v1, t, prev);
+ if (t == triNr)
+ {
+ break;
+ }
+ }
+ if (t != triNr)
+ {
+ return false;
+ }
+
+ // not legal if there exists v != v0,v1 with (v0,v) and (v1,v) edges
+ // but (v,v0,v1) is not a triangle
+
+ prev = triNr;
+ t = t1;
+ int adjV = getOppositeVertex(triNr, v0, v1);
+ while (t >= 0)
+ {
+ if (t != t1)
+ {
+ int prev2 = prev;
+ int t2 = t;
+ while (t2 >= 0)
+ {
+ if (triangleContains(t2, v0))
+ {
+ return false;
+ }
+ advanceAdjTriangle((uint32_t)adjV, t2, prev2);
+ if (t2 == t)
+ {
+ break;
+ }
+ }
+ }
+ adjV = getOppositeVertex(t, v1, (uint32_t)adjV);
+ advanceAdjTriangle(v1, t, prev);
+ if (t == triNr || t == adj)
+ {
+ break;
+ }
+ }
+
+ if (areNeighbors(t0, t1))
+ {
+ return false;
+ }
+ if (areNeighbors(t2, t3))
+ {
+ return false;
+ }
+ return true;
+}
+
+
+
+void ApexMeshContractor::advanceAdjTriangle(uint32_t v, int32_t& t, int32_t& prev) const
+{
+ int32_t next = -1;
+ for (uint32_t i = 0; i < 3; i++)
+ {
+ int32_t n = mNeighbours[3 * t + i];
+ if (n >= 0 && n != prev && triangleContains(n, v))
+ {
+ next = n;
+ }
+ }
+ prev = t;
+ t = next;
+}
+
+
+
+bool ApexMeshContractor::areNeighbors(int32_t t0, int32_t t1) const
+{
+ if (t0 < 0 || 3 * t0 + 2 >= (int32_t)mNeighbours.size())
+ {
+ return false;
+ }
+ const uint32_t i = 3 * (uint32_t)t0;
+ return mNeighbours[i] == t1 || mNeighbours[i + 1] == t1 || mNeighbours[i + 2] == t1;
+}
+
+
+
+float ApexMeshContractor::findMin(const PxVec3& p, const PxVec3& maxDisp) const
+{
+ const uint32_t numSteps = 20;
+ const float dt = 1.0f / numSteps;
+
+ float minDist = PxAbs(interpolateDistanceAt(p));
+ float minT = 0.0f;
+
+ for (uint32_t i = 1; i < numSteps; i++)
+ {
+ const float t = i * dt;
+ float dist = PxAbs(interpolateDistanceAt(p + maxDisp * t));
+ if (dist < minDist)
+ {
+ minT = t;
+ // PH: isn't this missing?
+ //minDist = dist;
+ }
+ }
+ return minT;
+}
+
+
+
+float ApexMeshContractor::interpolateDistanceAt(const PxVec3& pos) const
+{
+ const PxVec3 p = pos - mOrigin;
+ const float h = mCellSize;
+ const float h1 = 1.0f / h;
+
+ int32_t x = (int32_t)PxFloor(p.x * h1);
+ const float dx = (p.x - h * x) * h1;
+ const float ex = 1.0f - dx;
+ int32_t y = (int32_t)PxFloor(p.y * h1);
+ const float dy = (p.y - h * y) * h1;
+ const float ey = 1.0f - dy;
+ int32_t z = (int32_t)PxFloor(p.z * h1);
+ const float dz = (p.z - h * z) * h1;
+ const float ez = 1.0f - dz;
+
+ if (x < 0)
+ {
+ x = 0;
+ }
+ if (x + 1 >= (int32_t)mNumX)
+ {
+ x = (int32_t)mNumX - 2; // todo: handle boundary correctly
+ }
+ if (y < 0)
+ {
+ y = 0;
+ }
+ if (y + 1 >= (int32_t)mNumY)
+ {
+ y = (int32_t)mNumY - 2;
+ }
+ if (z < 0)
+ {
+ z = 0;
+ }
+ if (z + 1 >= (int32_t)mNumZ)
+ {
+ z = (int32_t)mNumZ - 2;
+ }
+
+ float d0, d1, d2, d3, d4, d5, d6, d7;
+ d0 = constCellAt(x, y, z).distance;
+ d4 = constCellAt(x + 1, y, z).distance;
+ d1 = constCellAt(x, y + 1, z).distance;
+ d5 = constCellAt(x + 1, y + 1, z).distance;
+ d2 = constCellAt(x, y + 1, z + 1).distance;
+ d6 = constCellAt(x + 1, y + 1, z + 1).distance;
+ d3 = constCellAt(x, y, z + 1).distance;
+ d7 = constCellAt(x + 1, y, z + 1).distance;
+
+ float dist = ex * (d0 * ey * ez + d1 * dy * ez + d2 * dy * dz + d3 * ey * dz)
+ + dx * (d4 * ey * ez + d5 * dy * ez + d6 * dy * dz + d7 * ey * dz);
+
+ return dist;
+}
+
+
+
+
+struct DistTriangle
+{
+ int32_t triNr;
+ float dist;
+ bool operator < (const DistTriangle& t) const
+ {
+ return dist > t.dist;
+ }
+};
+
+void ApexMeshContractor::collectNeighborhood(int32_t triNr, float radius, uint32_t newMark, physx::Array<int32_t> &tris, physx::Array<float> &dists, uint32_t* triMarks) const
+{
+ tris.clear();
+ dists.clear();
+ ApexBinaryHeap<DistTriangle> heap;
+
+ DistTriangle dt;
+ dt.triNr = triNr;
+ dt.dist = 0.0f;
+ heap.push(dt);
+
+ while (!heap.isEmpty())
+ {
+ heap.pop(dt);
+
+ if (triMarks[dt.triNr] == newMark)
+ {
+ continue;
+ }
+ triMarks[dt.triNr] = newMark;
+
+ tris.pushBack(dt.triNr);
+ dists.pushBack(-dt.dist);
+ PxVec3 center;
+ getTriangleCenter(dt.triNr, center);
+
+ for (uint32_t i = 0; i < 3; i++)
+ {
+ int32_t adj = mNeighbours[3 * dt.triNr + i];
+ if (adj < 0)
+ {
+ continue;
+ }
+ if (triMarks[adj] == newMark)
+ {
+ continue;
+ }
+
+ PxVec3 adjCenter;
+ getTriangleCenter(adj, adjCenter);
+ DistTriangle adjDt;
+ adjDt.triNr = adj;
+ adjDt.dist = dt.dist - (adjCenter - center).magnitude(); // it is a max heap, we need the smallest dist first
+ //adjDt.dist = adjCenter.distance(center) - dt.dist; // PH: inverting heap distance, now it's a min heap
+ if (-adjDt.dist > radius)
+ {
+ continue;
+ }
+
+ heap.push(adjDt);
+ }
+ }
+}
+
+
+
+void ApexMeshContractor::getTriangleCenter(int32_t triNr, PxVec3& center) const
+{
+ const PxVec3& p0 = mVertices[mIndices[3 * (uint32_t)triNr + 0]];
+ const PxVec3& p1 = mVertices[mIndices[3 * (uint32_t)triNr + 1]];
+ const PxVec3& p2 = mVertices[mIndices[3 * (uint32_t)triNr + 2]];
+ center = (p0 + p1 + p2) / 3.0f;
+}
+
+//------------------------------------------------------------------------------------
+float ApexMeshContractor::curvatureAt(int triNr, int v)
+{
+ int prev = -1;
+ int t = triNr;
+ PxVec3 n0, n1;
+ float minDot = 1.0f;
+ while (t >= 0)
+ {
+ advanceAdjTriangle((uint32_t)v, t, prev);
+ if (t < 0 || t == triNr)
+ {
+ break;
+ }
+
+ PxVec3& p0 = mVertices[mIndices[3 * (uint32_t)prev]];
+ PxVec3& p1 = mVertices[mIndices[3 * (uint32_t)prev + 1]];
+ PxVec3& p2 = mVertices[mIndices[3 * (uint32_t)prev + 2]];
+ n0 = (p1 - p0).cross(p2 - p0);
+ n0.normalize();
+
+ PxVec3& q0 = mVertices[mIndices[3 * (uint32_t)t]];
+ PxVec3& q1 = mVertices[mIndices[3 * (uint32_t)t + 1]];
+ PxVec3& q2 = mVertices[mIndices[3 * (uint32_t)t + 2]];
+ n1 = (q1 - q0).cross(q2 - q0);
+ n1.normalize();
+ float dot = n0.dot(n1);
+ if (dot < minDot)
+ {
+ minDot = dot;
+ }
+ }
+ return (1.0f - minDot) * 0.5f;
+}
+
+}
+} // end namespace nvidia::apex
diff --git a/APEX_1.4/common/src/ApexMeshHash.cpp b/APEX_1.4/common/src/ApexMeshHash.cpp
new file mode 100644
index 00000000..36f40791
--- /dev/null
+++ b/APEX_1.4/common/src/ApexMeshHash.cpp
@@ -0,0 +1,297 @@
+/*
+ * 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 "ApexMeshHash.h"
+
+#include "PxBounds3.h"
+
+#include "PsSort.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+ApexMeshHash::ApexMeshHash() :
+ mHashIndex(NULL)
+{
+ mHashIndex = (MeshHashRoot*)PX_ALLOC(sizeof(MeshHashRoot) * HashIndexSize, PX_DEBUG_EXP("ApexMeshHash"));
+ mTime = 1;
+ for (uint32_t i = 0; i < HashIndexSize; i++)
+ {
+ mHashIndex[i].first = -1;
+ mHashIndex[i].timeStamp = 0;
+ }
+ mSpacing = 0.25f;
+ mInvSpacing = 1.0f / mSpacing;
+}
+
+
+
+ApexMeshHash::~ApexMeshHash()
+{
+ if (mHashIndex != NULL)
+ {
+ PX_FREE(mHashIndex);
+ mHashIndex = NULL;
+ }
+}
+
+
+
+void ApexMeshHash::setGridSpacing(float spacing)
+{
+ mSpacing = spacing;
+ mInvSpacing = 1.0f / spacing;
+ reset();
+}
+
+
+
+void ApexMeshHash::reset()
+{
+ mTime++;
+ mEntries.clear();
+}
+
+
+
+void ApexMeshHash::add(const PxBounds3& bounds, uint32_t itemIndex)
+{
+ int32_t x1, y1, z1;
+ int32_t x2, y2, z2;
+ cellCoordOf(bounds.minimum, x1, y1, z1);
+ cellCoordOf(bounds.maximum, x2, y2, z2);
+ MeshHashEntry entry;
+ entry.itemIndex = itemIndex;
+
+ for (int32_t x = x1; x <= x2; x++)
+ {
+ for (int32_t y = y1; y <= y2; y++)
+ {
+ for (int32_t z = z1; z <= z2; z++)
+ {
+ uint32_t h = hashFunction(x, y, z);
+ MeshHashRoot& r = mHashIndex[h];
+ uint32_t n = mEntries.size();
+ if (r.timeStamp != mTime || r.first < 0)
+ {
+ entry.next = -1;
+ }
+ else
+ {
+ entry.next = r.first;
+ }
+ r.first = (int32_t)n;
+ r.timeStamp = mTime;
+ mEntries.pushBack(entry);
+ }
+ }
+ }
+}
+
+
+
+void ApexMeshHash::add(const PxVec3& pos, uint32_t itemIndex)
+{
+ int x, y, z;
+ cellCoordOf(pos, x, y, z);
+ MeshHashEntry entry;
+ entry.itemIndex = itemIndex;
+
+ uint32_t h = hashFunction(x, y, z);
+ MeshHashRoot& r = mHashIndex[h];
+ uint32_t n = mEntries.size();
+ if (r.timeStamp != mTime || r.first < 0)
+ {
+ entry.next = -1;
+ }
+ else
+ {
+ entry.next = r.first;
+ }
+ r.first = (int32_t)n;
+ r.timeStamp = mTime;
+ mEntries.pushBack(entry);
+}
+
+
+
+void ApexMeshHash::query(const PxBounds3& bounds, physx::Array<uint32_t>& itemIndices, int32_t maxIndices)
+{
+ int32_t x1, y1, z1;
+ int32_t x2, y2, z2;
+ cellCoordOf(bounds.minimum, x1, y1, z1);
+ cellCoordOf(bounds.maximum, x2, y2, z2);
+ itemIndices.clear();
+
+ for (int32_t x = x1; x <= x2; x++)
+ {
+ for (int32_t y = y1; y <= y2; y++)
+ {
+ for (int32_t z = z1; z <= z2; z++)
+ {
+ uint32_t h = hashFunction(x, y, z);
+ MeshHashRoot& r = mHashIndex[h];
+ if (r.timeStamp != mTime)
+ {
+ continue;
+ }
+ int32_t i = r.first;
+ while (i >= 0)
+ {
+ MeshHashEntry& entry = mEntries[(uint32_t)i];
+ itemIndices.pushBack(entry.itemIndex);
+ if (maxIndices >= 0 && itemIndices.size() >= (uint32_t)maxIndices)
+ {
+ return;
+ }
+ i = entry.next;
+ }
+ }
+ }
+ }
+}
+
+
+
+void ApexMeshHash::queryUnique(const PxBounds3& bounds, physx::Array<uint32_t>& itemIndices, int32_t maxIndices)
+{
+ query(bounds, itemIndices, maxIndices);
+ compressIndices(itemIndices);
+}
+
+
+
+void ApexMeshHash::query(const PxVec3& pos, physx::Array<uint32_t>& itemIndices, int32_t maxIndices)
+{
+ int32_t x, y, z;
+ cellCoordOf(pos, x, y, z);
+ itemIndices.clear();
+
+ uint32_t h = hashFunction(x, y, z);
+ MeshHashRoot& r = mHashIndex[h];
+ if (r.timeStamp != mTime)
+ {
+ return;
+ }
+ int32_t i = r.first;
+ while (i >= 0)
+ {
+ MeshHashEntry& entry = mEntries[(uint32_t)i];
+ itemIndices.pushBack(entry.itemIndex);
+ if (maxIndices >= 0 && itemIndices.size() >= (uint32_t)maxIndices)
+ {
+ return;
+ }
+ i = entry.next;
+ }
+}
+
+
+
+void ApexMeshHash::queryUnique(const PxVec3& pos, physx::Array<uint32_t>& itemIndices, int32_t maxIndices)
+{
+ query(pos, itemIndices, maxIndices);
+ compressIndices(itemIndices);
+}
+
+
+class U32Less
+{
+public:
+ bool operator()(uint32_t u1, uint32_t u2) const
+ {
+ return u1 < u2;
+ }
+};
+
+
+void ApexMeshHash::compressIndices(physx::Array<uint32_t>& itemIndices)
+{
+ if (itemIndices.empty())
+ {
+ return;
+ }
+
+ shdfnd::sort(itemIndices.begin(), itemIndices.size(), U32Less());
+
+ // mark duplicates
+ uint32_t i = 0;
+ while (i < itemIndices.size())
+ {
+ uint32_t j = i + 1;
+ while (j < itemIndices.size() && itemIndices[i] == itemIndices[j])
+ {
+ itemIndices[j] = (uint32_t) - 1;
+ j++;
+ }
+ i = j;
+ }
+
+ // remove duplicates
+ i = 0;
+ while (i < itemIndices.size())
+ {
+ if (itemIndices[i] == (uint32_t)-1)
+ {
+ itemIndices.replaceWithLast(i);
+ }
+ else
+ {
+ i++;
+ }
+ }
+}
+
+int32_t ApexMeshHash::getClosestPointNr(const PxVec3* points, uint32_t numPoints, uint32_t pointStride, const PxVec3& pos)
+{
+ PX_ASSERT(numPoints > 0);
+ PxBounds3 queryBounds;
+ queryBounds.minimum = pos;
+ queryBounds.maximum = pos;
+ PX_ASSERT(!queryBounds.isEmpty());
+ queryBounds.fattenFast(mSpacing);
+ query(queryBounds, mTempIndices);
+
+ // remove false positives due to hash collisions
+ uint32_t next = 0;
+ for (uint32_t i = 0; i < mTempIndices.size(); i++)
+ {
+ uint32_t pointNr = mTempIndices[i];
+ const PxVec3* p = (PxVec3*)((uint8_t*)points + (pointNr * pointStride));
+ if (pointNr < numPoints && queryBounds.contains(*p))
+ {
+ mTempIndices[next++] = pointNr;
+ }
+ }
+ mTempIndices.resize(next);
+ bool fallBack = mTempIndices.size() == 0;
+ uint32_t numRes = fallBack ? numPoints : mTempIndices.size();
+
+ float min2 = 0.0f;
+ int minNr = -1;
+ for (uint32_t j = 0; j < numRes; j++)
+ {
+ uint32_t k = fallBack ? j : mTempIndices[j];
+ const PxVec3* p = (PxVec3*)((uint8_t*)points + (k * pointStride));
+ float d2 = (pos - *p).magnitudeSquared();
+ if (minNr < 0 || d2 < min2)
+ {
+ min2 = d2;
+ minNr = (int32_t)k;
+ }
+ }
+ return minNr;
+}
+
+}
+} // end namespace nvidia::apex
diff --git a/APEX_1.4/common/src/ApexPreview.cpp b/APEX_1.4/common/src/ApexPreview.cpp
new file mode 100644
index 00000000..f2dc53c6
--- /dev/null
+++ b/APEX_1.4/common/src/ApexPreview.cpp
@@ -0,0 +1,49 @@
+/*
+ * 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 "Apex.h"
+#include "ApexPreview.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+ApexPreview::ApexPreview() :
+ mInRelease(false),
+ mPose(physx::PxIdentity)
+{
+}
+
+ApexPreview::~ApexPreview()
+{
+ destroy();
+}
+
+void ApexPreview::setPose(const PxMat44& pose)
+{
+ mPose = pose;
+}
+
+const PxMat44 ApexPreview::getPose() const
+{
+ return mPose;
+}
+
+void ApexPreview::destroy()
+{
+ mInRelease = true;
+
+ renderDataLock();
+}
+
+}
+} // end namespace nvidia::apex
diff --git a/APEX_1.4/common/src/ApexPvdClient.cpp b/APEX_1.4/common/src/ApexPvdClient.cpp
new file mode 100644
index 00000000..95d24512
--- /dev/null
+++ b/APEX_1.4/common/src/ApexPvdClient.cpp
@@ -0,0 +1,378 @@
+/*
+ * 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 "ApexPvdClient.h"
+
+#ifndef WITHOUT_PVD
+
+#include "Module.h"
+#include "ApexSDKIntl.h"
+#include "ModuleIntl.h"
+
+#include "PxPvd.h"
+#include "PxPvdUserRenderer.h"
+#include "PxPvdDataStream.h"
+#include "PxPvdTransport.h"
+#include "PxPvdObjectModelBaseTypes.h"
+
+#include "PxAllocatorCallback.h"
+#include "PsUserAllocated.h"
+
+#include "ModuleFrameworkRegistration.h"
+
+#include "PVDParameterizedHandler.h"
+
+#define INIT_PVD_CLASSES_PARAMETERIZED( parameterizedClassName ) { \
+ pvdStream.createClass(NamespacedName(APEX_PVD_NAMESPACE, #parameterizedClassName)); \
+ parameterizedClassName* params = DYNAMIC_CAST(parameterizedClassName*)(GetInternalApexSDK()->getParameterizedTraits()->createNvParameterized(#parameterizedClassName)); \
+ mParameterizedHandler->initPvdClasses(*params->rootParameterDefinition(), #parameterizedClassName); \
+ params->destroy(); }
+
+// NOTE: the PvdDataStream is not threadsafe.
+
+using namespace nvidia;
+using namespace nvidia::shdfnd;
+using namespace physx::pvdsdk;
+
+struct SimpleAllocator : public PxAllocatorCallback
+{
+ virtual void* allocate(size_t size, const char* typeName, const char* filename, int line)
+ {
+ PX_UNUSED(filename);
+ PX_UNUSED(line);
+ PX_UNUSED(typeName);
+
+ // Ensure that we don't use a tracking allocation so that we don't get infinite recursion
+ return physx::shdfnd::getAllocator().allocate(size, typeName, filename, line);
+ }
+
+ virtual void deallocate(void* ptr)
+ {
+ physx::shdfnd::getAllocator().deallocate(ptr);
+ }
+};
+static SimpleAllocator sAllocator;
+
+class ApexPvdClientImpl : public UserAllocated, public ApexPvdClient, public PxAllocatorCallback
+{
+ PX_NOCOPY(ApexPvdClientImpl)
+
+ PsPvd* mPvd;
+ bool mIsConnected;
+ Array<void*> mInstances;
+ PvdDataStream* mDataStream;
+ PvdUserRenderer* mRenderer;
+ PvdParameterizedHandler* mParameterizedHandler;
+
+public:
+ static const char* getApexPvdClientNamespace() { return "PVD.ApexPvdClient"; }
+ static const NamespacedName getApexPvdClientNamespacedName()
+ {
+ static NamespacedName instanceNamespace(APEX_PVD_NAMESPACE, "scene");
+ return instanceNamespace;
+ }
+
+ ApexPvdClientImpl( PxPvd* inPvd )
+ : mDataStream( NULL )
+ , mRenderer( NULL )
+ , mParameterizedHandler( NULL )
+ , mIsConnected(false)
+ {
+ mPvd = static_cast<PsPvd*>(inPvd);
+ if (mPvd)
+ {
+ mPvd->addClient(this);
+ }
+ }
+
+ virtual ~ApexPvdClientImpl()
+ {
+ if (mPvd)
+ {
+ mPvd->removeClient(this);
+ }
+ }
+
+ virtual PxPvd& getPxPvd()
+ {
+ return *mPvd;
+ }
+
+ virtual bool isConnected() const
+ {
+ return mIsConnected;
+ }
+
+ virtual void onPvdConnected()
+ {
+ if(mIsConnected || !mPvd)
+ return;
+
+ mIsConnected = true;
+ mDataStream = PvdDataStream::create(mPvd);
+ mRenderer = PvdUserRenderer::create();
+
+ mParameterizedHandler = PX_NEW(PvdParameterizedHandler)(*mDataStream);
+
+ if (mPvd->getInstrumentationFlags() & PxPvdInstrumentationFlag::eDEBUG)
+ {
+ initPvdClasses();
+ initPvdInstances();
+ }
+
+ //Setting the namespace ensure that our class definition *can't* collide with
+ //someone else's. It doesn't protect against instance ids colliding which is why
+ //people normally use memory addresses casted to unsigned 64 bit numbers for those.
+
+ //mDataStream->setNamespace( getApexPvdClientNamespace() );
+ //mDataStream->createClass( "ApexPvdClient", 1 );
+ //mDataStream->defineProperty( 1, "Frame", "", PvdCommLayerDatatype::Section, 1 );
+ mDataStream->createClass( getApexPvdClientNamespacedName() );
+ }
+
+ virtual void onPvdDisconnected()
+ {
+ if(!mIsConnected)
+ return;
+ mIsConnected = false;
+
+ if ( mParameterizedHandler != NULL )
+ {
+ PX_DELETE(mParameterizedHandler);
+ mParameterizedHandler = NULL;
+ }
+
+ if ( mDataStream != NULL )
+ {
+ mDataStream->release();
+ mDataStream = NULL;
+ }
+
+ if ( mRenderer != NULL )
+ {
+ mRenderer->release();
+ mRenderer = NULL;
+ }
+
+ mInstances.clear();
+ }
+
+ virtual void flush()
+ {
+ }
+
+ void* ensureInstance( void* inInstance )
+ {
+ uint32_t instCount = mInstances.size();
+ for ( uint32_t idx = 0; idx < instCount; ++idx )
+ {
+ if ( mInstances[idx] == inInstance )
+ return inInstance;
+ }
+ if ( mDataStream )
+ {
+ mDataStream->createInstance(getApexPvdClientNamespacedName(), inInstance);
+ }
+ mInstances.pushBack( inInstance );
+ return inInstance;
+ }
+
+ virtual void beginFrame( void* inInstance )
+ {
+ if ( mDataStream == NULL ) return;
+ mDataStream->beginSection( ensureInstance( inInstance ), "ApexFrame");
+ }
+
+ virtual void endFrame( void* inInstance )
+ {
+ if ( mDataStream == NULL ) return;
+ //Flush the outstanding memory events. PVD in some situations tracks memory events
+ //and can display graphs of memory usage at certain points. They have to get flushed
+ //at some point...
+
+ //getConnectionManager().flushMemoryEvents();
+
+ //Also note that PVD is a consumer of the profiling system events. This ensures
+ //that PVD gets a view of the profiling events that pertained to the last frame.
+
+
+ //mDataStream->setPropertyValue( ensureInstance( inInstance ), 1, createSection( SectionType::End ) );
+ PxPvdTransport* transport = mPvd->getTransport();
+ if ( transport )
+ {
+ //Flushes memory and profiling events out of any buffered areas.
+ transport->flush();
+ }
+
+ mDataStream->endSection( ensureInstance( inInstance ), "ApexFrame");
+
+ //flush our data to the main connection
+ //and flush the main connection.
+ //This could be an expensive call.
+ //mDataStream->flush();
+ mRenderer->flushRenderEvents();
+ }
+
+
+ //destroy this instance;
+ virtual void release()
+ {
+ PX_DELETE( this );
+ }
+
+ virtual void* allocate(size_t size, const char* typeName, const char* filename, int line)
+ {
+ PX_UNUSED(filename);
+ PX_UNUSED(line);
+ PX_UNUSED(typeName);
+ return PX_ALLOC(size, typeName);
+ }
+
+ virtual void deallocate(void* ptr)
+ {
+ PX_FREE(ptr);
+ }
+
+ virtual PvdDataStream* getDataStream()
+ {
+ //PX_ASSERT(mIsLocked);
+ return mDataStream;
+ }
+
+ virtual PvdUserRenderer* getUserRender()
+ {
+ //PX_ASSERT(mIsLocked);
+ return mRenderer;
+ }
+
+ virtual void initPvdClasses()
+ {
+ //PX_ASSERT(mIsLocked);
+
+ // ApexSDK
+ NamespacedName apexSdkName = NamespacedName(APEX_PVD_NAMESPACE, "ApexSDK");
+ mDataStream->createClass(apexSdkName);
+ mDataStream->createProperty(apexSdkName, "Platform", "", getPvdNamespacedNameForType<const char*>(), PropertyType::Scalar);
+ mDataStream->createProperty(apexSdkName, "Modules", "", getPvdNamespacedNameForType<ObjectRef>(), PropertyType::Array);
+
+ // init framework parameterized classes
+ PvdDataStream& pvdStream = *mDataStream;
+ INIT_PVD_CLASSES_PARAMETERIZED(VertexFormatParameters);
+ INIT_PVD_CLASSES_PARAMETERIZED(VertexBufferParameters);
+ INIT_PVD_CLASSES_PARAMETERIZED(SurfaceBufferParameters);
+ INIT_PVD_CLASSES_PARAMETERIZED(SubmeshParameters);
+ INIT_PVD_CLASSES_PARAMETERIZED(RenderMeshAssetParameters);
+ INIT_PVD_CLASSES_PARAMETERIZED(BufferU8x1);
+ INIT_PVD_CLASSES_PARAMETERIZED(BufferU8x2);
+ INIT_PVD_CLASSES_PARAMETERIZED(BufferU8x3);
+ INIT_PVD_CLASSES_PARAMETERIZED(BufferU8x4);
+ INIT_PVD_CLASSES_PARAMETERIZED(BufferU16x1);
+ INIT_PVD_CLASSES_PARAMETERIZED(BufferU16x2);
+ INIT_PVD_CLASSES_PARAMETERIZED(BufferU16x3);
+ INIT_PVD_CLASSES_PARAMETERIZED(BufferU16x4);
+ INIT_PVD_CLASSES_PARAMETERIZED(BufferU32x1);
+ INIT_PVD_CLASSES_PARAMETERIZED(BufferU32x2);
+ INIT_PVD_CLASSES_PARAMETERIZED(BufferU32x3);
+ INIT_PVD_CLASSES_PARAMETERIZED(BufferU32x4);
+ INIT_PVD_CLASSES_PARAMETERIZED(BufferF32x1);
+ INIT_PVD_CLASSES_PARAMETERIZED(BufferF32x2);
+ INIT_PVD_CLASSES_PARAMETERIZED(BufferF32x3);
+ INIT_PVD_CLASSES_PARAMETERIZED(BufferF32x4);
+
+ // module classes
+ ApexSDKIntl* niApexSDK = GetInternalApexSDK();
+ uint32_t numModules = niApexSDK->getNbModules();
+ for (uint32_t i = 0; i < numModules; ++i)
+ {
+ ModuleIntl* niModule = niApexSDK->getInternalModules()[i];
+ Module* nxModule = niApexSDK->getModules()[i];
+
+ NamespacedName moduleName;
+ moduleName.mNamespace = APEX_PVD_NAMESPACE;
+ moduleName.mName = nxModule->getName();
+ mDataStream->createClass(moduleName);
+
+ niModule->initPvdClasses(*mDataStream);
+ }
+ }
+
+ virtual void initPvdInstances()
+ {
+ //PX_ASSERT(mIsLocked);
+
+ ApexSDK* apexSdk = GetApexSDK();
+ mDataStream->createInstance( NamespacedName(APEX_PVD_NAMESPACE, "ApexSDK"), apexSdk);
+
+ // set platform name
+ NvParameterized::SerializePlatform platform;
+ apexSdk->getCurrentPlatform(platform);
+ const char* platformName = apexSdk->getPlatformName(platform);
+ mDataStream->setPropertyValue(apexSdk, "Platform", platformName);
+
+ mDataStream->setIsTopLevelUIElement(apexSdk, true);
+
+ // add module instances
+ uint32_t numModules = apexSdk->getNbModules();
+ ApexSDKIntl* niApexSDK = GetInternalApexSDK();
+ for (uint32_t i = 0; i < numModules; ++i)
+ {
+ // init pvd instances
+ Module* nxModule = apexSdk->getModules()[i];
+ ModuleIntl* niModule = niApexSDK->getInternalModules()[i];
+
+ NamespacedName moduleName;
+ moduleName.mNamespace = APEX_PVD_NAMESPACE;
+ moduleName.mName = nxModule->getName();
+ mDataStream->createInstance(moduleName, nxModule);
+ mDataStream->pushBackObjectRef(apexSdk, "Modules", nxModule);
+
+ niModule->initPvdInstances(*mDataStream);
+ }
+ }
+
+
+ virtual void initPvdClasses(const NvParameterized::Definition& paramsHandle, const char* pvdClassName)
+ {
+ //PX_ASSERT(mIsLocked);
+
+ if (mParameterizedHandler != NULL)
+ {
+ mParameterizedHandler->initPvdClasses(paramsHandle, pvdClassName);
+ }
+ }
+
+
+ virtual void updatePvd(const void* pvdInstance, NvParameterized::Interface& params, PvdAction::Enum pvdAction)
+ {
+ //PX_ASSERT(mIsLocked);
+
+ if (mParameterizedHandler != NULL)
+ {
+ NvParameterized::Handle paramsHandle(params);
+ mParameterizedHandler->updatePvd(pvdInstance, paramsHandle, pvdAction);
+ }
+ }
+};
+
+
+ApexPvdClient* ApexPvdClient::create( PxPvd* inPvd )
+{
+ return PX_NEW( ApexPvdClientImpl) ( inPvd );
+}
+
+#else
+
+physx::pvdsdk::ApexPvdClient* physx::pvdsdk::ApexPvdClient::create( physx::PxPvd& )
+{
+ return NULL;
+}
+
+#endif // WITHOUT_PVD \ No newline at end of file
diff --git a/APEX_1.4/common/src/ApexQuadricSimplifier.cpp b/APEX_1.4/common/src/ApexQuadricSimplifier.cpp
new file mode 100644
index 00000000..56b5ea27
--- /dev/null
+++ b/APEX_1.4/common/src/ApexQuadricSimplifier.cpp
@@ -0,0 +1,1073 @@
+/*
+ * 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 "Apex.h"
+#include "ApexQuadricSimplifier.h"
+
+#include "ApexSharedUtils.h"
+
+#define MERGE_THRESHOLD 1.0e-6f
+
+// PH: Verification code, must be set to 0 unless you're debugging this code
+#define TESTING 0
+
+namespace nvidia
+{
+namespace apex
+{
+
+ApexQuadricSimplifier::ApexQuadricSimplifier() : mNumDeletedTriangles(0), mNumDeletedVertices(0), mNumDeletedHeapElements(0)
+{
+ mBounds.setEmpty();
+}
+
+
+
+ApexQuadricSimplifier::~ApexQuadricSimplifier()
+{
+ clear();
+}
+
+
+
+void ApexQuadricSimplifier::clear()
+{
+ for (uint32_t i = 0; i < mVertices.size(); i++)
+ {
+ delete mVertices[i];
+ }
+
+ mVertices.clear();
+ mEdges.clear();
+ mTriangles.clear();
+ mHeap.clear();
+ mVertexRefs.clear();
+ mBounds.setEmpty();
+
+ mNumDeletedTriangles = 0;
+ mNumDeletedVertices = 0;
+ mNumDeletedHeapElements = 0;
+}
+
+
+
+void ApexQuadricSimplifier::registerVertex(const PxVec3& pos)
+{
+ mVertices.pushBack(PX_NEW(QuadricVertex)(pos));
+ mBounds.include(pos);
+}
+
+
+
+void ApexQuadricSimplifier::registerTriangle(uint32_t v0, uint32_t v1, uint32_t v2)
+{
+ const uint32_t numVertices = mVertices.size();
+ PX_ASSERT(v0 < numVertices);
+ PX_ASSERT(v1 < numVertices);
+ PX_ASSERT(v2 < numVertices);
+ PX_UNUSED(numVertices);
+
+ QuadricTriangle t;
+ t.init(v0, v1, v2);
+ uint32_t tNr = mTriangles.size();
+ mVertices[t.vertexNr[0]]->mTriangles.pushBack(tNr);
+ mVertices[t.vertexNr[0]]->bReferenced = 1;
+ mVertices[t.vertexNr[1]]->mTriangles.pushBack(tNr);
+ mVertices[t.vertexNr[1]]->bReferenced = 1;
+ mVertices[t.vertexNr[2]]->mTriangles.pushBack(tNr);
+ mVertices[t.vertexNr[2]]->bReferenced = 1;
+ mTriangles.pushBack(t);
+}
+
+
+
+bool ApexQuadricSimplifier::endRegistration(bool mergeCloseVertices, IProgressListener* progressListener)
+{
+ HierarchicalProgressListener progress(100, progressListener);
+
+ if (mergeCloseVertices)
+ {
+ progress.setSubtaskWork(20, "Merge Vertices");
+ mergeVertices();
+ progress.completeSubtask();
+ }
+
+ // remove unreferenced vertices
+ for (uint32_t i = 0; i < mVertices.size(); i++)
+ {
+ if (mVertices[i]->bReferenced == 0)
+ {
+ mVertices[i]->bDeleted = 1;
+ mNumDeletedVertices++;
+ }
+ }
+ progress.setSubtaskWork(20, "Init Edge List");
+
+ mEdges.clear();
+ for (uint32_t i = 0; i < mTriangles.size(); i++)
+ {
+ QuadricTriangle& t = mTriangles[i];
+ QuadricVertex* qv0 = mVertices[t.vertexNr[0]];
+ QuadricVertex* qv1 = mVertices[t.vertexNr[1]];
+ QuadricVertex* qv2 = mVertices[t.vertexNr[2]];
+ Quadric q;
+ q.setFromPlane(qv0->pos, qv1->pos, qv2->pos);
+ qv0->q += q;
+ qv1->q += q;
+ qv2->q += q;
+ QuadricEdge e;
+ e.init((int32_t)t.vertexNr[0], (int32_t)t.vertexNr[1]);
+ mEdges.pushBack(e);
+ e.init((int32_t)t.vertexNr[1], (int32_t)t.vertexNr[2]);
+ mEdges.pushBack(e);
+ e.init((int32_t)t.vertexNr[2], (int32_t)t.vertexNr[0]);
+ mEdges.pushBack(e);
+ }
+
+ progress.completeSubtask();
+
+ // remove duplicated edges
+ progress.setSubtaskWork(10, "Sort Edges");
+ quickSortEdges(0, (int32_t)mEdges.size() - 1);
+ progress.completeSubtask();
+
+ progress.setSubtaskWork(10, "Process Edges");
+
+ physx::Array<QuadricEdge> edges2;
+ uint32_t i = 0;
+ while (i < mEdges.size())
+ {
+ QuadricEdge& e = mEdges[i];
+ edges2.pushBack(e);
+ i++;
+
+ bool border = true;
+ while (i < mEdges.size() && mEdges[i] == e)
+ {
+ i++;
+ border = false;
+ }
+ if (border)
+ {
+ edges2.back().border = true;
+ mVertices[e.vertexNr[0]]->bBorder = 1;
+ mVertices[e.vertexNr[1]]->bBorder = 1;
+ }
+ }
+ progress.completeSubtask();
+
+
+
+
+ progress.setSubtaskWork(10, "Init Edges");
+
+ mEdges.clear();
+ mEdges.resize(edges2.size());
+
+ for (i = 0; i < edges2.size(); i++)
+ {
+ mEdges[i] = edges2[i];
+ QuadricEdge& e = mEdges[i];
+ computeCost(e);
+ mVertices[e.vertexNr[0]]->mEdges.pushBack(i);
+ mVertices[e.vertexNr[1]]->mEdges.pushBack(i);
+ }
+
+ progress.completeSubtask();
+
+ progress.setSubtaskWork(10, "Insert Heap");
+
+ // make heap
+ uint32_t num = mEdges.size();
+ mHeap.clear();
+ mHeap.pushBack(NULL); // dummy, root must be at position 1!
+ for (i = 0; i < num; i++)
+ {
+ mHeap.pushBack(&mEdges[i]);
+ mEdges[i].heapPos = (int32_t)i + 1;
+ }
+
+ progress.completeSubtask();
+
+ progress.setSubtaskWork(mergeCloseVertices ? 20 : 40, "Create Heap");
+
+ for (i = mHeap.size() >> 1; i >= 1; i--)
+ {
+ heapSift(i);
+ }
+
+ progress.completeSubtask();
+
+ mNumDeletedTriangles = 0;
+ mNumDeletedHeapElements = 0;
+ return true;
+}
+
+
+
+uint32_t ApexQuadricSimplifier::simplify(uint32_t subdivision, int32_t maxSteps, float maxError, IProgressListener* progressListener)
+{
+ float maxLength = 0.0f;
+
+ uint32_t nbCollapsed = 0;
+
+ if (subdivision > 0)
+ {
+ maxLength = (mBounds.minimum - mBounds.maximum).magnitude() / subdivision;
+ }
+
+ uint32_t progressCounter = 0;
+ uint32_t maximum = maxSteps >= 0 ? maxSteps : mHeap.size();
+
+ HierarchicalProgressListener progress(100, progressListener);
+ progress.setSubtaskWork(90, "Isomesh simplicifaction");
+#if TESTING
+ testHeap();
+#endif
+
+ while (maxSteps == -1 || (maxSteps-- > 0))
+ {
+
+ if ((++progressCounter & 0xff) == 0)
+ {
+ const int32_t percent = (int32_t)(100 * progressCounter / maximum);
+ progress.setProgress(percent);
+ }
+
+ bool edgeFound = false;
+ QuadricEdge* e = NULL;
+ while (mHeap.size() - mNumDeletedHeapElements > 1)
+ {
+ e = mHeap[1];
+
+ if (maxError >= 0 && e->cost > maxError)
+ {
+ // get me out of here
+ edgeFound = false;
+ break;
+ }
+
+ if (legalCollapse(*e, maxLength))
+ {
+ heapRemove(1, false);
+#if TESTING
+ testHeap();
+#endif
+ edgeFound = true;
+ break;
+ }
+ uint32_t vNr0 = e->vertexNr[0];
+ uint32_t vNr1 = e->vertexNr[1];
+ QuadricVertex* qv0 = mVertices[vNr0];
+ QuadricVertex* qv1 = mVertices[vNr1];
+ heapRemove(1, qv0->bDeleted == 0 && qv1->bDeleted == 0);
+#if TESTING
+ testHeap();
+#endif
+ }
+
+ if (!edgeFound)
+ {
+ break;
+ }
+
+ collapseEdge(*e);
+ nbCollapsed++;
+ }
+
+ progress.completeSubtask();
+ progress.setSubtaskWork(10, "Heap rebuilding");
+
+ progressCounter = mNumDeletedHeapElements;
+ while (mNumDeletedHeapElements > 0)
+ {
+ if ((mNumDeletedHeapElements & 0x7f) == 0)
+ {
+ const int32_t percent = (int32_t)(100 * (progressCounter - mNumDeletedHeapElements) / progressCounter);
+ progress.setProgress(percent);
+ }
+#if TESTING
+ testHeap();
+#endif
+ mNumDeletedHeapElements--;
+ heapUpdate(mHeap.size() - 1 - mNumDeletedHeapElements);
+ }
+
+ progress.completeSubtask();
+#if TESTING
+ testHeap();
+#endif
+ return nbCollapsed;
+}
+
+
+
+int32_t ApexQuadricSimplifier::getTriangleNr(uint32_t v0, uint32_t v1, uint32_t v2) const
+{
+ uint32_t num = mVertices.size();
+
+ if (v0 >= num || v1 >= num || v2 >= num)
+ {
+ return -1;
+ }
+
+ QuadricVertex* qv0 = mVertices[v0];
+
+ if (qv0->bDeleted == 1)
+ {
+ return -1;
+ }
+
+ for (unsigned i = 0; i < qv0->mTriangles.size(); i++)
+ {
+ const QuadricTriangle& t = mTriangles[qv0->mTriangles[i]];
+ if (!t.containsVertex(v1) || !t.containsVertex(v2))
+ {
+ continue;
+ }
+
+ return (int32_t)qv0->mTriangles[i];
+ }
+
+ return -1;
+}
+
+
+
+bool ApexQuadricSimplifier::getTriangle(uint32_t i, uint32_t& v0, uint32_t& v1, uint32_t& v2) const
+{
+ if (i >= mTriangles.size())
+ {
+ return false;
+ }
+
+ const QuadricTriangle& t = mTriangles[i];
+ if (t.deleted)
+ {
+ return false;
+ }
+
+ v0 = t.vertexNr[0];
+ v1 = t.vertexNr[1];
+ v2 = t.vertexNr[2];
+ return true;
+}
+
+
+
+
+
+
+
+
+void ApexQuadricSimplifier::computeCost(QuadricEdge& edge)
+{
+ const uint32_t numSteps = 10;
+
+ QuadricVertex* qv0 = mVertices[edge.vertexNr[0]];
+ QuadricVertex* qv1 = mVertices[edge.vertexNr[1]];
+
+ edge.cost = FLT_MAX;
+ edge.lengthSquared = (qv0->pos - qv1->pos).magnitudeSquared();
+ edge.ratio = -1.0f;
+
+ Quadric q;
+ q = qv0->q + qv1->q;
+
+ float sumCost = 0;
+ for (uint32_t i = 0; i <= numSteps; i++)
+ {
+ const float ratio = 1.0f / numSteps * i;
+ const PxVec3 pos = qv0->pos * (1.0f - ratio) + qv1->pos * ratio;
+
+ const float cost = PxAbs(q.outerProduct(pos));
+ sumCost += cost;
+ if (cost < edge.cost)
+ {
+ edge.cost = cost;
+ edge.ratio = ratio;
+ }
+ }
+
+ if (sumCost < 0.0001f)
+ {
+ edge.cost = 0;
+ edge.ratio = 0.5f;
+ }
+}
+
+
+
+bool ApexQuadricSimplifier::legalCollapse(QuadricEdge& edge, float maxLength)
+{
+ uint32_t vNr0 = edge.vertexNr[0];
+ uint32_t vNr1 = edge.vertexNr[1];
+ QuadricVertex* qv0 = mVertices[vNr0];
+ QuadricVertex* qv1 = mVertices[vNr1];
+
+ // here we make sure that the border does not shrink
+ uint32_t numBorder = 0;
+ if (qv0->bBorder == 1)
+ {
+ numBorder++;
+ }
+ if (qv1->bBorder == 1)
+ {
+ numBorder++;
+ }
+ if (numBorder == 1)
+ {
+ return false;
+ }
+
+ if (qv0->bDeleted == 1 || qv1->bDeleted == 1)
+ {
+ return false;
+ }
+
+ // this is a test to make sure edges don't get too long
+ if (maxLength != 0.0f)
+ {
+ if ((qv0->pos - qv1->pos).magnitudeSquared() > maxLength * maxLength)
+ {
+ return false;
+ }
+ }
+
+ // not legal if there exists v != v0,v1 with (v0,v) and (v1,v) edges
+ // but (v,v0,v1) is not a triangle
+
+ for (uint32_t i = 0; i < qv0->mEdges.size(); i++)
+ {
+ uint32_t v = mEdges[qv0->mEdges[i]].otherVertex(vNr0);
+ bool edgeFound = false;
+ for (uint32_t j = 0; j < qv1->mEdges.size(); j++)
+ {
+ if (mEdges[qv1->mEdges[j]].otherVertex(vNr1) == v)
+ {
+ edgeFound = true;
+ break;
+ }
+ }
+ if (!edgeFound)
+ {
+ continue;
+ }
+
+ bool triFound = false;
+ for (uint32_t j = 0; j < qv0->mTriangles.size(); j++)
+ {
+ QuadricTriangle& t = mTriangles[qv0->mTriangles[j]];
+ if (t.containsVertex(vNr0) && t.containsVertex(vNr1) && t.containsVertex(v))
+ {
+ triFound = true;
+ break;
+ }
+ }
+ if (!triFound)
+ {
+ return false;
+ }
+
+ }
+
+ // any triangle flips?
+ PxVec3 newPos = qv0->pos * (1.0f - edge.ratio) + qv1->pos * edge.ratio;
+ for (uint32_t i = 0; i < 2; i++)
+ {
+ QuadricVertex* v = (i == 0 ? qv0 : qv1);
+ for (uint32_t j = 0; j < v->mTriangles.size(); j++)
+ {
+ QuadricTriangle& t = mTriangles[v->mTriangles[j]];
+ if (t.deleted)
+ {
+ continue;
+ }
+ if (t.containsVertex(vNr0) && t.containsVertex(vNr1)) // this one will be deleted
+ {
+ continue;
+ }
+ PxVec3 p[3], q[3];
+ for (uint32_t k = 0; k < 3; k++)
+ {
+ p[k] = mVertices[t.vertexNr[k]]->pos;
+ if (t.vertexNr[k] == vNr0 || t.vertexNr[k] == vNr1)
+ {
+ q[k] = newPos;
+ }
+ else
+ {
+ q[k] = p[k];
+ }
+ }
+ PxVec3 n0 = (p[1] - p[0]).cross(p[2] - p[0]);
+ // n0.normalize(); // not needed for 90 degree checks
+ PxVec3 n1 = (q[1] - q[0]).cross(q[2] - q[0]);
+ //n1.normalize(); // not needed for 90 degree checks
+ if (n0.dot(n1) < 0.0f)
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+
+
+void ApexQuadricSimplifier::collapseEdge(QuadricEdge& edge)
+{
+ uint32_t vNr0 = edge.vertexNr[0];
+ uint32_t vNr1 = edge.vertexNr[1];
+ QuadricVertex* qv0 = mVertices[vNr0];
+ QuadricVertex* qv1 = mVertices[vNr1];
+
+ PX_ASSERT(qv0->bDeleted == 0);
+ PX_ASSERT(qv1->bDeleted == 0);
+
+ //FILE* f = NULL;
+ //fopen_s(&f, "c:\\collapse.txt", "a");
+ //fprintf_s(f, "Collapse Vertex %d -> %d\n", vNr1, vNr0);
+
+ // contract edge to the vertex0
+ qv0->pos = qv0->pos * (1.0f - edge.ratio) + qv1->pos * edge.ratio;
+ qv0->q += qv1->q;
+
+ // merge the edges
+ for (uint32_t i = 0; i < qv1->mEdges.size(); i++)
+ {
+ QuadricEdge& ei = mEdges[qv1->mEdges[i]];
+ uint32_t vi = ei.otherVertex(vNr1);
+ if (vi == vNr0)
+ {
+ continue;
+ }
+
+ // test whether we already have this neighbor
+ bool found = false;
+ for (uint32_t j = 0; j < qv0->mEdges.size(); j++)
+ {
+ QuadricEdge& ej = mEdges[qv0->mEdges[j]];
+ if (ej.otherVertex(vNr0) == vi)
+ {
+ found = true;
+ break;
+ }
+ }
+ if (found)
+ {
+ mVertices[vi]->removeEdge((int32_t)qv1->mEdges[i]);
+ ei.deleted = true;
+ if (ei.heapPos >= 0)
+ {
+ heapRemove((uint32_t)ei.heapPos, false);
+ }
+#if TESTING
+ testHeap();
+#endif
+ }
+ else
+ {
+ ei.replaceVertex(vNr1, vNr0);
+ qv0->mEdges.pushBack(qv1->mEdges[i]);
+ }
+ }
+ // remove common edge and update adjacent edges
+ for (int32_t i = (int32_t)qv0->mEdges.size() - 1; i >= 0; i--)
+ {
+ QuadricEdge& ei = mEdges[qv0->mEdges[(uint32_t)i]];
+ if (ei.otherVertex(vNr0) == vNr1)
+ {
+ qv0->mEdges.replaceWithLast((uint32_t)i);
+ }
+ else
+ {
+ computeCost(ei);
+ if (ei.heapPos >= 0)
+ {
+ heapUpdate((uint32_t)ei.heapPos);
+ }
+#if TESTING
+ testHeap();
+#endif
+ }
+ }
+
+ // delete collapsed triangles
+ for (int32_t i = (int32_t)qv0->mTriangles.size() - 1; i >= 0; i--)
+ {
+ uint32_t triangleIndex = qv0->mTriangles[(uint32_t)i];
+ QuadricTriangle& t = mTriangles[triangleIndex];
+ if (!t.deleted && t.containsVertex(vNr1))
+ {
+ mNumDeletedTriangles++;
+ t.deleted = true;
+ //fprintf_s(f, "Delete Triangle %d\n", triangleIndex);
+
+ PX_ASSERT(t.containsVertex(vNr0));
+
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ mVertices[t.vertexNr[j]]->removeTriangle((int32_t)triangleIndex);
+ //fprintf_s(f, " v %d\n", t.vertexNr[j]);
+ }
+ }
+ }
+ // update triangles
+ for (uint32_t i = 0; i < qv1->mTriangles.size(); i++)
+ {
+ QuadricTriangle& t = mTriangles[qv1->mTriangles[i]];
+ if (t.deleted)
+ {
+ continue;
+ }
+ if (t.containsVertex(vNr1))
+ {
+ qv0->mTriangles.pushBack(qv1->mTriangles[i]);
+ }
+ t.replaceVertex(vNr1, vNr0);
+ }
+
+ mNumDeletedVertices += qv1->bDeleted == 1 ? 0 : 1;
+ qv1->bDeleted = 1;
+ edge.deleted = true;
+ //fclose(f);
+
+#if TESTING
+ testMesh();
+ testHeap();
+#endif
+}
+
+
+
+void ApexQuadricSimplifier::quickSortEdges(int32_t l, int32_t r)
+{
+ uint32_t i, j, mi;
+ QuadricEdge k, m;
+
+ i = (uint32_t)l;
+ j = (uint32_t)r;
+ mi = (uint32_t)(l + r) / 2;
+ m = mEdges[mi];
+ while (i <= j)
+ {
+ while (mEdges[i] < m)
+ {
+ i++;
+ }
+
+ while (m < mEdges[j])
+ {
+ j--;
+ }
+
+ if (i <= j)
+ {
+ k = mEdges[i];
+ mEdges[i] = mEdges[j];
+ mEdges[j] = k;
+ i++;
+ j--;
+ }
+ }
+
+ if (l < (int32_t)j)
+ {
+ quickSortEdges(l, (int32_t)j);
+ }
+
+ if ((int32_t)i < r)
+ {
+ quickSortEdges((int32_t)i, r);
+ }
+}
+
+
+
+void ApexQuadricSimplifier::quickSortVertexRefs(int32_t l, int32_t r)
+{
+ uint32_t i, j, mi;
+ QuadricVertexRef k, m;
+
+ i = (uint32_t)l;
+ j = (uint32_t)r;
+ mi = (uint32_t)(l + r) / 2;
+ m = mVertexRefs[mi];
+ while (i <= j)
+ {
+ while (mVertexRefs[i] < m)
+ {
+ i++;
+ }
+
+ while (m < mVertexRefs[j])
+ {
+ j--;
+ }
+
+ if (i <= j)
+ {
+ k = mVertexRefs[i];
+ mVertexRefs[i] = mVertexRefs[j];
+ mVertexRefs[j] = k;
+ i++;
+ j--;
+ }
+ }
+
+ if (l < (int32_t)j)
+ {
+ quickSortVertexRefs(l, (int32_t)j);
+ }
+
+ if ((int32_t)i < r)
+ {
+ quickSortVertexRefs((int32_t)i, r);
+ }
+}
+
+
+
+void ApexQuadricSimplifier::mergeVertices()
+{
+ float d = (mBounds.minimum - mBounds.maximum).magnitude() * MERGE_THRESHOLD;
+ float d2 = d * d;
+ mVertexRefs.clear();
+ QuadricVertexRef vr;
+
+ for (uint32_t i = 0; i < mVertices.size(); i++)
+ {
+ QuadricVertex* v = mVertices[i];
+ vr.init(v->pos, (int32_t)i);
+ mVertexRefs.pushBack(vr);
+ }
+
+ quickSortVertexRefs(0, (int32_t)mVertexRefs.size() - 1);
+
+ for (uint32_t i = 0; i < mVertexRefs.size() - 1; i++)
+ {
+ uint32_t iNr = mVertexRefs[i].vertexNr;
+ QuadricVertex* vi = mVertices[iNr];
+
+ if (vi->bDeleted == 1)
+ {
+ continue;
+ }
+
+ PxVec3 pos = mVertexRefs[i].pos;
+ uint32_t j = i + 1;
+ while (j < mVertexRefs.size() && fabs(mVertexRefs[j].pos.x - pos.x) < MERGE_THRESHOLD)
+ {
+ if ((mVertexRefs[j].pos - pos).magnitudeSquared() < d2)
+ {
+ uint32_t jNr = mVertexRefs[j].vertexNr;
+ QuadricVertex* vj = mVertices[jNr];
+ for (uint32_t k = 0; k < vj->mTriangles.size(); k++)
+ {
+ mTriangles[vj->mTriangles[k]].replaceVertex(jNr, iNr);
+ vi->addTriangle((int32_t)vj->mTriangles[k]);
+ }
+ mNumDeletedVertices += vj->bDeleted == 1 ? 0 : 1;
+ vj->bDeleted = 1;
+ }
+ j++;
+ }
+ }
+}
+
+
+
+bool ApexQuadricSimplifier::heapElementSmaller(QuadricEdge* e0, QuadricEdge* e1)
+{
+ // if both costs are 0 use edge length
+ if (e0->cost == 0 && e1->cost == 0)
+ {
+ return e0->lengthSquared < e1->lengthSquared;
+ }
+
+ const float costDiff = e0->cost - e1->cost;
+
+ if (costDiff != 0.0f)
+ {
+ return costDiff < 0;
+ }
+
+ // else use edge length
+ return e0->lengthSquared < e1->lengthSquared;
+}
+
+
+
+void ApexQuadricSimplifier::heapUpdate(uint32_t i)
+{
+ const uint32_t num = mHeap.size() - mNumDeletedHeapElements;
+ PX_ASSERT(1 <= i && i < num);
+ QuadricEdge* e = mHeap[i];
+ while (i > 1)
+ {
+ uint32_t j = i >> 1;
+ if (heapElementSmaller(e, mHeap[j]))
+ {
+ mHeap[i] = mHeap[j];
+ mHeap[i]->heapPos = (int32_t)i;
+ i = j;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ while ((i << 1) < num)
+ {
+ uint32_t j = i << 1;
+ if (j + 1 < num && heapElementSmaller(mHeap[j + 1], mHeap[j]))
+ {
+ j++;
+ }
+
+ if (heapElementSmaller(mHeap[j], e))
+ {
+ mHeap[i] = mHeap[j];
+ mHeap[i]->heapPos = (int32_t)i;
+ i = j;
+ }
+ else
+ {
+ break;
+ }
+ }
+ mHeap[i] = e;
+ mHeap[i]->heapPos = (int32_t)i;
+}
+
+
+
+void ApexQuadricSimplifier::heapSift(uint32_t i)
+{
+ const uint32_t num = mHeap.size() - mNumDeletedHeapElements;
+ PX_ASSERT(1 <= i && i < num);
+ QuadricEdge* e = mHeap[i];
+ while ((i << 1) < num)
+ {
+ uint32_t j = i << 1;
+ if (j + 1 < num && heapElementSmaller(mHeap[j + 1], mHeap[j]))
+ {
+ j++;
+ }
+
+ if (heapElementSmaller(mHeap[j], e))
+ {
+ mHeap[i] = mHeap[j];
+ mHeap[i]->heapPos = (int32_t)i;
+ i = j;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ mHeap[i] = e;
+ mHeap[i]->heapPos = (int32_t)i;
+}
+
+
+
+void ApexQuadricSimplifier::heapRemove(uint32_t i, bool append)
+{
+ const uint32_t num = mHeap.size() - mNumDeletedHeapElements;
+ PX_ASSERT(1 <= i && i < num);
+ QuadricEdge* e = mHeap[i];
+ mHeap[i]->heapPos = -1;
+ mHeap[i] = mHeap[num - 1];
+ if (append)
+ {
+ mHeap[num - 1] = e;
+ mNumDeletedHeapElements++;
+ }
+ else if (mNumDeletedHeapElements > 0)
+ {
+ mHeap[num - 1] = mHeap.back();
+ mHeap[num - 1]->heapPos = -1;
+ mHeap.popBack();
+ }
+ else
+ {
+ mHeap.popBack();
+ }
+
+ PX_ASSERT(e->heapPos == -1);
+ if (i < num - 1)
+ {
+ mHeap[i]->heapPos = (int32_t)i;
+ heapUpdate(i);
+ }
+ PX_ASSERT(e->heapPos == -1);
+}
+
+
+
+void ApexQuadricSimplifier::testHeap()
+{
+ const uint32_t num = mHeap.size() - mNumDeletedHeapElements;
+ for (uint32_t i = 1; i < num; i++)
+ {
+ PX_ASSERT(mHeap[i]->heapPos == (int32_t) i);
+ if ((i << 1) < num)
+ {
+ uint32_t j = i << 1;
+ if (j + 1 < num && heapElementSmaller(mHeap[j + 1], mHeap[j]))
+ {
+ j++;
+ }
+ PX_ASSERT(!heapElementSmaller(mHeap[j], mHeap[i]));
+ }
+ }
+
+ for (uint32_t i = num; i < mHeap.size(); i++)
+ {
+ PX_ASSERT(mHeap[i]->heapPos == -1);
+ }
+}
+
+
+
+void ApexQuadricSimplifier::testMesh()
+{
+ for (uint32_t i = 0; i < mVertices.size(); i++)
+ {
+ QuadricVertex* v = mVertices[i];
+ if (v->bDeleted == 1)
+ {
+ continue;
+ }
+
+ for (uint32_t j = 0; j < v->mEdges.size(); j++)
+ {
+ uint32_t eNr = v->mEdges[j];
+ PX_ASSERT(eNr < mEdges.size());
+ QuadricEdge& e = mEdges[eNr];
+ PX_ASSERT(e.vertexNr[0] == i || e.vertexNr[1] == i);
+ PX_ASSERT(!e.deleted);
+ PX_UNUSED(e);
+ }
+
+ for (uint32_t j = 0; j < (uint32_t)v->mTriangles.size(); j++)
+ {
+ uint32_t tNr = v->mTriangles[j];
+ PX_ASSERT(tNr < mTriangles.size());
+ QuadricTriangle& t = mTriangles[tNr];
+ PX_ASSERT(t.vertexNr[0] == i || t.vertexNr[1] == i || t.vertexNr[2] == i);
+ PX_ASSERT(!t.deleted);
+ PX_UNUSED(t);
+ }
+ }
+
+ for (uint32_t i = 0; i < mEdges.size(); i++)
+ {
+ QuadricEdge& e = mEdges[i];
+ if (e.deleted)
+ {
+ continue;
+ }
+
+ for (uint32_t j = 0; j < 2; j++)
+ {
+ uint32_t vNr = e.vertexNr[j];
+ PX_ASSERT(vNr < mVertices.size());
+ QuadricVertex* v = mVertices[vNr];
+ PX_ASSERT(v->bDeleted == 0);
+ uint32_t found = 0;
+ for (uint32_t k = 0; k < v->mEdges.size(); k++)
+ {
+ found += (v->mEdges[k] == i) ? 1 : 0;
+ }
+
+ PX_ASSERT(found == 1);
+ }
+ }
+ for (uint32_t i = 0; i < mTriangles.size(); i++)
+ {
+ QuadricTriangle& t = mTriangles[i];
+ if (t.deleted)
+ {
+ continue;
+ }
+
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ uint32_t vNr = t.vertexNr[j];
+ PX_ASSERT(vNr < mVertices.size());
+ QuadricVertex* v = mVertices[vNr];
+ PX_ASSERT(v->bDeleted == 0);
+ uint32_t found = 0;
+ for (uint32_t k = 0; k < v->mTriangles.size(); k++)
+ {
+ found += (v->mTriangles[k] == i) ? 1 : 0;
+ }
+
+ PX_ASSERT(found == 1);
+ }
+ }
+}
+
+
+
+
+// --- Quadric Vertex -----------------------------------------
+
+void ApexQuadricSimplifier::QuadricVertex::removeEdge(int32_t edgeNr)
+{
+ for (int32_t i = (int32_t)mEdges.size() - 1; i >= 0; i--)
+ {
+ if (mEdges[(uint32_t)i] == (uint32_t) edgeNr)
+ {
+ mEdges.replaceWithLast((uint32_t)i);
+ }
+ }
+}
+
+
+
+void ApexQuadricSimplifier::QuadricVertex::addTriangle(int32_t triangleNr)
+{
+ for (uint32_t i = 0; i < mTriangles.size(); i++)
+ {
+ if (mTriangles[i] == (uint32_t) triangleNr)
+ {
+ return;
+ }
+ }
+ mTriangles.pushBack((uint32_t)triangleNr);
+}
+
+
+
+void ApexQuadricSimplifier::QuadricVertex::removeTriangle(int32_t triangleNr)
+{
+ uint32_t found = 0;
+ for (int32_t i = (int32_t)mTriangles.size() - 1; i >= 0; i--)
+ {
+ if (mTriangles[(uint32_t)i] == (uint32_t) triangleNr)
+ {
+ mTriangles.replaceWithLast((uint32_t)i);
+ found++;
+ }
+ }
+ PX_ASSERT(found == 1);
+}
+
+}
+} // end namespace nvidia::apex
+
diff --git a/APEX_1.4/common/src/ApexRWLockable.cpp b/APEX_1.4/common/src/ApexRWLockable.cpp
new file mode 100644
index 00000000..280a640b
--- /dev/null
+++ b/APEX_1.4/common/src/ApexRWLockable.cpp
@@ -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.
+
+#include "ApexRWLockable.h"
+#include "PsThread.h"
+#include "PsAtomic.h"
+#include "ApexSDKIntl.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+ApexRWLockable::ApexRWLockable()
+ :
+ mEnabled (true)
+ , mCurrentWriter(0)
+ , mRWLock()
+ , mConcurrentWriteCount (0)
+ , mConcurrentReadCount (0)
+ , mConcurrentErrorCount (0)
+{
+}
+
+ApexRWLockable::~ApexRWLockable()
+{
+}
+
+void ApexRWLockable::setEnabled(bool e)
+{
+ mEnabled = e;
+}
+
+bool ApexRWLockable::isEnabled() const
+{
+ return mEnabled;
+}
+
+void ApexRWLockable::acquireReadLock(const char*, uint32_t) const
+{
+ mRWLock.lockReader();
+}
+
+void ApexRWLockable::acquireWriteLock(const char*, uint32_t) const
+{
+ mRWLock.lockWriter();
+ mCurrentWriter = Thread::getId();
+}
+
+void ApexRWLockable::releaseReadLock(void) const
+{
+ mRWLock.unlockReader();
+}
+
+void ApexRWLockable::releaseWriteLock(void) const
+{
+ mCurrentWriter = 0;
+ mRWLock.unlockWriter();
+}
+
+bool ApexRWLockable::startWrite(bool allowReentry)
+{
+ PX_COMPILE_TIME_ASSERT(sizeof(ThreadReadWriteCount) == 4);
+ mDataLock.lock();
+ bool error = false;
+
+ ThreadReadWriteCount& rwc = mData[Thread::getId()];
+ // check that we are the only thread reading (this allows read->write order on a single thread)
+ error |= mConcurrentReadCount != rwc.counters.readDepth;
+
+ // check no other threads are writing
+ error |= mConcurrentWriteCount != rwc.counters.writeDepth;
+
+ // increment shared write counter
+ shdfnd::atomicIncrement(&mConcurrentWriteCount);
+
+ // in the normal case (re-entry is allowed) then we simply increment
+ // the writeDepth by 1, otherwise (re-entry is not allowed) increment
+ // by 2 to force subsequent writes to fail by creating a mismatch between
+ // the concurrent write counter and the local counter, any value > 1 will do
+ if (allowReentry)
+ rwc.counters.writeDepth++;
+ else
+ rwc.counters.writeDepth += 2;
+ mDataLock.unlock();
+
+ if (error)
+ shdfnd::atomicIncrement(&mConcurrentErrorCount);
+
+ return !error;
+}
+
+void ApexRWLockable::stopWrite(bool allowReentry)
+{
+ shdfnd::atomicDecrement(&mConcurrentWriteCount);
+
+ // decrement depth of writes for this thread
+ mDataLock.lock();
+ nvidia::ThreadImpl::Id id = nvidia::Thread::getId();
+
+ // see comment in startWrite()
+ if (allowReentry)
+ mData[id].counters.writeDepth--;
+ else
+ mData[id].counters.writeDepth -= 2;
+
+ mDataLock.unlock();
+}
+
+nvidia::Thread::Id ApexRWLockable::getCurrentWriter() const
+{
+ return mCurrentWriter;
+}
+
+bool ApexRWLockable::startRead() const
+{
+ shdfnd::atomicIncrement(&mConcurrentReadCount);
+
+ mDataLock.lock();
+ nvidia::ThreadImpl::Id id = nvidia::Thread::getId();
+ ThreadReadWriteCount& rwc = mData[id];
+ rwc.counters.readDepth++;
+ bool success = (rwc.counters.writeDepth > 0 || mConcurrentWriteCount == 0);
+ mDataLock.unlock();
+
+ if (!success)
+ shdfnd::atomicIncrement(&mConcurrentErrorCount);
+
+ return success;
+}
+
+void ApexRWLockable::stopRead() const
+{
+ shdfnd::atomicDecrement(&mConcurrentReadCount);
+ mDataLock.lock();
+ nvidia::ThreadImpl::Id id = nvidia::Thread::getId();
+ mData[id].counters.readDepth--;
+ mDataLock.unlock();
+}
+
+uint32_t ApexRWLockable::getReadWriteErrorCount() const
+{
+ return static_cast<uint32_t>(mConcurrentErrorCount);
+}
+
+ApexRWLockableScopedDisable::ApexRWLockableScopedDisable(RWLockable* rw) : mLockable(static_cast<ApexRWLockable*>(rw))
+{
+ mLockable->setEnabled(false);
+}
+
+ApexRWLockableScopedDisable::~ApexRWLockableScopedDisable()
+{
+ mLockable->setEnabled(true);
+}
+
+ApexRWLockableScopedDisable::ApexRWLockableScopedDisable(const ApexRWLockableScopedDisable& o) : mLockable(o.mLockable)
+{
+}
+
+ApexRWLockableScopedDisable& ApexRWLockableScopedDisable::operator=(const ApexRWLockableScopedDisable&)
+{
+ return *this;
+}
+
+}
+} \ No newline at end of file
diff --git a/APEX_1.4/common/src/ApexResource.cpp b/APEX_1.4/common/src/ApexResource.cpp
new file mode 100644
index 00000000..e0e0aa3d
--- /dev/null
+++ b/APEX_1.4/common/src/ApexResource.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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 "ApexResource.h"
+#include "ApexSDKHelpers.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+ApexResource::~ApexResource()
+{
+ removeSelf();
+}
+
+void ApexResource::removeSelf()
+{
+ if (m_list && m_listIndex != 0xFFFFFFFF)
+ {
+ m_list->remove(m_listIndex);
+ }
+ m_list = NULL;
+ m_listIndex = 0xFFFFFFFF;
+}
+
+} // namespace apex
+} // namespace nvidia
diff --git a/APEX_1.4/common/src/ApexSDKCachedDataImpl.cpp b/APEX_1.4/common/src/ApexSDKCachedDataImpl.cpp
new file mode 100644
index 00000000..8212c653
--- /dev/null
+++ b/APEX_1.4/common/src/ApexSDKCachedDataImpl.cpp
@@ -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.
+ */
+
+
+#include "ApexSDKCachedDataImpl.h"
+#include "nvparameterized/NvParameterized.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+bool ApexSDKCachedDataImpl::registerModuleDataCache(ModuleCachedDataIntl* cache)
+{
+ if (cache == NULL)
+ {
+ return false;
+ }
+
+ for (uint32_t i = 0; i < mModuleCaches.size(); ++i)
+ {
+ if (cache == mModuleCaches[i])
+ {
+ return false;
+ }
+ }
+
+ mModuleCaches.pushBack(cache);
+
+ return true;
+}
+
+bool ApexSDKCachedDataImpl::unregisterModuleDataCache(ModuleCachedDataIntl* cache)
+{
+ if (cache == NULL)
+ {
+ return false;
+ }
+
+ for (uint32_t i = mModuleCaches.size(); i--;)
+ {
+ if (cache == mModuleCaches[i])
+ {
+ mModuleCaches.replaceWithLast(i);
+ break;
+ }
+ }
+
+ return false;
+}
+
+ApexSDKCachedDataImpl::ApexSDKCachedDataImpl()
+{
+}
+
+ApexSDKCachedDataImpl::~ApexSDKCachedDataImpl()
+{
+}
+
+ModuleCachedData* ApexSDKCachedDataImpl::getCacheForModule(AuthObjTypeID moduleID)
+{
+ for (uint32_t i = 0; i < mModuleCaches.size(); ++i)
+ {
+ if (moduleID == mModuleCaches[i]->getModuleID())
+ {
+ return mModuleCaches[i];
+ }
+ }
+
+ return NULL;
+}
+
+PxFileBuf& ApexSDKCachedDataImpl::serialize(PxFileBuf& stream) const
+{
+ stream.storeDword((uint32_t)Version::Current);
+
+ for (uint32_t i = 0; i < mModuleCaches.size(); ++i)
+ {
+ mModuleCaches[i]->serialize(stream);
+ }
+
+ return stream;
+}
+
+PxFileBuf& ApexSDKCachedDataImpl::deserialize(PxFileBuf& stream)
+{
+ clear(false); // false => don't delete cached data for referenced sets
+
+ /*const uint32_t version =*/
+ stream.readDword(); // Original version
+
+ for (uint32_t i = 0; i < mModuleCaches.size(); ++i)
+ {
+ mModuleCaches[i]->deserialize(stream);
+ }
+
+ return stream;
+}
+
+void ApexSDKCachedDataImpl::clear(bool force)
+{
+ for (uint32_t i = mModuleCaches.size(); i--;)
+ {
+ mModuleCaches[i]->clear(force);
+ }
+}
+
+}
+} // end namespace nvidia::apex
diff --git a/APEX_1.4/common/src/ApexSDKHelpers.cpp b/APEX_1.4/common/src/ApexSDKHelpers.cpp
new file mode 100644
index 00000000..2cccff31
--- /dev/null
+++ b/APEX_1.4/common/src/ApexSDKHelpers.cpp
@@ -0,0 +1,310 @@
+/*
+ * 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 "Apex.h"
+#include "ApexSDKIntl.h"
+#include "ApexResource.h"
+#include "ApexSDKHelpers.h"
+#include "AuthorableObjectIntl.h"
+
+#include "ApexPvdClient.h"
+
+#ifndef WITHOUT_PVD
+#include "PxPvdDataStream.h"
+#endif
+
+namespace nvidia
+{
+using namespace physx::pvdsdk;
+
+namespace apex
+{
+
+/*
+ ResourceList functions
+ */
+ResourceList::~ResourceList()
+{
+ clear();
+}
+
+void ResourceList::clear()
+{
+ ScopedWriteLock scopedLock(mRWLock);
+
+ uint32_t s = mArray.size();
+ while (s--)
+ {
+ mArray.back()->release();
+ if (mArray.size() != s)
+ {
+ PX_ASSERT(!"Error - resource did not remove itself from list upon release\n");
+ if (mArray.size())
+ {
+ mArray.popBack(); // Force removal
+ }
+ }
+ }
+}
+
+#ifndef WITHOUT_PVD
+void ResourceList::setupForPvd(const void* owner, const char* listName, const char* entryName)
+{
+ mOwner = owner;
+ mListName = listName;
+ mEntryName = entryName;
+}
+
+
+void ResourceList::initPvdInstances(PvdDataStream& pvdStream)
+{
+ PX_UNUSED(pvdStream);
+ ScopedWriteLock scopedLock(mRWLock);
+
+ for (uint32_t i = 0; i < mArray.size(); ++i)
+ {
+ const void* entry = (const void*)mArray[i];
+ pvdStream.createInstance(NamespacedName(APEX_PVD_NAMESPACE, mEntryName.c_str()), entry);
+ pvdStream.pushBackObjectRef(mOwner, mListName.c_str(), entry);
+ mArray[i]->initPvdInstances(pvdStream);
+ }
+}
+#endif
+
+void ResourceList::add(ApexResourceInterface& resource)
+{
+ ScopedWriteLock scopedLock(mRWLock);
+
+ if (resource.getListIndex() != 0xFFFFFFFF)
+ {
+ PX_ASSERT(!"Error - attempting to add a resource to a list twice");
+ return;
+ }
+ resource.setListIndex(*this, mArray.size());
+ mArray.pushBack(&resource);
+
+ // add to pvd
+ if (mOwner != NULL)
+ {
+ ApexPvdClient* client = GetInternalApexSDK()->getApexPvdClient();
+ if (client != NULL)
+ {
+ if (client->isConnected() && client->getPxPvd().getInstrumentationFlags() & PxPvdInstrumentationFlag::eDEBUG)
+ {
+ PvdDataStream* pvdStream = client->getDataStream();
+ {
+ if (pvdStream != NULL)
+ {
+ pvdStream->createInstance(NamespacedName(APEX_PVD_NAMESPACE, mEntryName.c_str()), &resource);
+ pvdStream->pushBackObjectRef(mOwner, mListName.c_str(), &resource);
+ resource.initPvdInstances(*pvdStream);
+ }
+ }
+ }
+ }
+ }
+}
+
+void ResourceList::remove(uint32_t index)
+{
+ ScopedWriteLock scopedLock(mRWLock);
+
+ PX_ASSERT(index < mArray.size());
+
+ // remove from pvd
+ if (mOwner != NULL)
+ {
+ ApexPvdClient* client = GetInternalApexSDK()->getApexPvdClient();
+ if (client != NULL)
+ {
+ if (client->isConnected() && client->getPxPvd().getInstrumentationFlags() & PxPvdInstrumentationFlag::eDEBUG)
+ {
+ PvdDataStream* pvdStream = client->getDataStream();
+ {
+ if (pvdStream != NULL)
+ {
+ // would be nice to be able to call resource->destroyPvdInstances() here,
+ // but the resource has already been destroyed, so it's too late here
+ ApexResourceInterface* resource = mArray[index];
+ pvdStream->removeObjectRef(mOwner, mListName.c_str(), resource);
+ pvdStream->destroyInstance(resource);
+ }
+ }
+ }
+ }
+ }
+
+ mArray.replaceWithLast(index);
+ if (index < mArray.size())
+ {
+ mArray[index]->setListIndex(*this, index);
+ }
+}
+
+#if 0
+// these are poison
+void writeStreamHeader(PxFileBuf& stream, ApexSimpleString& streamName, uint32_t versionStamp)
+{
+ uint32_t streamStamp = GetStamp(streamName);
+
+ stream.storeDword(versionStamp);
+ stream.storeDword(streamStamp);
+}
+
+uint32_t readStreamHeader(const PxFileBuf& stream, ApexSimpleString& streamName)
+{
+ uint32_t version = stream.readDword();
+
+ uint32_t streamStamp = stream.readDword();
+ if (streamStamp != GetStamp(streamName))
+ {
+ APEX_INVALID_PARAMETER("Wrong input stream. The provided stream has to contain %s.", streamName.c_str());
+ return (uint32_t) - 1;
+ }
+
+ return version;
+}
+#endif
+
+/******************************************************************************
+ * Helper function for loading assets
+ *
+ * This method's purpose is to generalize this process:
+ *
+ * 1. Get the module's namespace resource ID (this also checks that the module is loaded)
+ * 2. If the asset has not been created yet, it will call createResource()
+ * 3. It will call getResource() and return the result
+ *
+ * This allows both the asset's forceLoad method AND the actors init methods to get
+ * an asset pointer.
+ *
+ * This also allows the forceLoad method to call this method repeatedly until getResource()
+ * returns a valid pointer (for async loading).
+
+ *****************************************************************************/
+void* ApexAssetHelper::getAssetFromName(ApexSDKIntl* sdk,
+ const char* authoringTypeName,
+ const char* assetName,
+ ResID& inOutResID,
+ ResID optionalPsID)
+{
+ /* Get the NRP */
+ ResourceProviderIntl* nrp = sdk->getInternalResourceProvider();
+
+ /* Get the asset namespace ID */
+ ResID typePsID = INVALID_RESOURCE_ID;
+ if (optionalPsID == INVALID_RESOURCE_ID)
+ {
+ AuthorableObjectIntl* ao = sdk->getAuthorableObject(authoringTypeName);
+ if (ao)
+ {
+ typePsID = ao->getResID();
+ }
+ else
+ {
+ APEX_INTERNAL_ERROR("Unknown authorable type: %s, please load all required modules.", authoringTypeName);
+ return NULL;
+ }
+ }
+ else
+ {
+ typePsID = optionalPsID;
+ }
+
+ if (inOutResID == INVALID_RESOURCE_ID)
+ {
+ if (optionalPsID == sdk->getOpaqueMeshNameSpace())
+ {
+ AuthorableObjectIntl* ao = sdk->getAuthorableObject(RENDER_MESH_AUTHORING_TYPE_NAME);
+ if (ao)
+ {
+ typePsID = ao->getResID();
+ }
+
+ ResID opaqueMesh = nrp->createResource(optionalPsID, assetName);
+ inOutResID = nrp->createResource(typePsID, assetName);
+ if (!nrp->checkResource(inOutResID))
+ {
+ UserOpaqueMesh* om = (UserOpaqueMesh*)nrp->getResource(opaqueMesh);
+ Asset* asset = sdk->createAsset(assetName, om);
+ nrp->setResource(authoringTypeName, assetName, asset, true, false);
+ }
+ }
+ else
+ {
+ inOutResID = nrp->createResource(typePsID, assetName);
+ }
+ }
+
+ // If resID is valid, get the resource
+ if (inOutResID != INVALID_RESOURCE_ID)
+ {
+ return nrp->getResource(inOutResID);
+ }
+ else
+ {
+ APEX_DEBUG_INFO("ApexAssetHelper::getAssetFromName: Could not create resource ID asset: %s", assetName);
+ return NULL;
+ }
+
+}
+
+
+
+/* getAssetFromNameList
+ *
+ * This method's purpose is to generalize this process:
+ *
+ * 1. Find the asset name in this asset type's name list
+ * 2. Call the SDK's helper method, getAssetFromName
+ *
+ * This allows both the asset's forceLoad method AND the actors init methods to get
+ * an asset pointer.
+ *
+ * This also allows the forceLoad method to call this method repeatedly until getResource()
+ * returns a valid pointer (for async loading).
+ */
+void* ApexAssetHelper::getAssetFromNameList(ApexSDKIntl* sdk,
+ const char* authoringTypeName,
+ physx::Array<AssetNameIDMapping*>& nameIdList,
+ const char* assetName,
+ ResID assetPsId)
+{
+ // find the index of the asset name in our list of name->resID maps
+ uint32_t assetIdx = 0;
+ for (assetIdx = 0; assetIdx < nameIdList.size(); assetIdx++)
+ {
+ if (nameIdList[assetIdx]->assetName == assetName)
+ {
+ break;
+ }
+ }
+
+ // This can't ever happen
+ PX_ASSERT(assetIdx < nameIdList.size());
+
+ if (assetIdx < nameIdList.size())
+ {
+ return ApexAssetHelper::getAssetFromName(sdk,
+ authoringTypeName,
+ assetName,
+ nameIdList[assetIdx]->resID,
+ assetPsId);
+ }
+ else
+ {
+ APEX_DEBUG_WARNING("Request for asset %s of type %s not registered in asset tracker's list", assetName, authoringTypeName);
+ return NULL;
+ }
+}
+
+}
+} // end namespace nvidia::apex
diff --git a/APEX_1.4/common/src/ApexShape.cpp b/APEX_1.4/common/src/ApexShape.cpp
new file mode 100644
index 00000000..30bb398d
--- /dev/null
+++ b/APEX_1.4/common/src/ApexShape.cpp
@@ -0,0 +1,402 @@
+/*
+ * 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 "ApexShape.h"
+#include "RenderDebugInterface.h"
+
+#include "PsMathUtils.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+bool isBoundsEmpty(PxBounds3 bounds)
+{
+ return bounds.minimum.x >= bounds.maximum.x || bounds.minimum.y >= bounds.maximum.y || bounds.minimum.z >= bounds.maximum.z;
+}
+
+
+ApexSphereShape::ApexSphereShape()
+{
+ mRadius = 0.5;
+ mTransform4x4 = PxMat44(PxIdentity);
+ mOldTransform4x4 = PxMat44(PxIdentity);
+ calculateAABB();
+}
+
+void ApexSphereShape::setRadius(float radius)
+{
+ mRadius = radius;
+ calculateAABB();
+};
+
+void ApexSphereShape::setPose(PxMat44 pose)
+{
+ mOldTransform4x4 = mTransform4x4;
+ mTransform4x4 = pose;
+ calculateAABB();
+};
+
+void ApexSphereShape::calculateAABB()
+{
+ //find extreme points of the (transformed by mPose and mTranslation) sphere and construct an AABB from it
+ PxVec3 points[6];
+ points[0] = PxVec3( mRadius, 0.0f, 0.0f);
+ points[1] = PxVec3(-mRadius, 0.0f, 0.0f);
+ points[2] = PxVec3(0.0f, mRadius, 0.0f);
+ points[3] = PxVec3(0.0f, -mRadius, 0.0f);
+ points[4] = PxVec3(0.0f, 0.0f, mRadius);
+ points[5] = PxVec3(0.0f, 0.0f, -mRadius);
+
+ PxVec3 maxBounds(0.0f), minBounds(0.0f);
+ for (int i = 0; i < 6; i++)
+ {
+ PxVec3 tempPoint = mTransform4x4.transform(points[i]);
+ if (i == 0)
+ {
+ minBounds = maxBounds = tempPoint;
+ }
+ else
+ {
+ if (tempPoint.x < minBounds.x)
+ {
+ minBounds.x = tempPoint.x;
+ }
+ if (tempPoint.x > maxBounds.x)
+ {
+ maxBounds.x = tempPoint.x;
+ }
+ if (tempPoint.y < minBounds.y)
+ {
+ minBounds.y = tempPoint.y;
+ }
+ if (tempPoint.y > maxBounds.y)
+ {
+ maxBounds.y = tempPoint.y;
+ }
+ if (tempPoint.z < minBounds.z)
+ {
+ minBounds.z = tempPoint.z;
+ }
+ if (tempPoint.z > maxBounds.z)
+ {
+ maxBounds.z = tempPoint.z;
+ }
+ }
+ }
+ mBounds = PxBounds3(minBounds, maxBounds);
+}
+
+bool ApexSphereShape::intersectAgainstAABB(PxBounds3 bounds)
+{
+ if (!isBoundsEmpty(mBounds) && !isBoundsEmpty(bounds)) //if the bounds have some real volume then check bounds intersection
+ {
+ return bounds.intersects(mBounds);
+ }
+ else
+ {
+ return false; //if the bounds had no volume then return false
+ }
+}
+
+void ApexSphereShape::visualize(RenderDebugInterface* renderer) const
+{
+ const physx::PxMat44& savedPose = *RENDER_DEBUG_IFACE(renderer)->getPoseTyped();
+ RENDER_DEBUG_IFACE(renderer)->setIdentityPose();
+ RENDER_DEBUG_IFACE(renderer)->debugSphere(mTransform4x4.getPosition(), 2);
+ RENDER_DEBUG_IFACE(renderer)->setPose(savedPose);
+}
+
+ApexCapsuleShape::ApexCapsuleShape()
+{
+ mRadius = 1.0f;
+ mHeight = 1.0f;
+ mTransform4x4 = PxMat44(PxIdentity);
+ mOldTransform4x4 = PxMat44(PxIdentity);
+ calculateAABB();
+}
+
+void ApexCapsuleShape::setDimensions(float height, float radius)
+{
+ mRadius = radius;
+ mHeight = height;
+ calculateAABB();
+};
+
+void ApexCapsuleShape::setPose(PxMat44 pose)
+{
+ mOldTransform4x4 = mTransform4x4;
+ mTransform4x4 = pose;
+ calculateAABB();
+};
+
+void ApexCapsuleShape::calculateAABB()
+{
+ //find extreme points of the (transformed by mPose and mTranslation) capsule and construct an AABB from it
+ PxVec3 points[6];
+ points[0] = PxVec3(mRadius, 0.0f, 0.0f);
+ points[1] = PxVec3(-mRadius, 0.0f, 0.0f);
+ points[2] = PxVec3(0.0f, mRadius + mHeight / 2.0f, 0.0f);
+ points[3] = PxVec3(0.0f, -(mRadius + mHeight / 2.0f), 0.0f);
+ points[4] = PxVec3(0.0f, 0.0f, mRadius);
+ points[5] = PxVec3(0.0f, 0.0f, -mRadius);
+
+ PxVec3 maxBounds(0.0f), minBounds(0.0f);
+ for (int i = 0; i < 6; i++)
+ {
+ PxVec3 tempPoint = mTransform4x4.transform(points[i]);
+ if (i == 0)
+ {
+ minBounds = maxBounds = tempPoint;
+ }
+ else
+ {
+ if (tempPoint.x < minBounds.x)
+ {
+ minBounds.x = tempPoint.x;
+ }
+ if (tempPoint.x > maxBounds.x)
+ {
+ maxBounds.x = tempPoint.x;
+ }
+ if (tempPoint.y < minBounds.y)
+ {
+ minBounds.y = tempPoint.y;
+ }
+ if (tempPoint.y > maxBounds.y)
+ {
+ maxBounds.y = tempPoint.y;
+ }
+ if (tempPoint.z < minBounds.z)
+ {
+ minBounds.z = tempPoint.z;
+ }
+ if (tempPoint.z > maxBounds.z)
+ {
+ maxBounds.z = tempPoint.z;
+ }
+ }
+ }
+ mBounds = PxBounds3(minBounds, maxBounds);
+}
+
+bool ApexCapsuleShape::intersectAgainstAABB(PxBounds3 bounds)
+{
+ if (!isBoundsEmpty(mBounds) && !isBoundsEmpty(bounds)) //if the bounds have some real volume then check bounds intersection
+ {
+ return bounds.intersects(mBounds);
+ }
+ else
+ {
+ return false; //if the bounds had no volume then return false
+ }
+}
+
+void ApexCapsuleShape::visualize(RenderDebugInterface* renderer) const
+{
+ const physx::PxMat44& savedPose = *RENDER_DEBUG_IFACE(renderer)->getPoseTyped();
+ RENDER_DEBUG_IFACE(renderer)->setPose(&mTransform4x4.column0.x);
+ RENDER_DEBUG_IFACE(renderer)->debugCapsule(mRadius, mHeight);
+ RENDER_DEBUG_IFACE(renderer)->setPose(savedPose);
+}
+
+ApexBoxShape::ApexBoxShape()
+{
+ mSize = PxVec3(1, 1, 1);
+ mTransform4x4 = PxMat44(PxIdentity);
+ mOldTransform4x4 = PxMat44(PxIdentity);
+ calculateAABB();
+}
+
+void ApexBoxShape::setSize(PxVec3 size)
+{
+ mSize = size;
+ calculateAABB();
+};
+
+void ApexBoxShape::setPose(PxMat44 pose)
+{
+ mOldTransform4x4 = mTransform4x4;
+ mTransform4x4 = pose;
+ calculateAABB();
+};
+
+void ApexBoxShape::calculateAABB()
+{
+ //find extreme points of the (transformed by mPose and mTranslation) box and construct an AABB from it
+ PxVec3 points[8];
+ PxVec3 sizeHalf = PxVec3(mSize.x / 2.0f, mSize.y / 2.0f, mSize.z / 2.0f);
+ points[0] = PxVec3(sizeHalf.x, sizeHalf.y, sizeHalf.z);
+ points[1] = PxVec3(-sizeHalf.x, sizeHalf.y, sizeHalf.z);
+ points[2] = PxVec3(sizeHalf.x, -sizeHalf.y, sizeHalf.z);
+ points[3] = PxVec3(sizeHalf.x, sizeHalf.y, -sizeHalf.z);
+ points[4] = PxVec3(sizeHalf.x, -sizeHalf.y, -sizeHalf.z);
+ points[5] = PxVec3(-sizeHalf.x, -sizeHalf.y, sizeHalf.z);
+ points[6] = PxVec3(-sizeHalf.x, sizeHalf.y, -sizeHalf.z);
+ points[7] = PxVec3(-sizeHalf.x, -sizeHalf.y, -sizeHalf.z);
+
+ PxVec3 maxBounds(0.0f), minBounds(0.0f);
+ for (int i = 0; i < 8; i++)
+ {
+ PxVec3 tempPoint = mTransform4x4.transform(points[i]);
+ if (i == 0)
+ {
+ minBounds = maxBounds = tempPoint;
+ }
+ else
+ {
+ if (tempPoint.x < minBounds.x)
+ {
+ minBounds.x = tempPoint.x;
+ }
+ if (tempPoint.x > maxBounds.x)
+ {
+ maxBounds.x = tempPoint.x;
+ }
+ if (tempPoint.y < minBounds.y)
+ {
+ minBounds.y = tempPoint.y;
+ }
+ if (tempPoint.y > maxBounds.y)
+ {
+ maxBounds.y = tempPoint.y;
+ }
+ if (tempPoint.z < minBounds.z)
+ {
+ minBounds.z = tempPoint.z;
+ }
+ if (tempPoint.z > maxBounds.z)
+ {
+ maxBounds.z = tempPoint.z;
+ }
+ }
+ }
+ mBounds = PxBounds3(minBounds, maxBounds);
+}
+
+bool ApexBoxShape::intersectAgainstAABB(PxBounds3 bounds)
+{
+ if (!isBoundsEmpty(mBounds) && !isBoundsEmpty(bounds)) //if the bounds have some real volume then check bounds intersection
+ {
+ return bounds.intersects(mBounds);
+ }
+ else
+ {
+ return false; //if the bounds had no volume then return false
+ }
+}
+
+void ApexBoxShape::visualize(RenderDebugInterface* renderer) const
+{
+ PxVec3 halfSize = mSize / 2;
+ const PxBounds3 bounds(-halfSize, halfSize);
+ const physx::PxMat44& savedPose = *RENDER_DEBUG_IFACE(renderer)->getPoseTyped();
+ RENDER_DEBUG_IFACE(renderer)->setPose(&mTransform4x4.column0.x);
+ RENDER_DEBUG_IFACE(renderer)->debugBound(bounds);
+ RENDER_DEBUG_IFACE(renderer)->setPose(savedPose);
+}
+
+bool ApexHalfSpaceShape::isPointInside(PxVec3 pos)
+{
+ PxVec3 vecToPos = pos - mOrigin;
+ if (mNormal.dot(vecToPos) < 0.0f)
+ {
+ return true;
+ }
+ return false;
+}
+
+//if any of the corners of the bounds is inside then the bounds is inside
+bool ApexHalfSpaceShape::intersectAgainstAABB(PxBounds3 bounds)
+{
+ PxVec3 center = bounds.getCenter();
+ PxVec3 sizeHalf = bounds.getDimensions() / 2.0f;
+
+ if (isPointInside(PxVec3(center.x + sizeHalf.x, center.y + sizeHalf.y, center.z + sizeHalf.z)))
+ {
+ return true;
+ }
+ if (isPointInside(PxVec3(center.x - sizeHalf.x, center.y + sizeHalf.y, center.z + sizeHalf.z)))
+ {
+ return true;
+ }
+ if (isPointInside(PxVec3(center.x + sizeHalf.x, center.y - sizeHalf.y, center.z + sizeHalf.z)))
+ {
+ return true;
+ }
+ if (isPointInside(PxVec3(center.x + sizeHalf.x, center.y + sizeHalf.y, center.z - sizeHalf.z)))
+ {
+ return true;
+ }
+ if (isPointInside(PxVec3(center.x + sizeHalf.x, center.y - sizeHalf.y, center.z - sizeHalf.z)))
+ {
+ return true;
+ }
+ if (isPointInside(PxVec3(center.x - sizeHalf.x, center.y - sizeHalf.y, center.z + sizeHalf.z)))
+ {
+ return true;
+ }
+ if (isPointInside(PxVec3(center.x - sizeHalf.x, center.y + sizeHalf.y, center.z - sizeHalf.z)))
+ {
+ return true;
+ }
+ if (isPointInside(PxVec3(center.x - sizeHalf.x, center.y - sizeHalf.y, center.z - sizeHalf.z)))
+ {
+ return true;
+ }
+
+ return false;
+
+}
+
+ApexHalfSpaceShape::ApexHalfSpaceShape()
+{
+ mOrigin = mPreviousOrigin = mNormal = mPreviousNormal = PxVec3(0, 0, 0);
+}
+
+void ApexHalfSpaceShape::setOriginAndNormal(PxVec3 origin, PxVec3 normal)
+{
+ mPreviousOrigin = mOrigin;
+ mOrigin = origin;
+ mPreviousNormal = mNormal;
+ mNormal = normal;
+};
+
+void ApexHalfSpaceShape::visualize(RenderDebugInterface* renderer) const
+{
+ float radius = 2 * mNormal.magnitude();
+ const PxPlane plane(mOrigin, mNormal);
+ const physx::PxMat44& savedPose = *RENDER_DEBUG_IFACE(renderer)->getPoseTyped();
+ RENDER_DEBUG_IFACE(renderer)->setIdentityPose();
+ RENDER_DEBUG_IFACE(renderer)->debugPlane(plane, radius, radius);
+ RENDER_DEBUG_IFACE(renderer)->debugRay(mOrigin, mOrigin + mNormal);
+ RENDER_DEBUG_IFACE(renderer)->setPose(savedPose);
+}
+
+static PX_INLINE PxMat44 OriginAndNormalToPose(const PxVec3& origin, const PxVec3& normal)
+{
+ return PxMat44(physx::shdfnd::rotFrom2Vectors(PxVec3(0, 1, 0), normal), origin);
+}
+
+PxMat44 ApexHalfSpaceShape::getPose() const
+{
+ return OriginAndNormalToPose(mOrigin, mNormal);
+}
+
+PxMat44 ApexHalfSpaceShape::getPreviousPose() const
+{
+ return OriginAndNormalToPose(mPreviousOrigin, mPreviousNormal);
+}
+
+}
+} // end namespace nvidia::apex
+
diff --git a/APEX_1.4/common/src/ApexSharedUtils.cpp b/APEX_1.4/common/src/ApexSharedUtils.cpp
new file mode 100644
index 00000000..9cdc2a30
--- /dev/null
+++ b/APEX_1.4/common/src/ApexSharedUtils.cpp
@@ -0,0 +1,4177 @@
+/*
+ * 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 "Apex.h"
+#include "ApexSharedUtils.h"
+#include "ApexRand.h"
+#include "PsMemoryBuffer.h"
+
+#if PX_PHYSICS_VERSION_MAJOR == 3
+#include "PxPhysics.h"
+#include "cooking/PxConvexMeshDesc.h"
+#include "cooking/PxCooking.h"
+#include <PxShape.h>
+#endif
+
+#include "PsSort.h"
+#include "PsBitUtils.h"
+
+#include "ApexSDKIntl.h"
+
+#include "Cof44.h"
+#include "PxPlane.h"
+
+#include "PsVecMath.h"
+#include "PsMathUtils.h"
+
+#include "../../shared/general/stan_hull/include/StanHull.h"
+
+#define REDUCE_CONVEXHULL_INPUT_POINT_SET 0
+
+namespace nvidia
+{
+namespace apex
+{
+// Local utilities
+
+// copied from //sw/physx/PhysXSDK/3.3/trunk/Samples/SampleBase/RenderClothActor.cpp
+float det(PxVec4 v0, PxVec4 v1, PxVec4 v2, PxVec4 v3)
+{
+ const PxVec3& d0 = reinterpret_cast<const PxVec3&>(v0);
+ const PxVec3& d1 = reinterpret_cast<const PxVec3&>(v1);
+ const PxVec3& d2 = reinterpret_cast<const PxVec3&>(v2);
+ const PxVec3& d3 = reinterpret_cast<const PxVec3&>(v3);
+
+ return v0.w * d1.cross(d2).dot(d3)
+ - v1.w * d0.cross(d2).dot(d3)
+ + v2.w * d0.cross(d1).dot(d3)
+ - v3.w * d0.cross(d1).dot(d2);
+}
+
+PX_INLINE float det(const PxMat44& m)
+{
+ return det(m.column0, m.column1, m.column2, m.column3);
+}
+
+PX_INLINE float extentDistance(float min0, float max0, float min1, float max1)
+{
+ return PxMax(min0 - max1, min1 - max0);
+}
+
+PX_INLINE float extentDistanceAndNormalDirection(float min0, float max0, float min1, float max1, float& midpoint, bool& normalPointsFrom0to1)
+{
+ const float d01 = min1 - max0;
+ const float d10 = min0 - max1;
+
+ normalPointsFrom0to1 = d01 > d10;
+
+ if (normalPointsFrom0to1)
+ {
+ midpoint = 0.5f*(min1 + max0);
+ return d01;
+ }
+ else
+ {
+ midpoint = 0.5f*(min0 + max1);
+ return d10;
+ }
+}
+
+PX_INLINE void extentOverlapTimeInterval(float& tIn, float& tOut, float vel0, float min0, float max0, float min1, float max1)
+{
+ if (PxAbs(vel0) < PX_EPS_F32)
+ {
+ // Not moving
+ if (extentDistance(min0, max0, min1, max1) < 0.0f)
+ {
+ // Always overlap
+ tIn = -PX_MAX_F32;
+ tOut = PX_MAX_F32;
+ }
+ else
+ {
+ // Never overlap
+ tIn = PX_MAX_F32;
+ tOut = -PX_MAX_F32;
+ }
+ return;
+ }
+
+ const float recipVel0 = 1.0f / vel0;
+
+ if (vel0 > 0.0f)
+ {
+ tIn = (min1 - max0) * recipVel0;
+ tOut = (max1 - min0) * recipVel0;
+ }
+ else
+ {
+ tIn = (max1 - min0) * recipVel0;
+ tOut = (min1 - max0) * recipVel0;
+ }
+}
+
+PX_INLINE bool updateTimeIntervalAndNormal(float& in, float& out, float& tNormal, PxVec3* normal, float tIn, float tOut, const PxVec3& testNormal)
+{
+ if (tIn >= out || tOut <= in)
+ {
+ return false; // No intersection will occur
+ }
+
+ if (normal != NULL && tIn > tNormal)
+ {
+ tNormal = tIn;
+ *normal = testNormal;
+ }
+
+ in = PxMax(tIn, in);
+ out = PxMin(tOut, out);
+
+ return true;
+}
+
+PX_INLINE void getExtent(float& min, float& max, const void* points, uint32_t pointCount, const uint32_t pointByteStride, const PxVec3& normal)
+{
+ min = PX_MAX_F32;
+ max = -PX_MAX_F32;
+ const PxVec3* p = (const PxVec3*)points;
+ for (uint32_t i = 0; i < pointCount; ++i, p = (const PxVec3*)(((const uint8_t*)p) + pointByteStride))
+ {
+ const float d = normal.dot(*p);
+ if (d < min)
+ {
+ min = d;
+ }
+ if (d > max)
+ {
+ max = d;
+ }
+ }
+}
+
+PX_INLINE bool intersectPlanes(PxVec3& point, const PxPlane& p0, const PxPlane& p1, const PxPlane& p2)
+{
+ const PxVec3 p1xp2 = p1.n.cross(p2.n);
+ const float det = p0.n.dot(p1xp2);
+ if (PxAbs(det) < 1.0e-18)
+ {
+ return false; // No intersection
+ }
+ point = (-p0.d * p1xp2 - p1.d * (p2.n.cross(p0.n)) - p2.d * (p0.n.cross(p1.n))) / det;
+ return true;
+}
+
+PX_INLINE bool pointInsidePlanes(const PxVec3& point, const PxPlane* planes, uint32_t numPlanes, float eps)
+{
+ for (uint32_t i = 0; i < numPlanes; ++i)
+ {
+ const PxPlane& plane = planes[i];
+ if (plane.distance(point) > eps)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+static void findPrincipleComponents(PxVec3& mean, PxVec3& variance, PxMat33& axes, const PxVec3* points, uint32_t pointCount)
+{
+ // Find the average of the points
+ mean = PxVec3(0.0f);
+ for (uint32_t i = 0; i < pointCount; ++i)
+ {
+ mean += points[i];
+ }
+
+ PxMat33 cov = PxMat33(PxZero);
+
+ if (pointCount > 0)
+ {
+ mean *= 1.0f/pointCount;
+
+ // Now subtract the mean and add to the covariance matrix cov
+ for (uint32_t i = 0; i < pointCount; ++i)
+ {
+ const PxVec3 relativePoint = points[i] - mean;
+ for (uint32_t j = 0; j < 3; ++j)
+ {
+ for (uint32_t k = 0; k < 3; ++k)
+ {
+ cov(j,k) += relativePoint[j]*relativePoint[k];
+ }
+ }
+ }
+ cov *= 1.0f/pointCount;
+ }
+
+ // Now diagonalize cov
+ variance = diagonalizeSymmetric(axes, cov);
+}
+
+#if 0
+/* John's k-means clustering function, slightly specialized */
+static uint32_t kmeans_cluster(const PxVec3* input,
+ uint32_t inputCount,
+ PxVec3* clusters,
+ uint32_t clumpCount,
+ float threshold = 0.01f, // controls how long it works to converge towards a least errors solution.
+ float collapseDistance = 0.0001f) // distance between clumps to consider them to be essentially equal.
+{
+ uint32_t convergeCount = 64; // maximum number of iterations attempting to converge to a solution..
+ physx::Array<uint32_t> counts(clumpCount);
+ float error = 0.0f;
+ if (inputCount <= clumpCount) // if the number of input points is less than our clumping size, just return the input points.
+ {
+ clumpCount = inputCount;
+ for (uint32_t i = 0; i < inputCount; ++i)
+ {
+ clusters[i] = input[i];
+ counts[i] = 1;
+ }
+ }
+ else
+ {
+ physx::Array<PxVec3> centroids(clumpCount);
+
+ // Take a sampling of the input points as initial centroid estimates.
+ for (uint32_t i = 0; i < clumpCount; ++i)
+ {
+ uint32_t index = (i*inputCount)/clumpCount;
+ PX_ASSERT( index < inputCount );
+ clusters[i] = input[index];
+ }
+
+ // Here is the main convergence loop
+ float old_error = PX_MAX_F32; // old and initial error estimates are max float
+ error = PX_MAX_F32;
+ do
+ {
+ old_error = error; // preserve the old error
+ // reset the counts and centroids to current cluster location
+ for (uint32_t i = 0; i < clumpCount; ++i)
+ {
+ counts[i] = 0;
+ centroids[i] = PxVec3(0.0f);
+ }
+ error = 0.0f;
+ // For each input data point, figure out which cluster it is closest too and add it to that cluster.
+ for (uint32_t i = 0; i < inputCount; ++i)
+ {
+ float min_distance2 = PX_MAX_F32;
+ uint32_t j_nearest = 0;
+ // find the nearest clump to this point.
+ for (uint32_t j = 0; j < clumpCount; ++j)
+ {
+ const float distance2 = (input[i]-clusters[j]).magnitudeSquared();
+ if (distance2 < min_distance2)
+ {
+ min_distance2 = distance2;
+ j_nearest = j; // save which clump this point indexes
+ }
+ }
+ centroids[j_nearest] += input[i];
+ ++counts[j_nearest]; // increment the counter indicating how many points are in this clump.
+ error += min_distance2; // save the error accumulation
+ }
+ // Now, for each clump, compute the mean and store the result.
+ for (uint32_t i = 0; i < clumpCount; ++i)
+ {
+ if (counts[i]) // if this clump got any points added to it...
+ {
+ centroids[i] /= (float)counts[i]; // compute the average center of the points in this clump.
+ clusters[i] = centroids[i]; // store it as the new cluster.
+ }
+ }
+ // decrement the convergence counter and bail if it is taking too long to converge to a solution.
+ --convergeCount;
+ if (convergeCount == 0)
+ {
+ break;
+ }
+ if (error < threshold) // early exit if our first guess is already good enough (if all input points are the same)
+ {
+ break;
+ }
+ } while (PxAbs(error - old_error) > threshold); // keep going until the error is reduced by this threshold amount.
+ }
+
+ // ok..now we prune the clumps if necessary.
+ // The rules are; first, if a clump has no 'counts' then we prune it as it's unused.
+ // The second, is if the centroid of this clump is essentially the same (based on the distance tolerance)
+ // as an existing clump, then it is pruned and all indices which used to point to it, now point to the one
+ // it is closest too.
+ uint32_t outCount = 0; // number of clumps output after pruning performed.
+ float d2 = collapseDistance*collapseDistance; // squared collapse distance.
+ for (uint32_t i = 0; i < clumpCount; ++i)
+ {
+ if (counts[i] == 0) // if no points ended up in this clump, eliminate it.
+ {
+ continue;
+ }
+ // see if this clump is too close to any already accepted clump.
+ bool add = true;
+ for (uint32_t j = 0; j < outCount; ++j)
+ {
+ if ((clusters[i]-clusters[j]).magnitudeSquared() < d2)
+ {
+ add = false; // we do not add this clump
+ break;
+ }
+ }
+ if (add)
+ {
+ clusters[outCount++] = clusters[i];
+ }
+ }
+
+ clumpCount = outCount;
+
+ return clumpCount;
+};
+#endif
+
+// barycentric utilities
+void generateBarycentricCoordinatesTri(const PxVec3& pa, const PxVec3& pb, const PxVec3& pc, const PxVec3& p, float& s, float& t)
+{
+ // pe = pb-ba, pf = pc-pa
+ // Barycentric coordinates: (s,t) -> pa + s*pe + t*pf
+ // Minimize: [s*pe + t*pf - (p-pa)]^2
+ // Minimize: a s^2 + 2 b s t + c t^2 + 2 d s + 2 e t + f
+ // Minimization w.r.t s and t :
+ // as + bt = -d
+ // bs + ct = -e
+
+ PxVec3 pe = pb - pa;
+ PxVec3 pf = pc - pa;
+ PxVec3 pg = pa - p;
+
+ float a = pe.dot(pe);
+ float b = pe.dot(pf);
+ float c = pf.dot(pf);
+ float d = pe.dot(pg);
+ float e = pf.dot(pg);
+
+ float det = a * c - b * b;
+ if (det != 0.0f)
+ {
+ s = (b * e - c * d) / det;
+ t = (b * d - a * e) / det;
+ }
+}
+
+void generateBarycentricCoordinatesTet(const PxVec3& pa, const PxVec3& pb, const PxVec3& pc, const PxVec3& pd, const PxVec3& p, PxVec3& bary)
+{
+ PxVec3 q = p - pd;
+ PxVec3 q0 = pa - pd;
+ PxVec3 q1 = pb - pd;
+ PxVec3 q2 = pc - pd;
+ PxMat33 m(q0,q1,q2);
+ float det = m.getDeterminant();
+ m.column0 = q;
+ bary.x = m.getDeterminant();
+ m.column0 = q0;
+ m.column1 = q;
+ bary.y = m.getDeterminant();
+ m.column1 = q1;
+ m.column2 = q;
+ bary.z = m.getDeterminant();
+ if (det != 0.0f)
+ {
+ bary /= det;
+ }
+}
+
+/* TriangleFrame */
+
+size_t TriangleFrame::s_offsets[TriangleFrame::VertexFieldCount];
+
+static TriangleFrameBuilder sTriangleFrameBuilder;
+
+/*
+ File-local functions and definitions
+ */
+
+struct Marker
+{
+ float pos;
+ uint32_t id; // lsb = type (0 = max, 1 = min), other bits used for object index
+
+ void set(float _pos, int32_t _id)
+ {
+ pos = _pos;
+ id = (uint32_t)_id;
+ }
+};
+
+static int compareMarkers(const void* A, const void* B)
+{
+ // Sorts by value. If values equal, sorts min types greater than max types, to reduce the # of overlaps
+ const float delta = ((Marker*)A)->pos - ((Marker*)B)->pos;
+ return delta != 0 ? (delta < 0 ? -1 : 1) : ((int)(((Marker*)A)->id & 1) - (int)(((Marker*)B)->id & 1));
+}
+
+struct EdgeWithFace
+{
+ EdgeWithFace() {}
+ EdgeWithFace(uint32_t v0, uint32_t v1, uint32_t face, uint32_t oppositeFace, bool sort = false) : faceIndex(face), v0Index(v0), v1Index(v1), opposite(oppositeFace)
+ {
+ if (sort)
+ {
+ if (v1Index < v0Index)
+ {
+ nvidia::swap(v0Index, v1Index);
+ }
+ }
+ }
+
+ bool operator == (const EdgeWithFace& e)
+ {
+ return v0Index == e.v0Index && v1Index == e.v1Index;
+ }
+
+ uint32_t faceIndex;
+ uint32_t v0Index;
+ uint32_t v1Index;
+ uint32_t opposite;
+};
+
+/*
+ Global utilities
+ */
+
+void boundsCalculateOverlaps(physx::Array<IntPair>& overlaps, Bounds3Axes axesToUse, const BoundsRep* bounds, uint32_t boundsCount, uint32_t boundsByteStride,
+ const BoundsInteractions& interactions, bool append)
+{
+ if (!append)
+ {
+ overlaps.reset();
+ }
+
+ uint32_t D = 0;
+ uint32_t axisNums[3];
+ for (unsigned i = 0; i < 3; ++i)
+ {
+ if ((axesToUse >> i) & 1)
+ {
+ axisNums[D++] = i;
+ }
+ }
+
+ if (D == 0 || D > 3)
+ {
+ return;
+ }
+
+ physx::Array< physx::Array<Marker> > axes;
+ axes.resize(D);
+ uint32_t overlapCount[3];
+
+ for (uint32_t n = 0; n < D; ++n)
+ {
+ const uint32_t axisNum = axisNums[n];
+ physx::Array<Marker>& axis = axes[n];
+ overlapCount[n] = 0;
+ axis.resize(2 * boundsCount);
+ uint8_t* boundsPtr = (uint8_t*)bounds;
+ for (uint32_t i = 0; i < boundsCount; ++i, boundsPtr += boundsByteStride)
+ {
+ const BoundsRep& boundsRep = *(const BoundsRep*)boundsPtr;
+ const PxBounds3& box = boundsRep.aabb;
+ float min = box.minimum[axisNum];
+ float max = box.maximum[axisNum];
+ if (min >= max)
+ {
+ const float mid = 0.5f * (min + max);
+ float pad = 0.000001f * fabsf(mid);
+ min = mid - pad;
+ max = mid + pad;
+ }
+ axis[i << 1].set(min, (int32_t)i << 1 | 1);
+ axis[i << 1 | 1].set(max, (int32_t)i << 1);
+ }
+ qsort(axis.begin(), axis.size(), sizeof(Marker), compareMarkers);
+ uint32_t localOverlapCount = 0;
+ for (uint32_t i = 0; i < axis.size(); ++i)
+ {
+ Marker& marker = axis[i];
+ if (marker.id & 1)
+ {
+ overlapCount[n] += localOverlapCount;
+ ++localOverlapCount;
+ }
+ else
+ {
+ --localOverlapCount;
+ }
+ }
+ }
+
+ unsigned int axis0;
+ unsigned int axis1;
+ unsigned int axis2;
+ unsigned int maxBin;
+ if (D == 1)
+ {
+ maxBin = 0;
+ axis0 = axisNums[0];
+ axis1 = axis0;
+ axis2 = axis0;
+ }
+ else if (D == 2)
+ {
+ if (overlapCount[0] < overlapCount[1])
+ {
+ maxBin = 0;
+ axis0 = axisNums[0];
+ axis1 = axisNums[1];
+ axis2 = axis0;
+ }
+ else
+ {
+ maxBin = 1;
+ axis0 = axisNums[1];
+ axis1 = axisNums[0];
+ axis2 = axis0;
+ }
+ }
+ else
+ {
+ maxBin = overlapCount[0] < overlapCount[1] ? (overlapCount[0] < overlapCount[2] ? 0U : 2U) : (overlapCount[1] < overlapCount[2] ? 1U : 2U);
+ axis0 = axisNums[maxBin];
+ axis1 = (axis0 + 1) % 3;
+ axis2 = (axis0 + 2) % 3;
+ }
+
+ const uint64_t interactionBits = interactions.bits;
+
+ IndexBank<uint32_t> localOverlaps(boundsCount);
+ physx::Array<Marker>& axis = axes[maxBin];
+ float boxMin1 = 0.0f;
+ float boxMax1 = 0.0f;
+ float boxMin2 = 0.0f;
+ float boxMax2 = 0.0f;
+
+ for (uint32_t i = 0; i < axis.size(); ++i)
+ {
+ Marker& marker = axis[i];
+ const uint32_t index = marker.id >> 1;
+ if (marker.id & 1)
+ {
+ const BoundsRep& boundsRep = *(const BoundsRep*)((uint8_t*)bounds + index*boundsByteStride);
+ const uint8_t interaction = (uint8_t)((interactionBits >> (boundsRep.type << 3)) & 0xFF);
+ const PxBounds3& box = boundsRep.aabb;
+ // These conditionals compile out with optimization:
+ if (D > 1)
+ {
+ boxMin1 = box.minimum[axis1];
+ boxMax1 = box.maximum[axis1];
+ if (D == 3)
+ {
+ boxMin2 = box.minimum[axis2];
+ boxMax2 = box.maximum[axis2];
+ }
+ }
+ const uint32_t localOverlapCount = localOverlaps.usedCount();
+ const uint32_t* localOverlapIndices = localOverlaps.usedIndices();
+ for (uint32_t j = 0; j < localOverlapCount; ++j)
+ {
+ const uint32_t overlapIndex = localOverlapIndices[j];
+ const BoundsRep& overlapBoundsRep = *(const BoundsRep*)((uint8_t*)bounds + overlapIndex*boundsByteStride);
+ if ((interaction >> overlapBoundsRep.type) & 1)
+ {
+ const PxBounds3& overlapBox = overlapBoundsRep.aabb;
+ // These conditionals compile out with optimization:
+ if (D > 1)
+ {
+ if (boxMin1 >= overlapBox.maximum[axis1] || boxMax1 <= overlapBox.minimum[axis1])
+ {
+ continue;
+ }
+ if (D == 3)
+ {
+ if (boxMin2 >= overlapBox.maximum[axis2] || boxMax2 <= overlapBox.minimum[axis2])
+ {
+ continue;
+ }
+ }
+ }
+ // Add overlap
+ IntPair& pair = overlaps.insert();
+ pair.i0 = (int32_t)index;
+ pair.i1 = (int32_t)overlapIndex;
+ }
+ }
+ PX_ASSERT(localOverlaps.isValid(index));
+ PX_ASSERT(!localOverlaps.isUsed(index));
+ localOverlaps.use(index);
+ }
+ else
+ {
+ // Remove local overlap
+ PX_ASSERT(localOverlaps.isValid(index));
+ localOverlaps.free(index);
+ }
+ }
+}
+
+
+/*
+ ConvexHullImpl functions
+ */
+
+ConvexHullImpl::ConvexHullImpl() : mParams(NULL), mOwnsParams(false)
+{
+}
+
+ConvexHullImpl::~ConvexHullImpl()
+{
+ term();
+}
+
+// If params == NULL, ConvexHullImpl will build (and own) its own internal parameters
+void ConvexHullImpl::init(NvParameterized::Interface* params)
+{
+ term();
+
+ if (params != NULL)
+ {
+ mParams = DYNAMIC_CAST(ConvexHullParameters*)(params);
+ if (mParams == NULL)
+ {
+ PX_ASSERT(!"params must be ConvexHullParameters");
+ }
+ }
+ else
+ {
+ NvParameterized::Traits* traits = GetInternalApexSDK()->getParameterizedTraits();
+ mParams = DYNAMIC_CAST(ConvexHullParameters*)(traits->createNvParameterized(ConvexHullParameters::staticClassName()));
+ PX_ASSERT(mParams != NULL);
+ if (mParams != NULL)
+ {
+ mOwnsParams = true;
+ setEmpty();
+ }
+ }
+}
+
+
+NvParameterized::Interface* ConvexHullImpl::giveOwnersipOfNvParameters()
+{
+ if (mOwnsParams)
+ {
+ mOwnsParams = false;
+ return mParams;
+ }
+
+ return NULL;
+}
+
+// Releases parameters if it owns them
+void ConvexHullImpl::term()
+{
+ if (mParams != NULL && mOwnsParams)
+ {
+ mParams->destroy();
+ }
+ mParams = NULL;
+ mOwnsParams = false;
+}
+
+static int compareEdgesWithFaces(const void* A, const void* B)
+{
+ const EdgeWithFace& eA = *(const EdgeWithFace*)A;
+ const EdgeWithFace& eB = *(const EdgeWithFace*)B;
+ if (eA.v0Index != eB.v0Index)
+ {
+ return (int)eA.v0Index - (int)eB.v0Index;
+ }
+ if (eA.v1Index != eB.v1Index)
+ {
+ return (int)eA.v1Index - (int)eB.v1Index;
+ }
+ return (int)eA.faceIndex - (int)eB.faceIndex;
+}
+
+void ConvexHullImpl::buildFromDesc(const ConvexHullDesc& desc)
+{
+ if (!desc.isValid())
+ {
+ setEmpty();
+ return;
+ }
+
+ setEmpty();
+
+ Array<PxPlane> uniquePlanes;
+ Array<uint32_t> edges;
+ Array<float> widths;
+
+ NvParameterized::Handle handle(*mParams);
+
+ // Copy vertices and compute bounds
+ mParams->getParameterHandle("vertices", handle);
+ mParams->resizeArray(handle, (int32_t)desc.numVertices);
+ const uint8_t* vertPointer = (const uint8_t*)desc.vertices;
+ for (uint32_t i = 0; i < desc.numVertices; ++i, vertPointer += desc.vertexStrideBytes)
+ {
+ mParams->vertices.buf[i] = *(const PxVec3*)vertPointer;
+ mParams->bounds.include(mParams->vertices.buf[i]);
+ }
+
+ PxVec3 center;
+ center = mParams->bounds.getCenter();
+
+ // Find faces and compute volume
+ physx::Array<EdgeWithFace> fEdges;
+ const uint32_t* indices = desc.indices;
+ mParams->volume = 0.0f;
+ for (uint32_t fI = 0; fI < desc.numFaces; ++fI)
+ {
+ const uint32_t indexCount = (const uint32_t)desc.faceIndexCounts[fI];
+ const PxVec3& vI0 = mParams->vertices.buf[indices[0]];
+ PxVec3 normal(0.0f);
+ for (uint32_t pI = 1; pI < indexCount-1; ++pI)
+ {
+ const uint32_t i1 = indices[pI];
+ const uint32_t i2 = indices[pI+1];
+ const PxVec3& vI1 = mParams->vertices.buf[i1];
+ const PxVec3& vI2 = mParams->vertices.buf[i2];
+ const PxVec3 eI1 = vI1 - vI0;
+ const PxVec3 eI2 = vI2 - vI0;
+ PxVec3 normalI = eI1.cross(eI2);
+ mParams->volume += (normalI.dot(vI0 - center));
+ normal += normalI;
+ }
+
+ const bool normalValid = normal.normalize() > 0.0f;
+
+ float d = 0.0f;
+ for (uint32_t pI = 0; pI < indexCount; ++pI)
+ {
+ d -= normal.dot(mParams->vertices.buf[indices[pI]]);
+ }
+ d /= indexCount;
+
+ uint32_t oppositeFace = 0;
+ uint32_t faceN = uniquePlanes.size(); // unless we find an opposite
+
+ if (normalValid)
+ {
+ // See if this face is opposite an existing one
+ for (uint32_t j = 0; j < uniquePlanes.size(); ++j)
+ {
+ if (normal.dot(uniquePlanes[j].n) < -0.999999f && widths[j] == PX_MAX_F32)
+ {
+ oppositeFace = 1;
+ faceN = j;
+ widths[j] = -d - uniquePlanes[j].d;
+ break;
+ }
+ }
+ }
+
+ if (!oppositeFace)
+ {
+ uniquePlanes.pushBack(PxPlane(normal, d));
+ widths.pushBack(PX_MAX_F32);
+ }
+
+ for (uint32_t pI = 0; pI < indexCount; ++pI)
+ {
+ fEdges.pushBack(EdgeWithFace(indices[pI], indices[(pI+1)%indexCount], faceN, oppositeFace, true));
+ }
+
+ indices += indexCount;
+ }
+
+ // Create a map from current plane indices to the arrangement we'll have after the following loop
+ // This map will be its inverse
+ physx::Array<uint32_t> invMap;
+ invMap.resize(2*widths.size());
+ for (uint32_t i = 0; i < invMap.size(); ++i)
+ {
+ invMap[i] = i;
+ }
+
+ // This ensures that all the slabs are represented first in the planes list
+ uint32_t slabCount = widths.size();
+ for (uint32_t i = widths.size(); i--;)
+ {
+ if (widths[i] == PX_MAX_F32)
+ {
+ --slabCount;
+ nvidia::swap(widths[i], widths[slabCount]);
+ nvidia::swap(uniquePlanes[i], uniquePlanes[slabCount]);
+ nvidia::swap(invMap[i], invMap[slabCount]);
+ }
+ }
+
+ // Now invert invMap to get the map
+ physx::Array<uint32_t> map;
+ map.resize(invMap.size());
+ for (uint32_t i = 0; i < map.size(); ++i)
+ {
+ map[invMap[i]] = i;
+ }
+
+ // Plane indices have been rearranged, need to make corresponding rearrangements to fEdges' faceIndex value.
+ for (uint32_t i = 0; i < fEdges.size(); ++i)
+ {
+ fEdges[i].faceIndex = map[fEdges[i].faceIndex];
+ if (fEdges[i].opposite)
+ {
+ fEdges[i].faceIndex += uniquePlanes.size();
+ }
+ }
+
+ // Total plane count, with non-unique (back-facing) normals
+ mParams->planeCount = uniquePlanes.size() + slabCount;
+
+ // Fill in remaining widths
+ for (uint32_t fI = mParams->planeCount - uniquePlanes.size(); fI < widths.size(); ++fI)
+ {
+ widths[fI] = 0.0f;
+ for (uint32_t vI = 0; vI < desc.numVertices; ++vI)
+ {
+ const float vDepth = -uniquePlanes[fI].distance(mParams->vertices.buf[vI]);
+ if (vDepth > widths[fI])
+ {
+ widths[fI] = vDepth;
+ }
+ }
+ }
+
+ // Record faceIndex pairs in adjacentFaces
+ physx::Array<uint32_t> adjacentFaces;
+
+ // Eliminate redundant edges
+ qsort(fEdges.begin(), fEdges.size(), sizeof(EdgeWithFace), compareEdgesWithFaces);
+ for (uint32_t eI = 0; eI < fEdges.size();)
+ {
+ uint32_t i0 = fEdges[eI].v0Index;
+ uint32_t i1 = fEdges[eI].v1Index;
+ PX_ASSERT(i0 < 65536 && i1 < 65536);
+ if (eI < fEdges.size() - 1 && fEdges[eI] == fEdges[eI + 1])
+ {
+ if (fEdges[eI].faceIndex != fEdges[eI + 1].faceIndex)
+ {
+ edges.pushBack(i0 << 16 | i1);
+ adjacentFaces.pushBack(fEdges[eI].faceIndex << 16 | fEdges[eI + 1].faceIndex);
+ }
+ eI += 2;
+ }
+ else
+ {
+ edges.pushBack(i0 << 16 | i1);
+ adjacentFaces.pushBack(0xFFFF0000 | fEdges[eI].faceIndex);
+ ++eI;
+ }
+ }
+
+ // Find unique edge directions, put them at the front of the edge list
+ const uint32_t edgeCount = edges.size();
+ if (edgeCount > 0)
+ {
+ mParams->uniqueEdgeDirectionCount = 1;
+ for (uint32_t testEdgeIndex = 1; testEdgeIndex < edgeCount; ++testEdgeIndex)
+ {
+ const uint32_t testEdgeEndpointIndices = edges[testEdgeIndex];
+ const PxVec3 testEdge = mParams->vertices.buf[testEdgeEndpointIndices & 0xFFFF] - mParams->vertices.buf[testEdgeEndpointIndices >> 16];
+ const float testEdge2 = testEdge.magnitudeSquared();
+ uint32_t uniqueEdgeIndex = 0;
+ for (; uniqueEdgeIndex < mParams->uniqueEdgeDirectionCount; ++uniqueEdgeIndex)
+ {
+ const uint32_t uniqueEdgeEndpointIndices = edges[uniqueEdgeIndex];
+ const PxVec3 uniqueEdge = mParams->vertices.buf[uniqueEdgeEndpointIndices & 0xFFFF] - mParams->vertices.buf[uniqueEdgeEndpointIndices >> 16];
+ if (uniqueEdge.cross(testEdge).magnitudeSquared() < testEdge2 * uniqueEdge.magnitudeSquared()*PX_EPS_F32 * PX_EPS_F32)
+ {
+ break;
+ }
+ }
+ if (uniqueEdgeIndex == mParams->uniqueEdgeDirectionCount)
+ {
+ nvidia::swap(edges[mParams->uniqueEdgeDirectionCount], edges[testEdgeIndex]);
+ nvidia::swap(adjacentFaces[mParams->uniqueEdgeDirectionCount], adjacentFaces[testEdgeIndex]);
+ ++mParams->uniqueEdgeDirectionCount;
+ }
+ }
+ }
+
+ mParams->volume *= 0.1666666667f;
+
+ // Transfer from temporary arrays into mParams
+
+ // uniquePlanes
+ mParams->getParameterHandle("uniquePlanes", handle);
+ mParams->resizeArray(handle, (int32_t)uniquePlanes.size());
+ for (uint32_t i = 0; i < uniquePlanes.size(); ++i)
+ {
+ PxPlane& plane = uniquePlanes[i];
+ ConvexHullParametersNS::Plane_Type& paramPlane = mParams->uniquePlanes.buf[i];
+ paramPlane.normal = plane.n;
+ paramPlane.d = plane.d;
+ }
+
+ // edges
+ mParams->getParameterHandle("edges", handle);
+ mParams->resizeArray(handle, (int32_t)edges.size());
+ mParams->setParamU32Array(handle, edges.begin(), (int32_t)edges.size());
+
+ // adjacentFaces
+ mParams->getParameterHandle("adjacentFaces", handle);
+ mParams->resizeArray(handle, (int32_t)adjacentFaces.size());
+ mParams->setParamU32Array(handle, adjacentFaces.begin(), (int32_t)adjacentFaces.size());
+
+ // widths
+ mParams->getParameterHandle("widths", handle);
+ mParams->resizeArray(handle, (int32_t)widths.size());
+ mParams->setParamF32Array(handle, widths.begin(), (int32_t)widths.size());
+
+}
+
+void ConvexHullImpl::buildFromPoints(const void* points, uint32_t numPoints, uint32_t pointStrideBytes)
+{
+ if (numPoints < 4)
+ {
+ setEmpty();
+ return;
+ }
+
+ // First try stanhull
+
+ // We will transform the points of the hull such that they fit well into a rotated 2x2x2 cube.
+ // To find a suitable set of axes for this rotated cube, we will find the of the point distribution.
+
+ // Create an array of points which we will transform
+ physx::Array<PxVec3> transformedPoints(numPoints);
+ uint8_t* pointPtr = (uint8_t*)points;
+ for (uint32_t i = 0; i < numPoints; ++i, pointPtr += pointStrideBytes)
+ {
+ transformedPoints[i] = *(PxVec3*)pointPtr;
+ }
+
+ // Optionally reduce the point set
+#if REDUCE_CONVEXHULL_INPUT_POINT_SET
+ const uint32_t maxSetSize = 400;
+ physx::Array<PxVec3> reducedPointSet(numPoints);
+ const uint32_t reducedSetSize = kmeans_cluster(&transformedPoints[0], numPoints, &reducedPointSet[0], maxSetSize);
+ PX_ASSERT(reducedSetSize <= 400 && reducedSetSize >= 4);
+ transformedPoints = reducedPointSet;
+#endif // REDUCE_CONVEXHULL_INPUT_POINT_SET
+
+ PxVec3 mean;
+ PxVec3 variance;
+ PxMat33 axes;
+ findPrincipleComponents(mean, variance, axes, &transformedPoints[0], numPoints);
+
+ // Now subtract the mean from the points and rotate the points into the frame of the axes
+ for (uint32_t i = 0; i < numPoints; ++i)
+ {
+ transformedPoints[i] = axes.transformTranspose(transformedPoints[i] - mean);
+ }
+
+ // Finally find a scale such that the maximum absolute coordinate on each axis is 1
+ PxVec3 scale(0.0f);
+ for (uint32_t i = 0; i < numPoints; ++i)
+ {
+ for (unsigned j = 0; j < 3; ++j)
+ {
+ scale[j] = PxMax(scale[j], PxAbs(transformedPoints[i][j]));
+ }
+ }
+ if (scale.x*scale.y*scale.z == 0.0f)
+ {
+ // We have a degeneracy, planar (or colinear or coincident) points
+ setEmpty();
+ return;
+ }
+
+ // Now scale the points
+ const PxVec3 recipScale(1.0f/scale.x, 1.0f/scale.y, 1.0f/scale.z);
+ for (uint32_t i = 0; i < numPoints; ++i)
+ {
+ transformedPoints[i] = transformedPoints[i].multiply(recipScale);
+ }
+
+ // The points are transformed, and for completeness let us now build the transform which restores them
+ const PxMat44 tm(axes.column0*scale.x, axes.column1*scale.y, axes.column2*scale.z, mean);
+
+#if 0
+ // Now find the convex hull of the transformed points
+ physx::stanhull::HullDesc hullDesc;
+ hullDesc.mVertices = (const float*)&transformedPoints[0];
+ hullDesc.mVcount = numPoints;
+ hullDesc.mVertexStride = sizeof(PxVec3);
+ hullDesc.mSkinWidth = 0.0f;
+
+ physx::stanhull::HullLibrary hulllib;
+ physx::stanhull::HullResult hull;
+ if (physx::stanhull::QE_OK == hulllib.CreateConvexHull(hullDesc, hull))
+ { // Success
+ ConvexHullDesc desc;
+ desc.vertices = hull.mOutputVertices;
+ desc.numVertices = hull.mNumOutputVertices;
+ desc.vertexStrideBytes = 3*sizeof(float);
+ desc.indices = hull.mIndices;
+ desc.numIndices = hull.mNumIndices;
+ desc.faceIndexCounts = hull.mFaces;
+ desc.numFaces = hull.mNumFaces;
+ buildFromDesc(desc);
+ hulllib.ReleaseResult(hull);
+
+ // Transform our hull back before returning
+ applyTransformation(tm);
+
+ return;
+ }
+#endif
+
+#if PX_PHYSICS_VERSION_MAJOR == 3
+ // Stanhull failed, try physx sdk cooker
+ ApexSDK* sdk = GetApexSDK();
+ if (sdk && sdk->getCookingInterface() && sdk->getPhysXSDK())
+ {
+
+ physx::PxConvexMeshDesc convexMeshDesc;
+ convexMeshDesc.points.count = numPoints;
+ convexMeshDesc.points.data = &transformedPoints[0];
+ convexMeshDesc.points.stride = pointStrideBytes;
+ convexMeshDesc.flags = physx::PxConvexFlag::eCOMPUTE_CONVEX;
+
+ nvidia::PsMemoryBuffer stream;
+ stream.setEndianMode(PxFileBuf::ENDIAN_NONE);
+ PxStreamFromFileBuf nvs(stream);
+ if (sdk->getCookingInterface()->cookConvexMesh(convexMeshDesc, nvs))
+ {
+ physx::PxConvexMesh* mesh = sdk->getPhysXSDK()->createConvexMesh(nvs);
+ if (mesh)
+ {
+ buildFromConvexMesh(mesh);
+ mesh->release();
+ // Transform our hull back before returning
+ applyTransformation(tm);
+ return;
+ }
+ }
+ }
+#endif
+
+ // No luck
+ setEmpty();
+}
+
+void ConvexHullImpl::buildFromPlanes(const PxPlane* planes, uint32_t numPlanes, float eps)
+{
+ physx::Array<PxVec3> points;
+ points.reserve((numPlanes * (numPlanes - 1) * (numPlanes - 2)) / 6);
+ for (uint32_t i = 0; i < numPlanes; ++i)
+ {
+ const PxPlane& planeI = planes[i];
+ for (uint32_t j = i + 1; j < numPlanes; ++j)
+ {
+ const PxPlane& planeJ = planes[j];
+ for (uint32_t k = j + 1; k < numPlanes; ++k)
+ {
+ const PxPlane& planeK = planes[k];
+ PxVec3 point;
+ if (intersectPlanes(point, planeI, planeJ, planeK))
+ {
+ if (pointInsidePlanes(point, planes, i, eps) &&
+ pointInsidePlanes(point, planes + i + 1, j - (i + 1), eps) &&
+ pointInsidePlanes(point, planes + j + 1, k - (j + 1), eps) &&
+ pointInsidePlanes(point, planes + k + 1, numPlanes - (k + 1), eps))
+ {
+ uint32_t m = 0;
+ for (; m < points.size(); ++m)
+ {
+ if ((point - points[m]).magnitudeSquared() < eps)
+ {
+ break;
+ }
+ }
+ if (m == points.size())
+ {
+ points.pushBack(point);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ buildFromPoints(points.begin(), points.size(), sizeof(PxVec3));
+}
+
+
+#if PX_PHYSICS_VERSION_MAJOR == 3
+
+void ConvexHullImpl::buildFromConvexMesh(const ConvexMesh* mesh)
+{
+ setEmpty();
+
+ if (!mesh)
+ {
+ return;
+ }
+
+ const uint32_t numVerts = mesh->getNbVertices();
+ const PxVec3* verts = (const PxVec3*)mesh->getVertices();
+ const uint32_t numPolygons = mesh->getNbPolygons();
+ const uint8_t* index = (const uint8_t*)mesh->getIndexBuffer();
+
+
+ Array<PxPlane> uniquePlanes;
+ Array<uint32_t> edges;
+ Array<float> widths;
+
+ NvParameterized::Handle handle(*mParams);
+
+ // Copy vertices and compute bounds
+ mParams->getParameterHandle("vertices", handle);
+ mParams->resizeArray(handle, (int32_t)numVerts);
+ for (uint32_t i = 0; i < numVerts; ++i)
+ {
+ mParams->vertices.buf[i] = verts[i];
+ mParams->bounds.include(verts[i]);
+ }
+
+ PxVec3 center;
+ center = mParams->bounds.getCenter();
+
+ PxMat33 localInertia;
+ PxVec3 localCenterOfMass;
+ mesh->getMassInformation(mParams->volume, localInertia, localCenterOfMass);
+
+ // Find planes and compute volume
+ physx::Array<EdgeWithFace> fEdges;
+
+ for (uint32_t i = 0; i < numPolygons; i++)
+ {
+ physx::PxHullPolygon data;
+ bool status = mesh->getPolygonData(i, data);
+ PX_ASSERT(status);
+ if (!status)
+ {
+ continue;
+ }
+
+ const uint32_t numIndices = data.mNbVerts;
+ for (uint32_t vI = 0; vI < numIndices; ++vI)
+ {
+ const uint16_t i0 = (uint16_t)index[data.mIndexBase + vI];
+ const uint16_t i1 = (uint16_t)index[data.mIndexBase + ((vI+1)%numIndices)];
+ const PxVec3& vI0 = verts[i0];
+ const PxVec3 normal(data.mPlane[0], data.mPlane[1], data.mPlane[2]);
+ PX_ASSERT(PxEquals(normal.magnitudeSquared(), 1.0f, 0.000001f));
+ uint32_t faceIndex;
+ uint32_t oppositeFace = 0;
+ for (faceIndex = 0; faceIndex < uniquePlanes.size(); ++faceIndex)
+ {
+ const float cosTheta = normal.dot(uniquePlanes[faceIndex].n);
+ oppositeFace = (uint32_t)(cosTheta < 0.0f);
+ if (cosTheta * cosTheta > 0.999999f)
+ {
+ break;
+ }
+ }
+ if (faceIndex == uniquePlanes.size())
+ {
+ uniquePlanes.pushBack(PxPlane(vI0, normal));
+ widths.pushBack(PX_MAX_F32);
+ oppositeFace = 0;
+ }
+ else if (oppositeFace && widths[faceIndex] == PX_MAX_F32)
+ {
+ // New slab
+ widths[faceIndex] = -uniquePlanes[faceIndex].distance(vI0);
+ }
+ fEdges.pushBack(EdgeWithFace(i0, i1, faceIndex, oppositeFace, true));
+ }
+ }
+
+ // Create a map from current plane indices to the arrangement we'll have after the following loop
+ // This map will be its inverse
+ physx::Array<uint32_t> invMap;
+ invMap.resize(2*widths.size());
+ for (uint32_t i = 0; i < invMap.size(); ++i)
+ {
+ invMap[i] = i;
+ }
+
+ // This ensures that all the slabs are represented first in the planes list
+ uint32_t slabCount = widths.size();
+ for (uint32_t i = widths.size(); i--;)
+ {
+ if (widths[i] == PX_MAX_F32)
+ {
+ --slabCount;
+ nvidia::swap(widths[i], widths[slabCount]);
+ nvidia::swap(uniquePlanes[i], uniquePlanes[slabCount]);
+ nvidia::swap(invMap[i], invMap[slabCount]);
+ }
+ }
+
+ // Now invert invMap to get the map
+ physx::Array<uint32_t> map;
+ map.resize(invMap.size());
+ for (uint32_t i = 0; i < map.size(); ++i)
+ {
+ map[invMap[i]] = i;
+ }
+
+ // Plane indices have been rearranged, need to make corresponding rearrangements to fEdges' faceIndex value.
+ for (uint32_t i = 0; i < fEdges.size(); ++i)
+ {
+ fEdges[i].faceIndex = map[fEdges[i].faceIndex];
+ if (fEdges[i].opposite)
+ {
+ fEdges[i].faceIndex += uniquePlanes.size();
+ }
+ }
+
+ // Total plane count, with non-unique (back-facing) normals
+ mParams->planeCount = uniquePlanes.size() + slabCount;
+
+ // Fill in remaining widths
+ for (uint32_t pI = mParams->planeCount - uniquePlanes.size(); pI < widths.size(); ++pI)
+ {
+ widths[pI] = 0.0f;
+ for (uint32_t i = 0; i < numPolygons; i++)
+ {
+ physx::PxHullPolygon data;
+ bool status = mesh->getPolygonData(i, data);
+ PX_ASSERT(status);
+ if (!status)
+ {
+ continue;
+ }
+
+ const uint32_t numIndices = (uint32_t)data.mNbVerts - 2;
+ for (uint32_t vI = 0; vI < numIndices; ++vI)
+ {
+ const float vDepth = -uniquePlanes[pI].distance(verts[index[data.mIndexBase + vI]]);
+ if (vDepth > widths[pI])
+ {
+ widths[pI] = vDepth;
+ }
+ }
+ }
+ }
+
+ // Record faceIndex pairs in adjacentFaces
+ physx::Array<uint32_t> adjacentFaces;
+
+ // Eliminate redundant edges
+ qsort(fEdges.begin(), fEdges.size(), sizeof(EdgeWithFace), compareEdgesWithFaces);
+ for (uint32_t eI = 0; eI < fEdges.size();)
+ {
+ uint32_t i0 = fEdges[eI].v0Index;
+ uint32_t i1 = fEdges[eI].v1Index;
+ PX_ASSERT(i0 < 65536 && i1 < 65536);
+ if (eI < fEdges.size() - 1 && fEdges[eI] == fEdges[eI + 1])
+ {
+ if (fEdges[eI].faceIndex != fEdges[eI + 1].faceIndex)
+ {
+ edges.pushBack(i0 << 16 | i1);
+ adjacentFaces.pushBack(fEdges[eI].faceIndex << 16 | fEdges[eI + 1].faceIndex);
+ }
+ eI += 2;
+ }
+ else
+ {
+ edges.pushBack(i0 << 16 | i1);
+ adjacentFaces.pushBack(0xFFFF0000 | fEdges[eI].faceIndex);
+ ++eI;
+ }
+ }
+
+ // Find unique edge directions, put them at the front of the edge list
+ const uint32_t edgeCount = edges.size();
+ if (edgeCount > 0)
+ {
+ mParams->uniqueEdgeDirectionCount = 1;
+ for (uint32_t testEdgeIndex = 1; testEdgeIndex < edgeCount; ++testEdgeIndex)
+ {
+ const PxVec3 testEdge = verts[edges[testEdgeIndex] & 0xFFFF] - verts[edges[testEdgeIndex] >> 16];
+ const float testEdge2 = testEdge.magnitudeSquared();
+ uint32_t uniqueEdgeIndex = 0;
+ for (; uniqueEdgeIndex < mParams->uniqueEdgeDirectionCount; ++uniqueEdgeIndex)
+ {
+ const PxVec3 uniqueEdge = verts[edges[uniqueEdgeIndex] & 0xFFFF] - verts[edges[uniqueEdgeIndex] >> 16];
+ if (uniqueEdge.cross(testEdge).magnitudeSquared() < testEdge2 * uniqueEdge.magnitudeSquared()*PX_EPS_F32 * PX_EPS_F32)
+ {
+ break;
+ }
+ }
+ if (uniqueEdgeIndex == mParams->uniqueEdgeDirectionCount)
+ {
+ nvidia::swap(edges[mParams->uniqueEdgeDirectionCount], edges[testEdgeIndex]);
+ nvidia::swap(adjacentFaces[mParams->uniqueEdgeDirectionCount], adjacentFaces[testEdgeIndex]);
+ ++mParams->uniqueEdgeDirectionCount;
+ }
+ }
+ }
+
+ // Transfer from temporary arrays into mParams
+
+ // uniquePlanes
+ mParams->getParameterHandle("uniquePlanes", handle);
+ mParams->resizeArray(handle, (int32_t)uniquePlanes.size());
+ for (uint32_t i = 0; i < uniquePlanes.size(); ++i)
+ {
+ PxPlane& plane = uniquePlanes[i];
+ ConvexHullParametersNS::Plane_Type& paramPlane = mParams->uniquePlanes.buf[i];
+ paramPlane.normal = plane.n;
+ paramPlane.d = plane.d;
+ }
+
+ // edges
+ mParams->getParameterHandle("edges", handle);
+ mParams->resizeArray(handle, (int32_t)edges.size());
+ mParams->setParamU32Array(handle, edges.begin(), (int32_t)edges.size());
+
+ // adjacentFaces
+ mParams->getParameterHandle("adjacentFaces", handle);
+ mParams->resizeArray(handle, (int32_t)adjacentFaces.size());
+ mParams->setParamU32Array(handle, adjacentFaces.begin(), (int32_t)adjacentFaces.size());
+
+ // widths
+ mParams->getParameterHandle("widths", handle);
+ mParams->resizeArray(handle, (int32_t)widths.size());
+ mParams->setParamF32Array(handle, widths.begin(), (int32_t)widths.size());
+}
+#endif
+
+
+
+void ConvexHullImpl::buildFromAABB(const PxBounds3& aabb)
+{
+ PxVec3 center, extent;
+ center = aabb.getCenter();
+ extent = aabb.getExtents();
+
+ NvParameterized::Handle handle(*mParams);
+
+ // Copy vertices and compute bounds
+ mParams->getParameterHandle("vertices", handle);
+ mParams->resizeArray(handle, 8);
+ for (int i = 0; i < 8; ++i)
+ {
+ mParams->vertices.buf[i] = center + PxVec3((2.0f * (i & 1) - 1.0f) * extent.x, ((float)(i & 2) - 1.0f) * extent.y, (0.5f * (i & 4) - 1.0f) * extent.z);
+ }
+
+ mParams->getParameterHandle("uniquePlanes", handle);
+ mParams->resizeArray(handle, 3);
+ mParams->getParameterHandle("widths", handle);
+ mParams->resizeArray(handle, 3);
+ for (unsigned i = 0; i < 3; ++i)
+ {
+ ConvexHullParametersNS::Plane_Type& plane = mParams->uniquePlanes.buf[i];
+ plane.normal = PxVec3(0.0f);
+ plane.normal[i] = -1.0f;
+ plane.d = -aabb.maximum[i];
+ mParams->widths.buf[i] = aabb.maximum[i] - aabb.minimum[i];
+ }
+ mParams->planeCount = 6;
+
+ mParams->getParameterHandle("edges", handle);
+ mParams->resizeArray(handle, 12);
+ mParams->getParameterHandle("adjacentFaces", handle);
+ mParams->resizeArray(handle, 12);
+ for (uint32_t i = 0; i < 3; ++i)
+ {
+ uint32_t i1 = ((i + 1) % 3);
+ uint32_t i2 = ((i + 2) % 3);
+ uint32_t vOffset1 = 1u << i1;
+ uint32_t vOffset2 = 1u << i2;
+ for (int j = 0; j < 4; ++j)
+ {
+ uint32_t v0 = 0;
+ uint32_t v1 = 1u << i;
+ uint32_t f0 = i1;
+ uint32_t f1 = i2;
+ if (j & 1)
+ {
+ v0 += vOffset1;
+ v1 += vOffset1;
+ f0 += 3;
+ }
+ if (j & 2)
+ {
+ v0 += vOffset2;
+ v1 += vOffset2;
+ f1 += 3;
+ }
+ if (j == 1 || j == 2)
+ {
+ nvidia::swap(f0, f1);
+ }
+ uint32_t index = i + 3 * j;
+ mParams->edges.buf[index] = v0 << 16 | v1;
+ mParams->adjacentFaces.buf[i] = f0 << 16 | f1;
+ }
+ }
+ mParams->uniqueEdgeDirectionCount = 3;
+
+ mParams->bounds = aabb;
+
+ const PxVec3 diag = mParams->bounds.maximum - mParams->bounds.minimum;
+ mParams->volume = diag.x * diag.y * diag.z;
+}
+
+void ConvexHullImpl::buildKDOP(const void* points, uint32_t numPoints, uint32_t pointStrideBytes, const PxVec3* directions, uint32_t numDirections)
+{
+ setEmpty();
+
+ if (numPoints == 0)
+ {
+ return;
+ }
+
+ float size = 0;
+
+ physx::Array<PxPlane> planes;
+ planes.reserve(2 * numDirections);
+ for (uint32_t i = 0; i < numDirections; ++i)
+ {
+ PxVec3 dir = directions[i];
+ dir.normalize();
+ float min, max;
+ getExtent(min, max, points, numPoints, pointStrideBytes, dir);
+ planes.pushBack(PxPlane(dir, -max));
+ planes.pushBack(PxPlane(-dir, min));
+ size = PxMax(size, max - min);
+ }
+
+ buildFromPlanes(planes.begin(), planes.size(), 0.00001f * size);
+}
+
+void ConvexHullImpl::intersectPlaneSide(const PxPlane& plane)
+{
+ const float size = (mParams->bounds.maximum - mParams->bounds.minimum).magnitude();
+ const float eps = 0.00001f * size;
+
+ const uint32_t oldVertexCount = (uint32_t)mParams->vertices.arraySizes[0];
+
+ Array<PxVec3> vertices;
+ vertices.resize(oldVertexCount);
+ NvParameterized::Handle handle(*mParams);
+ mParams->getParameterHandle("vertices", handle);
+ mParams->getParamVec3Array(handle, vertices.begin(), (int32_t)vertices.size());
+
+ // Throw out all vertices on the + side of the plane
+ for (uint32_t i = oldVertexCount; i--;)
+ {
+ if (plane.distance(vertices[i]) > eps)
+ {
+ vertices.replaceWithLast(i);
+ }
+ }
+
+ if (vertices.size() == 0)
+ {
+ // plane excludes this whole hull. Delete everything.
+ setEmpty();
+ return;
+ }
+
+ if (vertices.size() == oldVertexCount)
+ {
+ // plane includes this whole hull. Do nothing.
+ return;
+ }
+
+ // Intersect new plane with all pairs of old planes.
+ const uint32_t planeCount = getPlaneCount();
+ for (uint32_t j = 1; j < planeCount; ++j)
+ {
+ const PxPlane planeJ = getPlane(j);
+ for (uint32_t i = 0; i < j; ++i)
+ {
+ const PxPlane planeI = getPlane(i);
+ PxVec3 point;
+ if (intersectPlanes(point, plane, planeI, planeJ))
+ {
+ // See if point is excluded by any of the other planes
+ uint32_t k;
+ for (k = 0; k < planeCount; ++k)
+ {
+ if (k != i && k != j && getPlane(k).distance(point) > eps)
+ {
+ break;
+ }
+ }
+ if (k == planeCount)
+ {
+ // Point is part of the new intersected hull
+ uint32_t m = 0;
+ for (; m < vertices.size(); ++m)
+ {
+ if ((point - vertices[m]).magnitudeSquared() < eps)
+ {
+ break;
+ }
+ }
+ if (m == vertices.size())
+ {
+ vertices.pushBack(point);
+ }
+ }
+ }
+ }
+ }
+
+ buildFromPoints(vertices.begin(), vertices.size(), sizeof(vertices[0]));
+}
+
+void ConvexHullImpl::intersectHull(const ConvexHullImpl& hull)
+{
+ if (hull.getPlaneCount() == 0)
+ {
+ setEmpty();
+ return;
+ }
+
+ physx::Array<PxPlane> planes;
+ planes.reserve(getPlaneCount() + hull.getPlaneCount());
+ for (uint32_t planeN = 0; planeN < getPlaneCount(); ++planeN)
+ {
+ planes.pushBack(getPlane(planeN));
+ }
+ for (uint32_t planeN = 0; planeN < hull.getPlaneCount(); ++planeN)
+ {
+ planes.pushBack(hull.getPlane(planeN));
+ }
+
+ const float size = (mParams->bounds.maximum - mParams->bounds.minimum).magnitude();
+
+ buildFromPlanes(planes.begin(), planes.size(), 0.00001f * size);
+}
+
+// Returns true iff distance does not exceed result and maxDistance
+PX_INLINE bool updateResultAndSeparation(bool& updated, bool& normalPointsFrom0to1, float& result, ConvexHullImpl::Separation* separation,
+ float min0, float max0, float min1, float max1, const PxVec3& n, float maxDistance)
+{
+ float midpoint;
+ const float dist = extentDistanceAndNormalDirection(min0, max0, min1, max1, midpoint, normalPointsFrom0to1);
+ updated = dist > result;
+ if (updated)
+ {
+ if (dist > maxDistance)
+ {
+ return false;
+ }
+ result = dist;
+ if (separation != NULL)
+ {
+ if (normalPointsFrom0to1)
+ {
+ separation->plane = PxPlane(n, -midpoint);
+ separation->min0 = min0;
+ separation->max0 = max0;
+ separation->min1 = min1;
+ separation->max1 = max1;
+ }
+ else
+ {
+ separation->plane = PxPlane(-n, midpoint);
+ separation->min0 = -max0;
+ separation->max0 = -min0;
+ separation->min1 = -max1;
+ separation->max1 = -min1;
+ }
+ }
+ }
+ return true;
+}
+
+
+namespace GjkInternal
+{
+using namespace physx::aos;
+
+PX_NOALIAS PX_FORCE_INLINE BoolV PointOutsideOfPlane4(const Vec3VArg _a, const Vec3VArg _b, const Vec3VArg _c, const Vec3VArg _d)
+{
+ // this is not 0 because of the following scenario:
+ // All the points lie on the same plane and the plane goes through the origin (0,0,0).
+ // On the Wii U, the math below has the problem that when point A gets projected on the
+ // plane cumputed by A, B, C, the distance to the plane might not be 0 for the mentioned
+ // scenario but a small positive or negative value. This can lead to the wrong boolean
+ // results. Using a small negative value as threshold is more conservative but safer.
+ const Vec4V zero = V4Load(-1e-6);
+
+ const Vec3V ab = V3Sub(_b, _a);
+ const Vec3V ac = V3Sub(_c, _a);
+ const Vec3V ad = V3Sub(_d, _a);
+ const Vec3V bd = V3Sub(_d, _b);
+ const Vec3V bc = V3Sub(_c, _b);
+
+ const Vec3V v0 = V3Cross(ab, ac);
+ const Vec3V v1 = V3Cross(ac, ad);
+ const Vec3V v2 = V3Cross(ad, ab);
+ const Vec3V v3 = V3Cross(bd, bc);
+
+ const FloatV signa0 = V3Dot(v0, _a);
+ const FloatV signa1 = V3Dot(v1, _a);
+ const FloatV signa2 = V3Dot(v2, _a);
+ const FloatV signd3 = V3Dot(v3, _a);
+
+ const FloatV signd0 = V3Dot(v0, _d);
+ const FloatV signd1 = V3Dot(v1, _b);
+ const FloatV signd2 = V3Dot(v2, _c);
+ const FloatV signa3 = V3Dot(v3, _b);
+
+ const Vec4V signa = V4Merge(signa0, signa1, signa2, signa3);
+ const Vec4V signd = V4Merge(signd0, signd1, signd2, signd3);
+ return V4IsGrtrOrEq(V4Mul(signa, signd), zero);//same side, outside of the plane
+}
+
+PX_NOALIAS PX_FORCE_INLINE Vec3V closestPtPointSegment(const Vec3VArg a, const Vec3VArg b)
+{
+ const FloatV zero = FZero();
+ const FloatV one = FOne();
+
+ //Test degenerated case
+ const Vec3V ab = V3Sub(b, a);
+ const FloatV denom = V3Dot(ab, ab);
+ const Vec3V ap = V3Neg(a);//V3Sub(origin, a);
+ const FloatV nom = V3Dot(ap, ab);
+ const BoolV con = FIsEq(denom, zero);
+ const FloatV tValue = FClamp(FDiv(nom, denom), zero, one);
+ const FloatV t = FSel(con, zero, tValue);
+
+ return V3Sel(con, a, V3ScaleAdd(ab, t, a));
+}
+
+PX_NOALIAS PX_FORCE_INLINE Vec3V closestPtPointSegment(const Vec3VArg Q0, const Vec3VArg Q1, const Vec3VArg A0, const Vec3VArg A1,
+ const Vec3VArg B0, const Vec3VArg B1, PxU32& size, Vec3V& closestA, Vec3V& closestB)
+{
+ const Vec3V a = Q0;
+ const Vec3V b = Q1;
+
+ const BoolV bTrue = BTTTT();
+ const FloatV zero = FZero();
+ const FloatV one = FOne();
+
+ //Test degenerated case
+ const Vec3V ab = V3Sub(b, a);
+ const FloatV denom = V3Dot(ab, ab);
+ const Vec3V ap = V3Neg(a);//V3Sub(origin, a);
+ const FloatV nom = V3Dot(ap, ab);
+ const BoolV con = FIsEq(denom, zero);
+
+ if (BAllEq(con, bTrue))
+ {
+ size = 1;
+ closestA = A0;
+ closestB = B0;
+ return Q0;
+ }
+
+ const Vec3V v = V3Sub(A1, A0);
+ const Vec3V w = V3Sub(B1, B0);
+ const FloatV tValue = FClamp(FDiv(nom, denom), zero, one);
+ const FloatV t = FSel(con, zero, tValue);
+
+ const Vec3V tempClosestA = V3ScaleAdd(v, t, A0);
+ const Vec3V tempClosestB = V3ScaleAdd(w, t, B0);
+ closestA = tempClosestA;
+ closestB = tempClosestB;
+ return V3Sub(tempClosestA, tempClosestB);
+}
+
+PX_NOALIAS Vec3V closestPtPointSegmentTesselation(const Vec3VArg Q0, const Vec3VArg Q1, const Vec3VArg A0, const Vec3VArg A1,
+ const Vec3VArg B0, const Vec3VArg B1, PxU32& size, Vec3V& closestA, Vec3V& closestB)
+{
+ const FloatV half = FHalf();
+
+ const FloatV targetSegmentLengthSq = FLoad(10000.f);//100 unit
+
+ Vec3V q0 = Q0;
+ Vec3V q1 = Q1;
+ Vec3V a0 = A0;
+ Vec3V a1 = A1;
+ Vec3V b0 = B0;
+ Vec3V b1 = B1;
+
+ do
+ {
+ const Vec3V midPoint = V3Scale(V3Add(q0, q1), half);
+ const Vec3V midA = V3Scale(V3Add(a0, a1), half);
+ const Vec3V midB = V3Scale(V3Add(b0, b1), half);
+
+ const Vec3V v = V3Sub(midPoint, q0);
+ const FloatV sqV = V3Dot(v, v);
+ if (FAllGrtr(targetSegmentLengthSq, sqV))
+ break;
+ //split the segment into half
+ const Vec3V tClos0 = closestPtPointSegment(q0, midPoint);
+ const FloatV sqDist0 = V3Dot(tClos0, tClos0);
+
+ const Vec3V tClos1 = closestPtPointSegment(q1, midPoint);
+ const FloatV sqDist1 = V3Dot(tClos1, tClos1);
+ //const BoolV con = FIsGrtr(sqDist0, sqDist1);
+ if (FAllGrtr(sqDist0, sqDist1))
+ {
+ //segment [m, q1]
+ q0 = midPoint;
+ a0 = midA;
+ b0 = midB;
+ }
+ else
+ {
+ //segment [q0, m]
+ q1 = midPoint;
+ a1 = midA;
+ b1 = midB;
+ }
+
+ } while (1);
+
+ return closestPtPointSegment(q0, q1, a0, a1, b0, b1, size, closestA, closestB);
+}
+
+PX_NOALIAS Vec3V closestPtPointTriangleTesselation(const Vec3V* PX_RESTRICT Q, const Vec3V* PX_RESTRICT A, const Vec3V* PX_RESTRICT B, const PxU32* PX_RESTRICT indices, PxU32& size, Vec3V& closestA, Vec3V& closestB)
+{
+ size = 3;
+ const FloatV zero = FZero();
+ const FloatV eps = FEps();
+ const FloatV half = FHalf();
+ const BoolV bTrue = BTTTT();
+ const FloatV four = FLoad(4.f);
+ const FloatV sixty = FLoad(100.f);
+
+ const PxU32 ind0 = indices[0];
+ const PxU32 ind1 = indices[1];
+ const PxU32 ind2 = indices[2];
+
+ const Vec3V a = Q[ind0];
+ const Vec3V b = Q[ind1];
+ const Vec3V c = Q[ind2];
+
+ Vec3V ab_ = V3Sub(b, a);
+ Vec3V ac_ = V3Sub(c, a);
+ Vec3V bc_ = V3Sub(b, c);
+
+ const FloatV dac_ = V3Dot(ac_, ac_);
+ const FloatV dbc_ = V3Dot(bc_, bc_);
+ if (FAllGrtrOrEq(eps, FMin(dac_, dbc_)))
+ {
+ //degenerate
+ size = 2;
+ return closestPtPointSegment(Q[ind0], Q[ind1], A[ind0], A[ind1], B[ind0], B[ind1], size, closestA, closestB);
+ }
+
+ Vec3V ap = V3Neg(a);
+ Vec3V bp = V3Neg(b);
+ Vec3V cp = V3Neg(c);
+
+ FloatV d1 = V3Dot(ab_, ap); // snom
+ FloatV d2 = V3Dot(ac_, ap); // tnom
+ FloatV d3 = V3Dot(ab_, bp); // -sdenom
+ FloatV d4 = V3Dot(ac_, bp); // unom = d4 - d3
+ FloatV d5 = V3Dot(ab_, cp); // udenom = d5 - d6
+ FloatV d6 = V3Dot(ac_, cp); // -tdenom
+ /* FloatV unom = FSub(d4, d3);
+ FloatV udenom = FSub(d5, d6);*/
+
+ FloatV va = FNegScaleSub(d5, d4, FMul(d3, d6));//edge region of BC
+ FloatV vb = FNegScaleSub(d1, d6, FMul(d5, d2));//edge region of AC
+ FloatV vc = FNegScaleSub(d3, d2, FMul(d1, d4));//edge region of AB
+
+ //check if p in vertex region outside a
+ const BoolV con00 = FIsGrtrOrEq(zero, d1); // snom <= 0
+ const BoolV con01 = FIsGrtrOrEq(zero, d2); // tnom <= 0
+ const BoolV con0 = BAnd(con00, con01); // vertex region a
+ if (BAllEq(con0, bTrue))
+ {
+ //size = 1;
+ closestA = A[ind0];
+ closestB = B[ind0];
+ return Q[ind0];
+ }
+
+ //check if p in vertex region outside b
+ const BoolV con10 = FIsGrtrOrEq(d3, zero);
+ const BoolV con11 = FIsGrtrOrEq(d3, d4);
+ const BoolV con1 = BAnd(con10, con11); // vertex region b
+ if (BAllEq(con1, bTrue))
+ {
+ /*size = 1;
+ indices[0] = ind1;*/
+ closestA = A[ind1];
+ closestB = B[ind1];
+ return Q[ind1];
+ }
+
+
+ //check if p in vertex region outside of c
+ const BoolV con20 = FIsGrtrOrEq(d6, zero);
+ const BoolV con21 = FIsGrtrOrEq(d6, d5);
+ const BoolV con2 = BAnd(con20, con21); // vertex region c
+ if (BAllEq(con2, bTrue))
+ {
+ closestA = A[ind2];
+ closestB = B[ind2];
+ return Q[ind2];
+ }
+
+ //check if p in edge region of AB
+ const BoolV con30 = FIsGrtrOrEq(zero, vc);
+ const BoolV con31 = FIsGrtrOrEq(d1, zero);
+ const BoolV con32 = FIsGrtrOrEq(zero, d3);
+ const BoolV con3 = BAnd(con30, BAnd(con31, con32));
+
+ if (BAllEq(con3, bTrue))
+ {
+ //size = 2;
+ //p in edge region of AB, split AB
+ return closestPtPointSegmentTesselation(Q[ind0], Q[ind1], A[ind0], A[ind1], B[ind0], B[ind1], size, closestA, closestB);
+ }
+
+ //check if p in edge region of BC
+ const BoolV con40 = FIsGrtrOrEq(zero, va);
+ const BoolV con41 = FIsGrtrOrEq(d4, d3);
+ const BoolV con42 = FIsGrtrOrEq(d5, d6);
+ const BoolV con4 = BAnd(con40, BAnd(con41, con42));
+
+ if (BAllEq(con4, bTrue))
+ {
+ //p in edge region of BC, split BC
+ return closestPtPointSegmentTesselation(Q[ind1], Q[ind2], A[ind1], A[ind2], B[ind1], B[ind2], size, closestA, closestB);
+ }
+
+ //check if p in edge region of AC
+ const BoolV con50 = FIsGrtrOrEq(zero, vb);
+ const BoolV con51 = FIsGrtrOrEq(d2, zero);
+ const BoolV con52 = FIsGrtrOrEq(zero, d6);
+ const BoolV con5 = BAnd(con50, BAnd(con51, con52));
+
+ if (BAllEq(con5, bTrue))
+ {
+ //p in edge region of AC, split AC
+ return closestPtPointSegmentTesselation(Q[ind0], Q[ind2], A[ind0], A[ind2], B[ind0], B[ind2], size, closestA, closestB);
+ }
+
+ size = 3;
+
+ Vec3V q0 = Q[ind0];
+ Vec3V q1 = Q[ind1];
+ Vec3V q2 = Q[ind2];
+ Vec3V a0 = A[ind0];
+ Vec3V a1 = A[ind1];
+ Vec3V a2 = A[ind2];
+ Vec3V b0 = B[ind0];
+ Vec3V b1 = B[ind1];
+ Vec3V b2 = B[ind2];
+
+ do
+ {
+
+ const Vec3V ab = V3Sub(q1, q0);
+ const Vec3V ac = V3Sub(q2, q0);
+ const Vec3V bc = V3Sub(q2, q1);
+
+ const FloatV dab = V3Dot(ab, ab);
+ const FloatV dac = V3Dot(ac, ac);
+ const FloatV dbc = V3Dot(bc, bc);
+
+ const FloatV fMax = FMax(dab, FMax(dac, dbc));
+ const FloatV fMin = FMin(dab, FMin(dac, dbc));
+
+ const Vec3V w = V3Cross(ab, ac);
+
+ const FloatV area = V3Length(w);
+ const FloatV ratio = FDiv(FSqrt(fMax), FSqrt(fMin));
+ if (FAllGrtr(four, ratio) && FAllGrtr(sixty, area))
+ break;
+
+ //calculate the triangle normal
+ const Vec3V triNormal = V3Normalize(w);
+
+ PX_ASSERT(V3AllEq(triNormal, V3Zero()) == 0);
+
+
+ //split the longest edge
+ if (FAllGrtrOrEq(dab, dac) && FAllGrtrOrEq(dab, dbc))
+ {
+ //split edge q0q1
+ const Vec3V midPoint = V3Scale(V3Add(q0, q1), half);
+ const Vec3V midA = V3Scale(V3Add(a0, a1), half);
+ const Vec3V midB = V3Scale(V3Add(b0, b1), half);
+
+ const Vec3V v = V3Sub(midPoint, q2);
+ const Vec3V n = V3Normalize(V3Cross(v, triNormal));
+
+ const FloatV d = FNeg(V3Dot(n, midPoint));
+ const FloatV dp = FAdd(V3Dot(n, q0), d);
+ const FloatV sum = FMul(d, dp);
+
+ if (FAllGrtr(sum, zero))
+ {
+ //q0 and origin at the same side, split triangle[q0, m, q2]
+ q1 = midPoint;
+ a1 = midA;
+ b1 = midB;
+ }
+ else
+ {
+ //q1 and origin at the same side, split triangle[m, q1, q2]
+ q0 = midPoint;
+ a0 = midA;
+ b0 = midB;
+ }
+
+ }
+ else if (FAllGrtrOrEq(dac, dbc))
+ {
+ //split edge q0q2
+ const Vec3V midPoint = V3Scale(V3Add(q0, q2), half);
+ const Vec3V midA = V3Scale(V3Add(a0, a2), half);
+ const Vec3V midB = V3Scale(V3Add(b0, b2), half);
+
+ const Vec3V v = V3Sub(midPoint, q1);
+ const Vec3V n = V3Normalize(V3Cross(v, triNormal));
+
+ const FloatV d = FNeg(V3Dot(n, midPoint));
+ const FloatV dp = FAdd(V3Dot(n, q0), d);
+ const FloatV sum = FMul(d, dp);
+
+ if (FAllGrtr(sum, zero))
+ {
+ //q0 and origin at the same side, split triangle[q0, q1, m]
+ q2 = midPoint;
+ a2 = midA;
+ b2 = midB;
+ }
+ else
+ {
+ //q2 and origin at the same side, split triangle[m, q1, q2]
+ q0 = midPoint;
+ a0 = midA;
+ b0 = midB;
+ }
+ }
+ else
+ {
+ //split edge q1q2
+ const Vec3V midPoint = V3Scale(V3Add(q1, q2), half);
+ const Vec3V midA = V3Scale(V3Add(a1, a2), half);
+ const Vec3V midB = V3Scale(V3Add(b1, b2), half);
+
+ const Vec3V v = V3Sub(midPoint, q0);
+ const Vec3V n = V3Normalize(V3Cross(v, triNormal));
+
+ const FloatV d = FNeg(V3Dot(n, midPoint));
+ const FloatV dp = FAdd(V3Dot(n, q1), d);
+ const FloatV sum = FMul(d, dp);
+
+ if (FAllGrtr(sum, zero))
+ {
+ //q1 and origin at the same side, split triangle[q0, q1, m]
+ q2 = midPoint;
+ a2 = midA;
+ b2 = midB;
+ }
+ else
+ {
+ //q2 and origin at the same side, split triangle[q0, m, q2]
+ q1 = midPoint;
+ a1 = midA;
+ b1 = midB;
+ }
+
+
+ }
+ } while (1);
+
+ //P must project inside face region. Compute Q using Barycentric coordinates
+ ab_ = V3Sub(q1, q0);
+ ac_ = V3Sub(q2, q0);
+ ap = V3Neg(q0);
+ bp = V3Neg(q1);
+ cp = V3Neg(q2);
+
+ d1 = V3Dot(ab_, ap); // snom
+ d2 = V3Dot(ac_, ap); // tnom
+ d3 = V3Dot(ab_, bp); // -sdenom
+ d4 = V3Dot(ac_, bp); // unom = d4 - d3
+ d5 = V3Dot(ab_, cp); // udenom = d5 - d6
+ d6 = V3Dot(ac_, cp); // -tdenom
+
+ va = FNegScaleSub(d5, d4, FMul(d3, d6));//edge region of BC
+ vb = FNegScaleSub(d1, d6, FMul(d5, d2));//edge region of AC
+ vc = FNegScaleSub(d3, d2, FMul(d1, d4));//edge region of AB
+
+ const FloatV toRecipD = FAdd(va, FAdd(vb, vc));
+ const FloatV denom = FRecip(toRecipD);//V4GetW(recipTmp);
+ const Vec3V v0 = V3Sub(a1, a0);
+ const Vec3V v1 = V3Sub(a2, a0);
+ const Vec3V w0 = V3Sub(b1, b0);
+ const Vec3V w1 = V3Sub(b2, b0);
+
+ const FloatV t = FMul(vb, denom);
+ const FloatV w = FMul(vc, denom);
+ const Vec3V vA1 = V3Scale(v1, w);
+ const Vec3V vB1 = V3Scale(w1, w);
+ const Vec3V tempClosestA = V3Add(a0, V3ScaleAdd(v0, t, vA1));
+ const Vec3V tempClosestB = V3Add(b0, V3ScaleAdd(w0, t, vB1));
+ closestA = tempClosestA;
+ closestB = tempClosestB;
+ return V3Sub(tempClosestA, tempClosestB);
+}
+
+PX_NOALIAS Vec3V closestPtPointTetrahedronTesselation(Vec3V* PX_RESTRICT Q, Vec3V* PX_RESTRICT A, Vec3V* PX_RESTRICT B, PxU32& size, Vec3V& closestA, Vec3V& closestB)
+{
+ const FloatV eps = FEps();
+ const Vec3V zeroV = V3Zero();
+ PxU32 tempSize = size;
+
+ FloatV bestSqDist = FLoad(PX_MAX_REAL);
+ const Vec3V a = Q[0];
+ const Vec3V b = Q[1];
+ const Vec3V c = Q[2];
+ const Vec3V d = Q[3];
+ const BoolV bTrue = BTTTT();
+ const BoolV bFalse = BFFFF();
+
+ //degenerated
+ const Vec3V ad = V3Sub(d, a);
+ const Vec3V bd = V3Sub(d, b);
+ const Vec3V cd = V3Sub(d, c);
+ const FloatV dad = V3Dot(ad, ad);
+ const FloatV dbd = V3Dot(bd, bd);
+ const FloatV dcd = V3Dot(cd, cd);
+ const FloatV fMin = FMin(dad, FMin(dbd, dcd));
+ if (FAllGrtr(eps, fMin))
+ {
+ size = 3;
+ PxU32 tempIndices[] = { 0, 1, 2 };
+ return closestPtPointTriangleTesselation(Q, A, B, tempIndices, size, closestA, closestB);
+ }
+
+ Vec3V _Q[] = { Q[0], Q[1], Q[2], Q[3] };
+ Vec3V _A[] = { A[0], A[1], A[2], A[3] };
+ Vec3V _B[] = { B[0], B[1], B[2], B[3] };
+
+ PxU32 indices[3] = { 0, 1, 2 };
+
+ const BoolV bIsOutside4 = PointOutsideOfPlane4(a, b, c, d);
+
+ if (BAllEq(bIsOutside4, bFalse))
+ {
+ //origin is inside the tetrahedron, we are done
+ return zeroV;
+ }
+
+ Vec3V result = zeroV;
+ Vec3V tempClosestA, tempClosestB;
+
+ if (BAllEq(BGetX(bIsOutside4), bTrue))
+ {
+
+ PxU32 tempIndices[] = { 0, 1, 2 };
+ PxU32 _size = 3;
+
+ result = closestPtPointTriangleTesselation(_Q, _A, _B, tempIndices, _size, tempClosestA, tempClosestB);
+
+ const FloatV sqDist = V3Dot(result, result);
+ bestSqDist = sqDist;
+
+ indices[0] = tempIndices[0];
+ indices[1] = tempIndices[1];
+ indices[2] = tempIndices[2];
+
+ tempSize = _size;
+ closestA = tempClosestA;
+ closestB = tempClosestB;
+ }
+
+ if (BAllEq(BGetY(bIsOutside4), bTrue))
+ {
+
+ PxU32 tempIndices[] = { 0, 2, 3 };
+
+ PxU32 _size = 3;
+
+ const Vec3V q = closestPtPointTriangleTesselation(_Q, _A, _B, tempIndices, _size, tempClosestA, tempClosestB);
+
+ const FloatV sqDist = V3Dot(q, q);
+ const BoolV con = FIsGrtr(bestSqDist, sqDist);
+ if (BAllEq(con, bTrue))
+ {
+ result = q;
+ bestSqDist = sqDist;
+ indices[0] = tempIndices[0];
+ indices[1] = tempIndices[1];
+ indices[2] = tempIndices[2];
+
+ tempSize = _size;
+ closestA = tempClosestA;
+ closestB = tempClosestB;
+ }
+ }
+
+ if (BAllEq(BGetZ(bIsOutside4), bTrue))
+ {
+
+ PxU32 tempIndices[] = { 0, 3, 1 };
+ PxU32 _size = 3;
+
+ const Vec3V q = closestPtPointTriangleTesselation(_Q, _A, _B, tempIndices, _size, tempClosestA, tempClosestB);
+
+ const FloatV sqDist = V3Dot(q, q);
+ const BoolV con = FIsGrtr(bestSqDist, sqDist);
+ if (BAllEq(con, bTrue))
+ {
+ result = q;
+ bestSqDist = sqDist;
+ indices[0] = tempIndices[0];
+ indices[1] = tempIndices[1];
+ indices[2] = tempIndices[2];
+ tempSize = _size;
+ closestA = tempClosestA;
+ closestB = tempClosestB;
+ }
+
+ }
+
+ if (BAllEq(BGetW(bIsOutside4), bTrue))
+ {
+
+ PxU32 tempIndices[] = { 1, 3, 2 };
+ PxU32 _size = 3;
+
+ const Vec3V q = closestPtPointTriangleTesselation(_Q, _A, _B, tempIndices, _size, tempClosestA, tempClosestB);
+
+ const FloatV sqDist = V3Dot(q, q);
+ const BoolV con = FIsGrtr(bestSqDist, sqDist);
+
+ if (BAllEq(con, bTrue))
+ {
+ result = q;
+ bestSqDist = sqDist;
+
+ indices[0] = tempIndices[0];
+ indices[1] = tempIndices[1];
+ indices[2] = tempIndices[2];
+
+ tempSize = _size;
+ closestA = tempClosestA;
+ closestB = tempClosestB;
+ }
+ }
+
+ A[0] = _A[indices[0]]; A[1] = _A[indices[1]]; A[2] = _A[indices[2]];
+ B[0] = _B[indices[0]]; B[1] = _B[indices[1]]; B[2] = _B[indices[2]];
+ Q[0] = _Q[indices[0]]; Q[1] = _Q[indices[1]]; Q[2] = _Q[indices[2]];
+
+
+ size = tempSize;
+ return result;
+}
+
+PX_NOALIAS PX_FORCE_INLINE Vec3V doTesselation(Vec3V* PX_RESTRICT Q, Vec3V* PX_RESTRICT A, Vec3V* PX_RESTRICT B,
+ const Vec3VArg support, const Vec3VArg supportA, const Vec3VArg supportB, PxU32& size, Vec3V& closestA, Vec3V& closestB)
+{
+ switch (size)
+ {
+ case 1:
+ {
+ closestA = supportA;
+ closestB = supportB;
+ return support;
+ }
+ case 2:
+ {
+ return closestPtPointSegmentTesselation(Q[0], support, A[0], supportA, B[0], supportB, size, closestA, closestB);
+ }
+ case 3:
+ {
+
+ PxU32 tempIndices[3] = { 0, 1, 2 };
+ return closestPtPointTriangleTesselation(Q, A, B, tempIndices, size, closestA, closestB);
+ }
+ case 4:
+ {
+ return closestPtPointTetrahedronTesselation(Q, A, B, size, closestA, closestB);
+ }
+ default:
+ PX_ASSERT(0);
+ }
+ return support;
+}
+
+struct ConvexV
+{
+ void calcExtent(const Vec3V& dir, PxF32& minOut, PxF32& maxOut) const
+ {
+ // Expand
+ const Vec4V x = Vec4V_From_FloatV(V3GetX(dir));
+ const Vec4V y = Vec4V_From_FloatV(V3GetY(dir));
+ const Vec4V z = Vec4V_From_FloatV(V3GetZ(dir));
+
+ const Vec4V* src = mAovVertices;
+ const Vec4V* end = src + mNumAovVertices * 3;
+
+ // Do first step
+ Vec4V max = V4MulAdd(x, src[0], V4MulAdd(y, src[1], V4Mul(z, src[2])));
+ Vec4V min = max;
+ src += 3;
+ // Do the rest
+ for (; src < end; src += 3)
+ {
+ const Vec4V dot = V4MulAdd(x, src[0], V4MulAdd(y, src[1], V4Mul(z, src[2])));
+ max = V4Max(dot, max);
+ min = V4Min(dot, min);
+ }
+ FStore(V4ExtractMax(max), &maxOut);
+ FStore(V4ExtractMin(min), &minOut);
+ }
+ Vec3V calcSupport(const Vec3V& dir) const
+ {
+ // Expand
+ const Vec4V x = Vec4V_From_FloatV(V3GetX(dir));
+ const Vec4V y = Vec4V_From_FloatV(V3GetY(dir));
+ const Vec4V z = Vec4V_From_FloatV(V3GetZ(dir));
+
+ PX_ALIGN(16, static const PxF32 index4const[]) = { 0.0f, 1.0f, 2.0f, 3.0f };
+ Vec4V index4 = *(const Vec4V*)index4const;
+ PX_ALIGN(16, static const PxF32 delta4const[]) = { 4.0f, 4.0f, 4.0f, 4.0f };
+ const Vec4V delta4 = *(const Vec4V*)delta4const;
+
+ const Vec4V* src = mAovVertices;
+ const Vec4V* end = src + mNumAovVertices * 3;
+
+ // Do first step
+ Vec4V max = V4MulAdd(x, src[0], V4MulAdd(y, src[1], V4Mul(z, src[2])));
+ Vec4V maxIndex = index4;
+ index4 = V4Add(index4, delta4);
+ src += 3;
+ // Do the rest
+ for (; src < end; src += 3)
+ {
+ const Vec4V dot = V4MulAdd(x, src[0], V4MulAdd(y, src[1], V4Mul(z, src[2])));
+ const BoolV cmp = V4IsGrtr(dot, max);
+ max = V4Max(dot, max);
+ maxIndex = V4Sel(cmp, index4, maxIndex);
+ index4 = V4Add(index4, delta4);
+ }
+ Vec4V horiMax = Vec4V_From_FloatV(V4ExtractMax(max));
+ PxU32 mask = BGetBitMask(V4IsEq(horiMax, max));
+ const PxU32 simdIndex = (0x12131210 >> (mask + mask)) & PxU32(3);
+
+ /// NOTE! Could be load hit store
+ /// Would be better to have all simd.
+ PX_ALIGN(16, PxF32 f[4]);
+ V4StoreA(maxIndex, f);
+ PxU32 index = PxU32(PxI32(f[simdIndex]));
+
+ const Vec4V* aovIndex = (mAovVertices + (index >> 2) * 3);
+ const PxF32* aovOffset = ((const PxF32*)aovIndex) + (index & 3);
+
+ return Vec3V_From_Vec4V(V4LoadXYZW(aovOffset[0], aovOffset[4], aovOffset[8], 1.0f));
+ }
+
+ const Vec4V* mAovVertices; ///< Vertices storex x,x,x,x, y,y,y,y, z,z,z,z
+ PxU32 mNumAovVertices; ///< Number of groups of 4 of vertices
+};
+
+struct Output
+{
+ /// Get the normal to push apart in direction from A to B
+ PX_FORCE_INLINE Vec3V getNormal() const { const Vec3V dir = V3Sub(mClosestB, mClosestA); if (!V3AllGrtr(V3Eps(), V3Abs(dir))) return V3Normalize(dir); return V3Zero(); }
+ Vec3V mClosestA; ///< Closest point on A
+ Vec3V mClosestB; ///< Closest point on B
+ FloatV mDistSq;
+};
+
+enum Status
+{
+ STATUS_NON_INTERSECT,
+ STATUS_CONTACT,
+ STATUS_DEGENERATE,
+};
+
+Status Collide(const Vec3V& initialDir, const ConvexV& convexA, const Mat34V& bToA, const ConvexV& convexB, Output& out)
+{
+ Vec3V Q[4];
+ Vec3V A[4];
+ Vec3V B[4];
+
+ Mat33V aToB = M34Trnsps33(bToA);
+
+ PxU32 size = 0;
+
+ const Vec3V zeroV = V3Zero();
+ const BoolV bTrue = BTTTT();
+
+ //Vec3V v = V3UnitX();
+ Vec3V v = V3Sel(FIsGrtr(V3Dot(initialDir, initialDir), FZero()), initialDir, V3UnitX());
+
+ //const FloatV minMargin = zero;
+ //const FloatV eps2 = FMul(minMargin, FLoad(0.01f));
+ //FloatV eps2 = zero;
+ FloatV eps2 = FLoad(1e-6f);
+ const FloatV epsRel = FLoad(0.000225f);
+
+ Vec3V closA(zeroV), closB(zeroV);
+ FloatV sDist = FMax();
+ FloatV minDist = sDist;
+ Vec3V closAA = zeroV;
+ Vec3V closBB = zeroV;
+
+ BoolV bNotTerminated = bTrue;
+ BoolV bCon = bTrue;
+
+ do
+ {
+ minDist = sDist;
+ closAA = closA;
+ closBB = closB;
+
+ PxU32 index = size++;
+ PX_ASSERT(index < 4);
+
+ const Vec3V supportA = convexA.calcSupport(V3Neg(v));
+ const Vec3V supportB = M34MulV3(bToA, convexB.calcSupport(M33MulV3(aToB, v)));
+ const Vec3V support = Vec3V_From_Vec4V(Vec4V_From_Vec3V(V3Sub(supportA, supportB)));
+
+ A[index] = supportA;
+ B[index] = supportB;
+ Q[index] = support;
+
+ const FloatV signDist = V3Dot(v, support);
+ const FloatV tmp0 = FSub(sDist, signDist);
+ if (FAllGrtr(FMul(epsRel, sDist), tmp0))
+ {
+ out.mClosestA = closA;
+ out.mClosestB = closB;
+ out.mDistSq = sDist;
+ return STATUS_NON_INTERSECT;
+ }
+
+ //calculate the closest point between two convex hull
+ v = doTesselation(Q, A, B, support, supportA, supportB, size, closA, closB);
+ sDist = V3Dot(v, v);
+ bCon = FIsGrtr(minDist, sDist);
+
+ bNotTerminated = BAnd(FIsGrtr(sDist, eps2), bCon);
+ } while (BAllEq(bNotTerminated, bTrue));
+
+ out.mClosestA = V3Sel(bCon, closA, closAA);
+ out.mClosestB = V3Sel(bCon, closB, closBB);
+ out.mDistSq = FSel(bCon, sDist, minDist);
+ return Status(BAllEq(bCon, bTrue) == 1 ? STATUS_CONTACT : STATUS_DEGENERATE);
+}
+
+Status CollidePoint(const ConvexV& convexA, const Vec3V& pointB, Output& out)
+{
+ Vec3V Q[4];
+ Vec3V A[4];
+ Vec3V B[4];
+
+ PxU32 size = 0;
+
+ const Vec3V zeroV = V3Zero();
+ //const FloatV zero = FZero();
+ const BoolV bTrue = BTTTT();
+
+ Vec3V v = V3UnitX();
+
+ //const FloatV minMargin = zero;
+ //const FloatV eps2 = FMul(minMargin, FLoad(0.01f));
+ //FloatV eps2 = zero;
+ FloatV eps2 = FLoad(1e-6f);
+ const FloatV epsRel = FLoad(0.000225f);
+
+ Vec3V closA(zeroV), closB(zeroV);
+ FloatV sDist = FMax();
+ FloatV minDist = sDist;
+ Vec3V closAA = zeroV;
+ Vec3V closBB = zeroV;
+
+ BoolV bNotTerminated = bTrue;
+ BoolV bCon = bTrue;
+
+ do
+ {
+ minDist = sDist;
+ closAA = closA;
+ closBB = closB;
+
+ PxU32 index = size++;
+ PX_ASSERT(index < 4);
+
+ const Vec3V supportA = convexA.calcSupport(V3Neg(v));
+ const Vec3V supportB = pointB;
+ const Vec3V support = Vec3V_From_Vec4V(Vec4V_From_Vec3V(V3Sub(supportA, supportB)));
+
+ A[index] = supportA;
+ B[index] = supportB;
+ Q[index] = support;
+
+ const FloatV signDist = V3Dot(v, support);
+ const FloatV tmp0 = FSub(sDist, signDist);
+ if (FAllGrtr(FMul(epsRel, sDist), tmp0))
+ {
+ out.mClosestA = closA;
+ out.mClosestB = closB;
+ out.mDistSq = sDist;
+ return STATUS_NON_INTERSECT;
+ }
+
+ //calculate the closest point between two convex hull
+ v = doTesselation(Q, A, B, support, supportA, supportB, size, closA, closB);
+ sDist = V3Dot(v, v);
+ bCon = FIsGrtr(minDist, sDist);
+
+ bNotTerminated = BAnd(FIsGrtr(sDist, eps2), bCon);
+ } while (BAllEq(bNotTerminated, bTrue));
+
+ out.mClosestA = V3Sel(bCon, closA, closAA);
+ out.mClosestB = V3Sel(bCon, closB, closBB);
+ out.mDistSq = FSel(bCon, sDist, minDist);
+ return Status(BAllEq(bCon, bTrue) == 1 ? STATUS_CONTACT : STATUS_DEGENERATE);
+}
+
+
+} // namespace GjkInternal
+
+static void _arrayVec3ToVec4(const PxVec3* src, physx::aos::Vec4V* dst, PxU32 num)
+{
+ using namespace physx::aos;
+ const PxU32 num4 = num >> 2;
+ for (PxU32 i = 0; i < num4; i++, dst += 3, src += 4)
+ {
+ Vec3V v0 = V3LoadU(&src[0].x);
+ Vec3V v1 = V3LoadU(&src[1].x);
+ Vec3V v2 = V3LoadU(&src[2].x);
+ Vec3V v3 = V3LoadU(&src[3].x);
+ // Transpose
+ V4Transpose(v0, v1, v2, v3);
+ // Save
+ dst[0] = v0;
+ dst[1] = v1;
+ dst[2] = v2;
+ }
+ const PxU32 remain = num & 3;
+ if (remain)
+ {
+ Vec3V work[4];
+ PxU32 i = 0;
+ for (; i < remain; i++) work[i] = V3LoadU(&src[i].x);
+ for (; i < 4; i++) work[i] = work[remain - 1];
+ V4Transpose(work[0], work[1], work[2], work[3]);
+ dst[0] = work[0];
+ dst[1] = work[1];
+ dst[2] = work[2];
+ }
+}
+
+static void _arrayVec3ToVec4(const PxVec3* src, const physx::aos::Vec3V& scale, physx::aos::Vec4V* dst, PxU32 num)
+{
+ using namespace physx::aos;
+
+ // If no scale - use the faster version
+ if (V3AllEq(scale, V3One()))
+ {
+ return _arrayVec3ToVec4(src, dst, num);
+ }
+
+ const PxU32 num4 = num >> 2;
+ for (PxU32 i = 0; i < num4; i++, dst += 3, src += 4)
+ {
+ Vec3V v0 = V3Mul(scale, V3LoadU(&src[0].x));
+ Vec3V v1 = V3Mul(scale, V3LoadU(&src[1].x));
+ Vec3V v2 = V3Mul(scale, V3LoadU(&src[2].x));
+ Vec3V v3 = V3Mul(scale, V3LoadU(&src[3].x));
+ // Transpose
+ V4Transpose(v0, v1, v2, v3);
+ // Save
+ dst[0] = v0;
+ dst[1] = v1;
+ dst[2] = v2;
+ }
+ const PxU32 remain = num & 3;
+ if (remain)
+ {
+ Vec3V work[4];
+ PxU32 i = 0;
+ for (; i < remain; i++) work[i] = V3Mul(scale, V3LoadU(&src[i].x));
+ for (; i < 4; i++) work[i] = work[remain - 1];
+ V4Transpose(work[0], work[1], work[2], work[3]);
+ dst[0] = work[0];
+ dst[1] = work[1];
+ dst[2] = work[2];
+ }
+}
+
+static void _calcSeparation(const GjkInternal::ConvexV& convexA, const physx::PxTransform& aToWorldIn, const physx::aos::Mat34V& bToA, const GjkInternal::ConvexV& convexB, const GjkInternal::Output& out, ConvexHullImpl::Separation& sep)
+{
+ using namespace physx::aos;
+
+ Mat33V aToB = M34Trnsps33(bToA);
+ Vec3V normalA = out.getNormal();
+
+ convexA.calcExtent(normalA, sep.min0, sep.max0);
+ Vec3V normalB = M33MulV3(aToB, normalA);
+ convexB.calcExtent(normalB, sep.min1, sep.max1);
+
+ {
+ // Offset the min max taking into account transform
+ // Distance of origin from B's space in As space in direction of the normal in As space should fix it...
+ PxF32 fix;
+ FStore(V3Dot(bToA.col3, normalA), &fix);
+ sep.min1 += fix;
+ sep.max1 += fix;
+ }
+
+ // Looks like it's the plane at the midpoint
+ Vec3V center = V3Scale(V3Add(out.mClosestA, out.mClosestB), FLoad(0.5f));
+ // Transform to world space
+ Mat34V aToWorld;
+ *(PxMat44*)&aToWorld = aToWorldIn;
+ // Put the normal in world space
+ Vec3V worldCenter = M34MulV3(aToWorld, center);
+ Vec3V worldNormal = M34Mul33V3(aToWorld, normalA);
+
+ FloatV dist = V3Dot(worldNormal, worldCenter);
+ V3StoreU(worldNormal, sep.plane.n);
+ FStore(dist, &sep.plane.d);
+ sep.plane.d = -sep.plane.d;
+}
+
+bool ConvexHullImpl::hullsInProximity(const ConvexHullImpl& hull0, const physx::PxTransform& localToWorldRT0In, const physx::PxVec3& scale0In,
+ const ConvexHullImpl& hull1, const physx::PxTransform& localToWorldRT1In, const physx::PxVec3& scale1In,
+ physx::PxF32 maxDistance, Separation* separation)
+{
+ using namespace physx::aos;
+
+ const PxU32 numVerts0 = hull0.getVertexCount();
+ const PxU32 numVerts1 = hull1.getVertexCount();
+ const PxU32 numAov0 = (numVerts0 + 3) >> 2;
+ const PxU32 numAov1 = (numVerts1 + 3) >> 2;
+
+#if PX_ANDROID == 1
+ Vec4V* verts0 = (Vec4V*)PxAllocaAligned((numAov0 + numAov1) * sizeof(Vec4V) * 3, 16);
+#else
+ Vec4V* verts0 = (Vec4V*)PxAlloca((numAov0 + numAov1) * sizeof(Vec4V) * 3);
+#endif
+ // Make sure it's aligned
+ PX_ASSERT((size_t(verts0) & 0xf) == 0);
+
+ Vec4V* verts1 = verts0 + (numAov0 * 3);
+
+ const Vec3V scale0 = V3LoadU(&scale0In.x);
+ const Vec3V scale1 = V3LoadU(&scale1In.x);
+
+ _arrayVec3ToVec4(hull0.mParams->vertices.buf, scale0, verts0, numVerts0);
+ _arrayVec3ToVec4(hull1.mParams->vertices.buf, scale1, verts1, numVerts1);
+
+ const PxTransform trans1To0 = localToWorldRT0In.transformInv(localToWorldRT1In);
+
+ // Load into simd mat
+ Mat34V bToA;
+ *(PxMat44*)&bToA = trans1To0;
+ (*(PxMat44*)&bToA).column3.w = 0.0f; // AOS wants the 4th component of Vec3V to be 0 to work properly
+
+ GjkInternal::ConvexV convexA;
+ GjkInternal::ConvexV convexB;
+
+ convexA.mNumAovVertices = numAov0;
+ convexA.mAovVertices = verts0;
+
+ convexB.mNumAovVertices = numAov1;
+ convexB.mAovVertices = verts1;
+
+ // Take the origin of B in As space as the inital direction as it is 'the difference in transform origins B-A in A's space'
+ // Should be a good first guess
+ const Vec3V initialDir = bToA.col3;
+ GjkInternal::Output output;
+ GjkInternal::Status status = GjkInternal::Collide(initialDir, convexA, bToA, convexB, output);
+
+ if (status == GjkInternal::STATUS_DEGENERATE)
+ {
+ // Calculate the tolerance from the extents
+ const PxVec3 extents0 = hull0.getBounds().getExtents();
+ const PxVec3 extents1 = hull1.getBounds().getExtents();
+
+ const FloatV tolerance0 = V3ExtractMin(V3Mul(V3LoadU(&extents0.x), scale0));
+ const FloatV tolerance1 = V3ExtractMin(V3Mul(V3LoadU(&extents1.x), scale1));
+
+ const FloatV tolerance = FMul(FAdd(tolerance0, tolerance1), FLoad(0.01f));
+ const FloatV sqTolerance = FMul(tolerance, tolerance);
+
+ status = FAllGrtr(sqTolerance, output.mDistSq) ? GjkInternal::STATUS_CONTACT : GjkInternal::STATUS_NON_INTERSECT;
+ }
+
+ switch (status)
+ {
+ case GjkInternal::STATUS_CONTACT:
+ {
+ if (separation)
+ {
+ _calcSeparation(convexA, localToWorldRT0In, bToA, convexB, output, *separation);
+ }
+ return true;
+ }
+ default:
+ case GjkInternal::STATUS_NON_INTERSECT:
+ {
+ if (separation)
+ {
+ _calcSeparation(convexA, localToWorldRT0In, bToA, convexB, output, *separation);
+ }
+ PxF32 val;
+ FStore(output.mDistSq, &val);
+ return val < (maxDistance * maxDistance);
+ }
+ }
+}
+
+static void _calcSeparation(const GjkInternal::ConvexV& convex, const physx::PxTransform& hullLocalToWorldRT, const PxVec3& sphereCenterWorld, PxF32 sphereRadius, const GjkInternal::Output& gjkOut, ConvexHullImpl::Separation& sep)
+{
+ using namespace physx::aos;
+
+ const Vec3V normal = gjkOut.getNormal();
+
+ // Calc the plane normal (in world space)
+ V3StoreU(normal, sep.plane.n);
+ sep.plane.n = hullLocalToWorldRT.rotate(sep.plane.n);
+
+ const PxF32 originOffset = sep.plane.n.dot(hullLocalToWorldRT.p);
+ convex.calcExtent(normal, sep.min0, sep.max0);
+ // The min and mix are in local space -> fix by taking into account world space origin
+ sep.min0 += originOffset;
+ sep.max0 += originOffset;
+
+ // Calculate the sphere radius
+ const PxF32 centerDist = sep.plane.n.dot(sphereCenterWorld);
+ // Work out the spheres
+ sep.min1 = centerDist - sphereRadius;
+ sep.max1 = centerDist + sphereRadius;
+ // Set the plane distance
+ sep.plane.d = (sep.max0 + sep.min1) * -0.5f;
+}
+
+bool ConvexHullImpl::sphereInProximity(const physx::PxTransform& hullLocalToWorldRT, const physx::PxVec3& hullScaleIn,
+ const physx::PxVec3& sphereWorldCenterIn, physx::PxF32 sphereRadius,
+ physx::PxF32 maxDistance, Separation* separation)
+{
+ using namespace physx::aos;
+
+ const PxU32 numVerts = getVertexCount();
+ const PxU32 numAov = (numVerts + 3) >> 2;
+
+#if PX_ANDROID == 1
+ Vec4V* verts = (Vec4V*)PxAllocaAligned(numAov * sizeof(Vec4V) * 3, 16);
+#else
+ Vec4V* verts = (Vec4V*)PxAlloca(numAov * sizeof(Vec4V) * 3);
+#endif
+ // Make sure it's aligned
+ PX_ASSERT((size_t(verts) & 0xf) == 0);
+
+ const Vec3V hullScale = V3LoadU(&hullScaleIn.x);
+
+ _arrayVec3ToVec4(mParams->vertices.buf, hullScale, verts, numVerts);
+
+ // Put the spheres center in the hulls space
+ Vec3V sphereCenterLocal = V3LoadU(hullLocalToWorldRT.transformInv(sphereWorldCenterIn));
+
+ // Load into simd mat
+ GjkInternal::ConvexV convex;
+
+ convex.mNumAovVertices = numAov;
+ convex.mAovVertices = verts;
+
+ // Calculate distance to center of sphere
+ GjkInternal::Output gjkOutput;
+ GjkInternal::Status status = GjkInternal::CollidePoint(convex, sphereCenterLocal, gjkOutput);
+
+ if (status == GjkInternal::STATUS_DEGENERATE)
+ {
+ FloatV sphereRadiusV = FLoad(sphereRadius);
+ status = FAllGrtr(gjkOutput.mDistSq, FMul(sphereRadiusV, sphereRadiusV)) ? GjkInternal::STATUS_NON_INTERSECT : GjkInternal::STATUS_CONTACT;
+ }
+
+ switch (status)
+ {
+ case GjkInternal::STATUS_CONTACT:
+ {
+ if (separation)
+ {
+ _calcSeparation(convex, hullLocalToWorldRT, sphereWorldCenterIn, sphereRadius, gjkOutput, *separation);
+ }
+ return true;
+ }
+ default:
+ case GjkInternal::STATUS_NON_INTERSECT:
+ {
+ if (separation)
+ {
+ _calcSeparation(convex, hullLocalToWorldRT, sphereWorldCenterIn, sphereRadius, gjkOutput, *separation);
+ }
+ const PxF32 maxTotal = maxDistance + sphereRadius;
+ PxF32 val;
+ FStore(gjkOutput.mDistSq, &val);
+ return val < (maxTotal * maxTotal);
+ }
+ }
+}
+
+#if PX_PHYSICS_VERSION_MAJOR == 3
+bool ConvexHullImpl::intersects(const PxShape& shape, const PxTransform& localToWorldRT, const PxVec3& scale, float padding) const
+{
+ PX_UNUSED(localToWorldRT);
+ PX_UNUSED(scale);
+ PX_UNUSED(padding);
+
+ switch (shape.getGeometryType())
+ {
+ case PxGeometryType::ePLANE: // xxx todo - implement
+ return true;
+ case PxGeometryType::eSPHERE: // xxx todo - implement
+ return true;
+ case PxGeometryType::eBOX: // xxx todo - implement
+ return true;
+ case PxGeometryType::eCAPSULE: // xxx todo - implement
+ return true;
+ case PxGeometryType::eCONVEXMESH: // xxx todo - implement
+ return true;
+ case PxGeometryType::eTRIANGLEMESH: // xxx todo - implement
+ return true;
+ case PxGeometryType::eHEIGHTFIELD: // xxx todo - implement
+ return true;
+ default:
+ return false;
+ }
+}
+#endif
+
+
+
+bool ConvexHullImpl::rayCast(float& in, float& out, const PxVec3& orig, const PxVec3& dir, const PxTransform& localToWorldRT, const PxVec3& scale, PxVec3* normal) const
+{
+ const uint32_t numSlabs = getUniquePlaneNormalCount();
+
+ if (numSlabs == 0)
+ {
+ return false;
+ }
+
+ // Create hull-local ray
+ PxVec3 localorig, localdir;
+ if (!worldToLocalRay(localorig, localdir, orig, dir, localToWorldRT, scale))
+ {
+ return false;
+ }
+
+ // Intersect with hull - local and world intersect 'times' are equal
+
+ if (normal != NULL)
+ {
+ *normal = PxVec3(0.0f); // This will be the value if the ray origin is within the hull
+ }
+
+ const float tol2 = (float)1.0e-14 * localdir.magnitudeSquared();
+
+ for (uint32_t slabN = 0; slabN < numSlabs; ++slabN)
+ {
+ ConvexHullParametersNS::Plane_Type& paramPlane = mParams->uniquePlanes.buf[slabN];
+ const PxPlane plane(paramPlane.normal, paramPlane.d);
+ const float num0 = -plane.distance(localorig);
+ const float num1 = mParams->widths.buf[slabN] - num0;
+ const float den = localdir.dot(plane.n);
+ if (den* den <= tol2) // Needs to be <=, so that localdir = (0,0,0) will act as a point check
+ {
+ if (num0 < 0 || num1 < 0)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if (den > 0)
+ {
+ if (num0 < in * den || num1 < out * (-den))
+ {
+ return false;
+ }
+ const float recipDen = 1.0f / den;
+ const float slabIn = -num1 * recipDen;
+ if (slabIn > in)
+ {
+ in = slabIn;
+ if (normal != NULL)
+ {
+ *normal = -plane.n;
+ }
+ }
+ out = PxMin(num0 * recipDen, out);
+ }
+ else
+ {
+ if (num0 < out * den || num1 < in * (-den))
+ {
+ return false;
+ }
+ const float recipDen = 1.0f / den;
+ const float slabIn = num0 * recipDen;
+ if (slabIn > in)
+ {
+ in = slabIn;
+ if (normal != NULL)
+ {
+ *normal = plane.n;
+ }
+ }
+ out = PxMin(-num1 * recipDen, out);
+ }
+ }
+ }
+
+ if (normal != NULL)
+ {
+ Cof44 cof(localToWorldRT, scale);
+ *normal = cof.getBlock33().transform(*normal);
+ normal->normalize();
+ }
+
+ return true;
+}
+
+bool ConvexHullImpl::obbSweep(float& in, float& out, const PxVec3& worldBoxCenter, const PxVec3& worldBoxExtents, const PxVec3 worldBoxAxes[3],
+ const PxVec3& worldDisp, const PxTransform& localToWorldRT, const PxVec3& scale, PxVec3* normal) const
+{
+ float tNormal = -PX_MAX_F32;
+
+ // Leave hull untransformed
+ const uint32_t numHullSlabs = getUniquePlaneNormalCount();
+ const uint32_t numHullVerts = getVertexCount();
+ ConvexHullParametersNS::Plane_Type* paramPlanes = mParams->uniquePlanes.buf;
+ const PxVec3* hullVerts = mParams->vertices.buf;
+ const float* hullWidths = mParams->widths.buf;
+
+ // Create inverse transform for box and displacement
+ const float detS = scale.x * scale.y * scale.z;
+ if (detS == 0.0f)
+ {
+ return false; // Not handling singular TMs
+ }
+ const float recipDetS = 1.0f / detS;
+ const PxVec3 invS(scale.y * scale.z * recipDetS, scale.z * scale.x * recipDetS, scale.x * scale.y * recipDetS);
+
+ // Create box directions and displacement - the box will become a parallelepiped in general. For brevity we'll still call it a box.
+ PxVec3 disp = localToWorldRT.rotateInv(worldDisp);
+ disp = invS.multiply(disp);
+
+ PxVec3 boxCenter = localToWorldRT.transformInv(worldBoxCenter);
+ boxCenter = invS.multiply(boxCenter);
+
+ PxVec3 boxAxes[3]; // Will not be orthonormal in general
+ for (uint32_t i = 0; i < 3; ++i)
+ {
+ boxAxes[i] = localToWorldRT.rotateInv(worldBoxAxes[i]);
+ boxAxes[i] *= worldBoxExtents[i];
+ boxAxes[i] = invS.multiply(boxAxes[i]);
+ }
+
+ PxVec3 boxFaceNormals[3];
+ float boxRadii[3];
+ const float octantVol = boxAxes[0].dot(boxAxes[1].cross(boxAxes[2]));
+ for (uint32_t i = 0; i < 3; ++i)
+ {
+ boxFaceNormals[i] = boxAxes[(1 << i) & 3].cross(boxAxes[(3 >> i) ^ 1]);
+ const float norm = PxRecipSqrt(boxFaceNormals[i].magnitudeSquared());
+ boxFaceNormals[i] *= norm;
+ boxRadii[i] = octantVol * norm;
+ }
+
+ // Test box against slabs of hull
+ for (uint32_t slabIndex = 0; slabIndex < numHullSlabs; ++slabIndex)
+ {
+ ConvexHullParametersNS::Plane_Type& paramPlane = paramPlanes[slabIndex];
+ const PxPlane plane(paramPlane.normal, paramPlane.d);
+ const float projectedRadius = PxAbs(plane.n.dot(boxAxes[0])) + PxAbs(plane.n.dot(boxAxes[1])) + PxAbs(plane.n.dot(boxAxes[2]));
+ const float projectedCenter = plane.n.dot(boxCenter);
+ const float vel0 = disp.dot(plane.n);
+ float tIn, tOut;
+ extentOverlapTimeInterval(tIn, tOut, vel0, projectedCenter - projectedRadius, projectedCenter + projectedRadius, -plane.d - hullWidths[slabIndex], -plane.d);
+ if (!updateTimeIntervalAndNormal(in, out, tNormal, normal, tIn, tOut, (-PxSign(vel0))*plane.n))
+ {
+ return false; // No intersection within the input time interval
+ }
+ }
+
+ // Test hull against box face directions
+ for (uint32_t faceIndex = 0; faceIndex < 3; ++faceIndex)
+ {
+ const PxVec3& faceNormal = boxFaceNormals[faceIndex];
+ float min, max;
+ getExtent(min, max, hullVerts, numHullVerts, sizeof(PxVec3), faceNormal);
+ const float projectedRadius = boxRadii[faceIndex];
+ const float projectedCenter = faceNormal.dot(boxCenter);
+ const float vel0 = disp.dot(faceNormal);
+ float tIn, tOut;
+ extentOverlapTimeInterval(tIn, tOut, vel0, projectedCenter - projectedRadius, projectedCenter + projectedRadius, min, max);
+ PxVec3 testFace = (-PxSign(vel0)) * faceNormal;
+ if (!updateTimeIntervalAndNormal(in, out, tNormal, normal, tIn, tOut, testFace))
+ {
+ return false; // No intersection within the input time interval
+ }
+ }
+
+ // Test hulls against cross-edge planes
+ const uint32_t numHullEdges = getUniqueEdgeDirectionCount();
+ for (uint32_t hullEdgeIndex = 0; hullEdgeIndex < numHullEdges; ++hullEdgeIndex)
+ {
+ const PxVec3 hullEdge = getEdgeDirection(hullEdgeIndex);
+ for (uint32_t boxEdgeIndex = 0; boxEdgeIndex < 3; ++boxEdgeIndex)
+ {
+ PxVec3 n = hullEdge.cross(boxAxes[boxEdgeIndex]);
+ const float n2 = n.magnitudeSquared();
+ if (n2 < PX_EPS_F32 * PX_EPS_F32)
+ {
+ continue;
+ }
+ n *= nvidia::recipSqrtFast(n2);
+ float vel0 = disp.dot(n);
+ // Choose normal direction such that the normal component of velocity is negative
+ if (vel0 > 0.0f)
+ {
+ vel0 = -vel0;
+ n *= -1.0f;
+ }
+ const float projectedRadius = PxAbs(n.dot(boxAxes[(1 << boxEdgeIndex) & 3])) +
+ PxAbs(n.dot(boxAxes[(3 >> boxEdgeIndex) ^ 1]));
+ const float projectedCenter = n.dot(boxCenter);
+ float min, max;
+ getExtent(min, max, hullVerts, numHullVerts, sizeof(PxVec3), n);
+ float tIn, tOut;
+ extentOverlapTimeInterval(tIn, tOut, vel0, projectedCenter - projectedRadius, projectedCenter + projectedRadius, min, max);
+ if (!updateTimeIntervalAndNormal(in, out, tNormal, normal, tIn, tOut, n))
+ {
+ return false; // No intersection within the input time interval
+ }
+ }
+ }
+
+ if (normal != NULL)
+ {
+ Cof44 cof(localToWorldRT, scale);
+ *normal = cof.getBlock33().transform(*normal);
+ normal->normalize();
+ }
+
+ return true;
+}
+
+void ConvexHullImpl::extent(float& min, float& max, const PxVec3& normal) const
+{
+ getExtent(min, max, mParams->vertices.buf, (uint32_t)mParams->vertices.arraySizes[0], sizeof(PxVec3), normal);
+}
+
+void ConvexHullImpl::fill(physx::Array<PxVec3>& outPoints, const PxTransform& localToWorldRT, const PxVec3& scale,
+ float spacing, float jitter, uint32_t maxPoints, bool adjustSpacing) const
+{
+ if (!maxPoints)
+ {
+ return;
+ }
+
+ const uint32_t numPlanes = getPlaneCount();
+ PxPlane* hull = (PxPlane*)PxAlloca(numPlanes * sizeof(PxPlane));
+ float* recipDens = (float*)PxAlloca(numPlanes * sizeof(float));
+
+ const Cof44 cof(localToWorldRT, scale); // matrix of cofactors to correctly transform planes
+ PxMat44 srt(localToWorldRT);
+ srt.scale(PxVec4(scale, 1.f));
+
+ PxBounds3 bounds;
+ bounds.setEmpty();
+ for (uint32_t vertN = 0; vertN < getVertexCount(); ++vertN)
+ {
+ PxVec3 worldVert = srt.transform(getVertex(vertN));
+ bounds.include(worldVert);
+ }
+
+ PxVec3 center, extents;
+ center = bounds.getCenter();
+ extents = bounds.getExtents();
+
+ const PxVec3 areas(extents[1]*extents[2], extents[2]*extents[0], extents[0]*extents[1]);
+ const uint32_t axisN = areas[0] < areas[1] ? (areas[0] < areas[2] ? 0u : 2u) : (areas[1] < areas[2] ? 1u : 2u);
+ const uint32_t axisN1 = (axisN + 1) % 3;
+ const uint32_t axisN2 = (axisN + 2) % 3;
+
+ if (adjustSpacing)
+ {
+ const float boxVolume = 8 * extents[0] * areas[0];
+ const float cellVolume = spacing * spacing * spacing;
+ if (boxVolume > maxPoints * cellVolume)
+ {
+ spacing = PxPow(boxVolume / maxPoints, 0.333333333f);
+ }
+ }
+
+ for (uint32_t planeN = 0; planeN < numPlanes; ++planeN)
+ {
+ cof.transform(getPlane(planeN), hull[planeN]);
+ recipDens[planeN] = PxAbs(hull[planeN].n[axisN]) > 1.0e-7 ? 1.0f / hull[planeN].n[axisN] : 0.0f;
+ }
+
+ const float recipSpacing = 1.0f / spacing;
+ const int32_t num1 = (int32_t)(extents[axisN1] * recipSpacing);
+ const int32_t num2 = (int32_t)(extents[axisN2] * recipSpacing);
+
+ QDSRand rnd;
+ const float scaledJitter = jitter * spacing;
+
+ PxVec3 orig;
+ for (int32_t i1 = -num1; i1 <= num1; ++i1)
+ {
+ orig[axisN1] = i1 * spacing + center[axisN1];
+ for (int32_t i2 = -num2; i2 <= num2; ++i2)
+ {
+ orig[axisN2] = i2 * spacing + center[axisN2];
+
+ float out = extents[axisN];
+ float in = -out;
+
+ orig[axisN] = center[axisN];
+
+ uint32_t planeN;
+ for (planeN = 0; planeN < numPlanes; ++planeN)
+ {
+ const PxPlane& plane = hull[planeN];
+ const float recipDen = recipDens[planeN];
+ const float num = -plane.distance(orig);
+ if (recipDen == 0.0f)
+ {
+ if (num < 0)
+ {
+ break;
+ }
+ }
+ else
+ {
+ const float t = num * recipDen;
+ if (recipDen > 0)
+ {
+ if (t < in)
+ {
+ break;
+ }
+ out = PxMin(t, out);
+ }
+ else
+ {
+ if (t > out)
+ {
+ break;
+ }
+ in = PxMax(t, in);
+ }
+ }
+ }
+
+ if (planeN == numPlanes)
+ {
+ const float depth = out - in;
+ const float stop = orig[axisN] + out;
+ orig[axisN] += in + 0.5f * (depth - spacing * (int)(depth * recipSpacing));
+ do
+ {
+ outPoints.pushBack(orig + scaledJitter * PxVec3(rnd.getNext(), rnd.getNext(), rnd.getNext()));
+ if (!--maxPoints)
+ {
+ return;
+ }
+ }
+ while ((orig[axisN] += spacing) <= stop);
+ }
+ }
+ }
+}
+
+#if PX_PHYSICS_VERSION_MAJOR == 3
+uint32_t ConvexHullImpl::calculateCookedSizes(uint32_t& vertexCount, uint32_t& faceCount, bool inflated) const
+{
+ PX_UNUSED(inflated);
+ vertexCount = 0;
+ faceCount = 0;
+ nvidia::PsMemoryBuffer memStream;
+ memStream.setEndianMode(PxFileBuf::ENDIAN_NONE);
+ PxStreamFromFileBuf nvs(memStream);
+ physx::PxConvexMeshDesc meshDesc;
+ meshDesc.points.count = getVertexCount();
+ meshDesc.points.data = &getVertex(0);
+ meshDesc.points.stride = sizeof(PxVec3);
+ meshDesc.flags = physx::PxConvexFlag::eCOMPUTE_CONVEX;
+ const float skinWidth = GetApexSDK()->getCookingInterface() != NULL ? GetApexSDK()->getCookingInterface()->getParams().skinWidth : 0.0f;
+ if (inflated && skinWidth > 0.0f)
+ {
+ meshDesc.flags |= physx::PxConvexFlag::eINFLATE_CONVEX;
+ }
+ if (GetApexSDK()->getCookingInterface()->cookConvexMesh(meshDesc, nvs))
+ {
+ PxConvexMesh* convexMesh = GetApexSDK()->getPhysXSDK()->createConvexMesh(nvs);
+ if (convexMesh != NULL)
+ {
+ vertexCount = convexMesh->getNbVertices();
+ faceCount = convexMesh->getNbPolygons();
+ }
+ convexMesh->release();
+ }
+
+ return memStream.getFileLength();
+}
+
+bool ConvexHullImpl::reduceByCooking()
+{
+ bool reduced = false;
+ nvidia::PsMemoryBuffer memStream;
+ memStream.setEndianMode(PxFileBuf::ENDIAN_NONE);
+ PxStreamFromFileBuf nvs(memStream);
+ physx::PxConvexMeshDesc meshDesc;
+ meshDesc.points.count = getVertexCount();
+ meshDesc.points.data = &getVertex(0);
+ meshDesc.points.stride = sizeof(PxVec3);
+ meshDesc.flags = physx::PxConvexFlag::eCOMPUTE_CONVEX;
+ if (GetApexSDK()->getCookingInterface()->cookConvexMesh(meshDesc, nvs))
+ {
+ PxConvexMesh* convexMesh = GetApexSDK()->getPhysXSDK()->createConvexMesh(nvs);
+ if (convexMesh != NULL)
+ {
+ const uint32_t vertexCount = convexMesh->getNbVertices();
+ reduced = vertexCount < getVertexCount();
+ if (reduced)
+ {
+ buildFromConvexMesh(convexMesh);
+ }
+ }
+ convexMesh->release();
+ }
+
+ return reduced;
+}
+#endif
+
+struct IndexedAngle
+{
+ float angle;
+ uint32_t index;
+
+ struct LT
+ {
+ PX_INLINE bool operator()(const IndexedAngle& a, const IndexedAngle& b) const
+ {
+ return a.angle < b.angle;
+ }
+ };
+};
+
+#if PX_PHYSICS_VERSION_MAJOR == 3
+bool ConvexHullImpl::reduceHull(uint32_t maxVertexCount, uint32_t maxEdgeCount, uint32_t maxFaceCount, bool inflated)
+{
+ // Translate max = 0 => max = "infinity"
+ if (maxVertexCount == 0)
+ {
+ maxVertexCount = 0xFFFFFFFF;
+ }
+
+ if (maxEdgeCount == 0)
+ {
+ maxEdgeCount = 0xFFFFFFFF;
+ }
+
+ if (maxFaceCount == 0)
+ {
+ maxFaceCount = 0xFFFFFFFF;
+ }
+
+ while (reduceByCooking()) {}
+
+ // Calculate sizes
+ uint32_t cookedVertexCount;
+ uint32_t cookedFaceCount;
+ calculateCookedSizes(cookedVertexCount, cookedFaceCount, inflated);
+ uint32_t cookedEdgeCount = cookedVertexCount + cookedFaceCount - 2;
+
+ // Return successfully if we've met the required limits
+ if (cookedVertexCount <= maxVertexCount && cookedEdgeCount <= maxEdgeCount && cookedFaceCount <= maxFaceCount)
+ {
+ return true;
+ }
+
+ NvParameterized::Handle handle(*mParams, "vertices");
+ uint32_t vertexCount = 0;
+ mParams->getArraySize(handle, (int32_t&)vertexCount);
+ if (vertexCount < 4)
+ {
+ return false;
+ }
+ physx::Array<PxVec3> vertices(vertexCount);
+ mParams->getParamVec3Array(handle, &vertices[0], (int32_t)vertexCount);
+
+ // We have at least four vertices in our hull. Find the tetrahedron with the largest volume.
+ PxMat44 tetrahedron;
+ float maxTetVolume = 0.0f;
+ uint32_t tetIndices[4] = {0,1,2,3};
+ for (uint32_t i = 0; i < vertexCount-3; ++i)
+ {
+ tetrahedron.column0 = PxVec4(vertices[i], 1.0f);
+ for (uint32_t j = i+1; j < vertexCount-2; ++j)
+ {
+ tetrahedron.column1 = PxVec4(vertices[j], 1.0f);
+ for (uint32_t k = j+1; k < vertexCount-1; ++k)
+ {
+ tetrahedron.column2 = PxVec4(vertices[k], 1.0f);
+ for (uint32_t l = k+1; l < vertexCount; ++l)
+ {
+ tetrahedron.column3 = PxVec4(vertices[l], 1.0f);
+ const float v = PxAbs(det(tetrahedron));
+ if (v > maxTetVolume)
+ {
+ maxTetVolume = v;
+ tetIndices[0] = i;
+ tetIndices[1] = j;
+ tetIndices[2] = k;
+ tetIndices[3] = l;
+ }
+ }
+ }
+ }
+ }
+
+ // Remove tetradhedral vertices from vertices array, put in reducedVertices array
+ physx::Array<PxVec3> reducedVertices(4);
+ for (uint32_t vNum = 4; vNum--;)
+ {
+ reducedVertices[vNum] = vertices[tetIndices[vNum]];
+ vertices.replaceWithLast(tetIndices[vNum]); // Works because tetIndices[i] < tetIndices[j] if i < j
+ }
+ buildFromPoints(&reducedVertices[0], 4, sizeof(PxVec3));
+
+ calculateCookedSizes(cookedVertexCount, cookedFaceCount, inflated);
+ cookedEdgeCount = cookedVertexCount + cookedFaceCount - 2;
+ if (cookedVertexCount > maxVertexCount || cookedEdgeCount > maxEdgeCount || cookedFaceCount > maxFaceCount)
+ {
+ return false; // Even a tetrahedron exceeds our limits
+ }
+
+ physx::Array<uint32_t> faceEdges;
+ while (vertices.size())
+ {
+ float maxVolumeIncrease = 0.0f;
+ uint32_t bestVertexIndex = 0;
+ for (uint32_t testVertexIndex = 0; testVertexIndex < vertices.size(); ++testVertexIndex)
+ {
+ const PxVec3& testVertex = vertices[testVertexIndex];
+ float volumeIncrease = 0.0f;
+ PxMat44 addedTet;
+ addedTet.column0 = PxVec4(testVertex, 1.0f);
+ for (uint32_t planeIndex = 0; planeIndex < getPlaneCount(); ++planeIndex)
+ {
+ const PxPlane plane = getPlane(planeIndex);
+ if (plane.distance(testVertex) <= 0.0f)
+ {
+ continue;
+ }
+ faceEdges.resize(0);
+ PxVec3 faceCenter(0.0f);
+ for (uint32_t edgeIndex = 0; edgeIndex < getEdgeCount(); ++edgeIndex)
+ {
+ if (getEdgeAdjacentFaceIndex(edgeIndex, 0) == planeIndex || getEdgeAdjacentFaceIndex(edgeIndex, 1) == planeIndex)
+ {
+ faceCenter += getVertex(getEdgeEndpointIndex(edgeIndex, 0)) + getVertex(getEdgeEndpointIndex(edgeIndex, 1));
+ faceEdges.pushBack(edgeIndex);
+ }
+ }
+ if (faceEdges.size())
+ {
+ faceCenter *= 0.5f/(float)faceEdges.size();
+ }
+ addedTet.column1 = PxVec4(faceCenter, 1.0f);
+ for (uint32_t edgeNum = 0; edgeNum < faceEdges.size(); ++edgeNum)
+ {
+ const uint32_t edgeIndex = faceEdges[edgeNum];
+ addedTet.column2 = PxVec4(getVertex(getEdgeEndpointIndex(edgeIndex,0)), 1.0f);
+ addedTet.column3 = PxVec4(getVertex(getEdgeEndpointIndex(edgeIndex,1)), 1.0f);
+ volumeIncrease += PxAbs(det(addedTet));
+ }
+ }
+ if (volumeIncrease > maxVolumeIncrease)
+ {
+ maxVolumeIncrease = volumeIncrease;
+ bestVertexIndex = testVertexIndex;
+ }
+ }
+
+ reducedVertices.pushBack(vertices[bestVertexIndex]);
+ vertices.replaceWithLast(bestVertexIndex);
+ buildFromPoints(&reducedVertices[0], reducedVertices.size(), sizeof(PxVec3));
+
+ calculateCookedSizes(cookedVertexCount, cookedFaceCount, inflated);
+ cookedEdgeCount = cookedVertexCount + cookedFaceCount - 2;
+ if (cookedVertexCount > maxVertexCount || cookedEdgeCount > maxEdgeCount || cookedFaceCount > maxFaceCount)
+ {
+ // Exceeded limits, remove last
+ reducedVertices.popBack();
+ buildFromPoints(&reducedVertices[0], reducedVertices.size(), sizeof(PxVec3));
+ break;
+ }
+ }
+
+ return true;
+}
+#endif
+
+bool ConvexHullImpl::createKDOPDirections(physx::Array<PxVec3>& directions, ConvexHullMethod::Enum method)
+{
+ uint32_t dirs;
+ switch (method)
+ {
+ case ConvexHullMethod::USE_6_DOP:
+ dirs = 0;
+ break;
+ case ConvexHullMethod::USE_10_DOP_X:
+ dirs = 1;
+ break;
+ case ConvexHullMethod::USE_10_DOP_Y:
+ dirs = 2;
+ break;
+ case ConvexHullMethod::USE_10_DOP_Z:
+ dirs = 4;
+ break;
+ case ConvexHullMethod::USE_14_DOP_XY:
+ dirs = 3;
+ break;
+ case ConvexHullMethod::USE_14_DOP_YZ:
+ dirs = 6;
+ break;
+ case ConvexHullMethod::USE_14_DOP_ZX:
+ dirs = 5;
+ break;
+ case ConvexHullMethod::USE_18_DOP:
+ dirs = 7;
+ break;
+ case ConvexHullMethod::USE_26_DOP:
+ dirs = 15;
+ break;
+ default:
+ return false;
+ }
+ directions.reset();
+ directions.pushBack(PxVec3(1, 0, 0));
+ directions.pushBack(PxVec3(0, 1, 0));
+ directions.pushBack(PxVec3(0, 0, 1));
+ if (dirs & 1)
+ {
+ directions.pushBack(PxVec3(0, 1, 1));
+ directions.pushBack(PxVec3(0, -1, 1));
+ }
+ if (dirs & 2)
+ {
+ directions.pushBack(PxVec3(1, 0, 1));
+ directions.pushBack(PxVec3(1, 0, -1));
+ }
+ if (dirs & 4)
+ {
+ directions.pushBack(PxVec3(1, 1, 0));
+ directions.pushBack(PxVec3(-1, 1, 0));
+ }
+ if (dirs & 8)
+ {
+ directions.pushBack(PxVec3(1, 1, 1));
+ directions.pushBack(PxVec3(-1, 1, 1));
+ directions.pushBack(PxVec3(1, -1, 1));
+ directions.pushBack(PxVec3(1, 1, -1));
+ }
+ return true;
+}
+
+
+void createIndexStartLookup(physx::Array<uint32_t>& lookup, int32_t indexBase, uint32_t indexRange, int32_t* indexSource, uint32_t indexCount, uint32_t indexByteStride)
+{
+ if (indexRange == 0)
+ {
+ lookup.resize(PxMax(indexRange + 1, 2u));
+ lookup[0] = 0;
+ lookup[1] = indexCount;
+ }
+ else
+ {
+ lookup.resize(indexRange + 1);
+ uint32_t indexPos = 0;
+ for (uint32_t i = 0; i < indexRange; ++i)
+ {
+ for (; indexPos < indexCount; ++indexPos, indexSource = (int32_t*)((uintptr_t)indexSource + indexByteStride))
+ {
+ if (*indexSource >= (int32_t)i + indexBase)
+ {
+ lookup[i] = indexPos;
+ break;
+ }
+ }
+ if (indexPos == indexCount)
+ {
+ lookup[i] = indexPos;
+ }
+ }
+ lookup[indexRange] = indexCount;
+ }
+}
+
+void findIslands(physx::Array< physx::Array<uint32_t> >& islands, const physx::Array<IntPair>& overlaps, uint32_t indexRange)
+{
+ // symmetrize the overlap list
+ physx::Array<IntPair> symOverlaps;
+ symOverlaps.reserve(2 * overlaps.size());
+ for (uint32_t i = 0; i < overlaps.size(); ++i)
+ {
+ const IntPair& pair = overlaps[i];
+ symOverlaps.pushBack(pair);
+ IntPair& reversed = symOverlaps.insert();
+ reversed.set(pair.i1, pair.i0);
+ }
+ // Sort symmetrized list
+ qsort(symOverlaps.begin(), symOverlaps.size(), sizeof(IntPair), IntPair::compare);
+ // Create overlap look-up
+ physx::Array<uint32_t> overlapStarts;
+ createIndexStartLookup(overlapStarts, 0, indexRange, &symOverlaps.begin()->i0, symOverlaps.size(), sizeof(IntPair));
+ // Find islands
+ IndexBank<uint32_t> objectIndices(indexRange);
+ objectIndices.lockCapacity(true);
+ uint32_t seedIndex = UINT32_MAX;
+ while (objectIndices.useNextFree(seedIndex))
+ {
+ physx::Array<uint32_t>& island = islands.insert();
+ island.pushBack(seedIndex);
+ for (uint32_t i = 0; i < island.size(); ++i)
+ {
+ const uint32_t index = island[i];
+ for (uint32_t j = overlapStarts[index]; j < overlapStarts[index + 1]; ++j)
+ {
+ PX_ASSERT(symOverlaps[j].i0 == (int32_t)index);
+ const uint32_t overlapIndex = (uint32_t)symOverlaps[j].i1;
+ if (objectIndices.use(overlapIndex))
+ {
+ island.pushBack(overlapIndex);
+ }
+ }
+ }
+ }
+}
+
+
+// Neighbor-finding utility class
+
+void NeighborLookup::setBounds(const BoundsRep* bounds, uint32_t boundsCount, uint32_t boundsByteStride)
+{
+ m_neighbors.resize(0);
+ m_firstNeighbor.resize(0);
+
+ if (bounds != NULL && boundsCount > 0 && boundsByteStride >= sizeof(BoundsRep))
+ {
+ physx::Array<IntPair> overlaps;
+ boundsCalculateOverlaps(overlaps, Bounds3XYZ, bounds, boundsCount, boundsByteStride);
+ // symmetrize the overlap list
+ const uint32_t oldSize = overlaps.size();
+ overlaps.resize(2 * oldSize);
+ for (uint32_t i = 0; i < oldSize; ++i)
+ {
+ const IntPair& pair = overlaps[i];
+ overlaps[i+oldSize].set(pair.i1, pair.i0);
+ }
+ // Sort symmetrized list
+ qsort(overlaps.begin(), overlaps.size(), sizeof(IntPair), IntPair::compare);
+ // Create overlap look-up
+ if (overlaps.size() > 0)
+ {
+ createIndexStartLookup(m_firstNeighbor, 0, boundsCount, &overlaps[0].i0, overlaps.size(), sizeof(IntPair));
+ m_neighbors.resize(overlaps.size());
+ for (uint32_t i = 0; i < overlaps.size(); ++i)
+ {
+ m_neighbors[i] = (uint32_t)overlaps[i].i1;
+ }
+ }
+ }
+}
+
+uint32_t NeighborLookup::getNeighborCount(const uint32_t index) const
+{
+ if (index + 1 >= m_firstNeighbor.size())
+ {
+ return 0; // Invalid neighbor list or index
+ }
+
+ return m_firstNeighbor[index+1] - m_firstNeighbor[index];
+}
+
+const uint32_t* NeighborLookup::getNeighbors(const uint32_t index) const
+{
+ if (index + 1 >= m_firstNeighbor.size())
+ {
+ return 0; // Invalid neighbor list or index
+ }
+
+ return &m_neighbors[m_firstNeighbor[index]];
+}
+
+
+// Data conversion macros
+
+#define copyBuffer( _DstFormat, _SrcFormat ) \
+ { \
+ uint32_t _numVertices = numVertices; \
+ int32_t* _invMap = invMap; \
+ _DstFormat##_TYPE* _dst = (_DstFormat##_TYPE*)dst; \
+ const _SrcFormat##_TYPE* _src = (const _SrcFormat##_TYPE*)src; \
+ if( _invMap == NULL ) \
+ { \
+ while( _numVertices-- ) \
+ { \
+ convert_##_DstFormat##_from_##_SrcFormat( *_dst, *_src ); \
+ ((uint8_t*&)_dst) += dstStride; \
+ ((const uint8_t*&)_src) += srcStride; \
+ } \
+ } \
+ else \
+ { \
+ while( _numVertices-- ) \
+ { \
+ const int32_t invMapValue = *_invMap++; \
+ if (invMapValue >= 0) \
+ { \
+ _DstFormat##_TYPE* _dstElem = (_DstFormat##_TYPE*)((uint8_t*)_dst + invMapValue*dstStride); \
+ convert_##_DstFormat##_from_##_SrcFormat( *_dstElem, *_src ); \
+ } \
+ ((const uint8_t*&)_src) += srcStride; \
+ } \
+ } \
+ }
+
+
+#define HANDLE_COPY1( _DstFormat, _SrcFormat ) \
+ case RenderDataFormat::_DstFormat : \
+ if( srcFormat == RenderDataFormat::_SrcFormat ) \
+ { \
+ copyBuffer( _DstFormat, _SrcFormat ); \
+ } \
+ break;
+
+#define HANDLE_COPY2( _DstFormat, _SrcFormat1, _SrcFormat2 ) \
+ case RenderDataFormat::_DstFormat : \
+ if( srcFormat == RenderDataFormat::_SrcFormat1 ) \
+ { \
+ copyBuffer( _DstFormat, _SrcFormat1 ); \
+ } \
+ else if( srcFormat == RenderDataFormat::_SrcFormat2 ) \
+ { \
+ copyBuffer( _DstFormat, _SrcFormat2 ); \
+ } \
+ break;
+
+#define HANDLE_COPY3( _DstFormat, _SrcFormat1, _SrcFormat2, _SrcFormat3 ) \
+ case RenderDataFormat::_DstFormat : \
+ if( srcFormat == RenderDataFormat::_SrcFormat1 ) \
+ { \
+ copyBuffer( _DstFormat, _SrcFormat1 ); \
+ } \
+ else if( srcFormat == RenderDataFormat::_SrcFormat2 ) \
+ { \
+ copyBuffer( _DstFormat, _SrcFormat2 ); \
+ } \
+ else if( srcFormat == RenderDataFormat::_SrcFormat3 ) \
+ { \
+ copyBuffer( _DstFormat, _SrcFormat3 ); \
+ } \
+ break;
+
+// ... etc.
+
+
+bool copyRenderVertexBuffer(void* dst, RenderDataFormat::Enum dstFormat, uint32_t dstStride, uint32_t dstStart, const void* src, RenderDataFormat::Enum srcFormat, uint32_t srcStride, uint32_t srcStart, uint32_t numVertices, int32_t* invMap)
+{
+ const uint32_t dstDataSize = RenderDataFormat::getFormatDataSize(dstFormat);
+ if (dstStride == 0)
+ {
+ dstStride = dstDataSize;
+ }
+
+ if (dstStride < dstDataSize)
+ {
+ return false;
+ }
+
+ // advance src pointer
+ ((const uint8_t*&)src) += srcStart * srcStride;
+
+ PX_ASSERT((dstStart == 0) || (invMap == NULL)); // can only be one of them, won't work if its both!
+
+ if (dstFormat == srcFormat)
+ {
+ if (dstFormat != RenderDataFormat::UNSPECIFIED)
+ {
+ // Direct data copy
+
+ // advance dst pointer
+ ((const uint8_t*&)dst) += dstStart * dstStride;
+
+ if (invMap == NULL)
+ {
+ while (numVertices--)
+ {
+ memcpy(dst, src, dstDataSize);
+ ((uint8_t*&)dst) += dstStride;
+ ((const uint8_t*&)src) += srcStride;
+ }
+ }
+ else
+ {
+ while (numVertices--)
+ {
+ const int32_t invMapValue = *invMap++;
+ if (invMapValue >= 0)
+ {
+ void* mappedDst = (void*)((uint8_t*)dst + dstStride * (invMapValue));
+ memcpy(mappedDst, src, dstDataSize);
+ }
+ ((const uint8_t*&)src) += srcStride;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ // advance dst pointer
+ ((const uint8_t*&)dst) += dstStart * dstStride;
+
+ switch (dstFormat)
+ {
+ case RenderDataFormat::UNSPECIFIED:
+ // Handle unspecified by doing nothing (still no error!)
+ break;
+
+ // Put format converters here
+ HANDLE_COPY1(USHORT1, UINT1)
+ HANDLE_COPY1(USHORT2, UINT2)
+ HANDLE_COPY1(USHORT3, UINT3)
+ HANDLE_COPY1(USHORT4, UINT4)
+
+ HANDLE_COPY1(UINT1, USHORT1)
+ HANDLE_COPY1(UINT2, USHORT2)
+ HANDLE_COPY1(UINT3, USHORT3)
+ HANDLE_COPY1(UINT4, USHORT4)
+
+ HANDLE_COPY1(BYTE_SNORM1, FLOAT1)
+ HANDLE_COPY1(BYTE_SNORM2, FLOAT2)
+ HANDLE_COPY1(BYTE_SNORM3, FLOAT3)
+ HANDLE_COPY1(BYTE_SNORM4, FLOAT4)
+ HANDLE_COPY1(BYTE_SNORM4_QUATXYZW, FLOAT4_QUAT)
+ HANDLE_COPY1(SHORT_SNORM1, FLOAT1)
+ HANDLE_COPY1(SHORT_SNORM2, FLOAT2)
+ HANDLE_COPY1(SHORT_SNORM3, FLOAT3)
+ HANDLE_COPY1(SHORT_SNORM4, FLOAT4)
+ HANDLE_COPY1(SHORT_SNORM4_QUATXYZW, FLOAT4_QUAT)
+
+ HANDLE_COPY2(FLOAT1, BYTE_SNORM1, SHORT_SNORM1)
+ HANDLE_COPY2(FLOAT2, BYTE_SNORM2, SHORT_SNORM2)
+ HANDLE_COPY2(FLOAT3, BYTE_SNORM3, SHORT_SNORM3)
+ HANDLE_COPY2(FLOAT4, BYTE_SNORM4, SHORT_SNORM4)
+ HANDLE_COPY2(FLOAT4_QUAT, BYTE_SNORM4_QUATXYZW, SHORT_SNORM4_QUATXYZW)
+
+ HANDLE_COPY3(R8G8B8A8, B8G8R8A8, R32G32B32A32_FLOAT, B32G32R32A32_FLOAT)
+ HANDLE_COPY3(B8G8R8A8, R8G8B8A8, R32G32B32A32_FLOAT, B32G32R32A32_FLOAT)
+ HANDLE_COPY3(R32G32B32A32_FLOAT, R8G8B8A8, B8G8R8A8, B32G32R32A32_FLOAT)
+ HANDLE_COPY3(B32G32R32A32_FLOAT, R8G8B8A8, B8G8R8A8, R32G32B32A32_FLOAT)
+
+ default:
+ {
+ PX_ALWAYS_ASSERT(); // Format conversion not handled
+ return false;
+ }
+ }
+
+
+ return true;
+}
+
+
+
+/************************************************************************/
+// Convex Hull from Planes
+/************************************************************************/
+
+// copied from //sw/physx/PhysXSDK/3.2/trunk/Source/Common/src/CmMathUtils.cpp
+PxQuat PxShortestRotation(const PxVec3& v0, const PxVec3& v1)
+{
+ const float d = v0.dot(v1);
+ const PxVec3 cross = v0.cross(v1);
+
+ PxQuat q = d>-1 ? PxQuat(cross.x, cross.y, cross.z, 1+d)
+ : PxAbs(v0.x)<0.1f ? PxQuat(0.0f, v0.z, -v0.y, 0.0f) : PxQuat(v0.y, -v0.x, 0.0f, 0.0f);
+
+ return q.getNormalized();
+}
+
+PxTransform PxTransformFromPlaneEquation(const PxPlane& plane)
+{
+ PxPlane p = plane;
+ p.normalize();
+
+ // special case handling for axis aligned planes
+ const float halfsqrt2 = 0.707106781;
+ PxQuat q;
+ if(2 == (p.n.x == 0.0f) + (p.n.y == 0.0f) + (p.n.z == 0.0f)) // special handling for axis aligned planes
+ {
+ if(p.n.x > 0) q = PxQuat(PxIdentity);
+ else if(p.n.x < 0) q = PxQuat(0, 0, 1, 0);
+ else q = PxQuat(0.0f, -p.n.z, p.n.y, 1) * halfsqrt2;
+ }
+ else q = PxShortestRotation(PxVec3(1,0,0), p.n);
+
+ return PxTransform(-p.n * p.d, q);
+}
+
+
+
+PxVec3 intersect(PxVec4 p0, PxVec4 p1, PxVec4 p2)
+{
+ const PxVec3& d0 = reinterpret_cast<const PxVec3&>(p0);
+ const PxVec3& d1 = reinterpret_cast<const PxVec3&>(p1);
+ const PxVec3& d2 = reinterpret_cast<const PxVec3&>(p2);
+
+ return (p0.w * d1.cross(d2)
+ + p1.w * d2.cross(d0)
+ + p2.w * d0.cross(d1))
+ / d0.dot(d2.cross(d1));
+}
+
+const uint16_t sInvalid = uint16_t(-1);
+
+// restriction: only supports a single patch per vertex.
+struct HalfedgeMesh
+{
+ struct Halfedge
+ {
+ Halfedge(uint16_t vertex = sInvalid, uint16_t face = sInvalid,
+ uint16_t next = sInvalid, uint16_t prev = sInvalid)
+ : mVertex(vertex), mFace(face), mNext(next), mPrev(prev)
+ {}
+
+ uint16_t mVertex; // to
+ uint16_t mFace; // left
+ uint16_t mNext; // ccw
+ uint16_t mPrev; // cw
+ };
+
+ HalfedgeMesh() : mNumTriangles(0) {}
+
+ uint16_t findHalfedge(uint16_t v0, uint16_t v1)
+ {
+ uint16_t h = mVertices[v0], start = h;
+ while(h != sInvalid && mHalfedges[h].mVertex != v1)
+ {
+ h = mHalfedges[(uint32_t)h ^ 1].mNext;
+ if(h == start)
+ return sInvalid;
+ }
+ return h;
+ }
+
+ void connect(uint16_t h0, uint16_t h1)
+ {
+ mHalfedges[h0].mNext = h1;
+ mHalfedges[h1].mPrev = h0;
+ }
+
+ void addTriangle(uint16_t v0, uint16_t v1, uint16_t v2)
+ {
+ // add new vertices
+ uint16_t n = (uint16_t)(PxMax(v0, PxMax(v1, v2))+1);
+ if(mVertices.size() < n)
+ mVertices.resize(n, sInvalid);
+
+ // collect halfedges, prev and next of triangle
+ uint16_t verts[] = { v0, v1, v2 };
+ uint16_t handles[3], prev[3], next[3];
+ for(uint16_t i=0; i<3; ++i)
+ {
+ uint16_t j = (uint16_t)((i+1)%3);
+ uint16_t h = findHalfedge(verts[i], verts[j]);
+ if(h == sInvalid)
+ {
+ // add new edge
+ PX_ASSERT(mHalfedges.size() <= UINT16_MAX);
+ h = (uint16_t)mHalfedges.size();
+ mHalfedges.pushBack(Halfedge(verts[j]));
+ mHalfedges.pushBack(Halfedge(verts[i]));
+ }
+ handles[i] = h;
+ prev[i] = mHalfedges[h].mPrev;
+ next[i] = mHalfedges[h].mNext;
+ }
+
+ // patch connectivity
+ for(uint16_t i=0; i<3; ++i)
+ {
+ uint16_t j = (uint16_t)((i+1)%3);
+
+ PX_ASSERT(mFaces.size() <= UINT16_MAX);
+ mHalfedges[handles[i]].mFace = (uint16_t)mFaces.size();
+
+ // connect prev and next
+ connect(handles[i], handles[j]);
+
+ if(next[j] == sInvalid) // new next edge, connect opposite
+ connect((uint32_t)(handles[j]^1), next[i]!=sInvalid ? next[i] : (uint32_t)(handles[i]^1));
+
+ if(prev[i] == sInvalid) // new prev edge, connect opposite
+ connect(prev[j]!=sInvalid ? prev[j] : (uint32_t)(handles[j]^1), (uint32_t)(handles[i]^1));
+
+ // prev is boundary, update middle vertex
+ if(mHalfedges[(uint32_t)(handles[i]^1)].mFace == sInvalid)
+ mVertices[verts[j]] = (uint32_t)(handles[i]^1);
+ }
+
+ mFaces.pushBack(handles[2]);
+ ++mNumTriangles;
+ }
+
+ uint16_t removeTriangle(uint16_t f)
+ {
+ uint16_t result = sInvalid;
+
+ for(uint16_t i=0, h = mFaces[f]; i<3; ++i)
+ {
+ uint16_t v0 = mHalfedges[(uint32_t)(h^1)].mVertex;
+ uint16_t v1 = mHalfedges[h].mVertex;
+
+ mHalfedges[h].mFace = sInvalid;
+
+ if(mHalfedges[(uint32_t)(h^1)].mFace == sInvalid) // was boundary edge, remove
+ {
+ uint16_t v0Prev = mHalfedges[h ].mPrev;
+ uint16_t v0Next = mHalfedges[(uint32_t)(h^1)].mNext;
+ uint16_t v1Prev = mHalfedges[(uint32_t)(h^1)].mPrev;
+ uint16_t v1Next = mHalfedges[h ].mNext;
+
+ // update halfedge connectivity
+ connect(v0Prev, v0Next);
+ connect(v1Prev, v1Next);
+
+ // update vertex boundary or delete
+ mVertices[v0] = (v0Prev^1) == v0Next ? sInvalid : v0Next;
+ mVertices[v1] = (v1Prev^1) == v1Next ? sInvalid : v1Next;
+ }
+ else
+ {
+ mVertices[v0] = h; // update vertex boundary
+ result = v1;
+ }
+
+ h = mHalfedges[h].mNext;
+ }
+
+ mFaces[f] = sInvalid;
+ --mNumTriangles;
+
+ return result;
+ }
+
+ // true if vertex v is in front of face f
+ bool visible(uint16_t v, uint16_t f)
+ {
+ uint16_t h = mFaces[f];
+ if(h == sInvalid)
+ return false;
+
+ uint16_t v0 = mHalfedges[h].mVertex;
+ h = mHalfedges[h].mNext;
+ uint16_t v1 = mHalfedges[h].mVertex;
+ h = mHalfedges[h].mNext;
+ uint16_t v2 = mHalfedges[h].mVertex;
+ h = mHalfedges[h].mNext;
+
+ return det(mPoints[v], mPoints[v0], mPoints[v1], mPoints[v2]) < -1e-5f;
+ }
+
+ /*
+ void print() const
+ {
+ for(uint32_t i=0; i<mFaces.size(); ++i)
+ {
+ printf("f%u: ", i);
+ uint16_t h = mFaces[i];
+ if(h == sInvalid)
+ {
+ printf("deleted\n");
+ continue;
+ }
+
+ for(int j=0; j<3; ++j)
+ {
+ printf("h%u -> v%u -> ", uint32_t(h), uint32_t(mHalfedges[h].mVertex));
+ h = mHalfedges[h].mNext;
+ }
+
+ printf("\n");
+ }
+
+ for(uint32_t i=0; i<mVertices.size(); ++i)
+ {
+ printf("v%u: ", i);
+ uint16_t h = mVertices[i];
+ if(h == sInvalid)
+ {
+ printf("deleted\n");
+ continue;
+ }
+
+ uint16_t start = h;
+ do {
+ printf("h%u -> v%u, ", uint32_t(h), uint32_t(mHalfedges[h].mVertex));
+ h = mHalfedges[h^1].mNext;
+ } while (h != start);
+
+ printf("\n");
+ }
+
+ for(uint32_t i=0; i<mHalfedges.size(); ++i)
+ printf("h%u: v%u, f%u, p%u, n%u\n", i, uint32_t(mHalfedges[i].mVertex),
+ uint32_t(mHalfedges[i].mFace), uint32_t(mHalfedges[i].mPrev), uint32_t(mHalfedges[i].mNext));
+ }
+ */
+
+ nvidia::Array<Halfedge> mHalfedges;
+ nvidia::Array<uint16_t> mVertices; // vertex -> (boundary) halfedge
+ nvidia::Array<uint16_t> mFaces; // face -> halfedge
+ nvidia::Array<PxVec4> mPoints;
+ uint16_t mNumTriangles;
+};
+
+
+
+void ConvexMeshBuilder::operator()(uint32_t planeMask, float scale)
+{
+ uint32_t numPlanes = shdfnd::bitCount(planeMask);
+
+ if (numPlanes == 1)
+ {
+ PxTransform t = nvidia::apex::PxTransformFromPlaneEquation(reinterpret_cast<const PxPlane&>(mPlanes[lowestSetBit(planeMask)]));
+
+ if (!t.isValid())
+ return;
+
+ const uint16_t indices[] = { 0, 1, 2, 0, 2, 3 };
+ const PxVec3 vertices[] = {
+ PxVec3(0.0f, scale, scale),
+ PxVec3(0.0f, -scale, scale),
+ PxVec3(0.0f, -scale, -scale),
+ PxVec3(0.0f, scale, -scale) };
+
+ PX_ASSERT(mVertices.size() <= UINT16_MAX);
+ uint16_t baseIndex = (uint16_t)mVertices.size();
+
+ for (uint32_t i=0; i < 4; ++i)
+ mVertices.pushBack(t.transform(vertices[i]));
+
+ for (uint32_t i=0; i < 6; ++i)
+ mIndices.pushBack((uint16_t)(indices[i] + baseIndex));
+
+ return;
+ }
+
+ if(numPlanes < 4)
+ return; // todo: handle degenerate cases
+
+ HalfedgeMesh mesh;
+
+ // gather points (planes, that is)
+ mesh.mPoints.reserve(numPlanes);
+ for(; planeMask; planeMask &= planeMask-1)
+ mesh.mPoints.pushBack(mPlanes[shdfnd::lowestSetBit(planeMask)]);
+
+ // initialize to tetrahedron
+ mesh.addTriangle(0, 1, 2);
+ mesh.addTriangle(0, 3, 1);
+ mesh.addTriangle(1, 3, 2);
+ mesh.addTriangle(2, 3, 0);
+
+ // flip if inside-out
+ if(mesh.visible(3, 0))
+ shdfnd::swap(mesh.mPoints[0], mesh.mPoints[1]);
+
+ // iterate through remaining points
+ for(uint16_t i=4; i<mesh.mPoints.size(); ++i)
+ {
+ // remove any visible triangle
+ uint16_t v0 = sInvalid;
+ for(uint16_t j=0; j<mesh.mFaces.size(); ++j)
+ {
+ if(mesh.visible(i, j))
+ v0 = PxMin(v0, mesh.removeTriangle(j));
+ }
+
+ if(v0 == sInvalid)
+ continue; // no triangle removed
+
+ if(!mesh.mNumTriangles)
+ return; // empty mesh
+
+ // find non-deleted boundary vertex
+ for(uint16_t h=0; mesh.mVertices[v0] == sInvalid; h+=2)
+ {
+ if ((mesh.mHalfedges[h ].mFace == sInvalid) ^
+ (mesh.mHalfedges[(uint32_t)(h+1)].mFace == sInvalid))
+ {
+ v0 = mesh.mHalfedges[h].mVertex;
+ }
+ }
+
+ // tesselate hole
+ uint16_t start = v0;
+ do {
+ uint16_t h = mesh.mVertices[v0];
+ uint16_t v1 = mesh.mHalfedges[h].mVertex;
+ if(mesh.mFaces.size() == UINT16_MAX)
+ break; // safety net
+ mesh.addTriangle(v0, v1, i);
+ v0 = v1;
+ } while(v0 != start);
+
+ bool noHole = true;
+ for(uint16_t h=0; noHole && h < mesh.mHalfedges.size(); h+=2)
+ {
+ if ((mesh.mHalfedges[h ].mFace == sInvalid) ^
+ (mesh.mHalfedges[(uint32_t)(h+1)].mFace == sInvalid))
+ noHole = false;
+ }
+
+ if(!noHole || mesh.mFaces.size() == UINT16_MAX)
+ {
+ mesh.mFaces.resize(0);
+ mesh.mVertices.resize(0);
+ break;
+ }
+ }
+
+ // convert triangles to vertices (intersection of 3 planes)
+ nvidia::Array<uint32_t> face2Vertex(mesh.mFaces.size());
+ for(uint32_t i=0; i<mesh.mFaces.size(); ++i)
+ {
+ face2Vertex[i] = mVertices.size();
+
+ uint16_t h = mesh.mFaces[i];
+ if(h == sInvalid)
+ continue;
+
+ uint16_t v0 = mesh.mHalfedges[h].mVertex;
+ h = mesh.mHalfedges[h].mNext;
+ uint16_t v1 = mesh.mHalfedges[h].mVertex;
+ h = mesh.mHalfedges[h].mNext;
+ uint16_t v2 = mesh.mHalfedges[h].mVertex;
+
+ mVertices.pushBack(intersect(mesh.mPoints[v0], mesh.mPoints[v1], mesh.mPoints[v2]));
+ }
+
+ // convert vertices to polygons (face one-ring)
+ for(uint32_t i=0; i<mesh.mVertices.size(); ++i)
+ {
+ uint16_t h = mesh.mVertices[i];
+ if(h == sInvalid)
+ continue;
+
+ uint32_t v0 = face2Vertex[mesh.mHalfedges[h].mFace];
+ h = (uint16_t)(mesh.mHalfedges[h].mPrev^1);
+ uint32_t v1 = face2Vertex[mesh.mHalfedges[h].mFace];
+
+ while(true)
+ {
+ h = (uint16_t)(mesh.mHalfedges[h].mPrev^1);
+ uint32_t v2 = face2Vertex[mesh.mHalfedges[h].mFace];
+
+ if(v0 == v2)
+ break;
+
+ PX_ASSERT(v0 <= UINT16_MAX);
+ PX_ASSERT(v1 <= UINT16_MAX);
+ PX_ASSERT(v2 <= UINT16_MAX);
+ mIndices.pushBack((uint16_t)v0);
+ mIndices.pushBack((uint16_t)v2);
+ mIndices.pushBack((uint16_t)v1);
+
+ v1 = v2;
+ }
+
+ }
+}
+
+// Diagonalize a symmetric 3x3 matrix. Returns the eigenvectors in the first parameter, eigenvalues as the return value.
+PxVec3 diagonalizeSymmetric(PxMat33& eigenvectors, const PxMat33& m)
+{
+ // jacobi rotation using quaternions (from an idea of Stan Melax, with fix for precision issues)
+
+ const uint32_t MAX_ITERS = 24;
+
+ PxQuat q = PxQuat(PxIdentity);
+
+ PxMat33 d;
+ for(uint32_t i=0; i < MAX_ITERS;i++)
+ {
+ eigenvectors = PxMat33(q);
+ d = eigenvectors.getTranspose() * m * eigenvectors;
+
+ const float d0 = PxAbs(d[1][2]), d1 = PxAbs(d[0][2]), d2 = PxAbs(d[0][1]);
+ const uint32_t a = d0 > d1 && d0 > d2 ? 0u : d1 > d2 ? 1u : 2u; // rotation axis index, from largest off-diagonal element
+
+ const uint32_t a1 = (a+1)%3;
+ const uint32_t a2 = (a+2)%3;
+ if(d[a1][a2] == 0.0f || PxAbs(d[a1][a1]-d[a2][a2]) > 2e6*PxAbs(2.0f*d[a1][a2]))
+ {
+ break;
+ }
+
+ const float w = (d[a1][a1]-d[a2][a2]) / (2.0f*d[a1][a2]); // cot(2 * phi), where phi is the rotation angle
+ const float absw = PxAbs(w);
+
+ float c, s;
+ if(absw>1000)
+ {
+ c = 1;
+ s = 1/(4*w); // h will be very close to 1, so use small angle approx instead
+ }
+ else
+ {
+ float t = 1 / (absw + PxSqrt(w*w+1)); // absolute value of tan phi
+ float h = 1 / PxSqrt(t*t+1); // absolute value of cos phi
+ PX_ASSERT(h!=1); // |w|<1000 guarantees this with typical IEEE754 machine eps (approx 6e-8)
+ c = PxSqrt((1+h)/2);
+ s = PxSqrt((1-h)/2) * PxSign(w);
+ }
+
+ PxQuat r(0,0,0,c);
+ reinterpret_cast<PxVec4&>(r)[a] = s;
+
+ q = (q*r).getNormalized();
+ }
+
+ return PxVec3(d.column0.x, d.column1.y, d.column2.z);
+}
+
+
+
+}
+} // end namespace nvidia::apex
diff --git a/APEX_1.4/common/src/ApexSubdivider.cpp b/APEX_1.4/common/src/ApexSubdivider.cpp
new file mode 100644
index 00000000..072101ad
--- /dev/null
+++ b/APEX_1.4/common/src/ApexSubdivider.cpp
@@ -0,0 +1,766 @@
+/*
+ * 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 "ApexSubdivider.h"
+
+#include "ApexSDKIntl.h"
+
+#include "PsSort.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+ApexSubdivider::ApexSubdivider() :
+ mMarkedVertices(0),
+ mTriangleListEmptyElement(-1)
+{
+ mBound.setEmpty();
+ mRand.setSeed(0);
+}
+
+
+
+
+void ApexSubdivider::clear()
+{
+ mBound.setEmpty();
+ mRand.setSeed(0);
+}
+
+
+
+void ApexSubdivider::registerVertex(const PxVec3& v, uint32_t bitFlagPayload)
+{
+ SubdividerVertex vertex(v, bitFlagPayload);
+ mVertices.pushBack(vertex);
+ mBound.include(v);
+}
+
+
+
+void ApexSubdivider::registerTriangle(uint32_t i0, uint32_t i1, uint32_t i2)
+{
+ PX_ASSERT(i0 < mVertices.size());
+ PX_ASSERT(i1 < mVertices.size());
+ PX_ASSERT(i2 < mVertices.size());
+
+ SubdividerTriangle t;
+ t.init(i0, i1, i2);
+ uint32_t triangleNumber = mTriangles.size();
+ mTriangles.pushBack(t);
+ addTriangleToVertex(i0, triangleNumber);
+ addTriangleToVertex(i1, triangleNumber);
+ addTriangleToVertex(i2, triangleNumber);
+}
+
+
+
+void ApexSubdivider::endRegistration()
+{
+
+}
+
+
+
+void ApexSubdivider::mergeVertices(IProgressListener* progress)
+{
+ PX_UNUSED(progress);
+ if (mVertices.empty())
+ {
+ APEX_INVALID_OPERATION("no vertices available");
+ return;
+ }
+
+ const float MERGE_THRESHOLD = 1.0e-6f;
+
+ const float d = (mBound.minimum - mBound.maximum).magnitude() * MERGE_THRESHOLD;
+ const float d2 = d * d;
+
+ Array<SubdividerVertexRef> refs;
+ refs.reserve(mVertices.size());
+
+ for (uint32_t i = 0; i < mVertices.size(); i++)
+ {
+ SubdividerVertex& v = mVertices[i];
+ v.marked = false;
+ SubdividerVertexRef vr(v.pos, i);
+ refs.pushBack(vr);
+ }
+ mMarkedVertices = 0;
+
+ shdfnd::sort(refs.begin(), refs.size(), SubdividerVertexRef());
+
+ for (uint32_t i = 0; i < refs.size() - 1; i++)
+ {
+ uint32_t iNr = refs[i].vertexNr;
+ SubdividerVertex& vi = mVertices[iNr];
+
+ if (vi.marked)
+ {
+ continue;
+ }
+
+ const PxVec3 pos = refs[i].pos;
+ uint32_t j = i + 1;
+ while (j < refs.size() && fabs(refs[j].pos.x - pos.x) < MERGE_THRESHOLD)
+ {
+ if ((refs[j].pos - pos).magnitudeSquared() < d2)
+ {
+ uint32_t jNr = refs[j].vertexNr;
+ SubdividerVertex& vj = mVertices[jNr];
+
+ const uint32_t payload = vi.payload | vj.payload;
+ vi.payload = vj.payload = payload;
+
+ if (vj.firstTriangle != -1)
+ {
+ // find vi's last triangle, add the others there
+ int32_t lastTri = vi.firstTriangle;
+
+ for (;;)
+ {
+ TriangleList& t = mTriangleList[(uint32_t)lastTri];
+ if (t.nextTriangle == -1)
+ {
+ break;
+ }
+
+ PX_ASSERT(t.triangleNumber < mTriangles.size());
+
+ lastTri = t.nextTriangle;
+ }
+ PX_ASSERT(lastTri != -1);
+ PX_ASSERT((uint32_t)lastTri < mTriangleList.size());
+ PX_ASSERT(mTriangleList[(uint32_t)lastTri].nextTriangle == -1);
+ mTriangleList[(uint32_t)lastTri].nextTriangle = vj.firstTriangle;
+ vj.firstTriangle = -1;
+ lastTri = mTriangleList[(uint32_t)lastTri].nextTriangle;
+ while (lastTri != -1)
+ {
+ uint32_t tNr = mTriangleList[(uint32_t)lastTri].triangleNumber;
+ PX_ASSERT(tNr < mTriangles.size());
+ mTriangles[tNr].replaceVertex(refs[j].vertexNr, refs[i].vertexNr);
+
+ lastTri = mTriangleList[(uint32_t)lastTri].nextTriangle;
+ }
+ }
+ vj.marked = true;
+ mMarkedVertices++;
+ }
+ j++;
+ }
+ }
+
+ if (mMarkedVertices > 0)
+ {
+ compress();
+ }
+}
+
+
+
+void ApexSubdivider::closeMesh(IProgressListener* progress)
+{
+ PX_UNUSED(progress);
+ Array<SubdividerEdge> edges, borderEdges;
+ SubdividerEdge edge;
+
+ edges.reserve(mTriangles.size() * 3);
+
+ for (uint32_t i = 0; i < mTriangles.size(); i++)
+ {
+ SubdividerTriangle& t = mTriangles[i];
+ edge.init(t.vertexNr[0], t.vertexNr[1], i);
+ edges.pushBack(edge);
+ edge.init(t.vertexNr[1], t.vertexNr[2], i);
+ edges.pushBack(edge);
+ edge.init(t.vertexNr[2], t.vertexNr[0], i);
+ edges.pushBack(edge);
+ }
+
+ shdfnd::sort(edges.begin(), edges.size(), SubdividerEdge());
+
+ for (uint32_t i = 0; i < edges.size(); i++)
+ {
+ SubdividerEdge& ei = edges[i];
+ uint32_t j = i + 1;
+ while (j < edges.size() && edges[j] == ei)
+ {
+ j++;
+ }
+ if (j == i + 1)
+ {
+ borderEdges.pushBack(ei);
+ }
+ i = j - 1;
+ }
+
+ // find border circles
+ Array<uint32_t> borderVertices;
+ borderVertices.reserve(borderEdges.size());
+ while (!borderEdges.empty())
+ {
+ edge = borderEdges.back();
+ borderEdges.popBack();
+
+ borderVertices.clear();
+ // find orientation
+
+ const SubdividerTriangle& triangle = mTriangles[edge.triangleNr];
+ PX_ASSERT(triangle.containsVertex(edge.v0));
+ PX_ASSERT(triangle.containsVertex(edge.v1));
+ bool swap = triangle.vertexNr[0] == edge.v0 || (triangle.vertexNr[1] == edge.v0 && triangle.vertexNr[0] != edge.v1);
+
+ if (swap)
+ {
+ borderVertices.pushBack(edge.v1);
+ borderVertices.pushBack(edge.v0);
+ }
+ else
+ {
+ borderVertices.pushBack(edge.v0);
+ borderVertices.pushBack(edge.v1);
+ }
+ uint32_t currentV = borderVertices.back();
+ int32_t nextV = -1;
+ do
+ {
+ nextV = -1;
+ uint32_t i = 0;
+ for (; i < borderEdges.size(); i++)
+ {
+ SubdividerEdge& ei = borderEdges[i];
+ if (ei.v0 == currentV)
+ {
+ nextV = (int32_t)ei.v1;
+ break;
+ }
+ else if (ei.v1 == currentV)
+ {
+ nextV = (int32_t)ei.v0;
+ break;
+ }
+ }
+ if (nextV < 0)
+ {
+ break; // chain ended
+ }
+
+ PX_ASSERT(i < borderEdges.size());
+ borderEdges.replaceWithLast(i);
+ borderVertices.pushBack((uint32_t)nextV);
+ currentV = (uint32_t)nextV;
+ }
+ while (nextV >= 0);
+
+ if (borderVertices[0] == borderVertices[borderVertices.size() - 1])
+ {
+ borderVertices.popBack();
+ }
+
+ closeHole(borderVertices.begin(), borderVertices.size());
+ }
+}
+
+
+
+void ApexSubdivider::subdivide(uint32_t subdivisionGridSize, IProgressListener*)
+{
+ PX_ASSERT(subdivisionGridSize > 0);
+ if (subdivisionGridSize == 0)
+ {
+ return;
+ }
+
+ const float maxLength = (mBound.minimum - mBound.maximum).magnitude() / (float)subdivisionGridSize;
+ const float threshold = 2.0f * maxLength;
+ const float threshold2 = threshold * threshold;
+
+ PX_ASSERT(threshold2 > 0.0f);
+ if (threshold2 <= 0.0f)
+ {
+ return;
+ }
+
+ Array<SubdividerEdge> edges;
+ edges.reserve(mTriangles.size() * 3);
+ for (uint32_t i = 0; i < mTriangles.size(); i++)
+ {
+ SubdividerEdge edge;
+ SubdividerTriangle& t = mTriangles[i];
+ edge.init(t.vertexNr[0], t.vertexNr[1], i);
+ edges.pushBack(edge);
+ edge.init(t.vertexNr[1], t.vertexNr[2], i);
+ edges.pushBack(edge);
+ edge.init(t.vertexNr[2], t.vertexNr[0], i);
+ edges.pushBack(edge);
+ }
+
+ shdfnd::sort(edges.begin(), edges.size(), SubdividerEdge());
+
+ uint32_t i = 0;
+ while (i < edges.size())
+ {
+ SubdividerEdge& ei = edges[i];
+ uint32_t newI = i + 1;
+ while (newI < edges.size() && edges[newI] == ei)
+ {
+ newI++;
+ }
+
+ const PxVec3 p0 = mVertices[ei.v0].pos;
+ const PxVec3 p1 = mVertices[ei.v1].pos;
+ const float d2 = (p0 - p1).magnitudeSquared();
+
+ if (d2 < threshold2)
+ {
+ i = newI;
+ continue;
+ }
+
+ uint32_t newVertex = mVertices.size();
+ const float eps = 1.0e-4f;
+ SubdividerVertex vertex;
+ vertex.pos = (p0 + p1) * 0.5f + PxVec3(mRand.getNext(), mRand.getNext(), mRand.getNext()) * eps;
+ vertex.payload = mVertices[ei.v0].payload | mVertices[ei.v1].payload;
+ mVertices.pushBack(vertex);
+
+ uint32_t newEdgeNr = edges.size();
+ for (uint32_t j = i; j < newI; j++)
+ {
+ SubdividerEdge ej = edges[j];
+ SubdividerTriangle tj = mTriangles[ej.triangleNr];
+
+ uint32_t v2 = 0; // the vertex not contained in the edge
+ if (tj.vertexNr[1] != ej.v0 && tj.vertexNr[1] != ej.v1)
+ {
+ v2 = 1;
+ }
+ else if (tj.vertexNr[2] != ej.v0 && tj.vertexNr[2] != ej.v1)
+ {
+ v2 = 2;
+ }
+
+ const uint32_t v0 = (v2 + 1) % 3;
+ const uint32_t v1 = (v0 + 1) % 3;
+
+ // generate new triangle
+ const uint32_t newTriangle = mTriangles.size();
+
+ SubdividerTriangle tNew;
+ tNew.init(tj.vertexNr[v0], newVertex, tj.vertexNr[v2]);
+ mTriangles.pushBack(tNew);
+ addTriangleToVertex(tNew.vertexNr[0], newTriangle);
+ addTriangleToVertex(tNew.vertexNr[1], newTriangle);
+ addTriangleToVertex(tNew.vertexNr[2], newTriangle);
+
+ // modify existing triangle
+ removeTriangleFromVertex(tj.vertexNr[v0], ej.triangleNr);
+ tj.vertexNr[v0] = newVertex;
+ mTriangles[ej.triangleNr].vertexNr[v0] = newVertex;
+ addTriangleToVertex(newVertex, ej.triangleNr);
+
+ // update edges
+ int32_t k = binarySearchEdges(edges, tNew.vertexNr[2], tNew.vertexNr[0], ej.triangleNr);
+ PX_ASSERT(k >= 0);
+ edges[(uint32_t)k].triangleNr = newTriangle;
+
+ SubdividerEdge edge;
+ edge.init(tj.vertexNr[v2], tj.vertexNr[v0], ej.triangleNr);
+ edges.pushBack(edge);
+ edge.init(tj.vertexNr[v0], tj.vertexNr[v1], ej.triangleNr);
+ edges.pushBack(edge);
+ edge.init(tNew.vertexNr[0], tNew.vertexNr[1], newTriangle);
+ edges.pushBack(edge);
+ edge.init(tNew.vertexNr[1], tNew.vertexNr[2], newTriangle);
+ edges.pushBack(edge);
+ }
+ i = newI;
+ PX_ASSERT(newEdgeNr < edges.size());
+
+ shdfnd::sort(edges.begin() + newEdgeNr, edges.size() - newEdgeNr, SubdividerEdge());
+ }
+}
+
+
+
+uint32_t ApexSubdivider::getNumVertices() const
+{
+ PX_ASSERT(mMarkedVertices == 0);
+ return mVertices.size();
+}
+
+
+
+uint32_t ApexSubdivider::getNumTriangles() const
+{
+ return mTriangles.size();
+}
+
+
+
+void ApexSubdivider::getVertex(uint32_t i, PxVec3& v, uint32_t& bitFlagPayload) const
+{
+ PX_ASSERT(mMarkedVertices == 0);
+ PX_ASSERT(i < mVertices.size());
+ v = mVertices[i].pos;
+ bitFlagPayload = mVertices[i].payload;
+}
+
+
+
+void ApexSubdivider::getTriangle(uint32_t i, uint32_t& i0, uint32_t& i1, uint32_t& i2) const
+{
+ PX_ASSERT(i < mTriangles.size());
+ PX_ASSERT(mTriangles[i].isValid());
+
+ const SubdividerTriangle& t = mTriangles[i];
+ i0 = t.vertexNr[0];
+ i1 = t.vertexNr[1];
+ i2 = t.vertexNr[2];
+}
+
+
+
+void ApexSubdivider::compress()
+{
+ Array<uint32_t> oldToNew;
+ oldToNew.resize(mVertices.size());
+ Array<SubdividerVertex> newVertices;
+ newVertices.reserve(mVertices.size() - mMarkedVertices);
+
+ for (uint32_t i = 0; i < mVertices.size(); i++)
+ {
+ if (mVertices[i].marked)
+ {
+ oldToNew[i] = (uint32_t) - 1;
+ mMarkedVertices--;
+ }
+ else
+ {
+ oldToNew[i] = newVertices.size();
+ newVertices.pushBack(mVertices[i]);
+ }
+ }
+
+ mVertices.resize(newVertices.size());
+ for (uint32_t i = 0; i < newVertices.size(); i++)
+ {
+ mVertices[i] = newVertices[i];
+ }
+
+ for (uint32_t i = 0; i < mTriangles.size(); i++)
+ {
+ if (mTriangles[i].isValid())
+ {
+ SubdividerTriangle& t = mTriangles[i];
+ t.vertexNr[0] = oldToNew[t.vertexNr[0]];
+ t.vertexNr[1] = oldToNew[t.vertexNr[1]];
+ t.vertexNr[2] = oldToNew[t.vertexNr[2]];
+ }
+ else
+ {
+ mTriangles.replaceWithLast(i);
+ i--;
+ }
+ }
+
+ PX_ASSERT(mMarkedVertices == 0);
+}
+
+
+
+void ApexSubdivider::closeHole(uint32_t* indices, uint32_t numIndices)
+{
+ if (numIndices < 3)
+ {
+ return;
+ }
+
+ SubdividerTriangle triangle;
+ triangle.init(0, 0, 0);
+
+ // fill hole
+ while (numIndices > 3)
+ {
+ PxVec3 normal(0.0f);
+ for (uint32_t i = 0; i < numIndices; i++)
+ {
+ const PxVec3& p0 = mVertices[indices[i]].pos;
+ const PxVec3& p1 = mVertices[indices[(i + 1) % numIndices]].pos;
+ const PxVec3& p2 = mVertices[indices[(i + 2) % numIndices]].pos;
+
+ PxVec3 normalI = (p0 - p1).cross(p2 - p1);
+ normalI.normalize();
+ normal += normalI;
+ }
+ normal.normalize();
+
+ float maxQuality = -1.0f;
+ int32_t bestI = -1;
+ for (uint32_t i = 0; i < numIndices; i++)
+ {
+ const uint32_t i2 = (i + 2) % numIndices;
+
+ const uint32_t b0 = indices[i];
+ const uint32_t b1 = indices[(i + 1) % numIndices];
+ const uint32_t b2 = indices[i2];
+ const uint32_t b3 = indices[(i + 3) % numIndices];
+ const uint32_t b4 = indices[(i + 4) % numIndices];
+
+ if (getTriangleNr(b1, b2, b3) != -1)
+ {
+ continue;
+ }
+
+
+ // init best
+ //if (i == 0)
+ //{
+ // t.init(b1,b2,b3);
+ // bestI = i2;
+ //}
+
+ // check whether triangle is an ear
+ PxVec3 normalI = (mVertices[b1].pos - mVertices[b2].pos).cross(mVertices[b3].pos - mVertices[b2].pos);
+ normalI.normalize(); ///< \todo, remove again, only for debugging
+ if (normalI.dot(normal) < 0.0f)
+ {
+ continue;
+ }
+
+ float quality = qualityOfTriangle(b1, b2, b3) - qualityOfTriangle(b0, b1, b2) - qualityOfTriangle(b2, b3, b4);
+ if (maxQuality < 0.0f || quality > maxQuality)
+ {
+ maxQuality = quality;
+ triangle.init(b1, b2, b3);
+ bestI = (int32_t)i2;
+ }
+ }
+ PX_ASSERT(bestI != -1);
+ PX_ASSERT(triangle.isValid());
+
+
+ // remove ear vertex from temporary border
+ for (uint32_t i = (uint32_t)bestI; i < numIndices - 1; i++)
+ {
+ indices[i] = indices[i + 1];
+ }
+
+ numIndices--;
+
+ // do we have the triangle already?
+ //if (getTriangleNr(triangle.vertexNr[0], triangle.vertexNr[1], triangle.vertexNr[2]) >= 0)
+ // continue;
+
+ // TODO: triangle is potentially uninitialized.
+ // do we have to subdivide the triangle?
+ //PxVec3& p0 = mVertices[triangle.vertexNr[0]].pos;
+ //PxVec3& p2 = mVertices[triangle.vertexNr[2]].pos;
+ //PxVec3 dir = p2 - p0;
+ //float d = dir.normalize();
+ uint32_t triangleNr = mTriangles.size();
+ mTriangles.pushBack(triangle);
+ addTriangleToVertex(triangle.vertexNr[0], triangleNr);
+ addTriangleToVertex(triangle.vertexNr[1], triangleNr);
+ addTriangleToVertex(triangle.vertexNr[2], triangleNr);
+ }
+
+ triangle.init(indices[0], indices[1], indices[2]);
+ if (getTriangleNr(triangle.vertexNr[0], triangle.vertexNr[1], triangle.vertexNr[2]) < 0)
+ {
+ uint32_t triangleNr = mTriangles.size();
+ mTriangles.pushBack(triangle);
+ addTriangleToVertex(triangle.vertexNr[0], triangleNr);
+ addTriangleToVertex(triangle.vertexNr[1], triangleNr);
+ addTriangleToVertex(triangle.vertexNr[2], triangleNr);
+ }
+}
+
+
+
+float ApexSubdivider::qualityOfTriangle(uint32_t v0, uint32_t v1, uint32_t v2) const
+{
+ const PxVec3& p0 = mVertices[v0].pos;
+ const PxVec3& p1 = mVertices[v1].pos;
+ const PxVec3& p2 = mVertices[v2].pos;
+
+ const float a = (p0 - p1).magnitude();
+ const float b = (p1 - p2).magnitude();
+ const float c = (p2 - p0).magnitude();
+
+ if (a > b && a > c) // a is biggest
+ {
+ return b + c - a;
+ }
+ else if (b > c)
+ {
+ return a + c - b; // b is biggest
+ }
+ return a + b - c; // c is biggest
+}
+
+
+
+int32_t ApexSubdivider::getTriangleNr(const uint32_t v0, const uint32_t v1, const uint32_t v2) const
+{
+ const uint32_t num = mVertices.size();
+ if (v0 >= num || v1 >= num || v2 >= num)
+ {
+ return -1;
+ }
+
+ int32_t triangleListIndex = mVertices[v0].firstTriangle;
+ while (triangleListIndex != -1)
+ {
+ const TriangleList& tl = mTriangleList[(uint32_t)triangleListIndex];
+ const uint32_t triangleIndex = tl.triangleNumber;
+ const SubdividerTriangle& triangle = mTriangles[triangleIndex];
+ if (triangle.containsVertex(v1) && triangle.containsVertex(v2))
+ {
+ return (int32_t)triangleIndex;
+ }
+
+ triangleListIndex = tl.nextTriangle;
+ }
+
+ return -1;
+}
+
+
+
+int32_t ApexSubdivider::binarySearchEdges(const Array<SubdividerEdge>& edges, uint32_t v0, uint32_t v1, uint32_t triangleNr) const
+{
+ if (edges.empty())
+ {
+ return -1;
+ }
+
+ SubdividerEdge edge;
+ edge.init(v0, v1, (uint32_t) - 1);
+
+ uint32_t l = 0;
+ uint32_t r = edges.size() - 1;
+ int32_t m = 0;
+ while (l <= r)
+ {
+ m = (int32_t)(l + r) / 2;
+ if (edges[(uint32_t)m] < edge)
+ {
+ l = (uint32_t)m + 1;
+ }
+ else if (edge < edges[(uint32_t)m])
+ {
+ r = (uint32_t)m - 1;
+ }
+ else
+ {
+ break;
+ }
+ }
+ if (!(edges[(uint32_t)m] == edge))
+ {
+ return -1;
+ }
+
+ while (m >= 0 && edges[(uint32_t)m] == edge)
+ {
+ m--;
+ }
+ m++;
+
+ PX_ASSERT(m >= 0);
+ PX_ASSERT((uint32_t)m < edges.size());
+ while ((uint32_t)m < edges.size() && edges[(uint32_t)m] == edge && edges[(uint32_t)m].triangleNr != triangleNr)
+ {
+ m++;
+ }
+
+ if (edges[(uint32_t)m] == edge && edges[(uint32_t)m].triangleNr == triangleNr)
+ {
+ return m;
+ }
+
+ return -1;
+}
+
+
+
+void ApexSubdivider::addTriangleToVertex(uint32_t vertexNumber, uint32_t triangleNumber)
+{
+ PX_ASSERT(vertexNumber < mVertices.size());
+ PX_ASSERT(triangleNumber < mTriangles.size());
+
+ TriangleList& t = allocateTriangleElement();
+
+ t.triangleNumber = triangleNumber;
+ t.nextTriangle = mVertices[vertexNumber].firstTriangle;
+
+ mVertices[vertexNumber].firstTriangle = (int32_t)(&t - &mTriangleList[0]);
+ //int a = 0;
+}
+
+
+
+void ApexSubdivider::removeTriangleFromVertex(uint32_t vertexNumber, uint32_t triangleNumber)
+{
+ PX_ASSERT(vertexNumber < mVertices.size());
+ PX_ASSERT(triangleNumber < mTriangles.size());
+
+ int32_t* lastPointer = &mVertices[vertexNumber].firstTriangle;
+ int32_t triangleListIndex = *lastPointer;
+ while (triangleListIndex != -1)
+ {
+ if (mTriangleList[(uint32_t)triangleListIndex].triangleNumber == triangleNumber)
+ {
+ *lastPointer = mTriangleList[(uint32_t)triangleListIndex].nextTriangle;
+
+ freeTriangleElement((uint32_t)triangleListIndex);
+
+ break;
+ }
+ lastPointer = &mTriangleList[(uint32_t)triangleListIndex].nextTriangle;
+ triangleListIndex = *lastPointer;
+ }
+}
+
+
+
+ApexSubdivider::TriangleList& ApexSubdivider::allocateTriangleElement()
+{
+ if (mTriangleListEmptyElement == -1)
+ {
+ return mTriangleList.insert();
+ }
+ else
+ {
+ PX_ASSERT((uint32_t)mTriangleListEmptyElement < mTriangleList.size());
+ TriangleList& elem = mTriangleList[(uint32_t)mTriangleListEmptyElement];
+ mTriangleListEmptyElement = elem.nextTriangle;
+ elem.nextTriangle = -1;
+
+ return elem;
+ }
+}
+
+
+
+void ApexSubdivider::freeTriangleElement(uint32_t index)
+{
+ PX_ASSERT(index < mTriangleList.size());
+ mTriangleList[index].nextTriangle = mTriangleListEmptyElement;
+ mTriangleListEmptyElement = (int32_t)index;
+}
+
+}
+} // end namespace nvidia::apex
diff --git a/APEX_1.4/common/src/ApexTetrahedralizer.cpp b/APEX_1.4/common/src/ApexTetrahedralizer.cpp
new file mode 100644
index 00000000..b1e8fda0
--- /dev/null
+++ b/APEX_1.4/common/src/ApexTetrahedralizer.cpp
@@ -0,0 +1,1266 @@
+/*
+ * 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 "ApexTetrahedralizer.h"
+
+#include "ApexSDKIntl.h"
+
+#include "ApexCollision.h"
+#include "ApexMeshHash.h"
+#include "ApexSharedUtils.h"
+
+#include "PsSort.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+// check for sanity in between algorithms
+#define TETRALIZER_SANITY_CHECKS 0
+
+const uint32_t ApexTetrahedralizer::FullTetrahedron::sideIndices[4][3] = {{1, 2, 3}, {2, 0, 3}, {0, 1, 3}, {2, 1, 0}};
+
+void ApexTetrahedralizer::TetraEdgeList::sort()
+{
+ shdfnd::sort(mEdges.begin(), mEdges.size(), TetraEdge());
+}
+
+
+ApexTetrahedralizer::ApexTetrahedralizer(uint32_t subdivision) :
+ mMeshHash(NULL),
+ mSubdivision(subdivision),
+ mBoundDiagonal(0),
+ mFirstFarVertex(0),
+ mLastFarVertex(0)
+{
+ mBound.setEmpty();
+}
+
+
+
+ApexTetrahedralizer::~ApexTetrahedralizer()
+{
+ if (mMeshHash != NULL)
+ {
+ delete mMeshHash;
+ mMeshHash = NULL;
+ }
+}
+
+
+
+void ApexTetrahedralizer::registerVertex(const PxVec3& pos)
+{
+ TetraVertex v;
+ v.init(pos, 0);
+ mVertices.pushBack(v);
+ mBound.include(pos);
+}
+
+
+
+void ApexTetrahedralizer::registerTriangle(uint32_t i0, uint32_t i1, uint32_t i2)
+{
+ mIndices.pushBack(i0);
+ mIndices.pushBack(i1);
+ mIndices.pushBack(i2);
+}
+
+
+
+void ApexTetrahedralizer::endRegistration(IProgressListener* progressListener)
+{
+
+ // hash mesh triangles for faster access
+ mBoundDiagonal = (mBound.minimum - mBound.maximum).magnitude();
+
+ HierarchicalProgressListener progress(100, progressListener);
+
+ if (mMeshHash == NULL)
+ {
+ mMeshHash = PX_NEW(ApexMeshHash)();
+ }
+
+ // clears the hash if it's not empty
+ mMeshHash->setGridSpacing(0.1f * mBoundDiagonal);
+
+ weldVertices();
+
+ for (uint32_t i = 0; i < mIndices.size(); i += 3)
+ {
+ PxBounds3 triangleBound;
+ triangleBound.minimum = triangleBound.maximum = mVertices[mIndices[i]].pos;
+ triangleBound.include(mVertices[mIndices[i + 1]].pos);
+ triangleBound.include(mVertices[mIndices[i + 2]].pos);
+ mMeshHash->add(triangleBound, i);
+ }
+
+
+ progress.setSubtaskWork(10, "Delaunay Tetrahedralization");
+ delaunayTetrahedralization(&progress);
+ progress.completeSubtask();
+
+ // neighbor info is gone from this point on!
+ compressTetrahedra(true);
+
+#if 1 // do we really need this?
+ uint32_t tetStart = 0;
+ uint32_t oldNumTets = mTetras.size();
+ uint32_t numSwapped = 0;
+ uint32_t lastNumSwapped = mTetras.size() * 10; // just a number that is way too big
+ uint32_t iterations = 0; // this one is pure safety
+ int32_t fraction = 50;
+ do
+ {
+ fraction /= 2;
+ progress.setSubtaskWork(fraction, "Swapping Tetrahedra");
+ lastNumSwapped = numSwapped;
+ numSwapped = swapTetrahedra(tetStart, &progress);
+ tetStart = oldNumTets;
+ oldNumTets = mTetras.size();
+ progress.completeSubtask();
+ }
+ while (numSwapped > 0 && (numSwapped < lastNumSwapped) && (iterations++ < 20));
+
+
+ // just to fill the entire fraction up
+ progress.setSubtaskWork(fraction, "Swapping Tetrahedra");
+ progress.completeSubtask();
+#endif
+
+
+
+ progress.setSubtaskWork(-1, "Removing outer tetrahedra");
+ removeOuterTetrahedra(&progress);
+ progress.completeSubtask();
+
+ compressTetrahedra(true);
+ compressVertices();
+
+ // release the indices
+ mIndices.clear();
+}
+
+
+
+void ApexTetrahedralizer::getVertices(PxVec3* data)
+{
+ for (uint32_t i = 0; i < mVertices.size(); i++)
+ {
+ data[i] = mVertices[i].pos;
+ }
+}
+
+
+
+void ApexTetrahedralizer::getIndices(uint32_t* data)
+{
+ for (uint32_t i = 0; i < mTetras.size(); i++)
+ {
+ for (uint32_t j = 0; j < 4; j++)
+ {
+ data[i * 4 + j] = (uint32_t)mTetras[i].vertexNr[j];
+ }
+ }
+}
+
+
+
+void ApexTetrahedralizer::weldVertices()
+{
+ if (mSubdivision < 1)
+ {
+ return;
+ }
+
+ const float relativeThreshold = 0.3f;
+
+ const float d = mBoundDiagonal / mSubdivision * relativeThreshold;
+ const float d2 = d * d;
+
+ uint32_t readIndex = 0;
+ uint32_t writeIndex = 0;
+ physx::Array<int32_t> old2new(mVertices.size(), -1);
+ while (readIndex < mVertices.size())
+ {
+ for (uint32_t i = 0; i < writeIndex; i++)
+ {
+ if ((mVertices[i].pos - mVertices[readIndex].pos).magnitudeSquared() < d2)
+ {
+ old2new[readIndex] = (int32_t)i;
+ break;
+ }
+ }
+
+ if (old2new[readIndex] == -1)
+ {
+ old2new[readIndex] = (int32_t)writeIndex;
+ mVertices[writeIndex] = mVertices[readIndex];
+ writeIndex++;
+ }
+ readIndex++;
+ }
+
+ if (readIndex == writeIndex)
+ {
+ return;
+ }
+
+ for (uint32_t i = 0; i < mIndices.size(); i++)
+ {
+ PX_ASSERT(old2new[mIndices[i]] != -1);
+ mIndices[i] = (uint32_t)old2new[mIndices[i]];
+ }
+}
+
+
+void ApexTetrahedralizer::delaunayTetrahedralization(IProgressListener* progress)
+{
+ physx::Array<TetraEdge> edges;
+ TetraEdge edge;
+
+ // start with huge tetrahedron
+ mTetras.clear();
+
+ const float a = 3.0f * mBoundDiagonal;
+ const float x = 0.5f * a;
+ const float y0 = x / PxSqrt(3.0f);
+ const float y1 = x * PxSqrt(3.0f) - y0;
+ const float z0 = 0.25f * PxSqrt(6.0f) * a;
+ const float z1 = a * PxSqrt(6.0f) / 3.0f - z0;
+
+ PxVec3 center = mBound.getCenter();
+
+ mFirstFarVertex = mVertices.size();
+ PxVec3 p0(-x, -y0, -z1);
+ registerVertex(center + p0);
+ PxVec3 p1(x, -y0, -z1);
+ registerVertex(center + p1);
+ PxVec3 p2(0, y1, -z1);
+ registerVertex(center + p2);
+ PxVec3 p3(0, 0, z0);
+ registerVertex(center + p3);
+ mLastFarVertex = mVertices.size() - 1;
+
+ // do not update it as these vertices are irrelevant
+ //mBoundDiagonal = mBound.minimum.distance(mBound.maximum);
+
+ FullTetrahedron tetra;
+ tetra.set((int32_t)mFirstFarVertex, (int32_t)mFirstFarVertex + 1, (int32_t)mFirstFarVertex + 2, (int32_t)mFirstFarVertex + 3);
+ mTetras.pushBack(tetra);
+
+ // build Delaunay triangulation iteratively
+
+ for (uint32_t i = 0; i < mFirstFarVertex; i++)
+ {
+
+ if (progress != NULL && (i & 0x7f) == 0)
+ {
+ const int32_t percent = (int32_t)(100 * i / mFirstFarVertex);
+ progress->setProgress(percent);
+ }
+
+ PxVec3& v = mVertices[i].pos;
+ /// \todo vertex reordering could speed up this search via warm start
+ int tNr = findSurroundingTetra(mTetras.size() - 1, v); // fast walk
+ if (tNr == -1)
+ {
+ continue;
+ }
+ PX_ASSERT(tNr >= 0);
+
+ const uint32_t newTetraNr = mTetras.size();
+ const float volumeDiff = retriangulate((uint32_t)tNr, i);
+
+#if TETRALIZER_SANITY_CHECKS
+ if (PxAbs(volumeDiff) > 0.001f)
+ {
+ APEX_INTERNAL_ERROR("Volume added: %f", volumeDiff);
+ }
+#else
+ PX_UNUSED(volumeDiff);
+#endif
+
+ edges.clear();
+ for (uint32_t j = newTetraNr; j < mTetras.size(); j++)
+ {
+ FullTetrahedron& newTet = mTetras[j];
+ edge.init(newTet.vertexNr[2], newTet.vertexNr[3], (int32_t)j, 1);
+ edges.pushBack(edge);
+ edge.init(newTet.vertexNr[3], newTet.vertexNr[1], (int32_t)j, 2);
+ edges.pushBack(edge);
+ edge.init(newTet.vertexNr[1], newTet.vertexNr[2], (int32_t)j, 3);
+ edges.pushBack(edge);
+ }
+
+ shdfnd::sort(edges.begin(), edges.size(), TetraEdge());
+
+ for (uint32_t j = 0; j < edges.size(); j += 2)
+ {
+ TetraEdge& edge0 = edges[j];
+ TetraEdge& edge1 = edges[j + 1];
+ PX_ASSERT(edge0 == edge1);
+ mTetras[edge0.tetraNr].neighborNr[(uint32_t)edge0.neighborNr] = (int32_t)edge1.tetraNr;
+ mTetras[edge1.tetraNr].neighborNr[(uint32_t)edge1.neighborNr] = (int32_t)edge0.tetraNr;
+ }
+ }
+}
+
+
+
+
+
+int32_t ApexTetrahedralizer::findSurroundingTetra(uint32_t startTetra, const PxVec3& p) const
+{
+ // find the tetrahedra which contains the vertex
+ // by walking through mesh O(n ^ (1/3))
+
+ if (mTetras.empty())
+ {
+ return -1;
+ }
+
+ PX_ASSERT(mTetras[startTetra].bDeleted == 0);
+
+
+ uint32_t iterationCounter = 0;
+ const uint32_t iterationCounterMax = PxMin(1000u, mTetras.size());
+
+ int32_t tetNr = (int32_t)startTetra;
+ while (tetNr >= 0 && iterationCounter++ < iterationCounterMax)
+ {
+ const FullTetrahedron& tetra = mTetras[(uint32_t)tetNr];
+ PX_ASSERT(tetra.bDeleted == 0);
+
+ const PxVec3& p0 = mVertices[(uint32_t)tetra.vertexNr[0]].pos;
+ PxVec3 q = p - p0;
+ PxVec3 q0 = mVertices[(uint32_t)tetra.vertexNr[1]].pos - p0;
+ PxVec3 q1 = mVertices[(uint32_t)tetra.vertexNr[2]].pos - p0;
+ PxVec3 q2 = mVertices[(uint32_t)tetra.vertexNr[3]].pos - p0;
+ PxMat33 m(q0,q1,q2);
+ const float det = m.getDeterminant();
+ m.column0 = q;
+ const float x = m.getDeterminant();
+ if (x < 0.0f && tetra.neighborNr[1] >= 0)
+ {
+ tetNr = tetra.neighborNr[1];
+ continue;
+ }
+
+ m.column0 = q0;
+ m.column1 = q;
+ const float y = m.getDeterminant();
+ if (y < 0.0f && tetra.neighborNr[2] >= 0)
+ {
+ tetNr = tetra.neighborNr[2];
+ continue;
+ }
+
+ m.column1 = q1;
+ m.column2 = q;
+ const float z = m.getDeterminant();
+
+ if (z < 0.0f && tetra.neighborNr[3] >= 0)
+ {
+ tetNr = tetra.neighborNr[3];
+ continue;
+ }
+
+ if (x + y + z > det && tetra.neighborNr[0] >= 0)
+ {
+ tetNr = tetra.neighborNr[0];
+ continue;
+ }
+
+#if TETRALIZER_SANITY_CHECKS
+ static uint32_t maxIterationCounter = 0;
+ maxIterationCounter = PxMax(maxIterationCounter, iterationCounter);
+#endif
+ return tetNr;
+ }
+ if (iterationCounter == iterationCounterMax + 1)
+ {
+ // search all vertices
+ for (uint32_t i = 0; i < mVertices.size(); i++)
+ {
+ if (mVertices[i].pos == p)
+ {
+ PX_ASSERT(!mVertices[i].isDeleted());
+ return -1;
+ }
+ }
+
+ uint32_t nbDeleted = 0;
+ for (uint32_t i = 0; i < mTetras.size(); i++)
+ {
+ const FullTetrahedron& tetra = mTetras[i];
+ if (tetra.bDeleted == 0)
+ {
+ if (pointInTetra(tetra, p))
+ {
+ if (tetra.bDeleted == 0)
+ {
+ return (int32_t)i;
+ }
+ nbDeleted++;
+ }
+ }
+ }
+#if defined(_DEBUG) || TETRALIZER_SANITY_CHECKS
+ // PH: Do not give out this warning/error when running in release mode
+ APEX_INTERNAL_ERROR("Failed to find tetra for hull vertex");
+ //debugPoints.pushBack(p);
+#endif
+ }
+ return -1;
+}
+
+
+
+float ApexTetrahedralizer::retriangulate(const uint32_t tetraNr, uint32_t vertexNr)
+{
+ PX_ASSERT(tetraNr < mTetras.size());
+ PX_ASSERT(vertexNr < mVertices.size());
+
+ if (mTetras[tetraNr].bDeleted == 1)
+ {
+ return 0;
+ }
+
+#if TETRALIZER_SANITY_CHECKS
+ const float volumeDeleted = getTetraVolume(mTetras[tetraNr].vertexNr[0], mTetras[tetraNr].vertexNr[1], mTetras[tetraNr].vertexNr[2], mTetras[tetraNr].vertexNr[3]);;
+#endif
+ float volumeCreated = 0;
+
+ mTetras[tetraNr].bDeleted = 1;
+
+ PxVec3& v = mVertices[vertexNr].pos;
+ for (uint32_t i = 0; i < 4; i++)
+ {
+ int n = mTetras[tetraNr].neighborNr[i];
+ if (n >= 0 && mTetras[(uint32_t)n].bDeleted == 1)
+ {
+ continue;
+ }
+
+ if (n >= 0 && pointInCircumSphere(mTetras[(uint32_t)n], v))
+ {
+ volumeCreated += retriangulate((uint32_t)n, vertexNr);
+ }
+ else
+ {
+ FullTetrahedron& tetra = mTetras[tetraNr];
+ FullTetrahedron tNew;
+ tNew.set((int32_t)vertexNr,
+ tetra.vertexNr[FullTetrahedron::sideIndices[i][0]],
+ tetra.vertexNr[FullTetrahedron::sideIndices[i][1]],
+ tetra.vertexNr[FullTetrahedron::sideIndices[i][2]]
+ );
+
+#if TETRALIZER_SANITY_CHECKS
+ volumeCreated += getTetraVolume(tNew.vertexNr[0], tNew.vertexNr[1], tNew.vertexNr[2], tNew.vertexNr[3]);
+#endif
+
+ tNew.neighborNr[0] = n;
+
+ if (n >= 0)
+ {
+ PX_ASSERT(mTetras[(uint32_t)n].neighborOf(tNew.vertexNr[1], tNew.vertexNr[2], tNew.vertexNr[3]) == (int32_t)tetraNr);
+ mTetras[(uint32_t)n].neighborOf(tNew.vertexNr[1], tNew.vertexNr[2], tNew.vertexNr[3]) = (int32_t)mTetras.size();
+ }
+ mTetras.pushBack(tNew);
+ }
+ }
+#if TETRALIZER_SANITY_CHECKS
+ return volumeCreated - volumeDeleted;
+#else
+ return 0;
+#endif
+}
+
+
+
+uint32_t ApexTetrahedralizer::swapTetrahedra(uint32_t startTet, IProgressListener* progress)
+{
+ PX_ASSERT(mMeshHash != NULL);
+
+ const float threshold = 0.05f * mBoundDiagonal / mSubdivision;
+
+ TetraEdgeList edges;
+ edges.mEdges.reserve(mTetras.size() * 6);
+ for (uint32_t i = startTet; i < mTetras.size(); i++)
+ {
+ FullTetrahedron& t = mTetras[i];
+ if (t.bDeleted == 1)
+ {
+ continue;
+ }
+
+ TetraEdge edge;
+ edge.init(t.vertexNr[0], t.vertexNr[1], (int32_t)i);
+ edges.add(edge);
+ edge.init(t.vertexNr[1], t.vertexNr[2], (int32_t)i);
+ edges.add(edge);
+ edge.init(t.vertexNr[2], t.vertexNr[0], (int32_t)i);
+ edges.add(edge);
+ edge.init(t.vertexNr[0], t.vertexNr[3], (int32_t)i);
+ edges.add(edge);
+ edge.init(t.vertexNr[1], t.vertexNr[3], (int32_t)i);
+ edges.add(edge);
+ edge.init(t.vertexNr[2], t.vertexNr[3], (int32_t)i);
+ edges.add(edge);
+ }
+ edges.sort();
+
+
+ uint32_t index = 0;
+ uint32_t progressCounter = 0;
+ uint32_t numEdgesSwapped = 0;
+ while (index < edges.numEdges())
+ {
+ if (progress != NULL && ((progressCounter++ & 0xf) == 0))
+ {
+ const int32_t percent = (int32_t)(100 * index / edges.numEdges());
+ progress->setProgress(percent);
+ }
+ TetraEdge edge = edges[index];
+ uint32_t vNr[2] = { edge.vNr0, edge.vNr1 };
+
+ index++;
+ while (index < edges.numEdges() && edges[index] == edge)
+ {
+ index++;
+ }
+
+ if (isFarVertex(vNr[0]) || isFarVertex(vNr[1]))
+ {
+ continue;
+ }
+
+ const PxVec3 v0 = mVertices[vNr[0]].pos;
+ const PxVec3 v1 = mVertices[vNr[1]].pos;
+ PxBounds3 edgeBounds;
+ edgeBounds.setEmpty();
+ edgeBounds.include(v0);
+ edgeBounds.include(v1);
+ mMeshHash->queryUnique(edgeBounds, mTempItemIndices);
+ if (mTempItemIndices.size() == 0)
+ {
+ continue;
+ }
+
+ bool cut = false;
+ for (uint32_t k = 0; k < mTempItemIndices.size(); k++)
+ {
+ uint32_t triNr = mTempItemIndices[k];
+ PX_ASSERT(triNr % 3 == 0);
+ uint32_t* triangle = &mIndices[triNr];
+
+ // if one vertex is part of the iso surface
+ if (triangleContainsVertexNr(triangle, vNr, 2))
+ {
+ continue;
+ }
+
+ const PxVec3 p0 = mVertices[triangle[0]].pos;
+ const PxVec3 p1 = mVertices[triangle[1]].pos;
+ const PxVec3 p2 = mVertices[triangle[2]].pos;
+
+ PxBounds3 triBounds;
+ triBounds.minimum = triBounds.maximum = p0;
+ triBounds.include(p1);
+ triBounds.include(p2);
+
+ if (!triBounds.intersects(edgeBounds))
+ {
+ continue;
+ }
+
+ PxVec3 normal = (p1 - p0).cross(p2 - p0);
+ normal.normalize();
+
+ if (PxAbs(normal.dot(v0 - p0)) < threshold)
+ {
+ continue;
+ }
+ if (PxAbs(normal.dot(v1 - p0)) < threshold)
+ {
+ continue;
+ }
+
+ float t, u, v;
+ if (!APEX_RayTriangleIntersect(v0, v1 - v0, p0, p1, p2, t, u, v))
+ {
+ continue;
+ }
+
+ // PH: I guess we don't need to cut when edge does not intersect triangle
+ if (t < 0 || t > 1)
+ {
+ continue;
+ }
+
+ cut = true;
+ break;
+ }
+ if (cut)
+ {
+#if TETRAHEDRALIZER_DEBUG_RENDERING
+ debugLines.pushBack(mVertices[vNr[0]].pos);
+ debugLines.pushBack(mVertices[vNr[1]].pos);
+#endif
+ numEdgesSwapped += swapEdge(vNr[0], vNr[1]) ? 1 : 0;
+ }
+ }
+
+ return numEdgesSwapped;
+}
+
+
+
+bool ApexTetrahedralizer::swapEdge(uint32_t v0, uint32_t v1)
+{
+ physx::Array<int32_t> borderEdges;
+ physx::Array<FullTetrahedron> newTetras;
+
+ uint32_t nbDeleted = 0;
+
+ mTempItemIndices.clear();
+
+ for (uint32_t i = 0; i < mTetras.size(); i++)
+ {
+ FullTetrahedron& t = mTetras[i];
+
+ if (t.bDeleted == 1)
+ {
+ continue;
+ }
+
+ if (!t.containsVertex((int32_t)v0) || !t.containsVertex((int32_t)v1))
+ {
+ continue;
+ }
+
+ //t.bDeleted = 1;
+ mTempItemIndices.pushBack(i);
+ nbDeleted++;
+ int32_t v2, v3;
+ t.get2OppositeVertices((int32_t)v0, (int32_t)v1, v2, v3);
+ if (getTetraVolume((int32_t)v0, (int32_t)v1, v2, v3) >= 0.0f)
+ {
+ borderEdges.pushBack(v2);
+ borderEdges.pushBack(v3);
+ }
+ else
+ {
+ borderEdges.pushBack(v3);
+ borderEdges.pushBack(v2);
+ }
+ }
+
+ if (borderEdges.size() < 6)
+ {
+ return false;
+ }
+
+ // start with first edge
+ physx::Array<int32_t> borderVertices;
+ physx::Array<float> borderQuality;
+ borderVertices.pushBack(borderEdges[borderEdges.size() - 2]);
+ borderVertices.pushBack(borderEdges[borderEdges.size() - 1]);
+ borderEdges.popBack();
+ borderEdges.popBack();
+
+ // construct border
+ int vEnd = borderVertices[1];
+ while (borderEdges.size() > 0)
+ {
+ uint32_t i = 0;
+ uint32_t num = borderEdges.size();
+ for (; i < num - 1; i += 2)
+ {
+ if (borderEdges[i] == vEnd)
+ {
+ vEnd = borderEdges[i + 1];
+ break;
+ }
+ }
+ // not connected
+ if (i >= num)
+ {
+ return false;
+ }
+
+ borderVertices.pushBack(vEnd);
+ borderEdges[i] = borderEdges[num - 2];
+ borderEdges[i + 1] = borderEdges[num - 1];
+ borderEdges.popBack();
+ borderEdges.popBack();
+ }
+
+ // not circular
+ if (borderVertices[0] != borderVertices[borderVertices.size() - 1])
+ {
+ return false;
+ }
+
+ borderVertices.popBack();
+
+ if (borderVertices.size() < 3)
+ {
+ return false;
+ }
+
+ // generate tetrahedra
+ FullTetrahedron tetra0, tetra1;
+ borderQuality.resize(borderVertices.size());
+ while (borderVertices.size() > 3)
+ {
+ uint32_t num = borderVertices.size();
+ uint32_t i0, i1, i2;
+ for (i0 = 0; i0 < num; i0++)
+ {
+ i1 = (i0 + 1) % num;
+ i2 = (i1 + 1) % num;
+ tetra0.set(borderVertices[i0], borderVertices[i1], borderVertices[i2], (int32_t)v1);
+ borderQuality[i1] = getTetraQuality(tetra0);
+ }
+
+ float maxQ = 0.0f;
+ int32_t maxI0 = -1;
+ for (i0 = 0; i0 < num; i0++)
+ {
+ i1 = (i0 + 1) % num;
+ i2 = (i1 + 1) % num;
+ tetra0.set(borderVertices[i0], borderVertices[i1], borderVertices[i2], (int32_t)v1);
+ tetra1.set(borderVertices[i2], borderVertices[i1], borderVertices[i0], (int32_t)v0);
+ if (getTetraVolume(tetra0) < 0.0f || getTetraVolume(tetra1) < 0.0f)
+ {
+ continue;
+ }
+
+ bool ear = true;
+ for (uint32_t i = 0; i < num; i++)
+ {
+ if (i == i0 || i == i1 || i == i2)
+ {
+ continue;
+ }
+
+ PxVec3& pos = mVertices[(uint32_t)borderVertices[i]].pos;
+ if (pointInTetra(tetra0, pos) || pointInTetra(tetra1, pos))
+ {
+ ear = false;
+ }
+ }
+
+ if (!ear)
+ {
+ continue;
+ }
+
+ float q = (1.0f - borderQuality[i0]) + borderQuality[i1] + (1.0f - borderQuality[i2]);
+
+ if (maxI0 < 0 || q > maxQ)
+ {
+ maxQ = q;
+ maxI0 = (int32_t)i0;
+ }
+ }
+ if (maxI0 < 0)
+ {
+ return false;
+ }
+
+ i0 = (uint32_t)maxI0;
+ i1 = (i0 + 1) % num;
+ i2 = (i1 + 1) % num;
+ tetra0.set(borderVertices[i0], borderVertices[i1], borderVertices[i2], (int32_t)v1);
+ tetra1.set(borderVertices[i2], borderVertices[i1], borderVertices[i0], (int32_t)v0);
+
+ // add tetras, remove vertex;
+ newTetras.pushBack(tetra0);
+ newTetras.pushBack(tetra1);
+ for (uint32_t i = i1; i < num - 1; i++)
+ {
+ borderVertices[i] = borderVertices[i + 1];
+ }
+ borderVertices.popBack();
+ }
+ tetra0.set(borderVertices[0], borderVertices[1], borderVertices[2], (int32_t)v1);
+ tetra1.set(borderVertices[2], borderVertices[1], borderVertices[0], (int32_t)v0);
+
+ if (getTetraVolume(tetra0) < 0.0f || getTetraVolume(tetra1) < 0.0f)
+ {
+ return false;
+ }
+
+ newTetras.pushBack(tetra0);
+ newTetras.pushBack(tetra1);
+
+ PX_ASSERT(nbDeleted <= newTetras.size() + 1);
+
+ for (uint32_t i = 0; i < mTempItemIndices.size(); i++)
+ {
+ mTetras[mTempItemIndices[i]].bDeleted = 1;
+ }
+
+ // add new tetras;
+ for (uint32_t i = 0; i < newTetras.size(); i++)
+ {
+ mTetras.pushBack(newTetras[i]);
+ }
+
+ return true;
+}
+
+
+class F32Less
+{
+public:
+ PX_INLINE bool operator()(float v1, float v2) const
+ {
+ return v1 < v2;
+ }
+};
+
+
+
+bool ApexTetrahedralizer::removeOuterTetrahedra(IProgressListener* progress)
+{
+ const float EPSILON = 1e-5f;
+ PX_ASSERT((float)(mBoundDiagonal + EPSILON) > mBoundDiagonal);
+
+#if TETRAHEDRALIZER_DEBUG_RENDERING && TETRALIZER_SANITY_CHECKS
+ static uint32_t interesting = 0xffffffff;
+ debugBounds.clear();
+#endif
+
+ physx::Array<float> raycastHitTimes;
+
+ for (uint32_t i = 0; i < mTetras.size(); i++)
+ {
+ if (progress != NULL && (i & 0x7) == 0)
+ {
+ const int32_t percent = (int32_t)(100 * i / mTetras.size());
+ progress->setProgress(percent);
+ }
+ FullTetrahedron& tetra = mTetras[i];
+
+ if (isFarVertex((uint32_t)tetra.vertexNr[0]) || isFarVertex((uint32_t)tetra.vertexNr[1])
+ || isFarVertex((uint32_t)tetra.vertexNr[2]) || isFarVertex((uint32_t)tetra.vertexNr[3]))
+ {
+ tetra.bDeleted = 1;
+ }
+ else if (tetra.bDeleted == 0)
+ {
+ PxVec3 orig, dir;
+ orig = mVertices[(uint32_t)tetra.vertexNr[0]].pos;
+ orig += mVertices[(uint32_t)tetra.vertexNr[1]].pos;
+ orig += mVertices[(uint32_t)tetra.vertexNr[2]].pos;
+ orig += mVertices[(uint32_t)tetra.vertexNr[3]].pos;
+ orig *= 0.25f;
+
+ uint32_t numInside = 0; // test 6 standard rays, majority vote
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ PxBounds3 rayBounds(orig, orig);
+ switch (j)
+ {
+ case 0:
+ {
+ rayBounds.maximum.x = mBound.maximum.x + EPSILON;
+ rayBounds.minimum.x = mBound.minimum.x - EPSILON;
+ dir = PxVec3(1.0f, 0.0f, 0.0f);
+ }
+ break;
+ case 1:
+ {
+ rayBounds.maximum.y = mBound.maximum.y + EPSILON;
+ rayBounds.minimum.y = mBound.minimum.y - EPSILON;
+ dir = PxVec3(0.0f, 1.0f, 0.0f);
+ }
+ break;
+ case 2:
+ {
+ rayBounds.maximum.z = mBound.maximum.z + EPSILON;
+ rayBounds.minimum.z = mBound.minimum.z - EPSILON;
+ dir = PxVec3(0.0f, 0.0f, 1.0f);
+ }
+ break;
+ }
+ mMeshHash->queryUnique(rayBounds, mTempItemIndices);
+
+ raycastHitTimes.clear();
+
+#if TETRAHEDRALIZER_DEBUG_RENDERING && TETRALIZER_SANITY_CHECKS
+ if (i == interesting)
+ {
+ debugBounds.pushBack(rayBounds.minimum);
+ debugBounds.pushBack(rayBounds.maximum);
+ }
+#endif
+
+ for (uint32_t k = 0; k < mTempItemIndices.size(); k++)
+ {
+ uint32_t indexNr = mTempItemIndices[k];
+ PX_ASSERT(indexNr % 3 == 0);
+
+ const PxVec3 p0 = mVertices[mIndices[indexNr + 0]].pos;
+ const PxVec3 p1 = mVertices[mIndices[indexNr + 1]].pos;
+ const PxVec3 p2 = mVertices[mIndices[indexNr + 2]].pos;
+ PxBounds3 triBounds;
+ triBounds.minimum = triBounds.maximum = p0;
+ triBounds.include(p1);
+ triBounds.include(p2);
+
+ if (!rayBounds.intersects(triBounds))
+ {
+ continue;
+ }
+
+#if TETRAHEDRALIZER_DEBUG_RENDERING && TETRALIZER_SANITY_CHECKS
+ if (i == interesting)
+ {
+ //debugTriangles.pushBack(p0);
+ //debugTriangles.pushBack(p1);
+ //debugTriangles.pushBack(p2);
+ debugBounds.pushBack(triBounds.minimum);
+ debugBounds.pushBack(triBounds.maximum);
+ }
+#endif
+
+
+ float t, u, v;
+ if (!APEX_RayTriangleIntersect(orig, dir, p0, p1, p2, t, u, v))
+ {
+ continue;
+ }
+
+ raycastHitTimes.pushBack(t);
+ }
+
+ if (!raycastHitTimes.empty())
+ {
+ shdfnd::sort(raycastHitTimes.begin(), raycastHitTimes.size(), F32Less());
+
+ uint32_t negative = 0, positive = 0;
+#if TETRALIZER_SANITY_CHECKS
+ bool report = false;//0 <= i && i < 1033;
+#endif
+ for (uint32_t k = 0; k < raycastHitTimes.size(); k++)
+ {
+ if (k > 0 && PxAbs(raycastHitTimes[k] - raycastHitTimes[k - 1]) < EPSILON)
+ {
+#if TETRALIZER_SANITY_CHECKS
+ report = true;
+#endif
+ // PH: This proved to not be working right, or not making any difference
+ //continue;
+ }
+ if (raycastHitTimes[k] < 0)
+ {
+ negative++;
+ }
+ else
+ {
+ positive++;
+ }
+ }
+ numInside += (positive & 0x1) + (negative & 0x1);
+#if TETRAHEDRALIZER_DEBUG_RENDERING && TETRALIZER_SANITY_CHECKS
+ if (report)
+ {
+ float scale = 1.01f;
+ debugLines.pushBack(worldRay.orig - worldRay.dir * scale);
+ debugLines.pushBack(worldRay.orig + worldRay.dir * scale);
+ }
+#endif
+ }
+ }
+ if (numInside < 3)
+ {
+ tetra.bDeleted = 1;
+ }
+#if TETRAHEDRALIZER_DEBUG_RENDERING && TETRALIZER_SANITY_CHECKS
+ if (numInside > 0 && numInside < 6)
+ {
+ debugTetras.pushBack(mVertices[mTetras[i].vertexNr[0]].pos);
+ debugTetras.pushBack(mVertices[mTetras[i].vertexNr[1]].pos);
+ debugTetras.pushBack(mVertices[mTetras[i].vertexNr[2]].pos);
+ debugTetras.pushBack(mVertices[mTetras[i].vertexNr[3]].pos);
+ }
+#endif
+
+ // remove degenerated tetrahedra (slivers)
+ float quality = getTetraQuality(tetra);
+ PX_ASSERT(quality >= 0);
+ PX_ASSERT(quality <= 1);
+ tetra.quality = (uint32_t)(quality * 1023.0f);
+ if (quality < 0.001f)
+ {
+ tetra.bDeleted = 1;
+ }
+ }
+ }
+
+ return true;
+}
+
+
+
+void ApexTetrahedralizer::updateCircumSphere(FullTetrahedron& tetra) const
+{
+ if (tetra.bCircumSphereDirty == 0)
+ {
+ return;
+ }
+
+ const PxVec3 p0 = mVertices[(uint32_t)tetra.vertexNr[0]].pos;
+ const PxVec3 b = mVertices[(uint32_t)tetra.vertexNr[1]].pos - p0;
+ const PxVec3 c = mVertices[(uint32_t)tetra.vertexNr[2]].pos - p0;
+ const PxVec3 d = mVertices[(uint32_t)tetra.vertexNr[3]].pos - p0;
+
+ float det = b.x * (c.y * d.z - c.z * d.y) - b.y * (c.x * d.z - c.z * d.x) + b.z * (c.x * d.y - c.y * d.x);
+
+ if (det == 0.0f)
+ {
+ tetra.center = p0;
+ tetra.radiusSquared = 0.0f;
+ return; // singular case
+ }
+
+ det *= 2.0f;
+ PxVec3 v = c.cross(d) * b.dot(b) + d.cross(b) * c.dot(c) + b.cross(c) * d.dot(d);
+ v /= det;
+
+ tetra.radiusSquared = v.magnitudeSquared();
+ tetra.center = p0 + v;
+ tetra.bCircumSphereDirty = 0;
+}
+
+
+
+bool ApexTetrahedralizer::pointInCircumSphere(FullTetrahedron& tetra, const PxVec3& p) const
+{
+ updateCircumSphere(tetra);
+ return (tetra.center - p).magnitudeSquared() < tetra.radiusSquared;
+}
+
+
+
+bool ApexTetrahedralizer::pointInTetra(const FullTetrahedron& tetra, const PxVec3& p) const
+{
+ const PxVec3 q = p - mVertices[(uint32_t)tetra.vertexNr[0]].pos;
+ const PxVec3 q0 = mVertices[(uint32_t)tetra.vertexNr[1]].pos - mVertices[(uint32_t)tetra.vertexNr[0]].pos;
+ const PxVec3 q1 = mVertices[(uint32_t)tetra.vertexNr[2]].pos - mVertices[(uint32_t)tetra.vertexNr[0]].pos;
+ const PxVec3 q2 = mVertices[(uint32_t)tetra.vertexNr[3]].pos - mVertices[(uint32_t)tetra.vertexNr[0]].pos;
+
+ PxMat33 m(q0,q1,q2);
+ float det = m.getDeterminant();
+ m.column0 = q;
+ float x = m.getDeterminant();
+ m.column0 = q0;
+ m.column1 = q;
+ float y = m.getDeterminant();
+ m.column1 = q1;
+ m.column2 = q;
+ float z = m.getDeterminant();
+ if (det < 0.0f)
+ {
+ x = -x;
+ y = -y;
+ z = -z;
+ det = -det;
+ }
+
+ if (x < 0.0f || y < 0.0f || z < 0.0f)
+ {
+ return false;
+ }
+
+ return (x + y + z < det);
+}
+
+
+
+float ApexTetrahedralizer::getTetraVolume(const FullTetrahedron& tetra) const
+{
+ const PxVec3 v0 = mVertices[(uint32_t)tetra.vertexNr[0]].pos;
+ const PxVec3 v1 = mVertices[(uint32_t)tetra.vertexNr[1]].pos - v0;
+ const PxVec3 v2 = mVertices[(uint32_t)tetra.vertexNr[2]].pos - v0;
+ const PxVec3 v3 = mVertices[(uint32_t)tetra.vertexNr[3]].pos - v0;
+ return v3.dot(v1.cross(v2)) / 6.0f;
+}
+
+
+
+float ApexTetrahedralizer::getTetraVolume(int32_t v0, int32_t v1, int32_t v2, int32_t v3) const
+{
+ FullTetrahedron t;
+ t.set(v0, v1, v2, v3);
+ return getTetraVolume(t);
+}
+
+
+
+float ApexTetrahedralizer::getTetraQuality(const FullTetrahedron& tetra) const
+{
+ const float sqrt2 = 1.4142135623f;
+
+ const float e = getTetraLongestEdge(tetra);
+ if (e == 0.0f)
+ {
+ return 0.0f;
+ }
+
+ // for regular tetrahedron vol * 6 * sqrt(2) = s^3 -> quality = 1.0
+ return PxAbs(getTetraVolume(tetra)) * 6.0f * sqrt2 / (e * e * e);
+}
+
+
+
+float ApexTetrahedralizer::getTetraLongestEdge(const FullTetrahedron& tetra) const
+{
+ const PxVec3& v0 = mVertices[(uint32_t)tetra.vertexNr[0]].pos;
+ const PxVec3& v1 = mVertices[(uint32_t)tetra.vertexNr[1]].pos;
+ const PxVec3& v2 = mVertices[(uint32_t)tetra.vertexNr[2]].pos;
+ const PxVec3& v3 = mVertices[(uint32_t)tetra.vertexNr[3]].pos;
+ float max = (v0 - v1).magnitudeSquared();;
+ max = PxMax(max, (v0 - v2).magnitudeSquared());
+ max = PxMax(max, (v0 - v3).magnitudeSquared());
+ max = PxMax(max, (v1 - v2).magnitudeSquared());
+ max = PxMax(max, (v1 - v3).magnitudeSquared());
+ max = PxMax(max, (v2 - v3).magnitudeSquared());
+ return PxSqrt(max);
+}
+
+
+
+bool ApexTetrahedralizer::triangleContainsVertexNr(uint32_t* triangle, uint32_t* vertexNumber, uint32_t nbVertices)
+{
+ if (triangle != NULL && vertexNumber != NULL && nbVertices > 0)
+ {
+ for (uint32_t i = 0; i < nbVertices; i++)
+ {
+ if (triangle[0] == vertexNumber[i] || triangle[1] == vertexNumber[i] || triangle[2] == vertexNumber[i])
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+
+void ApexTetrahedralizer::compressTetrahedra(bool trashNeighbours)
+{
+ if (trashNeighbours)
+ {
+ uint32_t i = 0;
+ while (i < mTetras.size())
+ {
+ if (mTetras[i].bDeleted == 1)
+ {
+ mTetras.replaceWithLast(i);
+ }
+ else
+ {
+ mTetras[i].neighborNr[0] = mTetras[i].neighborNr[1] = mTetras[i].neighborNr[2] = mTetras[i].neighborNr[3] = -1;
+ i++;
+ }
+ }
+ }
+ else
+ {
+ physx::Array<int32_t> oldToNew(mTetras.size());
+
+ uint32_t i = 0;
+ while (i < mTetras.size())
+ {
+ if (mTetras[i].bDeleted == 1)
+ {
+ oldToNew[i] = -1;
+ if (mTetras[mTetras.size() - 1].bDeleted == 1)
+ {
+ oldToNew[mTetras.size() - 1] = -1;
+ }
+ else
+ {
+ oldToNew[mTetras.size() - 1] = (int32_t)i;
+ mTetras[i] = mTetras[mTetras.size() - 1];
+ i++;
+ }
+ mTetras.popBack();
+ }
+ else
+ {
+ oldToNew[i] = (int32_t)i;
+ i++;
+ }
+ }
+
+ for (i = 0; i < mTetras.size(); i++)
+ {
+ FullTetrahedron& t = mTetras[i];
+ for (uint32_t j = 0; j < 4; j++)
+ {
+ if (t.neighborNr[j] >= 0)
+ {
+ PX_ASSERT((uint32_t)t.neighborNr[j] < oldToNew.size());
+ t.neighborNr[j] = oldToNew[(uint32_t)t.neighborNr[j]];
+ }
+ }
+ }
+ }
+}
+
+
+
+void ApexTetrahedralizer::compressVertices()
+{
+ // remove vertices that are not referenced by any tetrahedra
+ physx::Array<int32_t> oldToNew;
+ physx::Array<TetraVertex> newVertices;
+
+ mBound.setEmpty();
+
+ oldToNew.resize(mVertices.size(), -1);
+
+ for (uint32_t i = 0; i < mTetras.size(); i++)
+ {
+ FullTetrahedron& t = mTetras[i];
+ for (uint32_t j = 0; j < 4; j++)
+ {
+ uint32_t vNr = (uint32_t)t.vertexNr[j];
+ if (oldToNew[vNr] < 0)
+ {
+ oldToNew[vNr] = (int32_t)newVertices.size();
+ newVertices.pushBack(mVertices[vNr]);
+ mBound.include(mVertices[vNr].pos);
+ }
+ t.vertexNr[j] = oldToNew[vNr];
+ }
+ }
+
+ mVertices.clear();
+ mVertices.resize(newVertices.size());
+ for (uint32_t i = 0; i < newVertices.size(); i++)
+ {
+ mVertices[i] = newVertices[i];
+ }
+}
+
+}
+} // end namespace nvidia::apex
+
diff --git a/APEX_1.4/common/src/CurveImpl.cpp b/APEX_1.4/common/src/CurveImpl.cpp
new file mode 100644
index 00000000..c2daba5c
--- /dev/null
+++ b/APEX_1.4/common/src/CurveImpl.cpp
@@ -0,0 +1,182 @@
+/*
+ * 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 "Apex.h"
+#include "PxAssert.h"
+#include "nvparameterized/NvParameterized.h"
+#include "Curve.h"
+#include "CurveImpl.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+/**
+ Linear interpolation. "in" and "out" stands here for X and Y coordinates of the control points
+*/
+inline float lerp(float inCurrent, float inMin, float inMax, float outMin, float outMax)
+{
+ if (inMin == inMax)
+ {
+ return outMin;
+ }
+
+ return ((inCurrent - inMin) / (inMax - inMin)) * (outMax - outMin) + outMin;
+}
+
+/**
+ The CurveImpl is a class for storing control points on a curve and evaluating the results later.
+*/
+
+/**
+ Retrieve the output Y for the specified input x, based on the properties of the stored curve described
+ by mControlPoints.
+*/
+float CurveImpl::evaluate(float x) const
+{
+ Vec2R xPoints, yPoints;
+ if (calculateControlPoints(x, xPoints, yPoints))
+ {
+ return lerp(x, xPoints[0], xPoints[1], yPoints[0], yPoints[1]);
+ }
+ else if (mControlPoints.size() == 1)
+ {
+ return mControlPoints[0].y;
+ }
+ else
+ {
+ // This is too noisy for editors...
+ //PX_ASSERT(!"Unable to find control points that contained the specified curve parameter");
+ return 0;
+ }
+}
+
+/**
+ Add a control point to the list of control points, returning the index of the new point.
+*/
+uint32_t CurveImpl::addControlPoint(const Vec2R& controlPoint)
+{
+ uint32_t index = calculateFollowingControlPoint(controlPoint.x);
+
+ if (index == mControlPoints.size())
+ {
+ // add element to the end
+ Vec2R& v2 = mControlPoints.insert();
+ v2 = controlPoint;
+ }
+ else
+ {
+ // memmove all elements from index - end to index+1 - new_end
+ uint32_t oldSize = mControlPoints.size();
+ mControlPoints.insert();
+ memmove(&mControlPoints[index + 1], &mControlPoints[index], sizeof(Vec2R) * (oldSize - index));
+ mControlPoints[index] = controlPoint;
+ }
+ return index;
+}
+
+/**
+ Add a control points to the list of control points. Assuming the
+ hPoints points to a list of vec2s
+*/
+void CurveImpl::addControlPoints(::NvParameterized::Interface* param, ::NvParameterized::Handle& hPoints)
+{
+ ::NvParameterized::Handle ih(*param), hMember(*param);
+ int arraySize = 0;
+ PX_ASSERT(hPoints.getConstInterface() == param);
+ hPoints.getArraySize(arraySize);
+ for (int i = 0; i < arraySize; i++)
+ {
+ hPoints.getChildHandle(i, ih);
+ Vec2R tmpVec2;
+ ih.getChildHandle(0, hMember);
+ hMember.getParamF32(tmpVec2.x);
+ ih.getChildHandle(1, hMember);
+ hMember.getParamF32(tmpVec2.y);
+
+ addControlPoint(tmpVec2);
+ }
+}
+
+/**
+ Locates the control points that contain x, placing the resulting control points in the two
+ out parameters. Returns true if the points were found, false otherwise. If the points were not
+ found, the output variables are untouched
+*/
+bool CurveImpl::calculateControlPoints(float x, Vec2R& outXPoints, Vec2R& outYPoints) const
+{
+ uint32_t controlPointSize = mControlPoints.size();
+ if (controlPointSize < 2)
+ {
+ return false;
+ }
+
+ uint32_t followControlPoint = calculateFollowingControlPoint(x);
+ if (followControlPoint == 0)
+ {
+ outXPoints[0] = outXPoints[1] = mControlPoints[0].x;
+ outYPoints[0] = outYPoints[1] = mControlPoints[0].y;
+ return true;
+ }
+ else if (followControlPoint == controlPointSize)
+ {
+ outXPoints[0] = outXPoints[1] = mControlPoints[followControlPoint - 1].x;
+ outYPoints[0] = outYPoints[1] = mControlPoints[followControlPoint - 1].y;
+ return true;
+ }
+
+ outXPoints[0] = mControlPoints[followControlPoint - 1].x;
+ outXPoints[1] = mControlPoints[followControlPoint].x;
+
+ outYPoints[0] = mControlPoints[followControlPoint - 1].y;
+ outYPoints[1] = mControlPoints[followControlPoint].y;
+
+ return true;
+}
+
+/**
+ Locates the first control point with x larger than xValue or the nimber of control points if such point doesn't exist
+*/
+uint32_t CurveImpl::calculateFollowingControlPoint(float xValue) const
+{
+ // TODO: This could be made O(log(N)), but I think there should
+ // be so few entries that it's not worth the code complexity.
+ uint32_t cpSize = mControlPoints.size();
+
+ for (uint32_t u = 0; u < cpSize; ++u)
+ {
+ if (xValue <= mControlPoints[u].x)
+ {
+ return u;
+ }
+ }
+
+ return cpSize;
+}
+
+///get the array of control points
+const Vec2R* CurveImpl::getControlPoints(uint32_t& outCount) const
+{
+ outCount = mControlPoints.size();
+ if (outCount)
+ {
+ return &mControlPoints.front();
+ }
+ else
+ {
+ // LRR: there's more to this, chase this down later
+ return NULL;
+ }
+}
+
+}
+} // namespace nvidia::apex
diff --git a/APEX_1.4/common/src/ModuleBase.cpp b/APEX_1.4/common/src/ModuleBase.cpp
new file mode 100644
index 00000000..51253706
--- /dev/null
+++ b/APEX_1.4/common/src/ModuleBase.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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 "Apex.h"
+#include "ApexSharedUtils.h"
+#include "PsUserAllocated.h"
+#include "ProfilerCallback.h"
+#include "ModuleBase.h"
+
+#ifdef PHYSX_PROFILE_SDK
+
+#if PX_WINDOWS_FAMILY
+nvidia::profile::PxProfileZone *gProfileZone=NULL;
+#endif
+
+#endif
+
+namespace nvidia
+{
+namespace apex
+{
+
+ModuleBase::ModuleBase() :
+ mSdk(0),
+ mApiProxy(0)
+{
+}
+
+const char* ModuleBase::getName() const
+{
+ return mName.c_str();
+}
+
+void ModuleBase::release()
+{
+ GetApexSDK()->releaseModule(mApiProxy);
+}
+
+void ModuleBase::destroy()
+{
+}
+
+}
+} // end namespace nvidia::apex
diff --git a/APEX_1.4/common/src/ModuleUpdateLoader.cpp b/APEX_1.4/common/src/ModuleUpdateLoader.cpp
new file mode 100644
index 00000000..a80803e4
--- /dev/null
+++ b/APEX_1.4/common/src/ModuleUpdateLoader.cpp
@@ -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.
+ */
+
+
+#ifdef WIN32
+#include "ModuleUpdateLoader.h"
+
+typedef HMODULE (GetUpdatedModule_FUNC)(const char*, const char*);
+
+ModuleUpdateLoader::ModuleUpdateLoader(const char* updateLoaderDllName)
+ : mGetUpdatedModuleFunc(NULL)
+{
+ mUpdateLoaderDllHandle = LoadLibrary(updateLoaderDllName);
+
+ if (mUpdateLoaderDllHandle != NULL)
+ {
+ mGetUpdatedModuleFunc = GetProcAddress(mUpdateLoaderDllHandle, "GetUpdatedModule");
+ }
+}
+
+ModuleUpdateLoader::~ModuleUpdateLoader()
+{
+ if (mUpdateLoaderDllHandle != NULL)
+ {
+ FreeLibrary(mUpdateLoaderDllHandle);
+ mUpdateLoaderDllHandle = NULL;
+ }
+}
+
+HMODULE ModuleUpdateLoader::loadModule(const char* moduleName, const char* appGuid)
+{
+ HMODULE result = NULL;
+
+ if (mGetUpdatedModuleFunc != NULL)
+ {
+ // Try to get the module through PhysXUpdateLoader
+ GetUpdatedModule_FUNC* getUpdatedModuleFunc = (GetUpdatedModule_FUNC*)mGetUpdatedModuleFunc;
+ result = getUpdatedModuleFunc(moduleName, appGuid);
+ }
+ else
+ {
+ // If no PhysXUpdateLoader, just load the DLL directly
+ result = LoadLibrary(moduleName);
+ }
+
+ return result;
+}
+
+
+#endif // WIN32
diff --git a/APEX_1.4/common/src/PVDParameterizedHandler.cpp b/APEX_1.4/common/src/PVDParameterizedHandler.cpp
new file mode 100644
index 00000000..61f2092b
--- /dev/null
+++ b/APEX_1.4/common/src/PVDParameterizedHandler.cpp
@@ -0,0 +1,658 @@
+/*
+ * 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 "PVDParameterizedHandler.h"
+#include "ApexPvdClient.h"
+
+#ifndef WITHOUT_PVD
+
+#include "PxPvdDataStream.h"
+#include "nvparameterized/NvParameterized.h"
+#include "NvParameters.h"
+
+using namespace nvidia;
+using namespace nvidia::shdfnd;
+
+#define SET_PROPERTY_VALUE \
+ if (pvdAction != PvdAction::DESTROY) \
+ {\
+ ok = propertyHandle.getParam(val) == NvParameterized::ERROR_NONE; \
+ if (ok)\
+ {\
+ if (isArrayElement)\
+ mPvdStream->appendPropertyValueData(DataRef<const uint8_t>((const uint8_t*)&val, sizeof(val)));\
+ else\
+ mPvdStream->setPropertyValue(pvdInstance, propertyName, val);\
+ }\
+ }\
+
+namespace physx
+{
+namespace pvdsdk
+{
+
+
+
+bool PvdParameterizedHandler::createClass(const NamespacedName& className)
+{
+ bool create = !mCreatedClasses.contains(className.mName);
+ if (create)
+ {
+ mPvdStream->createClass(className);
+ mCreatedClasses.insert(className.mName);
+ }
+
+ return create;
+}
+
+
+
+bool PvdParameterizedHandler::getPvdType(const NvParameterized::Definition& def, NamespacedName& pvdTypeName)
+{
+ NvParameterized::DataType paramType = def.type();
+
+ bool ok = true;
+ switch(paramType)
+ {
+ case NvParameterized::TYPE_BOOL :
+ pvdTypeName = getPvdNamespacedNameForType<bool>();
+ break;
+
+ case NvParameterized::TYPE_STRING :
+ pvdTypeName = getPvdNamespacedNameForType<const char*>();
+ break;
+
+ case NvParameterized::TYPE_I8 :
+ pvdTypeName = getPvdNamespacedNameForType<int8_t>();
+ break;
+
+ case NvParameterized::TYPE_I16 :
+ pvdTypeName = getPvdNamespacedNameForType<int16_t>();
+ break;
+
+ case NvParameterized::TYPE_I32 :
+ pvdTypeName = getPvdNamespacedNameForType<int32_t>();
+ break;
+
+ case NvParameterized::TYPE_I64 :
+ pvdTypeName = getPvdNamespacedNameForType<int64_t>();
+ break;
+
+ case NvParameterized::TYPE_U8 :
+ pvdTypeName = getPvdNamespacedNameForType<uint8_t>();
+ break;
+
+ case NvParameterized::TYPE_U16 :
+ pvdTypeName = getPvdNamespacedNameForType<uint16_t>();
+ break;
+
+ case NvParameterized::TYPE_U32 :
+ pvdTypeName = getPvdNamespacedNameForType<uint32_t>();
+ break;
+
+ case NvParameterized::TYPE_U64 :
+ pvdTypeName = getPvdNamespacedNameForType<uint64_t>();
+ break;
+
+ case NvParameterized::TYPE_F32 :
+ pvdTypeName = getPvdNamespacedNameForType<float>();
+ break;
+
+ case NvParameterized::TYPE_F64 :
+ pvdTypeName = getPvdNamespacedNameForType<double>();
+ break;
+
+ case NvParameterized::TYPE_VEC2 :
+ pvdTypeName = getPvdNamespacedNameForType<PxVec2>();
+ break;
+
+ case NvParameterized::TYPE_VEC3 :
+ pvdTypeName = getPvdNamespacedNameForType<PxVec3>();
+ break;
+
+ case NvParameterized::TYPE_VEC4 :
+ pvdTypeName = getPvdNamespacedNameForType<uint16_t>();
+ break;
+
+ case NvParameterized::TYPE_QUAT :
+ pvdTypeName = getPvdNamespacedNameForType<PxQuat>();
+ break;
+
+ case NvParameterized::TYPE_MAT33 :
+ pvdTypeName = getPvdNamespacedNameForType<PxMat33>();
+ break;
+
+ case NvParameterized::TYPE_BOUNDS3 :
+ pvdTypeName = getPvdNamespacedNameForType<PxBounds3>();
+ break;
+
+ case NvParameterized::TYPE_MAT44 :
+ pvdTypeName = getPvdNamespacedNameForType<PxMat44>();
+ break;
+
+ case NvParameterized::TYPE_POINTER :
+ pvdTypeName = getPvdNamespacedNameForType<VoidPtr>();
+ break;
+
+ case NvParameterized::TYPE_TRANSFORM :
+ pvdTypeName = getPvdNamespacedNameForType<PxTransform>();
+ break;
+
+ case NvParameterized::TYPE_REF :
+ case NvParameterized::TYPE_STRUCT :
+ pvdTypeName = getPvdNamespacedNameForType<ObjectRef>();
+ break;
+
+ case NvParameterized::TYPE_ARRAY:
+ {
+ PX_ASSERT(def.numChildren() > 0);
+ const NvParameterized::Definition* arrayMemberDef = def.child(0);
+
+ ok = getPvdType(*arrayMemberDef, pvdTypeName);
+
+ // array of strings is not supported by pvd
+ if (arrayMemberDef->type() == NvParameterized::TYPE_STRING)
+ {
+ ok = false;
+ }
+
+ break;
+ }
+
+ default:
+ ok = false;
+ break;
+ };
+
+ return ok;
+}
+
+
+size_t PvdParameterizedHandler::getStructId(void* structAddress, const char* structName, bool deleteId)
+{
+ StructId structId(structAddress, structName);
+
+ size_t pvdStructId = 0;
+ if (mStructIdMap.find(structId) != NULL)
+ {
+ pvdStructId = mStructIdMap[structId];
+ }
+ else
+ {
+ PX_ASSERT(!deleteId);
+
+ // addresses are 4 byte aligned, so this id is probably not used by another object
+ pvdStructId = mNextStructId++;
+ pvdStructId = (pvdStructId << 1) | 1;
+
+ mStructIdMap[structId] = pvdStructId;
+ }
+
+ if (deleteId)
+ {
+ mStructIdMap.erase(structId);
+ }
+
+ return pvdStructId;
+}
+
+
+const void* PvdParameterizedHandler::getPvdId(const NvParameterized::Handle& handle, bool deleteId)
+{
+ void* retVal = 0;
+ NvParameterized::DataType type = handle.parameterDefinition()->type();
+
+ switch(type)
+ {
+ case NvParameterized::TYPE_REF:
+ {
+ // references use the referenced interface pointer as ID
+ NvParameterized::Interface* paramRef = NULL;
+ handle.getParamRef(paramRef);
+ retVal = (void*)paramRef;
+ break;
+ }
+
+ case NvParameterized::TYPE_STRUCT:
+ {
+ // structs use custom ID's, because two structs can have the same location if
+ // a struct contains another struct as its first member
+ NvParameterized::NvParameters* param = (NvParameterized::NvParameters*)(handle.getInterface());
+ if (param != NULL)
+ {
+ // get struct address
+ size_t offset = 0;
+ void* structAddress = 0;
+ param->getVarPtr(handle, structAddress, offset);
+
+ // create an id from address and name
+ retVal = (void*)getStructId(structAddress, handle.parameterDefinition()->longName(), deleteId);
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return retVal;
+}
+
+
+bool PvdParameterizedHandler::setProperty(const void* pvdInstance, NvParameterized::Handle& propertyHandle, bool isArrayElement, PvdAction::Enum pvdAction)
+{
+ const char* propertyName = propertyHandle.parameterDefinition()->name();
+ NvParameterized::DataType propertyType = propertyHandle.parameterDefinition()->type();
+
+ bool ok = true;
+ switch(propertyType)
+ {
+ case NvParameterized::TYPE_BOOL :
+ {
+ //bool val;
+ //SET_PROPERTY_VALUE;
+ break;
+ }
+
+ case NvParameterized::TYPE_STRING :
+ {
+ if (isArrayElement)
+ {
+ // pvd doesn't support arrays of strings
+ ok = false;
+ }
+ else
+ {
+ const char* val;
+ ok = propertyHandle.getParamString(val) == NvParameterized::ERROR_NONE;
+ if (ok)
+ {
+ mPvdStream->setPropertyValue(pvdInstance, propertyName, val);
+ }
+ }
+
+ break;
+ }
+
+ case NvParameterized::TYPE_I8 :
+ {
+ int8_t val;
+ SET_PROPERTY_VALUE;
+ break;
+ }
+
+ case NvParameterized::TYPE_I16 :
+ {
+ int16_t val;
+ SET_PROPERTY_VALUE;
+ break;
+ }
+
+ case NvParameterized::TYPE_I32 :
+ {
+ int32_t val;
+ SET_PROPERTY_VALUE;
+ break;
+ }
+
+ case NvParameterized::TYPE_I64 :
+ {
+ int64_t val;
+ SET_PROPERTY_VALUE;
+ break;
+ }
+
+ case NvParameterized::TYPE_U8 :
+ {
+ uint8_t val;
+ SET_PROPERTY_VALUE;
+ break;
+ }
+
+ case NvParameterized::TYPE_U16 :
+ {
+ uint16_t val;
+ SET_PROPERTY_VALUE;
+ break;
+ }
+
+ case NvParameterized::TYPE_U32 :
+ {
+ uint32_t val;
+ SET_PROPERTY_VALUE;
+ break;
+ }
+
+ case NvParameterized::TYPE_U64 :
+ {
+ uint64_t val;
+ SET_PROPERTY_VALUE;
+ break;
+ }
+
+ case NvParameterized::TYPE_F32 :
+ {
+ float val;
+ SET_PROPERTY_VALUE;
+ break;
+ }
+
+ case NvParameterized::TYPE_F64 :
+ {
+ double val;
+ SET_PROPERTY_VALUE;
+ break;
+ }
+
+ case NvParameterized::TYPE_VEC2 :
+ {
+ PxVec2 val;
+ SET_PROPERTY_VALUE;
+ break;
+ }
+
+ case NvParameterized::TYPE_VEC3 :
+ {
+ PxVec3 val;
+ SET_PROPERTY_VALUE;
+ break;
+ }
+
+ case NvParameterized::TYPE_VEC4 :
+ {
+ PxVec4 val;
+ SET_PROPERTY_VALUE;
+ break;
+ }
+
+ case NvParameterized::TYPE_QUAT :
+ {
+ PxQuat val;
+ SET_PROPERTY_VALUE;
+ break;
+ }
+
+ case NvParameterized::TYPE_MAT33 :
+ {
+ PxMat33 val;
+ SET_PROPERTY_VALUE;
+ break;
+ }
+
+ case NvParameterized::TYPE_BOUNDS3 :
+ {
+ PxBounds3 val;
+ SET_PROPERTY_VALUE;
+ break;
+ }
+
+ case NvParameterized::TYPE_MAT44 :
+ {
+ PxMat44 val;
+ SET_PROPERTY_VALUE;
+ break;
+ }
+
+ /*
+ case NvParameterized::TYPE_POINTER :
+ {
+ void* val;
+ SET_PROPERTY_VALUE;
+ break;
+ }
+ */
+
+ case NvParameterized::TYPE_TRANSFORM :
+ {
+ PxTransform val;
+ SET_PROPERTY_VALUE;
+ break;
+ }
+
+ case NvParameterized::TYPE_STRUCT:
+ {
+ const void* pvdId = getPvdId(propertyHandle, pvdAction == PvdAction::DESTROY);
+
+ if (pvdId != 0)
+ {
+ if (!mInstanceIds.contains(pvdId))
+ {
+ // create pvd instance for struct
+ mInstanceIds.insert(pvdId);
+ NamespacedName structName(APEX_PVD_NAMESPACE, propertyHandle.parameterDefinition()->structName());
+ mPvdStream->createInstance(structName, pvdId);
+ mPvdStream->setPropertyValue(pvdInstance, propertyName, DataRef<const uint8_t>((const uint8_t*)&pvdId, sizeof(NvParameterized::Interface*)), getPvdNamespacedNameForType<ObjectRef>());
+ }
+
+ // recursively update struct properties
+ updatePvd(pvdId, propertyHandle, pvdAction);
+
+ if (pvdAction == PvdAction::DESTROY)
+ {
+ // destroy pvd instance of struct
+ mPvdStream->destroyInstance(pvdId);
+ mInstanceIds.erase(pvdId);
+ }
+ }
+ break;
+ }
+
+ case NvParameterized::TYPE_REF:
+ {
+ const void* pvdId = getPvdId(propertyHandle, pvdAction == PvdAction::DESTROY);
+
+ if (pvdId != 0)
+ {
+ // get a handle in the referenced parameterized object
+ NvParameterized::Handle refHandle = propertyHandle;
+ propertyHandle.getChildHandle(0, refHandle);
+ NvParameterized::Interface* paramRef = NULL;
+ ok = refHandle.getParamRef(paramRef) == NvParameterized::ERROR_NONE;
+
+ if (ok)
+ {
+ if (!mInstanceIds.contains(pvdId))
+ {
+ // create a pvd instance for the reference
+ mInstanceIds.insert(pvdId);
+ NamespacedName refClassName(APEX_PVD_NAMESPACE, paramRef->className());
+ mPvdStream->createInstance(refClassName, pvdId);
+ mPvdStream->setPropertyValue(pvdInstance, propertyName, DataRef<const uint8_t>((const uint8_t*)&pvdId, sizeof(NvParameterized::Interface*)), getPvdNamespacedNameForType<ObjectRef>());
+ }
+
+ // recursivly update pvd instance of the referenced object
+ refHandle = NvParameterized::Handle(paramRef);
+ updatePvd(pvdId, refHandle, pvdAction);
+
+ if (pvdAction == PvdAction::DESTROY)
+ {
+ // destroy pvd instance of reference
+ mPvdStream->destroyInstance(pvdId);
+ mInstanceIds.erase(pvdId);
+ }
+ }
+ }
+ break;
+ }
+
+ case NvParameterized::TYPE_ARRAY:
+ {
+ const NvParameterized::Definition* def = propertyHandle.parameterDefinition();
+ PX_ASSERT(def->numChildren() > 0);
+
+ const NvParameterized::Definition* arrayMemberDef = def->child(0);
+ NvParameterized::DataType arrayMemberType = arrayMemberDef->type();
+
+ PX_ASSERT(def->arrayDimension() == 1);
+ int32_t arraySize = 0;
+ propertyHandle.getArraySize(arraySize);
+
+ if (arraySize > 0)
+ {
+ if (arrayMemberType == NvParameterized::TYPE_STRUCT || arrayMemberType == NvParameterized::TYPE_REF)
+ {
+ for (int32_t i = 0; i < arraySize; ++i)
+ {
+ NvParameterized::Handle childHandle(propertyHandle);
+ propertyHandle.getChildHandle(i, childHandle);
+
+ const void* pvdId = getPvdId(childHandle, pvdAction == PvdAction::DESTROY);
+
+ // get the class name of the member
+ NamespacedName childClassName(APEX_PVD_NAMESPACE, "");
+ if (arrayMemberType == NvParameterized::TYPE_STRUCT)
+ {
+ childClassName.mName = childHandle.parameterDefinition()->structName();
+ }
+ else if (arrayMemberType == NvParameterized::TYPE_REF)
+ {
+ // continue on a handle in the referenced object
+ NvParameterized::Interface* paramRef = NULL;
+ ok = childHandle.getParamRef(paramRef) == NvParameterized::ERROR_NONE;
+ PX_ASSERT(ok);
+ if (!ok)
+ {
+ break;
+ }
+ childHandle = NvParameterized::Handle(paramRef);
+ childClassName.mName = paramRef->className();
+ }
+
+ if (!mInstanceIds.contains(pvdId))
+ {
+ // create pvd instance for struct or ref and add it to the array
+ mInstanceIds.insert(pvdId);
+ mPvdStream->createInstance(childClassName, pvdId);
+ mPvdStream->pushBackObjectRef(pvdInstance, propertyName, pvdId);
+ }
+
+ // recursively update the array member
+ updatePvd(pvdId, childHandle, pvdAction);
+
+ if (pvdAction == PvdAction::DESTROY)
+ {
+ // destroy pvd instance for struct or ref
+ mPvdStream->removeObjectRef(pvdInstance, propertyName, pvdId); // might not be necessary
+ mPvdStream->destroyInstance(pvdId);
+ mInstanceIds.erase(pvdId);
+ }
+ }
+ }
+ else if (pvdAction != PvdAction::DESTROY)
+ {
+ // for arrays of simple types just update the property values
+ NamespacedName pvdTypeName;
+ if (getPvdType(*def, pvdTypeName))
+ {
+ mPvdStream->beginSetPropertyValue(pvdInstance, propertyName, pvdTypeName);
+ for (int32_t i = 0; i < arraySize; ++i)
+ {
+ NvParameterized::Handle childHandle(propertyHandle);
+ propertyHandle.getChildHandle(i, childHandle);
+
+ setProperty(pvdInstance, childHandle, true, pvdAction);
+ }
+ mPvdStream->endSetPropertyValue();
+ }
+ }
+ }
+ break;
+ }
+
+ default:
+ ok = false;
+ break;
+ };
+
+ return ok;
+}
+
+
+
+void PvdParameterizedHandler::initPvdClasses(const NvParameterized::Definition& paramDefinition, const char* className)
+{
+ NamespacedName pvdClassName(APEX_PVD_NAMESPACE, className);
+
+ // iterate all properties
+ const int numChildren = paramDefinition.numChildren();
+ for (int i = 0; i < numChildren; i++)
+ {
+ const NvParameterized::Definition* childDef = paramDefinition.child(i);
+
+ const char* propertyName = childDef->name();
+ NvParameterized::DataType propertyDataType = childDef->type();
+
+
+ // First, recursively create pvd classes for encountered structs
+ //
+ // if it's an array, continue with its member type, and remember that it's an array
+ bool isArray = false;
+ if (propertyDataType == NvParameterized::TYPE_ARRAY)
+ {
+ PX_ASSERT(childDef->numChildren() > 0);
+
+ const NvParameterized::Definition* arrayMemberDef = childDef->child(0);
+ if (arrayMemberDef->type() == NvParameterized::TYPE_STRUCT)
+ {
+ NamespacedName memberClassName(APEX_PVD_NAMESPACE, arrayMemberDef->structName());
+ if (createClass(memberClassName))
+ {
+ // only recurse if this we encounter the struct the first time and a class has been created
+ initPvdClasses(*arrayMemberDef, memberClassName.mName);
+ }
+ }
+
+ isArray = true;
+ }
+ else if (propertyDataType == NvParameterized::TYPE_STRUCT)
+ {
+ // create classes for structs
+ // (doesn't work for refs, looks like Definitions don't contain the Definitions of references)
+
+ NamespacedName childClassName(APEX_PVD_NAMESPACE, childDef->structName());
+ if (createClass(childClassName))
+ {
+ // only recurse if this we encounter the struct the first time and a class has been created
+ initPvdClasses(*childDef, childClassName.mName);
+ }
+ }
+
+
+ // Then, create the property
+ NamespacedName typeName;
+ if (!childDef->hint("NOPVD") && getPvdType(*childDef, typeName))
+ {
+ mPvdStream->createProperty(pvdClassName, propertyName, "", typeName, isArray ? PropertyType::Array : PropertyType::Scalar);
+ }
+ }
+}
+
+
+void PvdParameterizedHandler::updatePvd(const void* pvdInstance, NvParameterized::Handle& paramsHandle, PvdAction::Enum pvdAction)
+{
+ // iterate all properties
+ const int numChildren = paramsHandle.parameterDefinition()->numChildren();
+ for (int i = 0; i < numChildren; i++)
+ {
+ paramsHandle.set(i);
+
+ if (!paramsHandle.parameterDefinition()->hint("NOPVD"))
+ {
+ setProperty(pvdInstance, paramsHandle, false, pvdAction);
+ }
+ paramsHandle.popIndex();
+ }
+}
+
+}
+}
+
+#endif \ No newline at end of file
diff --git a/APEX_1.4/common/src/ReadCheck.cpp b/APEX_1.4/common/src/ReadCheck.cpp
new file mode 100644
index 00000000..fe6994d9
--- /dev/null
+++ b/APEX_1.4/common/src/ReadCheck.cpp
@@ -0,0 +1,63 @@
+/*
+ * 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 "ReadCheck.h"
+#include "ApexRWLockable.h"
+#include "PsThread.h"
+#include "ApexSDKIntl.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+ReadCheck::ReadCheck(const ApexRWLockable* scene, const char* functionName)
+ : mLockable(scene), mName(functionName), mErrorCount(0)
+{
+ if (GetApexSDK()->isConcurrencyCheckEnabled() && mLockable && !mLockable->isEnabled())
+ {
+ if (!mLockable->startRead() && !mLockable->isEnabled())
+ {
+ APEX_INTERNAL_ERROR("An API read call (%s) was made from thread %d but acquireReadLock() was not called first, note that "
+ "when ApexSDKDesc::enableConcurrencyCheck is enabled all API reads and writes must be "
+ "wrapped in the appropriate locks.", mName, uint32_t(nvidia::Thread::getId()));
+ }
+
+ // Record the NpScene read/write error counter which is
+ // incremented any time a NpScene::startWrite/startRead fails
+ // (see destructor for additional error checking based on this count)
+ mErrorCount = mLockable->getReadWriteErrorCount();
+ }
+}
+
+
+ReadCheck::~ReadCheck()
+{
+ if (GetApexSDK()->isConcurrencyCheckEnabled() && mLockable)
+ {
+ // By checking if the NpScene::mConcurrentErrorCount has been incremented
+ // we can detect if an erroneous read/write was performed during
+ // this objects lifetime. In this case we also print this function's
+ // details so that the user can see which two API calls overlapped
+ if (mLockable->getReadWriteErrorCount() != mErrorCount && !mLockable->isEnabled())
+ {
+ APEX_INTERNAL_ERROR("Leaving %s on thread %d, an API overlapping write on another thread was detected.", mName, uint32_t(nvidia::Thread::getId()));
+ }
+
+ mLockable->stopRead();
+ }
+}
+
+}
+} \ No newline at end of file
diff --git a/APEX_1.4/common/src/Spline.cpp b/APEX_1.4/common/src/Spline.cpp
new file mode 100644
index 00000000..098883ca
--- /dev/null
+++ b/APEX_1.4/common/src/Spline.cpp
@@ -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.
+ */
+
+
+#include "Spline.h"
+#include <assert.h>
+
+using namespace nvidia;
+
+static float f(float x)
+{
+ return( x*x*x - x);
+}
+
+
+// build spline.
+// copied from Sedgwick's Algorithm's in C, page 548.
+void Spline::ComputeSpline(void)
+{
+ uint32_t i;
+ uint32_t n = mNodes.size();
+
+ float *d = new float[n];
+ float *w = new float[n];
+
+ for (i=1; i<(n-1); i++)
+ {
+ d[i] = 2.0f * (mNodes[i+1].x - mNodes[i-1].x);
+ }
+
+ for (i=0; i<(n-1); i++)
+ {
+ mNodes[i].u = mNodes[i+1].x-mNodes[i].x;}
+
+ for (i=1; i<(n-1); i++)
+ {
+ w[i] = 6.0f*((mNodes[i+1].y - mNodes[i].y) / mNodes[i].u - (mNodes[i].y - mNodes[i-1].y) / mNodes[i-1].u);
+ }
+
+ mNodes[0].p = 0.0f;
+ mNodes[n-1].p = 0.0f;
+
+ for (i=1; i<(n-2); i++)
+ {
+ w[i+1] = w[i+1] - w[i]*mNodes[i].u /d[i];
+ d[i+1] = d[i+1] - mNodes[i].u * mNodes[i].u / d[i];
+ }
+
+ for (i=n-2; i>0; i--)
+ {
+ mNodes[i].p = (w[i] - mNodes[i].u * mNodes[i+1].p ) / d[i];
+ }
+
+ delete[]d;
+ delete[]w;
+}
+
+float Spline::Evaluate(float v,uint32_t &index,float &fraction) const
+{
+ float t;
+ uint32_t i=0;
+ uint32_t n = mNodes.size();
+
+ while ( i < (n-1) && v > mNodes[i+1].x )
+ {
+ i++;
+ }
+ if ( i == (n-1) )
+ {
+ i = n-2;
+ }
+
+ index = (uint32_t)i;
+
+ t = (v - mNodes[i].x ) / mNodes[i].u;
+
+ fraction = t;
+
+ return( t*mNodes[i+1].y + (1-t)*mNodes[i].y + mNodes[i].u * mNodes[i].u * (f(t)*mNodes[i+1].p + f(1-t)*mNodes[i].p )/6.0f );
+}
+
+
+void Spline::AddNode(float x,float y)
+{
+ SplineNode s;
+ s.x = x;
+ s.y = y;
+ mNodes.pushBack(s);
+}
+
+float SplineCurve::AddControlPoint(const PxVec3& p) // add control point.
+{
+ int32_t size = mXaxis.GetSize();
+
+ if ( size )
+ {
+ size--;
+ PxVec3 last;
+ last.x = mXaxis.GetEntry(size);
+ last.y = mYaxis.GetEntry(size);
+ last.z = mZaxis.GetEntry(size);
+ PxVec3 diff = last-p;
+ float dist = diff.magnitude();
+ mTime+=dist;
+ }
+ else
+ {
+ mTime = 0;
+ }
+
+ mXaxis.AddNode(mTime,p.x);
+ mYaxis.AddNode(mTime,p.y);
+ mZaxis.AddNode(mTime,p.z);
+ return mTime;
+}
+
+void SplineCurve::AddControlPoint(const PxVec3& p,float t) // add control point.
+{
+ int32_t size = mXaxis.GetSize();
+ if ( size )
+ {
+ size--;
+ PxVec3 last;
+ last.x = mXaxis.GetEntry(size);
+ last.y = mYaxis.GetEntry(size);
+ last.z = mZaxis.GetEntry(size);
+ }
+
+ mTime = t;
+
+ mXaxis.AddNode(mTime,p.x);
+ mYaxis.AddNode(mTime,p.y);
+ mZaxis.AddNode(mTime,p.z);
+}
+
+void SplineCurve::ComputeSpline(void) // compute spline.
+{
+ mXaxis.ComputeSpline();
+ mYaxis.ComputeSpline();
+ mZaxis.ComputeSpline();
+}
+
+PxVec3 SplineCurve::Evaluate(float dist,uint32_t &index,float &fraction)
+{
+ PxVec3 p;
+
+ uint32_t index1,index2,index3;
+ float t1,t2,t3;
+ p.x = mXaxis.Evaluate(dist,index1,t1);
+ p.y = mYaxis.Evaluate(dist,index2,t2);
+ p.z = mZaxis.Evaluate(dist,index3,t3);
+ assert( index1 == index2 && index1 == index3 && index2 == index3 );
+ index = index1;
+ fraction = t1;
+
+ return p;
+}
+
+PxVec3 SplineCurve::GetEntry(int32_t i)
+{
+ PxVec3 p;
+ if ( i >= 0 && i < GetSize() )
+ {
+ p.x = mXaxis.GetEntry(i);
+ p.y = mYaxis.GetEntry(i);
+ p.z = mZaxis.GetEntry(i);
+ }
+ return p;
+}
diff --git a/APEX_1.4/common/src/WriteCheck.cpp b/APEX_1.4/common/src/WriteCheck.cpp
new file mode 100644
index 00000000..af177eb1
--- /dev/null
+++ b/APEX_1.4/common/src/WriteCheck.cpp
@@ -0,0 +1,62 @@
+/*
+ * 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 "WriteCheck.h"
+#include "ApexRWLockable.h"
+#include "PsThread.h"
+#include "ApexSDKIntl.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+WriteCheck::WriteCheck(ApexRWLockable* scene, const char* functionName, bool allowReentry)
+: mLockable(scene), mName(functionName), mAllowReentry(allowReentry), mErrorCount(0)
+{
+ if (GetApexSDK()->isConcurrencyCheckEnabled() && mLockable)
+ {
+ if (!mLockable->startWrite(mAllowReentry) && !mLockable->isEnabled())
+ {
+ APEX_INTERNAL_ERROR("An API write call (%s) was made from thread %d but acquireWriteLock() was not called first, note that "
+ "when ApexSDKDesc::enableConcurrencyCheck is enabled all API reads and writes must be "
+ "wrapped in the appropriate locks.", mName, uint32_t(nvidia::Thread::getId()));
+ }
+
+ // Record the Scene read/write error counter which is
+ // incremented any time a Scene::apexStartWrite/apexStartRead fails
+ // (see destructor for additional error checking based on this count)
+ mErrorCount = mLockable->getReadWriteErrorCount();
+ }
+}
+
+
+WriteCheck::~WriteCheck()
+{
+ if (GetApexSDK()->isConcurrencyCheckEnabled() && mLockable)
+ {
+ // By checking if the NpScene::mConcurrentErrorCount has been incremented
+ // we can detect if an erroneous read/write was performed during
+ // this objects lifetime. In this case we also print this function's
+ // details so that the user can see which two API calls overlapped
+ if (mLockable->getReadWriteErrorCount() != mErrorCount && !mLockable->isEnabled())
+ {
+ APEX_INTERNAL_ERROR("Leaving %s on thread %d, an overlapping API read or write by another thread was detected.", mName, uint32_t(nvidia::Thread::getId()));
+ }
+
+ mLockable->stopWrite(mAllowReentry);
+ }
+}
+
+}
+} \ No newline at end of file
diff --git a/APEX_1.4/common/src/autogen/ConvexHullParameters.cpp b/APEX_1.4/common/src/autogen/ConvexHullParameters.cpp
new file mode 100644
index 00000000..88ab1636
--- /dev/null
+++ b/APEX_1.4/common/src/autogen/ConvexHullParameters.cpp
@@ -0,0 +1,768 @@
+// 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 "ConvexHullParameters.h"
+#include <string.h>
+#include <stdlib.h>
+
+using namespace NvParameterized;
+
+namespace nvidia
+{
+namespace apex
+{
+
+using namespace ConvexHullParametersNS;
+
+const char* const ConvexHullParametersFactory::vptr =
+ NvParameterized::getVptr<ConvexHullParameters, ConvexHullParameters::ClassAlignment>();
+
+const uint32_t NumParamDefs = 17;
+static NvParameterized::DefinitionImpl* ParamDefTable; // now allocated in buildTree [NumParamDefs];
+
+
+static const size_t ParamLookupChildrenTable[] =
+{
+ 1, 3, 7, 9, 11, 13, 14, 15, 16, 2, 4, 5, 6, 8, 10, 12,
+};
+
+#define TENUM(type) nvidia::##type
+#define CHILDREN(index) &ParamLookupChildrenTable[index]
+static const NvParameterized::ParamLookupNode ParamLookupTable[NumParamDefs] =
+{
+ { TYPE_STRUCT, false, 0, CHILDREN(0), 9 },
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->vertices), CHILDREN(9), 1 }, // vertices
+ { TYPE_VEC3, false, 1 * sizeof(physx::PxVec3), NULL, 0 }, // vertices[]
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->uniquePlanes), CHILDREN(10), 1 }, // uniquePlanes
+ { TYPE_STRUCT, false, 1 * sizeof(Plane_Type), CHILDREN(11), 2 }, // uniquePlanes[]
+ { TYPE_VEC3, false, (size_t)(&((Plane_Type*)0)->normal), NULL, 0 }, // uniquePlanes[].normal
+ { TYPE_F32, false, (size_t)(&((Plane_Type*)0)->d), NULL, 0 }, // uniquePlanes[].d
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->widths), CHILDREN(13), 1 }, // widths
+ { TYPE_F32, false, 1 * sizeof(float), NULL, 0 }, // widths[]
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->edges), CHILDREN(14), 1 }, // edges
+ { TYPE_U32, false, 1 * sizeof(uint32_t), NULL, 0 }, // edges[]
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->adjacentFaces), CHILDREN(15), 1 }, // adjacentFaces
+ { TYPE_U32, false, 1 * sizeof(uint32_t), NULL, 0 }, // adjacentFaces[]
+ { TYPE_BOUNDS3, false, (size_t)(&((ParametersStruct*)0)->bounds), NULL, 0 }, // bounds
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->volume), NULL, 0 }, // volume
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->uniqueEdgeDirectionCount), NULL, 0 }, // uniqueEdgeDirectionCount
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->planeCount), NULL, 0 }, // planeCount
+};
+
+
+bool ConvexHullParameters::mBuiltFlag = false;
+NvParameterized::MutexType ConvexHullParameters::mBuiltFlagMutex;
+
+ConvexHullParameters::ConvexHullParameters(NvParameterized::Traits* traits, void* buf, int32_t* refCount) :
+ NvParameters(traits, buf, refCount)
+{
+ //mParameterizedTraits->registerFactory(className(), &ConvexHullParametersFactoryInst);
+
+ if (!buf) //Do not init data if it is inplace-deserialized
+ {
+ initDynamicArrays();
+ initStrings();
+ initReferences();
+ initDefaults();
+ }
+}
+
+ConvexHullParameters::~ConvexHullParameters()
+{
+ freeStrings();
+ freeReferences();
+ freeDynamicArrays();
+}
+
+void ConvexHullParameters::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->~ConvexHullParameters();
+
+ NvParameters::destroy(this, traits, doDeallocateSelf, refCount, buf);
+}
+
+const NvParameterized::DefinitionImpl* ConvexHullParameters::getParameterDefinitionTree(void)
+{
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+ if (!mBuiltFlag)
+ {
+ buildTree();
+ }
+ }
+
+ return(&ParamDefTable[0]);
+}
+
+const NvParameterized::DefinitionImpl* ConvexHullParameters::getParameterDefinitionTree(void) const
+{
+ ConvexHullParameters* tmpParam = const_cast<ConvexHullParameters*>(this);
+
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+ if (!mBuiltFlag)
+ {
+ tmpParam->buildTree();
+ }
+ }
+
+ return(&ParamDefTable[0]);
+}
+
+NvParameterized::ErrorType ConvexHullParameters::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 ConvexHullParameters::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 ConvexHullParameters::getVarPtr(const Handle& handle, void*& ptr, size_t& offset) const
+{
+ ptr = getVarPtrHelper(&ParamLookupTable[0], const_cast<ConvexHullParameters::ParametersStruct*>(&parameters()), handle, offset);
+}
+
+
+/* Dynamic Handle Indices */
+
+void ConvexHullParameters::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 ConvexHullParameters::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="vertices"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[1];
+ ParamDef->init("vertices", 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 vertices of a convex polytope.", true);
+ HintTable[1].init("shortDescription", "Convex hull vertices", true);
+ ParamDefTable[1].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=2, longName="vertices[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[2];
+ ParamDef->init("vertices", 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", "The vertices of a convex polytope.", true);
+ HintTable[1].init("shortDescription", "Convex hull vertices", true);
+ ParamDefTable[2].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=3, longName="uniquePlanes"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[3];
+ ParamDef->init("uniquePlanes", 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", "Unique planes (neglecting parallel opposites). That is, if two faces exist\n on the convex hull which have opposite normals, the plane for only one of those faces is recorded.\n The other face is implicitly recorded by a corresponding width (in the widths array). Edges and\n vertices are also recorded, explicitly defining all faces.", true);
+ HintTable[1].init("shortDescription", "Unique planes (neglecting parallel opposites)", true);
+ ParamDefTable[3].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=4, longName="uniquePlanes[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[4];
+ ParamDef->init("uniquePlanes", TYPE_STRUCT, "Plane", true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[2];
+ static Hint* HintPtrTable[2] = { &HintTable[0], &HintTable[1], };
+ HintTable[0].init("longDescription", "Unique planes (neglecting parallel opposites). That is, if two faces exist\n on the convex hull which have opposite normals, the plane for only one of those faces is recorded.\n The other face is implicitly recorded by a corresponding width (in the widths array). Edges and\n vertices are also recorded, explicitly defining all faces.", true);
+ HintTable[1].init("shortDescription", "Unique planes (neglecting parallel opposites)", true);
+ ParamDefTable[4].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=5, longName="uniquePlanes[].normal"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[5];
+ ParamDef->init("normal", 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", "A plane normal. This plane is used to define convex volumes.", true);
+ HintTable[1].init("shortDescription", "A plane normal", true);
+ ParamDefTable[5].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=6, longName="uniquePlanes[].d"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[6];
+ ParamDef->init("d", 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 plane displacement, defined by the negative of the plane normal\n dotted with a point in the plane. This plane is used to define convex volumes.", true);
+ HintTable[1].init("shortDescription", "A plane displacement", true);
+ ParamDefTable[6].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=7, longName="widths"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[7];
+ ParamDef->init("widths", 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", "For each unique plane (see uniquePlanes), this is the width of the convex polytope.\n That is, if an opposing face exists, it is the distance between the faces. If no opposing face exists,\n it is the maximum distance below the unique plane over all vertices.", true);
+ HintTable[1].init("shortDescription", "For each unique plane (see uniquePlanes), this is the width of the convex polytope", true);
+ ParamDefTable[7].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=8, longName="widths[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[8];
+ ParamDef->init("widths", 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", "For each unique plane (see uniquePlanes), this is the width of the convex polytope.\n That is, if an opposing face exists, it is the distance between the faces. If no opposing face exists,\n it is the maximum distance below the unique plane over all vertices.", true);
+ HintTable[1].init("shortDescription", "For each unique plane (see uniquePlanes), this is the width of the convex polytope", true);
+ ParamDefTable[8].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=9, longName="edges"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[9];
+ ParamDef->init("edges", 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 edges of the convex polytope, stored in a compressed index format.\n Each 32-bit integer stores the indices of two endpoints, in the high and low words. The indices\n refer to the vertices array.\n The edges are stored such that all unique edge directions are represented by the first\n uniqueEdgeDirectionCount entries.", true);
+ HintTable[1].init("shortDescription", "All edges of the convex polytope, stored in a compressed index format", true);
+ ParamDefTable[9].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=10, longName="edges[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[10];
+ ParamDef->init("edges", 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", "All edges of the convex polytope, stored in a compressed index format.\n Each 32-bit integer stores the indices of two endpoints, in the high and low words. The indices\n refer to the vertices array.\n The edges are stored such that all unique edge directions are represented by the first\n uniqueEdgeDirectionCount entries.", true);
+ HintTable[1].init("shortDescription", "All edges of the convex polytope, stored in a compressed index format", true);
+ ParamDefTable[10].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=11, longName="adjacentFaces"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[11];
+ ParamDef->init("adjacentFaces", 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", "Face (plane) indices which are adjacent to each edge in the edges array.\n Each 32-bit integer stores the indices of two faces, in the high and low words. The indices\n refer to the face planes, and will be in the range [0, planeCount). To interpret the indices\n correctly, see the description of planeCount.\n If a \"dangling edge\" is generated, the face index stored in the high word will be 0xFFFF. (Invalid value.)", true);
+ HintTable[1].init("shortDescription", "Face (plane) indices which are adjacent to each edge in the edges array.", true);
+ ParamDefTable[11].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+ ParamDef->setArraySize(-1);
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=12, longName="adjacentFaces[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[12];
+ ParamDef->init("adjacentFaces", 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", "Face (plane) indices which are adjacent to each edge in the edges array.\n Each 32-bit integer stores the indices of two faces, in the high and low words. The indices\n refer to the face planes, and will be in the range [0, planeCount). To interpret the indices\n correctly, see the description of planeCount.\n If a \"dangling edge\" is generated, the face index stored in the high word will be 0xFFFF. (Invalid value.)", true);
+ HintTable[1].init("shortDescription", "Face (plane) indices which are adjacent to each edge in the edges array.", true);
+ ParamDefTable[12].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=13, longName="bounds"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[13];
+ ParamDef->init("bounds", 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", "The AABB of the convex hull.", true);
+ HintTable[1].init("shortDescription", "The AABB of the convex hull", true);
+ ParamDefTable[13].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=14, longName="volume"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[14];
+ ParamDef->init("volume", 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", "The volume of the convex hull.", true);
+ HintTable[1].init("shortDescription", "The volume of the convex hull", true);
+ ParamDefTable[14].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=15, longName="uniqueEdgeDirectionCount"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[15];
+ ParamDef->init("uniqueEdgeDirectionCount", 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", "The number of unique edge directions. The first uniqueEdgeDirectionCount\n elements of the edges array represent these directions.", true);
+ HintTable[1].init("shortDescription", "The number of unique edge directions", true);
+ ParamDefTable[15].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=16, longName="planeCount"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[16];
+ ParamDef->init("planeCount", 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", "The total number of faces. This includes parallel opposite faces,\n so may be larger than the array size of uniquePlanes. For plane indices i less than uniquePlanes.size(),\n simply use uniquePlanes[i] to find the corresponding plane. For plane indicies i in the range\n [uniquePlanes.size(), planeCount), the uniquePlanes array is arranged such that you obtain the correct plane\n by starting with the plane p = uniquePlanes[index-uniquePlanes.size()]. Then, add widths[index-uniquePlanes.size()]\n to the plane displacement p.d, and finally negate both the plane normal p.n and the displacement p.d.", true);
+ HintTable[1].init("shortDescription", "The total number of faces", true);
+ ParamDefTable[16].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // SetChildren for: nodeIndex=0, longName=""
+ {
+ static Definition* Children[9];
+ Children[0] = PDEF_PTR(1);
+ Children[1] = PDEF_PTR(3);
+ Children[2] = PDEF_PTR(7);
+ Children[3] = PDEF_PTR(9);
+ Children[4] = PDEF_PTR(11);
+ Children[5] = PDEF_PTR(13);
+ Children[6] = PDEF_PTR(14);
+ Children[7] = PDEF_PTR(15);
+ Children[8] = PDEF_PTR(16);
+
+ ParamDefTable[0].setChildren(Children, 9);
+ }
+
+ // SetChildren for: nodeIndex=1, longName="vertices"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(2);
+
+ ParamDefTable[1].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=3, longName="uniquePlanes"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(4);
+
+ ParamDefTable[3].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=4, longName="uniquePlanes[]"
+ {
+ static Definition* Children[2];
+ Children[0] = PDEF_PTR(5);
+ Children[1] = PDEF_PTR(6);
+
+ ParamDefTable[4].setChildren(Children, 2);
+ }
+
+ // SetChildren for: nodeIndex=7, longName="widths"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(8);
+
+ ParamDefTable[7].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=9, longName="edges"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(10);
+
+ ParamDefTable[9].setChildren(Children, 1);
+ }
+
+ // SetChildren for: nodeIndex=11, longName="adjacentFaces"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(12);
+
+ ParamDefTable[11].setChildren(Children, 1);
+ }
+
+ mBuiltFlag = true;
+
+}
+void ConvexHullParameters::initStrings(void)
+{
+}
+
+void ConvexHullParameters::initDynamicArrays(void)
+{
+ vertices.buf = NULL;
+ vertices.isAllocated = true;
+ vertices.elementSize = sizeof(physx::PxVec3);
+ vertices.arraySizes[0] = 0;
+ uniquePlanes.buf = NULL;
+ uniquePlanes.isAllocated = true;
+ uniquePlanes.elementSize = sizeof(Plane_Type);
+ uniquePlanes.arraySizes[0] = 0;
+ widths.buf = NULL;
+ widths.isAllocated = true;
+ widths.elementSize = sizeof(float);
+ widths.arraySizes[0] = 0;
+ edges.buf = NULL;
+ edges.isAllocated = true;
+ edges.elementSize = sizeof(uint32_t);
+ edges.arraySizes[0] = 0;
+ adjacentFaces.buf = NULL;
+ adjacentFaces.isAllocated = true;
+ adjacentFaces.elementSize = sizeof(uint32_t);
+ adjacentFaces.arraySizes[0] = 0;
+}
+
+void ConvexHullParameters::initDefaults(void)
+{
+
+ freeStrings();
+ freeReferences();
+ freeDynamicArrays();
+ volume = float(0);
+ uniqueEdgeDirectionCount = uint32_t(0);
+ planeCount = uint32_t(0);
+
+ initDynamicArrays();
+ initStrings();
+ initReferences();
+}
+
+void ConvexHullParameters::initReferences(void)
+{
+}
+
+void ConvexHullParameters::freeDynamicArrays(void)
+{
+ if (vertices.isAllocated && vertices.buf)
+ {
+ mParameterizedTraits->free(vertices.buf);
+ }
+ if (uniquePlanes.isAllocated && uniquePlanes.buf)
+ {
+ mParameterizedTraits->free(uniquePlanes.buf);
+ }
+ if (widths.isAllocated && widths.buf)
+ {
+ mParameterizedTraits->free(widths.buf);
+ }
+ if (edges.isAllocated && edges.buf)
+ {
+ mParameterizedTraits->free(edges.buf);
+ }
+ if (adjacentFaces.isAllocated && adjacentFaces.buf)
+ {
+ mParameterizedTraits->free(adjacentFaces.buf);
+ }
+}
+
+void ConvexHullParameters::freeStrings(void)
+{
+}
+
+void ConvexHullParameters::freeReferences(void)
+{
+}
+
+} // namespace apex
+} // namespace nvidia
diff --git a/APEX_1.4/common/src/autogen/DebugColorParams.cpp b/APEX_1.4/common/src/autogen/DebugColorParams.cpp
new file mode 100644
index 00000000..72551910
--- /dev/null
+++ b/APEX_1.4/common/src/autogen/DebugColorParams.cpp
@@ -0,0 +1,1184 @@
+// 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 "DebugColorParams.h"
+#include <string.h>
+#include <stdlib.h>
+
+using namespace NvParameterized;
+
+namespace nvidia
+{
+namespace apex
+{
+
+using namespace DebugColorParamsNS;
+
+const char* const DebugColorParamsFactory::vptr =
+ NvParameterized::getVptr<DebugColorParams, DebugColorParams::ClassAlignment>();
+
+const uint32_t NumParamDefs = 37;
+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,
+};
+
+#define TENUM(type) nvidia::##type
+#define CHILDREN(index) &ParamLookupChildrenTable[index]
+static const NvParameterized::ParamLookupNode ParamLookupTable[NumParamDefs] =
+{
+ { TYPE_STRUCT, false, 0, CHILDREN(0), 36 },
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->Default), NULL, 0 }, // Default
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->PoseArrows), NULL, 0 }, // PoseArrows
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->MeshStatic), NULL, 0 }, // MeshStatic
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->MeshDynamic), NULL, 0 }, // MeshDynamic
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->Shape), NULL, 0 }, // Shape
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->Text0), NULL, 0 }, // Text0
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->Text1), NULL, 0 }, // Text1
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->ForceArrowsLow), NULL, 0 }, // ForceArrowsLow
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->ForceArrowsNorm), NULL, 0 }, // ForceArrowsNorm
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->ForceArrowsHigh), NULL, 0 }, // ForceArrowsHigh
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->Color0), NULL, 0 }, // Color0
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->Color1), NULL, 0 }, // Color1
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->Color2), NULL, 0 }, // Color2
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->Color3), NULL, 0 }, // Color3
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->Color4), NULL, 0 }, // Color4
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->Color5), NULL, 0 }, // Color5
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->Red), NULL, 0 }, // Red
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->Green), NULL, 0 }, // Green
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->Blue), NULL, 0 }, // Blue
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->DarkRed), NULL, 0 }, // DarkRed
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->DarkGreen), NULL, 0 }, // DarkGreen
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->DarkBlue), NULL, 0 }, // DarkBlue
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->LightRed), NULL, 0 }, // LightRed
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->LightGreen), NULL, 0 }, // LightGreen
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->LightBlue), NULL, 0 }, // LightBlue
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->Purple), NULL, 0 }, // Purple
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->DarkPurple), NULL, 0 }, // DarkPurple
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->Yellow), NULL, 0 }, // Yellow
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->Orange), NULL, 0 }, // Orange
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->Gold), NULL, 0 }, // Gold
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->Emerald), NULL, 0 }, // Emerald
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->White), NULL, 0 }, // White
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->Black), NULL, 0 }, // Black
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->Gray), NULL, 0 }, // Gray
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->LightGray), NULL, 0 }, // LightGray
+ { TYPE_U32, false, (size_t)(&((ParametersStruct*)0)->DarkGray), NULL, 0 }, // DarkGray
+};
+
+
+bool DebugColorParams::mBuiltFlag = false;
+NvParameterized::MutexType DebugColorParams::mBuiltFlagMutex;
+
+DebugColorParams::DebugColorParams(NvParameterized::Traits* traits, void* buf, int32_t* refCount) :
+ NvParameters(traits, buf, refCount)
+{
+ //mParameterizedTraits->registerFactory(className(), &DebugColorParamsFactoryInst);
+
+ if (!buf) //Do not init data if it is inplace-deserialized
+ {
+ initDynamicArrays();
+ initStrings();
+ initReferences();
+ initDefaults();
+ }
+}
+
+DebugColorParams::~DebugColorParams()
+{
+ freeStrings();
+ freeReferences();
+ freeDynamicArrays();
+}
+
+void DebugColorParams::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->~DebugColorParams();
+
+ NvParameters::destroy(this, traits, doDeallocateSelf, refCount, buf);
+}
+
+const NvParameterized::DefinitionImpl* DebugColorParams::getParameterDefinitionTree(void)
+{
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+ if (!mBuiltFlag)
+ {
+ buildTree();
+ }
+ }
+
+ return(&ParamDefTable[0]);
+}
+
+const NvParameterized::DefinitionImpl* DebugColorParams::getParameterDefinitionTree(void) const
+{
+ DebugColorParams* tmpParam = const_cast<DebugColorParams*>(this);
+
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+ if (!mBuiltFlag)
+ {
+ tmpParam->buildTree();
+ }
+ }
+
+ return(&ParamDefTable[0]);
+}
+
+NvParameterized::ErrorType DebugColorParams::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 DebugColorParams::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 DebugColorParams::getVarPtr(const Handle& handle, void*& ptr, size_t& offset) const
+{
+ ptr = getVarPtrHelper(&ParamLookupTable[0], const_cast<DebugColorParams::ParametersStruct*>(&parameters()), handle, offset);
+}
+
+
+/* Dynamic Handle Indices */
+
+void DebugColorParams::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 DebugColorParams::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="Default"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[1];
+ ParamDef->init("Default", 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 color value", true);
+ ParamDefTable[1].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=2, longName="PoseArrows"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[2];
+ ParamDef->init("PoseArrows", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Pose arrows color value", true);
+ ParamDefTable[2].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=3, longName="MeshStatic"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[3];
+ ParamDef->init("MeshStatic", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Static mesh color value", true);
+ ParamDefTable[3].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=4, longName="MeshDynamic"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[4];
+ ParamDef->init("MeshDynamic", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Dynamic mesh color value", true);
+ ParamDefTable[4].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=5, longName="Shape"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[5];
+ ParamDef->init("Shape", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Shape color value", true);
+ ParamDefTable[5].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=6, longName="Text0"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[6];
+ ParamDef->init("Text0", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Text0 color value", true);
+ ParamDefTable[6].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=7, longName="Text1"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[7];
+ ParamDef->init("Text1", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Text1 color value", true);
+ ParamDefTable[7].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=8, longName="ForceArrowsLow"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[8];
+ ParamDef->init("ForceArrowsLow", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Force arrows color value (low value)", true);
+ ParamDefTable[8].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=9, longName="ForceArrowsNorm"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[9];
+ ParamDef->init("ForceArrowsNorm", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Force arrows color value (normal value)", true);
+ ParamDefTable[9].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=10, longName="ForceArrowsHigh"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[10];
+ ParamDef->init("ForceArrowsHigh", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Force arrows color value (high value)", true);
+ ParamDefTable[10].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=11, longName="Color0"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[11];
+ ParamDef->init("Color0", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Color0 value", true);
+ ParamDefTable[11].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=12, longName="Color1"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[12];
+ ParamDef->init("Color1", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Color1 value", true);
+ ParamDefTable[12].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=13, longName="Color2"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[13];
+ ParamDef->init("Color2", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Color2 value", true);
+ ParamDefTable[13].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=14, longName="Color3"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[14];
+ ParamDef->init("Color3", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Color3 value", true);
+ ParamDefTable[14].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=15, longName="Color4"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[15];
+ ParamDef->init("Color4", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Color4 value", true);
+ ParamDefTable[15].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=16, longName="Color5"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[16];
+ ParamDef->init("Color5", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Color5 value", true);
+ ParamDefTable[16].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=17, longName="Red"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[17];
+ ParamDef->init("Red", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Red color value", true);
+ ParamDefTable[17].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=18, longName="Green"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[18];
+ ParamDef->init("Green", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Green color value", true);
+ ParamDefTable[18].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=19, longName="Blue"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[19];
+ ParamDef->init("Blue", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Blue color value", true);
+ ParamDefTable[19].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=20, longName="DarkRed"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[20];
+ ParamDef->init("DarkRed", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Dark red value", true);
+ ParamDefTable[20].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=21, longName="DarkGreen"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[21];
+ ParamDef->init("DarkGreen", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Dark green value", true);
+ ParamDefTable[21].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=22, longName="DarkBlue"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[22];
+ ParamDef->init("DarkBlue", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Dark blue value", true);
+ ParamDefTable[22].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=23, longName="LightRed"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[23];
+ ParamDef->init("LightRed", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Light red value", true);
+ ParamDefTable[23].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=24, longName="LightGreen"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[24];
+ ParamDef->init("LightGreen", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Light green value", true);
+ ParamDefTable[24].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=25, longName="LightBlue"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[25];
+ ParamDef->init("LightBlue", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Light blue value", true);
+ ParamDefTable[25].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=26, longName="Purple"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[26];
+ ParamDef->init("Purple", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Purple value", true);
+ ParamDefTable[26].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=27, longName="DarkPurple"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[27];
+ ParamDef->init("DarkPurple", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Dark purple value", true);
+ ParamDefTable[27].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=28, longName="Yellow"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[28];
+ ParamDef->init("Yellow", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Yellow value", true);
+ ParamDefTable[28].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=29, longName="Orange"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[29];
+ ParamDef->init("Orange", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Orange value", true);
+ ParamDefTable[29].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=30, longName="Gold"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[30];
+ ParamDef->init("Gold", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Gold value", true);
+ ParamDefTable[30].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=31, longName="Emerald"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[31];
+ ParamDef->init("Emerald", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Emerald value", true);
+ ParamDefTable[31].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=32, longName="White"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[32];
+ ParamDef->init("White", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "White value", true);
+ ParamDefTable[32].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=33, longName="Black"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[33];
+ ParamDef->init("Black", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Black value", true);
+ ParamDefTable[33].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=34, longName="Gray"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[34];
+ ParamDef->init("Gray", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Gray value", true);
+ ParamDefTable[34].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=35, longName="LightGray"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[35];
+ ParamDef->init("LightGray", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Light gray value", true);
+ ParamDefTable[35].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=36, longName="DarkGray"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[36];
+ ParamDef->init("DarkGray", TYPE_U32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "Dark gray value", true);
+ ParamDefTable[36].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // SetChildren for: nodeIndex=0, longName=""
+ {
+ static Definition* Children[36];
+ 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);
+
+ ParamDefTable[0].setChildren(Children, 36);
+ }
+
+ mBuiltFlag = true;
+
+}
+void DebugColorParams::initStrings(void)
+{
+}
+
+void DebugColorParams::initDynamicArrays(void)
+{
+}
+
+void DebugColorParams::initDefaults(void)
+{
+
+ freeStrings();
+ freeReferences();
+ freeDynamicArrays();
+ Default = uint32_t(0x00000000);
+ PoseArrows = uint32_t(0x00000000);
+ MeshStatic = uint32_t(0x00000000);
+ MeshDynamic = uint32_t(0x00000000);
+ Shape = uint32_t(0x00000000);
+ Text0 = uint32_t(0x00000000);
+ Text1 = uint32_t(0x00000000);
+ ForceArrowsLow = uint32_t(0xFFFFFF00);
+ ForceArrowsNorm = uint32_t(0xFF00FF00);
+ ForceArrowsHigh = uint32_t(0xFFFF0000);
+ Color0 = uint32_t(0x00000000);
+ Color1 = uint32_t(0x00000000);
+ Color2 = uint32_t(0x00000000);
+ Color3 = uint32_t(0x00000000);
+ Color4 = uint32_t(0x00000000);
+ Color5 = uint32_t(0x00000000);
+ Red = uint32_t(0xFFFF0000);
+ Green = uint32_t(0xFF00FF00);
+ Blue = uint32_t(0xFF0000FF);
+ DarkRed = uint32_t(0xFF800000);
+ DarkGreen = uint32_t(0xFF008000);
+ DarkBlue = uint32_t(0xFF000080);
+ LightRed = uint32_t(0xFFFF8080);
+ LightGreen = uint32_t(0xFF80FF00);
+ LightBlue = uint32_t(0xFF00FFFF);
+ Purple = uint32_t(0xFFFF00FF);
+ DarkPurple = uint32_t(0xFF800080);
+ Yellow = uint32_t(0xFFFFFF00);
+ Orange = uint32_t(0xFFFF8000);
+ Gold = uint32_t(0xFF808000);
+ Emerald = uint32_t(0xFF008080);
+ White = uint32_t(0xFFFFFFFF);
+ Black = uint32_t(0x00000000);
+ Gray = uint32_t(0xFF808080);
+ LightGray = uint32_t(0xFFC0C0C0);
+ DarkGray = uint32_t(0xFF404040);
+
+ initDynamicArrays();
+ initStrings();
+ initReferences();
+}
+
+void DebugColorParams::initReferences(void)
+{
+}
+
+void DebugColorParams::freeDynamicArrays(void)
+{
+}
+
+void DebugColorParams::freeStrings(void)
+{
+}
+
+void DebugColorParams::freeReferences(void)
+{
+}
+
+} // namespace apex
+} // namespace nvidia
diff --git a/APEX_1.4/common/src/autogen/DebugRenderParams.cpp b/APEX_1.4/common/src/autogen/DebugRenderParams.cpp
new file mode 100644
index 00000000..38f95033
--- /dev/null
+++ b/APEX_1.4/common/src/autogen/DebugRenderParams.cpp
@@ -0,0 +1,632 @@
+// 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 "DebugRenderParams.h"
+#include <string.h>
+#include <stdlib.h>
+
+using namespace NvParameterized;
+
+namespace nvidia
+{
+namespace apex
+{
+
+using namespace DebugRenderParamsNS;
+
+const char* const DebugRenderParamsFactory::vptr =
+ NvParameterized::getVptr<DebugRenderParams, DebugRenderParams::ClassAlignment>();
+
+const uint32_t NumParamDefs = 13;
+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,
+};
+
+#define TENUM(type) nvidia::##type
+#define CHILDREN(index) &ParamLookupChildrenTable[index]
+static const NvParameterized::ParamLookupNode ParamLookupTable[NumParamDefs] =
+{
+ { TYPE_STRUCT, false, 0, CHILDREN(0), 11 },
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->Enable), NULL, 0 }, // Enable
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->Scale), NULL, 0 }, // Scale
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->LodBenefits), NULL, 0 }, // LodBenefits
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->RelativeLodBenefitsScreenPos), NULL, 0 }, // RelativeLodBenefitsScreenPos
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->RelativeLodBenefitsThickness), NULL, 0 }, // RelativeLodBenefitsThickness
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->LodDistanceScale), NULL, 0 }, // LodDistanceScale
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->RenderNormals), NULL, 0 }, // RenderNormals
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->RenderTangents), NULL, 0 }, // RenderTangents
+ { TYPE_F32, false, (size_t)(&((ParametersStruct*)0)->RenderBitangents), NULL, 0 }, // RenderBitangents
+ { TYPE_BOOL, false, (size_t)(&((ParametersStruct*)0)->Bounds), NULL, 0 }, // Bounds
+ { TYPE_ARRAY, true, (size_t)(&((ParametersStruct*)0)->moduleName), CHILDREN(11), 1 }, // moduleName
+ { TYPE_REF, false, 1 * sizeof(NvParameterized::Interface*), NULL, 0 }, // moduleName[]
+};
+
+
+bool DebugRenderParams::mBuiltFlag = false;
+NvParameterized::MutexType DebugRenderParams::mBuiltFlagMutex;
+
+DebugRenderParams::DebugRenderParams(NvParameterized::Traits* traits, void* buf, int32_t* refCount) :
+ NvParameters(traits, buf, refCount)
+{
+ //mParameterizedTraits->registerFactory(className(), &DebugRenderParamsFactoryInst);
+
+ if (!buf) //Do not init data if it is inplace-deserialized
+ {
+ initDynamicArrays();
+ initStrings();
+ initReferences();
+ initDefaults();
+ }
+}
+
+DebugRenderParams::~DebugRenderParams()
+{
+ freeStrings();
+ freeReferences();
+ freeDynamicArrays();
+}
+
+void DebugRenderParams::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->~DebugRenderParams();
+
+ NvParameters::destroy(this, traits, doDeallocateSelf, refCount, buf);
+}
+
+const NvParameterized::DefinitionImpl* DebugRenderParams::getParameterDefinitionTree(void)
+{
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+ if (!mBuiltFlag)
+ {
+ buildTree();
+ }
+ }
+
+ return(&ParamDefTable[0]);
+}
+
+const NvParameterized::DefinitionImpl* DebugRenderParams::getParameterDefinitionTree(void) const
+{
+ DebugRenderParams* tmpParam = const_cast<DebugRenderParams*>(this);
+
+ if (!mBuiltFlag) // Double-checked lock
+ {
+ NvParameterized::MutexType::ScopedLock lock(mBuiltFlagMutex);
+ if (!mBuiltFlag)
+ {
+ tmpParam->buildTree();
+ }
+ }
+
+ return(&ParamDefTable[0]);
+}
+
+NvParameterized::ErrorType DebugRenderParams::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 DebugRenderParams::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 DebugRenderParams::getVarPtr(const Handle& handle, void*& ptr, size_t& offset) const
+{
+ ptr = getVarPtrHelper(&ParamLookupTable[0], const_cast<DebugRenderParams::ParametersStruct*>(&parameters()), handle, offset);
+}
+
+
+/* Dynamic Handle Indices */
+/* [0] - moduleName (not an array of structs) */
+
+void DebugRenderParams::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 DebugRenderParams::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="Enable"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[1];
+ ParamDef->init("Enable", 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 debug rendering", true);
+ ParamDefTable[1].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=2, longName="Scale"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[2];
+ 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", "Debug rendering scale", true);
+ ParamDefTable[2].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=3, longName="LodBenefits"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[3];
+ ParamDef->init("LodBenefits", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "LOD benefit debug visualization", true);
+ ParamDefTable[3].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=4, longName="RelativeLodBenefitsScreenPos"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[4];
+ ParamDef->init("RelativeLodBenefitsScreenPos", 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[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(-1.0), true);
+ HintTable[2].init("shortDescription", "The y-axis value of the relative benefits bar (-1.0 - 1.0)", true);
+ ParamDefTable[4].setHints((const NvParameterized::Hint**)HintPtrTable, 3);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=5, longName="RelativeLodBenefitsThickness"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[5];
+ ParamDef->init("RelativeLodBenefitsThickness", 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 scale of the relative benefits bar", true);
+ ParamDefTable[5].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=6, longName="LodDistanceScale"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[6];
+ ParamDef->init("LodDistanceScale", TYPE_F32, NULL, true);
+
+#ifdef NV_PARAMETERIZED_HIDE_DESCRIPTIONS
+
+#else
+
+ static HintImpl HintTable[1];
+ static Hint* HintPtrTable[1] = { &HintTable[0], };
+ HintTable[0].init("shortDescription", "LOD distance debug visualization", true);
+ ParamDefTable[6].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=7, longName="RenderNormals"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[7];
+ ParamDef->init("RenderNormals", 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 normals (blue) of the rendered mesh. (scalable)", true);
+ ParamDefTable[7].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=8, longName="RenderTangents"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[8];
+ ParamDef->init("RenderTangents", 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 tangents (red) of the rendered mesh. (scalable)", true);
+ ParamDefTable[8].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=9, longName="RenderBitangents"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[9];
+ ParamDef->init("RenderBitangents", 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 bitangents (green) of the rendered mesh. (scalable)", true);
+ ParamDefTable[9].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=10, longName="Bounds"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[10];
+ ParamDef->init("Bounds", 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 bounds of every apex actor", true);
+ ParamDefTable[10].setHints((const NvParameterized::Hint**)HintPtrTable, 1);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+
+
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=11, longName="moduleName"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[11];
+ ParamDef->init("moduleName", 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[11].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", "Module name", true);
+ ParamDefTable[11].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+ static const char* const RefVariantVals[] = { "BasicFSDebugRenderParams", "BasicIosDebugRenderParams", "ParticleIosDebugRenderParams", "ClothingDebugRenderParams", "DestructibleDebugRenderParams", "EmitterDebugRenderParams", "ForceFieldDebugRenderParams", "IofxDebugRenderParams", "TurbulenceFSDebugRenderParams", "ParticlesDebugRenderParams" };
+ ParamDefTable[11].setRefVariantVals((const char**)RefVariantVals, 10);
+
+
+ ParamDef->setArraySize(-1);
+ static const uint8_t dynHandleIndices[1] = { 0, };
+ ParamDef->setDynamicHandleIndicesMap(dynHandleIndices, 1);
+
+ }
+
+ // Initialize DefinitionImpl node: nodeIndex=12, longName="moduleName[]"
+ {
+ NvParameterized::DefinitionImpl* ParamDef = &ParamDefTable[12];
+ ParamDef->init("moduleName", 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[12].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", "Module name", true);
+ ParamDefTable[12].setHints((const NvParameterized::Hint**)HintPtrTable, 2);
+
+#endif /* NV_PARAMETERIZED_HIDE_DESCRIPTIONS */
+
+
+ static const char* const RefVariantVals[] = { "BasicFSDebugRenderParams", "BasicIosDebugRenderParams", "ParticleIosDebugRenderParams", "ClothingDebugRenderParams", "DestructibleDebugRenderParams", "EmitterDebugRenderParams", "ForceFieldDebugRenderParams", "IofxDebugRenderParams", "TurbulenceFSDebugRenderParams", "ParticlesDebugRenderParams" };
+ ParamDefTable[12].setRefVariantVals((const char**)RefVariantVals, 10);
+
+
+
+ }
+
+ // 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);
+ }
+
+ // SetChildren for: nodeIndex=11, longName="moduleName"
+ {
+ static Definition* Children[1];
+ Children[0] = PDEF_PTR(12);
+
+ ParamDefTable[11].setChildren(Children, 1);
+ }
+
+ mBuiltFlag = true;
+
+}
+void DebugRenderParams::initStrings(void)
+{
+}
+
+void DebugRenderParams::initDynamicArrays(void)
+{
+ moduleName.buf = NULL;
+ moduleName.isAllocated = true;
+ moduleName.elementSize = sizeof(NvParameterized::Interface*);
+ moduleName.arraySizes[0] = 0;
+}
+
+void DebugRenderParams::initDefaults(void)
+{
+
+ freeStrings();
+ freeReferences();
+ freeDynamicArrays();
+ Enable = bool(false);
+ Scale = float(0);
+ LodBenefits = float(0);
+ RelativeLodBenefitsScreenPos = float(-0.8);
+ RelativeLodBenefitsThickness = float(0.6);
+ LodDistanceScale = float(0);
+ RenderNormals = float(0);
+ RenderTangents = float(0);
+ RenderBitangents = float(0);
+ Bounds = bool(false);
+
+ initDynamicArrays();
+ initStrings();
+ initReferences();
+}
+
+void DebugRenderParams::initReferences(void)
+{
+}
+
+void DebugRenderParams::freeDynamicArrays(void)
+{
+ if (moduleName.isAllocated && moduleName.buf)
+ {
+ mParameterizedTraits->free(moduleName.buf);
+ }
+}
+
+void DebugRenderParams::freeStrings(void)
+{
+}
+
+void DebugRenderParams::freeReferences(void)
+{
+
+ for (int i = 0; i < moduleName.arraySizes[0]; ++i)
+ {
+ if (moduleName.buf[i])
+ {
+ moduleName.buf[i]->destroy();
+ }
+ }
+}
+
+} // namespace apex
+} // namespace nvidia
diff --git a/APEX_1.4/common/src/variable_oscillator.cpp b/APEX_1.4/common/src/variable_oscillator.cpp
new file mode 100644
index 00000000..50dcbb2f
--- /dev/null
+++ b/APEX_1.4/common/src/variable_oscillator.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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 "Apex.h"
+#include "variable_oscillator.h"
+#include "PxMath.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+variableOscillator::variableOscillator(float min, float max, float initial, float period) :
+ mMin(min),
+ mMax(max),
+ mPeriod(period),
+ mStartVal(initial),
+ mLastVal(initial)
+{
+ mCumTime = 0.0f;
+ mGoingUp = true;
+ mEndVal = computeEndVal(mMin, mMax);
+}
+
+
+variableOscillator::~variableOscillator()
+{
+}
+
+float variableOscillator::computeEndVal(float current, float maxOrMin)
+{
+ float target;
+ float maxDelta;
+ float quarterVal;
+
+ // compute the max range of the oscillator
+ maxDelta = maxOrMin - current;
+ // find the 'lower bound' of the oscillator peak
+ quarterVal = current + (maxDelta / 4.0f);
+ // get a rand between 0 and 1
+ target = (float) ::rand() / (float) RAND_MAX;
+ // scale the rand to the range we want
+ target = target * PxAbs(quarterVal - maxOrMin);
+ // add the offset to the scaled random number.
+ if (current < maxOrMin)
+ {
+ target = target + quarterVal;
+ }
+ else
+ {
+ target = quarterVal - target;
+ }
+ return(target);
+}
+
+float variableOscillator::updateVariableOscillator(float deltaTime)
+{
+ float returnVal;
+ float halfRange;
+
+ mCumTime += deltaTime;
+
+ // has the function crossed a max or a min?
+ if ((mGoingUp && (mCumTime > (mPeriod / 2.0f))) ||
+ (!mGoingUp && (mCumTime > mPeriod)))
+ {
+ mStartVal = mLastVal;
+ if (mGoingUp)
+ {
+ mEndVal = computeEndVal(mStartVal, mMin);
+ }
+ else
+ {
+ mEndVal = computeEndVal(mStartVal, mMax);
+ mCumTime = mCumTime - mPeriod;
+ }
+ mGoingUp = !mGoingUp;
+ }
+ halfRange = 0.5f * PxAbs(mEndVal - mStartVal);
+ returnVal = -halfRange * PxCos(mCumTime * PxTwoPi / mPeriod) + halfRange + PxMin(mStartVal, mEndVal);
+ mLastVal = returnVal;
+
+ return(returnVal);
+}
+
+}
+} // namespace nvidia::apex